Remove murano_tempest_tests from murano repo

Change-Id: I5da1c660393df335f8d5e8ab17b23bb21a8e3257
This commit is contained in:
zhurong 2017-12-04 15:18:38 +08:00
parent 05d95df793
commit 1ea1cda5d4
64 changed files with 83 additions and 6232 deletions

View File

@ -28,7 +28,7 @@ from murano.dsl import murano_package as dsl_package
from murano.engine import package_loader
from murano.packages import exceptions as pkg_exc
from murano.tests.unit import base
from murano_tempest_tests import utils
from murano.tests.unit import utils
class TestPackageCache(base.MuranoTestCase):

View File

@ -13,10 +13,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import shutil
import yaml
import zipfile
from murano import context
from murano.db import session
MANIFEST = {'Format': 'MuranoPL/1.0',
'Type': 'Application',
'Description': 'MockApp for API tests',
'Author': 'Mirantis, Inc'}
def dummy_context(user='test_username', tenant_id='test_tenant_id',
request_id='dummy-request', **kwargs):
@ -35,3 +46,74 @@ def save_models(*models):
s = session.get_session()
for m in models:
m.save(s)
def compose_package(app_name, package_dir,
require=None, archive_dir=None, add_class_name=False,
manifest_required=True, version=None):
"""Composes a murano package
Composes package `app_name` manifest and files from `package_dir`.
Includes `require` section if any in the manifest file.
Puts the resulting .zip file into `archive_dir` if present or in the
`package_dir`.
"""
tmp_package_dir = os.path.join(archive_dir, os.path.basename(package_dir))
shutil.copytree(package_dir, tmp_package_dir)
package_dir = tmp_package_dir
if manifest_required:
manifest = os.path.join(package_dir, "manifest.yaml")
with open(manifest, 'w') as f:
fqn = 'io.murano.apps.' + app_name
mfest_copy = MANIFEST.copy()
mfest_copy['FullName'] = fqn
mfest_copy['Name'] = app_name
mfest_copy['Classes'] = {fqn: 'mock_muranopl.yaml'}
if require:
mfest_copy['Require'] = {str(name): version
for name, version in require}
if version:
mfest_copy['Version'] = version
f.write(yaml.dump(mfest_copy, default_flow_style=False))
if add_class_name:
class_file = os.path.join(package_dir, 'Classes', 'mock_muranopl.yaml')
with open(class_file, 'r') as f:
contents = f.read()
index = contents.index('Extends')
contents = "{0}Name: {1}\n\n{2}".format(contents[:index], app_name,
contents[index:])
with open(class_file, 'w') as f:
f.write(contents)
if require:
class_file = os.path.join(package_dir, 'Classes', 'mock_muranopl.yaml')
with open(class_file, 'r') as f:
content = f.read()
index_string = 'deploy:\n Body:\n '
index = content.index(index_string) + len(index_string)
class_names = [req[0][req[0].rfind('.') + 1:] for req in require]
addition = "".join(["- new({})\n".format(name) + ' ' * 6
for name in class_names])
content = content[:index] + addition + content[index:]
with open(class_file, 'w') as f:
f.write(content)
name = app_name + '.zip'
if not archive_dir:
archive_dir = os.path.dirname(os.path.abspath(__file__))
archive_path = os.path.join(archive_dir, name)
with zipfile.ZipFile(archive_path, 'w') as zip_file:
for root, dirs, files in os.walk(package_dir):
for f in files:
zip_file.write(
os.path.join(root, f),
arcname=os.path.join(os.path.relpath(root, package_dir), f)
)
return archive_path, name

View File

@ -1,72 +0,0 @@
# Copyright (c) 2015 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.
from tempest.common import credentials_factory as common_creds
from tempest import config
from tempest.lib import auth
from murano_tempest_tests.services.application_catalog \
import application_catalog_client
from murano_tempest_tests.services.artifacts import artifacts_client
from murano_tempest_tests.services.service_broker import service_broker_client
CONF = config.CONF
class Manager(object):
def __init__(self,
credentials=None):
if credentials is None:
credentials = common_creds.\
get_configured_admin_credentials('identity_admin')
self.auth_provider = get_auth_provider(credentials)
self.service_broker_client = service_broker_client.ServiceBrokerClient(
self.auth_provider)
if CONF.application_catalog.glare_backend:
self.artifacts_client = artifacts_client.ArtifactsClient(
self.auth_provider)
else:
self.artifacts_client = None
self.application_catalog_client = \
application_catalog_client.ApplicationCatalogClient(
self.auth_provider)
class AltManager(Manager):
def __init__(self, service=None):
super(AltManager, self).__init__(
common_creds.get_configured_admin_credentials('alt_user'), service)
def get_auth_provider(credentials, scope='project'):
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
}
if isinstance(credentials, auth.KeystoneV3Credentials):
auth_provider_class, auth_url = \
auth.KeystoneV3AuthProvider, CONF.identity.uri_v3
else:
auth_provider_class, auth_url = \
auth.KeystoneV2AuthProvider, CONF.identity.uri
_auth_provider = auth_provider_class(credentials, auth_url,
scope=scope,
**default_params)
_auth_provider.set_auth()
return _auth_provider

View File

@ -1,132 +0,0 @@
# Copyright (c) 2015 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.
from oslo_config import cfg
service_option = [
cfg.BoolOpt("murano",
default=True,
help="Whether or not murano is expected to be available"),
cfg.BoolOpt("murano_cfapi",
default=False,
help="Whether or not murano-cfapi is expected to be "
"unavailable by default"),
cfg.BoolOpt("glare",
default=False,
help="Whether or not glare is expected to be unavailable")
]
application_catalog_group = cfg.OptGroup(name="application_catalog",
title="Application Catalog Options")
service_broker_group = cfg.OptGroup(name="service_broker",
title="Service Broker Options")
artifacts_group = cfg.OptGroup(name="artifacts",
title="Glance Artifacts Options")
ApplicationCatalogGroup = [
# Application catalog tempest configuration
cfg.StrOpt("region",
default="",
help="The application_catalog 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("linux_image",
default="debian-8-m-agent.qcow2",
help="Image for linux services"),
cfg.StrOpt("catalog_type",
default="application-catalog",
help="Catalog type of Application Catalog."),
cfg.StrOpt("endpoint_type",
default="publicURL",
choices=["publicURL", "adminURL", "internalURL"],
help="The endpoint type for application catalog service."),
cfg.IntOpt("build_interval",
default=3,
help="Time in seconds between application catalog"
" availability checks."),
cfg.IntOpt("build_timeout",
default=500,
help="Timeout in seconds to wait for a application catalog"
" to become available."),
cfg.BoolOpt("glare_backend",
default=False,
help="Tells tempest about murano glare backend "
"configuration."),
cfg.BoolOpt("cinder_volume_tests",
default=False,
help="Whether or not cinder volumes attachment tests "
"are expected to run"),
cfg.BoolOpt("deployment_tests",
default=False,
help="Whether or not deployment tests are expected to run")
]
ServiceBrokerGroup = [
# Test runs control
cfg.BoolOpt("run_service_broker_tests",
default=False,
help="Defines whether run service broker api tests or not"),
cfg.StrOpt("catalog_type",
default="service-broker",
help="Catalog type of Service Broker API"),
cfg.StrOpt("endpoint_type",
default="publicURL",
choices=["publicURL", "adminURL", "internalURL"],
help="The endpoint type for service broker service"),
cfg.IntOpt("build_interval",
default=3,
help="Time in seconds between service broker"
" availability checks."),
cfg.IntOpt("build_timeout",
default=500,
help="Timeout in seconds to wait for a service broker"
" to become available.")
]
ArtifactsGroup = [
# Glance artifacts options
cfg.StrOpt("catalog_type",
default="artifact",
help="Catalog type of Artifacts API"),
cfg.StrOpt("endpoint_type",
default="publicURL",
choices=["publicURL", "adminURL", "internalURL"],
help="The endpoint type for artifacts service"),
cfg.IntOpt("build_interval",
default=3,
help="Time in seconds between artifacts"
" availability checks."),
cfg.IntOpt("build_timeout",
default=500,
help="Timeout in seconds to wait for a artifacts"
" to become available.")
]

View File

@ -1,47 +0,0 @@
Namespaces:
=: io.murano.apps
std: io.murano
Extends: std:Application
Properties:
userName:
Contract: $.string()
greeting:
Usage: Static
Contract: $.string()
Default: 'Hello, '
Methods:
testAction:
Scope: Public
Body:
- $this.find(std:Environment).reporter.report($this, 'Completed')
getCredentials:
Scope: Public
Body:
- Return:
credentials:
uri: localhost
deploy:
Body:
- $this.find(std:Environment).reporter.report($this, 'Follow the white rabbit')
staticAction:
Scope: Public
Usage: Static
Arguments:
- myName:
Contract: $.string().notNull()
Body:
- Return: concat($.greeting, $myName)
staticNotAction:
Usage: Static
Arguments:
- myName:
Contract: $.string().notNull()
Body:
- Return: concat($.greeting, $myName)

View File

@ -1,22 +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.
Version: 2.2
Forms:
- appConfiguration:
fields:
- name: license
type: string
description: Apache License, Version 2.0
hidden: false
required: false

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,81 +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.
Namespaces:
=: io.murano.apps.test
std: io.murano
res: io.murano.resources
sys: io.murano.system
conf: io.murano.configuration
Name: ApacheHttpServerCustom
Extends: std:Application
Properties:
name:
Contract: $.string().notNull()
instance:
Contract: $.class(res:Instance).notNull()
userName:
Contract: $.string()
Methods:
initialize:
Body:
- $._environment: $.find(std:Environment).require()
deploy:
Body:
- If: not $.getAttr(deployed, false)
Then:
- $._environment.reporter.report($this, 'Creating VM for Apache Server.')
- $securityGroupIngress:
- ToPort: 80
FromPort: 80
IpProtocol: tcp
External: true
- ToPort: 443
FromPort: 443
IpProtocol: tcp
External: true
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
- $.instance.deploy()
- $._environment.reporter.report($this, 'Instance is created. Deploying Apache')
- $resources: new(sys:Resources)
- $linux: new(conf:Linux)
- $linux.runCommand($.instance.agent, 'apt-get -y install apache2')
- $linux.runCommand($.instance.agent, 'iptables -I INPUT 1 -p tcp --dport 443 -j ACCEPT')
- $linux.runCommand($.instance.agent, 'iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT')
- $._environment.reporter.report($this, 'Apache is installed.')
- If: $.userName != ''
Then:
- $linux.runCommand($.instance.agent, 'service apache2 stop')
- $fileReplacements:
"%USER_NAME%": $.userName
- $fileContent: $resources.string('index.html').replace($fileReplacements)
- $linux.putFile($.instance.agent, $fileContent, '/var/www/html/index.html')
- $linux.runCommand($.instance.agent, 'service apache2 start')
- If: $.instance.assignFloatingIp
Then:
- $host: $.instance.floatingIpAddress
Else:
- $host: $.instance.ipAddresses[0]
- $._environment.reporter.report($this, format('Apache is available at http://{0}', $host))
- $.setAttr(deployed, true)

View File

@ -1,8 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title> Hello World</title>
</head>
<body>Hello world. This is my first web page. My name is %USER_NAME%.
</body>
</html>

View File

@ -1,28 +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.
Format: 1.0
Type: Application
FullName: io.murano.test.apache.ApacheHttpServerCustom
Name: Apache HTTP Server Custom
Description: |
The Apache HTTP Server Project is an effort to develop and maintain an
open-source HTTP server for modern operating systems including UNIX and
Windows NT. The goal of this project is to provide a secure, efficient and
extensible server that provides HTTP services in sync with the current HTTP
standards.
Apache httpd has been the most popular web server on the Internet since
April 1996, and celebrated its 17th birthday as a project this February.
Author: 'Mirantis, Inc'
Tags: [HTTP, Server, WebServer, HTML, Apache]
Classes:
io.murano.apps.test.ApacheHttpServerCustom: ApacheHttpServer.yaml

View File

@ -1,55 +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.
Namespaces:
=: io.murano.apps.test
std: io.murano
sys: io.murano.system
Name: Lighttpd
Extends: std:Application
Properties:
updater:
Contract: $.class(UpdateExecutor).notNull()
Methods:
initialize:
Body:
- $._environment: $.find(std:Environment).require()
deploy:
Body:
- If: not $.getAttr(deployed, false)
Then:
- $securityGroupIngress:
- ToPort: 80
FromPort: 80
IpProtocol: tcp
External: true
- ToPort: 443
FromPort: 443
IpProtocol: tcp
External: true
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
- $._environment.reporter.report($this, 'Ensuring Updater is deployed.')
- $.updater.deploy()
- $resources: new(sys:Resources)
- $template: $resources.yaml('DeployLighttpd.template')
- $.updater.instance.agent.call($template, $resources)
- If: $.updater.instance.assignFloatingIp
Then:
- $address: $.updater.instance.floatingIpAddress
- $._environment.reporter.report($this, format('Running at http://{0}', $address))
- $.setAttr(deployed, true)

View File

@ -1,27 +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.
FormatVersion: 2.0.0
Version: 1.0.0
Name: Deploy Lighttpd
Body: |
deploy()
Scripts:
deploy:
Type: Application
Version: 1.0.0
EntryPoint: deployLighttpd.sh
Options:
captureStdout: true
captureStderr: true

View File

@ -1,14 +0,0 @@
#!/bin/bash
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
sudo apt-get -y -q install lighttpd

View File

@ -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.
Format: 1.0
Type: Application
FullName: io.murano.apps.test.Lighttpd
Name: Lighttpd
Description: |
Lighttpd... :)
Author: 'Mirantis, Inc'
Tags: [Web]
Classes:
io.murano.apps.test.Lighttpd: Lighttpd.yaml
Require:
io.murano.apps.test.UpdateExecutor:

View File

@ -1,47 +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.
Namespaces:
=: io.murano.apps.test
std: io.murano
res: io.murano.resources
sys: io.murano.system
conf: io.murano.configuration
Name: UpdateExecutor
Extends: std:Application
Properties:
name:
Contract: $.string().notNull()
instance:
Contract: $.class(res:Instance).notNull()
Methods:
initialize:
Body:
- $._environment: $.find(std:Environment).require()
deploy:
Body:
- If: not $.getAttr(deployed, false)
Then:
- $._environment.reporter.report($this, 'Creating VM.')
- $.instance.deploy()
- $._environment.reporter.report($this, 'Starting packages updating.')
- $file: sys:Resources.string('scripts/update.sh')
- conf:Linux.runCommand($.instance.agent, $file)
- $._environment.reporter.report($this, 'Update completed.')
- $.setAttr(deployed, true)

View File

@ -1,14 +0,0 @@
#!/bin/bash
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
sudo apt-get update

View File

@ -1,22 +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.
Format: 1.0
Type: Application
FullName: io.murano.apps.test.UpdateExecutor
Name: Update Executor
Description: |
Test application, which updates packages on VM
Author: 'Mirantis, Inc'
Tags: [application]
Classes:
io.murano.apps.test.UpdateExecutor: UpdateExecutor.yaml

View File

@ -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.
Namespaces:
=: io.murano.apps.test
std: io.murano
res: io.murano.resources
sys: io.murano.system
conf: io.murano.configuration
Name: VM
Extends: std:Application
Properties:
name:
Contract: $.string().notNull()
instance:
Contract: $.class(res:Instance).notNull()
userName:
Contract: $.string()
Methods:
initialize:
Body:
- $._environment: $.find(std:Environment).require()
deploy:
Body:
- If: not $.getAttr(deployed, false)
Then:
- $._environment.reporter.report($this, 'Creating VM')
- $securityGroupIngress:
- ToPort: 80
FromPort: 80
IpProtocol: tcp
External: true
- ToPort: 443
FromPort: 443
IpProtocol: tcp
External: true
- $._environment.securityGroupManager.addGroupIngress($securityGroupIngress)
- $.instance.deploy()
- $._environment.reporter.report($this, 'Instance is created.')
- $resources: new(sys:Resources)
- $linux: new(conf:Linux)
- If: $.instance.assignFloatingIp
Then:
- $host: $.instance.floatingIpAddress
Else:
- $host: $.instance.ipAddresses[0]
- $.setAttr(deployed, true)

View File

@ -1,8 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title> Hello World</title>
</head>
<body>Hello world. This is my first web page. My name is %USER_NAME%.
</body>
</html>

View File

@ -1,22 +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.
Format: 1.0
Type: Application
FullName: io.murano.test.VM.VM
Name: VM
Description: |
application which simply boot a virtual machine
Author: 'Mirantis, Inc'
Tags: [Server]
Classes:
io.murano.apps.test.VM: VM.yaml

View File

@ -1,54 +0,0 @@
# Copyright (c) 2015 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 os
from tempest import config
from tempest.test_discover import plugins
from murano_tempest_tests import config as config_application_catalog
class MuranoTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
base_path = os.path.split(os.path.dirname(
os.path.abspath(__file__)))[0]
test_dir = "murano_tempest_tests/tests"
full_test_dir = os.path.join(base_path, test_dir)
return full_test_dir, base_path
def register_opts(self, conf):
config.register_opt_group(
conf, config.service_available_group,
config_application_catalog.service_option)
config.register_opt_group(
conf, config_application_catalog.application_catalog_group,
config_application_catalog.ApplicationCatalogGroup)
config.register_opt_group(
conf, config_application_catalog.service_broker_group,
config_application_catalog.ServiceBrokerGroup)
config.register_opt_group(
conf, config_application_catalog.artifacts_group,
config_application_catalog.ArtifactsGroup)
def get_opt_lists(self):
return [(config_application_catalog.application_catalog_group.name,
config_application_catalog.ApplicationCatalogGroup),
(config_application_catalog.service_broker_group.name,
config_application_catalog.ServiceBrokerGroup),
(config.service_available_group.name,
config_application_catalog.service_option),
(config_application_catalog.artifacts_group.name,
config_application_catalog.ArtifactsGroup)]

View File

@ -1,449 +0,0 @@
# Copyright (c) 2015 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 json
import os
import requests
from tempest import config
from tempest.lib.common import rest_client
from murano_tempest_tests import utils
CONF = config.CONF
class ApplicationCatalogClient(rest_client.RestClient):
"""Tempest REST client for Murano Application Catalog"""
def __init__(self, auth_provider):
super(ApplicationCatalogClient, self).__init__(
auth_provider,
CONF.application_catalog.catalog_type,
CONF.identity.region,
endpoint_type=CONF.application_catalog.endpoint_type)
self.build_interval = CONF.application_catalog.build_interval
self.build_timeout = CONF.application_catalog.build_timeout
# -----------------------------Packages methods--------------------------------
def upload_package(self, package_name, package_path, top_dir, body):
"""Upload a Murano package into Murano repository
:param package_name: Package name
:param package_path: Path with .zip relatively top_dir
:param top_dir: Top directory with tests
:param body: dict of tags, parameters, etc
:return:
"""
headers = {'X-Auth-Token': self.auth_provider.get_token()}
files = open(os.path.join(top_dir, package_path), 'rb')
uri = "/v1/catalog/packages"
post_body = {'JsonString': json.dumps(body)}
endpoint = self.base_url
url = endpoint + uri
resp = requests.post(url, files={package_name: files}, data=post_body,
headers=headers, timeout=self.build_timeout)
self.expected_success(200, resp.status_code)
return self._parse_resp(resp.text)
def update_package(self, package_id, post_body):
headers = {
'content-type': 'application/murano-packages-json-patch'
}
uri = 'v1/catalog/packages/{0}'.format(package_id)
resp, body = self.patch(uri, json.dumps(post_body), headers=headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_package(self, package_id):
"""Removes a package from a repository
:param package_id: Package ID
"""
uri = 'v1/catalog/packages/{0}'.format(package_id)
resp, body = self.delete(uri)
self.expected_success(200, resp.status)
def get_package(self, package_id):
uri = 'v1/catalog/packages/{0}'.format(package_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_list_packages(self):
uri = 'v1/catalog/packages'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def download_package(self, package_id):
headers = {
'content-type': 'application/octet-stream'
}
uri = 'v1/catalog/packages/{0}/download'.format(package_id)
resp, body = self.get(uri, headers=headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_ui_definition(self, package_id):
headers = {
'content-type': 'application/octet-stream'
}
uri = 'v1/catalog/packages/{0}/ui'.format(package_id)
resp, body = self.get(uri, headers=headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_logo(self, package_id):
headers = {
'content-type': 'application/octet-stream'
}
uri = 'v1/catalog/packages/{0}/ui'.format(package_id)
resp, body = self.get(uri, headers=headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
# -----------------------Methods for environment CRUD--------------------------
def get_environments_list(self):
uri = 'v1/environments'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_environment(self, name):
uri = 'v1/environments'
post_body = {'name': name}
resp, body = self.post(uri, json.dumps(post_body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_environment(self, environment_id):
uri = 'v1/environments/{0}'.format(environment_id)
resp, body = self.delete(uri)
self.expected_success(200, resp.status)
def abandon_environment(self, environment_id):
uri = 'v1/environments/{0}?abandon=True'.format(environment_id)
resp, body = self.delete(uri)
self.expected_success(200, resp.status)
def update_environment(self, environment_id):
uri = 'v1/environments/{0}'.format(environment_id)
name = utils.generate_name("updated_env")
post_body = {"name": name}
resp, body = self.put(uri, json.dumps(post_body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_environment(self, environment_id):
uri = 'v1/environments/{0}'.format(environment_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_environment_model(self, environment_id, path='/', session_id=None):
headers = self.get_headers()
if session_id:
headers.update(
{'X-Configuration-Session': session_id}
)
uri = '/v1/environments/{id}/model/{path}'.format(
id=environment_id, path=path)
resp, body = self.get(uri, headers=headers)
self.expected_success(200, resp.status)
return json.loads(body)
def update_environment_model(self, environment_id, data, session_id):
headers = self.get_headers(send_type='env-model-json-patch')
headers.update(
{'X-Configuration-Session': session_id}
)
uri = '/v1/environments/{id}/model/'.format(id=environment_id)
resp, body = self.patch(uri, json.dumps(data), headers=headers)
self.expected_success(200, resp.status)
return json.loads(body)
# -----------------------Methods for session manage ---------------------------
def create_session(self, environment_id):
body = None
uri = 'v1/environments/{0}/configure'.format(environment_id)
resp, body = self.post(uri, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_session(self, environment_id, session_id):
uri = 'v1/environments/{0}/sessions/{1}'.format(environment_id,
session_id)
resp, body = self.delete(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_session(self, environment_id, session_id):
uri = 'v1/environments/{0}/sessions/{1}'.format(environment_id,
session_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def deploy_session(self, environment_id, session_id):
body = None
url = 'v1/environments/{0}/sessions/{1}/deploy'.format(environment_id,
session_id)
resp, body = self.post(url, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
# ----------------------------Deployment methods-------------------------------
def list_deployments(self, environment_id):
uri = 'v1/environments/{0}/deployments'.format(
environment_id)
body = None
resp, body = self.get(uri, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_deployment_statuses(self, environment_id, deployment_id):
uri = 'v1/environments/{0}/deployments/{1}'.format(
environment_id, deployment_id)
body = None
resp, body = self.get(uri, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_all_deployments(self):
uri = 'v1/deployments'
body = None
resp, body = self.get(uri, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
# -----------------------------Service methods---------------------------------
def create_service(self, environment_id, session_id, post_body):
headers = self.get_headers()
headers.update(
{'X-Configuration-Session': session_id}
)
uri = 'v1/environments/{0}/services'.format(environment_id)
resp, body = self.post(uri, json.dumps(post_body), headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_services(self, environment_id, session_id, put_body=None):
headers = self.get_headers()
headers.update(
{'X-Configuration-Session': session_id}
)
uri = 'v1/environments/{0}/services'.format(environment_id)
resp, body = self.put(uri, json.dumps(put_body), headers)
self.expected_success(200, resp.status)
# TODO(freerunner): Need to replace json.loads() to _parse_resp
# method, when fix for https://bugs.launchpad.net/tempest/+bug/1539927
# will resolved and new version of tempest-lib released.
return json.loads(body)
def delete_service(self, environment_id, session_id, service_id):
headers = self.get_headers()
headers.update(
{'X-Configuration-Session': session_id}
)
uri = 'v1/environments/{0}/services/{1}'.format(environment_id,
service_id)
resp, body = self.delete(uri, headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_services_list(self, environment_id, session_id=None):
headers = self.get_headers()
if session_id:
headers.update(
{'X-Configuration-Session': session_id}
)
uri = 'v1/environments/{0}/services'.format(environment_id)
resp, body = self.get(uri, headers)
self.expected_success(200, resp.status)
# TODO(freerunner): Need to replace json.loads() to _parse_resp
# method, when fix for https://bugs.launchpad.net/tempest/+bug/1539927
# will resolved and new version of tempest-lib released.
return json.loads(body)
def get_service(self, environment_id, service_id, session_id=None):
headers = self.get_headers()
if session_id:
headers.update(
{'X-Configuration-Session': session_id}
)
uri = 'v1/environments/{0}/services/{1}'.format(environment_id,
service_id)
resp, body = self.get(uri, headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
# -----------------------------Category methods--------------------------------
def list_categories(self):
uri = 'v1/catalog/categories'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_category(self, name):
body = {'name': name}
uri = 'v1/catalog/categories'
resp, body = self.post(uri, json.dumps(body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_category(self, category_id):
uri = 'v1/catalog/categories/{0}'.format(category_id)
resp, body = self.delete(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_category(self, category_id):
uri = 'v1/catalog/categories/{0}'.format(category_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
# ----------------------Environment templates methods--------------------------
def get_env_templates_list(self):
uri = 'v1/templates'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_public_env_templates_list(self):
uri = 'v1/templates?is_public=true'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_private_env_templates_list(self):
uri = 'v1/templates?is_public=false'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_env_template(self, env_template_name):
body = {'name': env_template_name, "is_public": False,
"description_text": "description"}
uri = 'v1/templates'
resp, body = self.post(uri, json.dumps(body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def clone_env_template(self, env_template_id, cloned_env_template_name):
body = {'name': cloned_env_template_name}
uri = 'v1/templates/{0}/clone'.format(env_template_id)
resp, body = self.post(uri, json.dumps(body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_public_env_template(self, env_template_name):
body = {'name': env_template_name, "is_public": True}
uri = 'v1/templates'
resp, body = self.post(uri, json.dumps(body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_env_template_with_services(self, env_template_name, post_body):
body = {
'name': env_template_name,
'services': [post_body]
}
uri = 'v1/templates'
resp, body = self.post(uri, json.dumps(body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_service_in_env_template(self, env_template_id, post_body):
uri = 'v1/templates/{0}/services'.format(env_template_id)
resp, body = self.post(uri, json.dumps(post_body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_services_list_in_env_template(self, env_template_id):
uri = 'v1/templates/{0}/services'.format(env_template_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
# TODO(freerunner): Need to replace json.loads() to _parse_resp
# method, when fix for https://bugs.launchpad.net/tempest/+bug/1539927
# will resolved and new version of tempest-lib released.
return json.loads(body)
def get_service_in_env_template(self, env_template_name, service_id):
uri = 'v1/templates/{0}/services/{1}'.format(env_template_name,
service_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return json.loads(body)
def update_service_from_env_template(self, env_template_id, service_id,
post_body):
uri = 'v1/templates/{0}/services/{1}'.format(env_template_id,
service_id)
resp, body = self.put(uri, json.dumps(post_body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_service_from_env_template(self, env_template_name, service_id):
uri = 'v1/templates/{0}/services/{1}'.format(env_template_name,
service_id)
resp, body = self.delete(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_env_template(self, env_template_id):
uri = 'v1/templates/{0}'.format(env_template_id)
resp, body = self.delete(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_env_template(self, env_template_id):
uri = 'v1/templates/{0}'.format(env_template_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_env_from_template(self, env_template_id, env_name):
body = {'name': env_name}
uri = 'v1/templates/{0}/create-environment'.format(env_template_id)
resp, body = self.post(uri, json.dumps(body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
# ----------------------------Static action methods----------------------------
def call_static_action(self, class_name=None, method_name=None, args=None,
package_name=None, class_version="=0"):
uri = 'v1/actions'
post_body = {
'parameters': args or {},
'packageName': package_name,
'classVersion': class_version
}
if class_name:
post_body['className'] = class_name
if method_name:
post_body['methodName'] = method_name
resp, body = self.post(uri, json.dumps(post_body))
self.expected_success(200, resp.status)
# _parse_resp() cannot be used because body is expected to be string
return body

View File

@ -1,157 +0,0 @@
# Copyright (c) 2016 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 json
import os
from tempest import config
from tempest.lib.common import rest_client
from murano_tempest_tests import utils
CONF = config.CONF
class ArtifactsClient(rest_client.RestClient):
"""Tempest REST client for Glance Artifacts"""
def __init__(self, auth_provider):
super(ArtifactsClient, self).__init__(
auth_provider,
CONF.artifacts.catalog_type,
CONF.identity.region,
endpoint_type=CONF.artifacts.endpoint_type)
self.build_interval = CONF.artifacts.build_interval
self.build_timeout = CONF.artifacts.build_timeout
# -----------------------------Artifacts methods-------------------------------
def list_artifacts(self):
uri = 'v0.1/artifacts/murano/v1'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
parsed = self._parse_resp(body)
return parsed['artifacts']
def list_drafts(self):
uri = 'v0.1/artifacts/murano/v1/creating'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_deactivated_drafts(self):
uri = 'v0.1/artifacts/murano/v1/deactivated'
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_artifact_draft(self, name, version, **kwargs):
uri = 'v0.1/artifacts/murano/v1/drafts'
kwargs.update({'name': name, 'version': version})
resp, body = self.post(uri, body=json.dumps(kwargs))
self.expected_success(201, resp.status)
return self._parse_resp(body)
def publish_artifact(self, artifact_id):
uri = 'v0.1/artifacts/murano/v1/{0}/publish'.format(artifact_id)
resp, body = self.post(uri, body='')
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_artifact(self, artifact_id):
uri = 'v0.1/artifacts/murano/v1/{0}'.format(artifact_id)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_artifact(self, artifact_id, body):
headers = {
'Content-Type': 'application/openstack-images-v2.1-json-patch'}
uri = 'v0.1/artifacts/murano/v1/{0}'.format(artifact_id)
resp, body = self.patch(uri, json.dumps(body), headers=headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_artifact(self, artifact_id):
uri = 'v0.1/artifacts/murano/v1/{0}'.format(artifact_id)
resp, body = self.delete(uri)
self.expected_success(204, resp.status)
return self._parse_resp(body)
def upload_blob(self, artifact_id, blob_type, data):
headers = {'Content-Type': 'application/octet-stream'}
uri = 'v0.1/artifacts/murano/v1/{0}/{1}'.format(
artifact_id, blob_type)
resp, body = self.put(uri, data, headers=headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def download_blob(self, artifact_id, blob_type):
uri = 'v0.1/artifacts/murano/v1/{0}/{1}/download'.format(
artifact_id, blob_type)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
# -----------------------------Packages methods-------------------------------
def get_list_packages(self):
return self.list_artifacts()
def delete_package(self, package_id):
return self.delete_artifact(package_id)
def upload_package(self, package_name, package_path, top_dir, body):
files = {package_name: open(os.path.join(top_dir, package_path), 'rb')}
is_public = body.pop('is_public', None)
if is_public is not None:
body['visibility'] = 'public' if is_public else 'private'
fqn = list(files.keys())[0]
package = utils.Package.from_file(files[fqn])
manifest = package.manifest
package_draft = {
'name': manifest.get('FullName', fqn),
'version': manifest.get('Version', '0.0.0'),
'description': manifest.get('Description'),
'display_name': manifest.get('Name', fqn),
'type': manifest.get('Type', 'Application'),
'author': manifest.get('Author'),
'tags': manifest.get('Tags', []),
'class_definitions': package.classes.keys()
}
for k, v in body.items():
package_draft[k] = v
inherits = utils.get_local_inheritance(package.classes)
# TODO(kzaitsev): add local and global inheritance information tests
package_draft['inherits'] = inherits
keywords = package_draft['tags']
package_draft['keywords'] = keywords
draft = self.create_artifact_draft(**package_draft)
self.upload_blob(draft['id'], 'archive', package.file())
# TODO(kzaitsev): add logo upload code, currently it's failing for me
# with io.UnsupportedOperation: fileno
# if package.logo is not None:
# self.upload_blob(draft['id'], 'logo', package.logo)
# if package.ui is not None:
# self.client.artifacts.upload_blob(draft['id'], 'ui_definition',
# package.ui)
self.publish_artifact(draft['id'])
return draft

View File

@ -1,108 +0,0 @@
# Copyright (c) 2015 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 base64
import json
from tempest import config
from tempest.lib.common import rest_client
from murano_tempest_tests import utils
CONF = config.CONF
class ServiceBrokerClient(rest_client.RestClient):
"""Tempest REST client for Murano Service Broker"""
def __init__(self, auth_provider):
super(ServiceBrokerClient, self).__init__(
auth_provider,
CONF.service_broker.catalog_type,
CONF.identity.region,
endpoint_type=CONF.service_broker.endpoint_type)
self.build_interval = CONF.service_broker.build_interval
self.build_timeout = CONF.service_broker.build_timeout
self.headers = self._generate_headers(auth_provider)
@classmethod
def _generate_headers(cls, auth_provider):
"""Generate base64-encoded auth string for murano-cfapi
:param auth_provider:
:return: headers
"""
uname = auth_provider.credentials.username
pwd = auth_provider.credentials.password
encoded_auth = base64.b64encode('{0}:{1}'.format(uname, pwd))
headers = {"Authorization": "Basic " + encoded_auth,
'content-type': 'application/json'}
return headers
def get_applications_list(self):
"""Get list of all available applications"""
uri = "/v2/catalog"
resp, body = self.get(uri, headers=self.headers)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def provision(self, instance_id, service_id, plan_id, space_id, post_json):
"""Create new service resources for developer"""
uri = '/v2/service_instances/{0}?accepts_incomplete=true'.\
format(instance_id)
body = {
'service_id': service_id,
'plan_id': plan_id,
'organization_guid': self.tenant_id,
'space_guid': space_id,
'parameters': post_json
}
body = json.dumps(body)
resp, body = self.put(uri, body, headers=self.headers)
self.expected_success([200, 202], resp.status)
return body
def deprovision(self, instance_id):
uri = '/v2/service_instances/{0}?accepts_incomplete=true'.\
format(instance_id)
resp, body = self.delete(uri, headers=self.headers)
self.expected_success(202, resp.status)
return body
def get_last_status(self, instance_id):
uri = '/v2/service_instances/{0}/last_operation'.format(instance_id)
resp, body = self.get(uri, headers=self.headers)
self.expected_success([200, 202], resp.status)
return self._parse_resp(body)
def get_application(self, name, app_list):
for app in app_list:
if app['name'] == name:
return app
def create_binding(self, instance_id):
binding_id = utils.generate_uuid()
uri = "/v2/service_instances/{0}/service_bindings/{1}".format(
instance_id, binding_id)
post_body = {
"plan_id": utils.generate_uuid(),
"service_id": utils.generate_uuid(),
"app_guid": utils.generate_uuid()
}
body = json.dumps(post_body)
resp, body = self.put(uri, body, headers=self.headers)
self.expected_success([200, 201], resp.status)
return self._parse_resp(body)

View File

@ -1,97 +0,0 @@
# Copyright (c) 2016 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.
from tempest.common import credentials_factory as common_creds
from tempest import config
from tempest import test
from murano_tempest_tests import clients
from murano_tempest_tests import utils
CONF = config.CONF
class BaseArtifactsTest(test.BaseTestCase):
"""Base test class for Murano Glare tests."""
@classmethod
def skip_checks(cls):
super(BaseArtifactsTest, cls).skip_checks()
if not CONF.service_available.murano:
skip_msg = "Murano is disabled"
raise cls.skipException(skip_msg)
@classmethod
def setup_clients(cls):
super(BaseArtifactsTest, cls).setup_clients()
if not hasattr(cls, "os_primary"):
creds = cls.get_configured_isolated_creds(type_of_creds='primary')
cls.os_primary = clients.Manager(credentials=creds)
cls.artifacts_client = cls.os_primary.artifacts_client
cls.application_catalog_client = \
cls.os_primary.application_catalog_client
@classmethod
def get_client_with_isolated_creds(cls, type_of_creds="admin"):
creds = cls.get_configured_isolated_creds(type_of_creds=type_of_creds)
os = clients.Manager(credentials=creds)
client = os.artifacts_client
return client
@classmethod
def get_configured_isolated_creds(cls, type_of_creds='admin'):
identity_version = CONF.identity.auth_version
if identity_version == 'v3':
cls.admin_role = CONF.identity.admin_role
else:
cls.admin_role = 'admin'
cls.credentials = common_creds.get_credentials_provider(
name=cls.__name__,
force_tenant_isolation=CONF.auth.use_dynamic_credentials,
identity_version=CONF.identity.auth_version)
if type_of_creds == 'primary':
creds = cls.credentials.get_primary_creds()
elif type_of_creds == 'admin':
creds = cls.credentials.get_admin_creds()
elif type_of_creds == 'alt':
creds = cls.credentials.get_alt_creds()
else:
creds = cls.credentials.get_credentials(type_of_creds)
cls.credentials.type_of_creds = type_of_creds
return creds.credentials
@classmethod
def upload_package(cls, application_name, version=None, require=None):
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name, version=version,
add_class_name=True, require=require)
package = cls.artifacts_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
return package, abs_archive_path
@staticmethod
def create_obj_model(package):
return {
"name": package['display_name'],
"?": {
"type": package['name'],
"id": utils.generate_uuid(),
"classVersion": package['version']
}
}

View File

@ -1,56 +0,0 @@
# Copyright (c) 2016 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 os
from tempest import config
from tempest.lib import decorators
from murano_tempest_tests.tests.api.application_catalog.artifacts import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestRepositorySanity(base.BaseArtifactsTest):
@classmethod
def resource_setup(cls):
if not CONF.application_catalog.glare_backend:
msg = ("Murano is not using GLARE backend. "
"Skipping GLARE tests.")
raise cls.skipException(msg)
super(TestRepositorySanity, cls).resource_setup()
@decorators.attr(type='smoke')
@decorators.idempotent_id('2818aaa0-6613-4bd9-8abe-02713121357a')
def test_get_list_packages(self):
package_list = self.artifacts_client.get_list_packages()
self.assertIsInstance(package_list, list)
@decorators.attr(type='smoke')
@decorators.idempotent_id('bc717c98-5f6b-42a6-9131-43a711cfe848')
def test_upload_and_delete_package(self):
application_name = utils.generate_name('package_test_upload')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.artifacts_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
package_list = self.artifacts_client.get_list_packages()
self.assertIn(package['id'], {pkg['id'] for pkg in package_list})
self.artifacts_client.delete_package(package['id'])
package_list = self.artifacts_client.get_list_packages()
self.assertNotIn(package['id'], {pkg['id'] for pkg in package_list})

View File

@ -1,166 +0,0 @@
# Copyright (c) 2016 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 os
from tempest import config
from tempest.lib import decorators
from murano_tempest_tests.tests.api.application_catalog.artifacts import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestVersioning(base.BaseArtifactsTest):
@classmethod
def resource_setup(cls):
if not CONF.application_catalog.glare_backend:
msg = ("Murano is not using GLARE backend. "
"Skipping GLARE tests.")
raise cls.skipException(msg)
super(TestVersioning, cls).resource_setup()
application_name = utils.generate_name('package_test')
# create first package
version1 = '1.0.0'
package1, _ = cls.upload_package(application_name,
version=version1)
# create second package
version2 = '2.0.0'
package2, path1 = cls.upload_package(application_name,
version=version2)
# create package with require >=2.0.0 for 2.0.0 package
expected_version = '>=2.0.0'
main_app_name = utils.generate_name('main_package_test')
require = [(package2['name'], expected_version)]
package3, path2 = cls.upload_package(main_app_name, require=require)
cls.packages = {
'1.0.0': package1,
'2.0.0': package2,
'require_for_2.0.0': package3,
}
cls.abs_archive_paths = [path1, path2]
@classmethod
def resource_cleanup(cls):
for pkg in cls.packages.values():
cls.artifacts_client.delete_package(pkg['id'])
map(os.remove, cls.abs_archive_paths)
super(TestVersioning, cls).resource_cleanup()
@decorators.attr(type='smoke')
@decorators.idempotent_id('03ee155c-d65f-4ea7-a00a-bdbc7105fc8b')
def test_availability_of_packages_with_different_versions(self):
"""Test availability of packages with different versions.
1) Check two packages to have the same names.
2) Check two packages to have different ids.
3) Check two packages to be in repository.
"""
self.assertEqual(self.packages['1.0.0']['name'],
self.packages['2.0.0']['name'])
self.assertNotEqual(self.packages['1.0.0']['id'],
self.packages['2.0.0']['id'])
# check packages availability
artifact_packages = {pkg['id'] for pkg in
self.artifacts_client.get_list_packages()}
self.assertIn(self.packages['1.0.0']['id'], artifact_packages)
self.assertIn(self.packages['2.0.0']['id'], artifact_packages)
@decorators.attr(type='smoke')
@decorators.idempotent_id('15c3a52d-cffe-4d03-82c2-31c9be8423d6')
def test_deploy_packages_with_different_versions(self):
"""Test deployment of packages with different versions.
1) Create environment.
2) Add package with version 1.0.0 to the environment.
3) Add package with version 2.0.0 to the environment.
4) Deploy environment.
5) Check if deployment status ok.
"""
# create environment
environment_name = utils.generate_name('create_environment')
environment = self.application_catalog_client.create_environment(
environment_name)
self.addCleanup(self.application_catalog_client.delete_environment,
environment['id'])
# create session
session = self.application_catalog_client.create_session(
environment['id'])
# add first application
object_model = self.create_obj_model(self.packages['1.0.0'])
self.application_catalog_client.create_service(
environment['id'], session['id'], object_model)
# add second application
object_model = self.create_obj_model(self.packages['2.0.0'])
self.application_catalog_client.create_service(
environment['id'], session['id'], object_model)
self.application_catalog_client.deploy_session(
environment['id'], session['id'])
deploy_result = utils.wait_for_environment_deploy(
self.application_catalog_client, environment['id'])['status']
self.assertEqual(deploy_result, 'ready')
@decorators.attr(type='smoke')
@decorators.idempotent_id('2c472476-f9cd-424b-91ee-cbc770602bf3')
def test_deploy_package_with_required_package_version(self):
"""Test deployment of package which requires package with present version.
1) Create environment.
2) Add to the environment package which requires version 2.0.0 of the
package, which is present with versions 1.0.0 and 2.0.0 in repository.
3) Deploy environment.
4) Check if deployment status ok.
"""
# create environment
environment_name = utils.generate_name('create_environment')
environment = self.application_catalog_client.create_environment(
environment_name)
self.addCleanup(self.application_catalog_client.delete_environment,
environment['id'])
# create session
session = self.application_catalog_client.create_session(
environment['id'])
object_model = self.create_obj_model(
self.packages['require_for_2.0.0'])
self.application_catalog_client.create_service(
environment['id'], session['id'], object_model)
self.application_catalog_client.deploy_session(
environment['id'], session['id'])
deploy_result = utils.wait_for_environment_deploy(
self.application_catalog_client, environment['id'])['status']
self.assertEqual(deploy_result, 'ready')

View File

@ -1,96 +0,0 @@
# Copyright (c) 2016 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 os
from tempest import config
from tempest.lib import decorators
from murano_tempest_tests.tests.api.application_catalog.artifacts import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestVersioningNegative(base.BaseArtifactsTest):
@classmethod
def resource_setup(cls):
if not CONF.application_catalog.glare_backend:
msg = ("Murano is not using GLARE backend. "
"Skipping GLARE tests.")
raise cls.skipException(msg)
super(TestVersioningNegative, cls).resource_setup()
# create package with version 1.0.0
application_name = utils.generate_name('package_test')
provided_version = '1.0.0'
package1, path1 = cls.upload_package(
application_name, version=provided_version)
# main application
expected_version = '2.0.0'
main_app_name = utils.generate_name('main_package_test')
require = [(package1['name'], expected_version)]
package2, path2 = cls.upload_package(main_app_name, require=require)
cls.packages = {
'1.0.0': package1,
'require_for_1.0.0': package2
}
cls.abs_archive_paths = [path1, path2]
@classmethod
def resource_cleanup(cls):
for pkg in cls.packages.values():
cls.artifacts_client.delete_package(pkg['id'])
map(os.remove, cls.abs_archive_paths)
super(TestVersioningNegative, cls).resource_cleanup()
@decorators.attr(type=['negative', 'smoke'])
@decorators.idempotent_id('c72fcd24-4694-4479-b550-bdd8cf0bd348')
def test_deploy_package_with_no_required_package_version(self):
"""Test deployment of package which requires package with absent version.
1) Create environment.
2) Add to the environment package which requires version 2.0.0 of the
package, which is present with version 1.0.0 only in repository.
3) Deploy environment.
4) Check if deployment status failure.
"""
# create environment
environment_name = utils.generate_name('create_environment')
environment = self.application_catalog_client.create_environment(
environment_name)
self.addCleanup(self.application_catalog_client.delete_environment,
environment['id'])
# create session
session = self.application_catalog_client.create_session(
environment['id'])
object_model = self.create_obj_model(
self.packages['require_for_1.0.0'])
self.application_catalog_client.create_service(
environment['id'], session['id'], object_model)
self.application_catalog_client.deploy_session(
environment['id'], session['id'])
deploy_result = utils.wait_for_environment_deploy(
self.application_catalog_client, environment['id'])['status']
self.assertEqual(deploy_result, 'deploy failure')

View File

@ -1,110 +0,0 @@
# Copyright (c) 2016 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.
from tempest.common import credentials_factory as common_creds
from tempest import config
from tempest import test
from murano_tempest_tests import clients
from murano_tempest_tests import utils
CONF = config.CONF
class BaseApplicationCatalogTest(test.BaseTestCase):
"""Base test class for Murano Service Broker API tests."""
@classmethod
def skip_checks(cls):
super(BaseApplicationCatalogTest, cls).skip_checks()
if not CONF.service_available.murano:
skip_msg = "Murano is disabled"
raise cls.skipException(skip_msg)
@classmethod
def setup_clients(cls):
super(BaseApplicationCatalogTest, cls).setup_clients()
if not hasattr(cls, "os_primary"):
creds = cls.get_configured_isolated_creds(type_of_creds='primary')
cls.os_primary = clients.Manager(credentials=creds)
cls.application_catalog_client = \
cls.os_primary.application_catalog_client
cls.artifacts_client = cls.os_primary.artifacts_client
@classmethod
def get_client_with_isolated_creds(cls, type_of_creds="admin"):
creds = cls.get_configured_isolated_creds(type_of_creds=type_of_creds)
os = clients.Manager(credentials=creds)
client = os.application_catalog_client
return client
@classmethod
def get_configured_isolated_creds(cls, type_of_creds='admin'):
identity_version = CONF.identity.auth_version
if identity_version == 'v3':
cls.admin_role = CONF.identity.admin_role
else:
cls.admin_role = 'admin'
cls.credentials = common_creds.get_credentials_provider(
name=cls.__name__,
force_tenant_isolation=CONF.auth.use_dynamic_credentials,
identity_version=CONF.identity.auth_version)
if type_of_creds == 'primary':
creds = cls.credentials.get_primary_creds()
elif type_of_creds == 'admin':
creds = cls.credentials.get_admin_creds()
elif type_of_creds == 'alt':
creds = cls.credentials.get_alt_creds()
else:
creds = cls.credentials.get_credentials(type_of_creds)
cls.credentials.type_of_creds = type_of_creds
return creds.credentials
@staticmethod
def _get_demo_app():
return {
"instance": {
"assignFloatingIp": "true",
"keyname": "mykeyname",
"image": "cloud-fedora-v3",
"flavor": "m1.medium",
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": "ef984a74-29a4-45c0-b1dc-2ab9f075732e"
}
},
"name": "orion",
"port": "8080",
"?": {
"type": "io.murano.apps.apache.Tomcat",
"id": utils.generate_uuid()
}
}
class BaseApplicationCatalogIsolatedAdminTest(BaseApplicationCatalogTest):
@classmethod
def setup_clients(cls):
super(BaseApplicationCatalogIsolatedAdminTest, cls).setup_clients()
if not hasattr(cls, "os_admin"):
creds = cls.get_configured_isolated_creds(type_of_creds='admin')
cls.os_admin = clients.Manager(credentials=creds)
cls.application_catalog_client = \
cls.os_admin.application_catalog_client
cls.artifacts_client = cls.os_admin.artifacts_client

View File

@ -1,113 +0,0 @@
# Copyright (c) 2016 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 os
from tempest.lib import decorators
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestCategories(base.BaseApplicationCatalogIsolatedAdminTest):
@classmethod
def resource_setup(cls):
super(TestCategories, cls).resource_setup()
application_name = utils.generate_name(cls.__name__)
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
cls.package = cls.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
name = utils.generate_name(cls.__name__)
cls.category = cls.application_catalog_client.create_category(name)
@classmethod
def resource_cleanup(cls):
os.remove(cls.abs_archive_path)
cls.application_catalog_client.delete_package(cls.package['id'])
cls.application_catalog_client.delete_category(cls.category['id'])
super(TestCategories, cls).resource_cleanup()
@decorators.attr(type='smoke')
@decorators.idempotent_id('4785781d-4bea-4559-939e-1c2fdf0dbec3')
def test_list_categories(self):
categories_list = self.application_catalog_client.list_categories()
self.assertIsInstance(categories_list, list)
@decorators.attr(type='smoke')
@decorators.idempotent_id('c02841bc-3305-4e88-a733-696fb8690552')
def test_create_and_delete_category(self):
name = utils.generate_name('create_and_delete_category')
categories_list = self.application_catalog_client.list_categories()
category_names = [c['name'] for c in categories_list]
self.assertNotIn(name, category_names)
category = self.application_catalog_client.create_category(name)
self.assertEqual(name, category['name'])
categories_list = self.application_catalog_client.list_categories()
category_names = [c['name'] for c in categories_list]
self.assertIn(name, category_names)
self.application_catalog_client.delete_category(category['id'])
categories_list = self.application_catalog_client.list_categories()
category_names = [c['name'] for c in categories_list]
self.assertNotIn(name, category_names)
@decorators.idempotent_id('c7931b7f-e811-4555-8ecc-84bea7885d96')
def test_get_category(self):
category = self.application_catalog_client.get_category(
self.category['id'])
self.assertEqual(self.category['id'], category['id'])
self.assertEqual(self.category['name'], category['name'])
@decorators.idempotent_id('9b92705a-4203-4f02-9d6b-abc797c0eaac')
def test_add_package_to_new_category_and_remove_it_from_category(self):
category = self.application_catalog_client.get_category(
self.category['id'])
self.assertEqual(0, category['package_count'])
post_body = [
{
"op": "add",
"path": "/categories",
"value": [category['name']]
}
]
package = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertIn(self.category['name'], package['categories'])
category = self.application_catalog_client.get_category(
self.category['id'])
self.assertEqual(1, category['package_count'])
self.assertEqual(1, len(category['packages']))
post_body = [
{
"op": "remove",
"path": "/categories",
"value": [category['name']]
}
]
package = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertNotIn(self.category['name'], package['categories'])
category = self.application_catalog_client.get_category(
self.category['id'])
self.assertEqual(0, category['package_count'])
self.assertEqual(0, len(category['packages']))

View File

@ -1,72 +0,0 @@
# Copyright (c) 2016 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 os
from tempest.lib import decorators
from tempest.lib import exceptions
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestCategoriesNegative(base.BaseApplicationCatalogIsolatedAdminTest):
@classmethod
def resource_setup(cls):
super(TestCategoriesNegative, cls).resource_setup()
application_name = utils.generate_name(cls.__name__)
name = utils.generate_name(cls.__name__)
cls.category = cls.application_catalog_client.create_category(name)
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
cls.package = cls.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [cls.category['name']],
"tags": [], 'is_public': False})
@classmethod
def resource_cleanup(cls):
os.remove(cls.abs_archive_path)
cls.application_catalog_client.delete_package(cls.package['id'])
cls.application_catalog_client.delete_category(cls.category['id'])
super(TestCategoriesNegative, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('20fe075f-7d07-462e-bfbc-3032b5367207')
def test_delete_category_by_incorrect_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_category,
utils.generate_uuid())
@decorators.attr(type='negative')
@decorators.idempotent_id('e655365b-ec8b-49da-8745-5c80b1f5e65b')
def test_get_category_by_incorrect_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_category,
utils.generate_uuid())
@decorators.attr(type='negative')
@decorators.idempotent_id('c4948d0f-3530-419c-8017-1ee8bbc29dee')
def test_create_category_with_same_name(self):
self.assertRaises(exceptions.Conflict,
self.application_catalog_client.create_category,
self.category['name'])
@decorators.attr(type='negative')
@decorators.idempotent_id('2bdce780-96dc-46d6-a28e-cdcf768359ae')
def test_delete_category_with_package(self):
self.assertRaises(exceptions.Forbidden,
self.application_catalog_client.delete_category,
self.category['id'])

View File

@ -1,86 +0,0 @@
# Copyright (c) 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 tempest.lib import decorators
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestDeployments(base.BaseApplicationCatalogTest):
def _create_and_deploy_env_session(self):
name = utils.generate_name('_create_and_deploy_env_session')
environment = self.application_catalog_client.create_environment(
name)
self.addCleanup(self.application_catalog_client.delete_environment,
environment['id'])
session = self.application_catalog_client.create_session(
environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
environment['id'], session['id'])
self.application_catalog_client.deploy_session(environment['id'],
session['id'])
utils.wait_for_environment_deploy(self.application_catalog_client,
environment['id'])
return environment
@decorators.idempotent_id('ea4f6f21-bd97-4b58-af93-6fe5417543f9')
def test_list_all_deployments(self):
# Given two environments with deployments
environment1 = self._create_and_deploy_env_session()
environment2 = self._create_and_deploy_env_session()
# When list_all_deployments is called
deployments = self.application_catalog_client.list_all_deployments()
# Then both environment's deployments are returned
self.assertEqual(2, len(deployments))
environment_ids = [d['environment_id'] for d in deployments]
self.assertIn(environment1['id'], environment_ids)
self.assertIn(environment2['id'], environment_ids)
@decorators.idempotent_id('d76706f6-9281-4fdc-9758-57da825311b1')
def test_list_deployments(self):
# Given two environments with deployments
environment1 = self._create_and_deploy_env_session()
self._create_and_deploy_env_session()
# When list_deployments is called for first environment
deployments = self.application_catalog_client.list_deployments(
environment1['id'])
# Then only the first environment's deployment is returned
self.assertEqual(1, len(deployments))
first_deployment = deployments[0]
self.assertEqual(environment1['id'],
first_deployment['environment_id'])
@decorators.idempotent_id('d6fbba34-92a9-49b3-9c49-e4b7a65eb6e8')
def test_list_deployment_statuses(self):
# Given an environment with a deployment
environment = self._create_and_deploy_env_session()
deployment = self.application_catalog_client.list_deployments(
environment['id'])[0]
# When list_deployment_statuses is called
statuses = self.application_catalog_client.list_deployment_statuses(
environment['id'], deployment['id'])
# Then the correct statuses for the deployment are returned
status_deployment_ids = set([s['task_id'] for s in statuses])
self.assertEqual([deployment['id']], list(status_deployment_ids))
status_texts = [s['text'] for s in statuses]
self.assertEqual(['Action deploy is scheduled', 'Deployment finished'],
sorted(status_texts))

View File

@ -1,258 +0,0 @@
# Copyright (c) 2015 Telefonica I+D.
# Copyright (c) 2016 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.lib import decorators
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestEnvironmentTemplatesSanity(base.BaseApplicationCatalogTest):
@decorators.idempotent_id('c13f9799-ed80-463f-8275-6bba62933226')
def test_list_empty_env_templates(self):
templates_list = self.application_catalog_client.\
get_env_templates_list()
self.assertIsInstance(templates_list, list)
@decorators.attr(type='smoke')
@decorators.idempotent_id('15363b15-c350-40b9-a96b-de8d7a56a185')
def test_create_and_delete_env_template(self):
name = utils.generate_name('create_and_delete_env_template')
env_template = self.application_catalog_client.\
create_env_template(name)
self.assertFalse(env_template['is_public'])
self.assertEqual(name, env_template['name'])
self.assertEqual("description", env_template['description_text'])
env_templates_list = self.application_catalog_client.\
get_env_templates_list()
# Deleting dates from dictionaries to skip it in assert
env_template.pop('updated', None)
env_template.pop('created', None)
map(lambda x: x.pop('updated', None), env_templates_list)
map(lambda x: x.pop('created', None), env_templates_list)
self.assertIn(env_template, env_templates_list)
self.application_catalog_client.\
delete_env_template(env_template['id'])
env_templates_list = self.application_catalog_client.\
get_env_templates_list()
self.assertNotIn(env_template, env_templates_list)
class TestEnvironmentTemplates(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestEnvironmentTemplates, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.env_template = cls.application_catalog_client.\
create_public_env_template(name)
cls.alt_client = cls.get_client_with_isolated_creds('alt')
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_env_template(cls.env_template['id'])
super(TestEnvironmentTemplates, cls).resource_cleanup()
@decorators.idempotent_id('3821a826-2d14-4287-b56b-4a022bca9044')
def test_get_env_template(self):
env_template = self.application_catalog_client.\
get_env_template(self.env_template['id'])
self.assertEqual(self.env_template['name'], env_template['name'])
@decorators.idempotent_id('c7f77fa4-cdc3-45b7-a013-668668da0c8e')
def test_create_env_template_with_a_service(self):
name = utils.generate_name('create_env_template_with_service')
post_body = self._get_demo_app()
env_template = self.application_catalog_client.\
create_env_template_with_services(name, post_body)
self.addCleanup(self.application_catalog_client.delete_env_template,
env_template['id'])
list_services = self.application_catalog_client.\
get_services_list_in_env_template(env_template['id'])
self.assertIsInstance(list_services, list)
self.assertIn(post_body, list_services)
@decorators.attr(type='smoke')
@decorators.idempotent_id('be1be6c8-b882-4b17-9221-4b88c71d8d31')
def test_add_and_remove_service_in_env_templates(self):
env_template_services = self.application_catalog_client.\
get_services_list_in_env_template(self.env_template['id'])
self.assertIsInstance(env_template_services, list)
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service_in_env_template(self.env_template['id'], post_body)
self.assertEqual(post_body['name'], service['name'])
services = self.application_catalog_client.\
get_services_list_in_env_template(self.env_template['id'])
self.assertIn(service, services)
self.application_catalog_client.\
delete_service_from_env_template(self.env_template['id'],
service['?']['id'])
services = self.application_catalog_client.\
get_services_list_in_env_template(self.env_template['id'])
self.assertNotIn(service, services)
@decorators.attr(type='smoke')
@decorators.idempotent_id('4c409154-f848-42b5-99e4-3d1352d0cf3f')
def test_update_service_in_env_templates(self):
env_template_services = self.application_catalog_client.\
get_services_list_in_env_template(self.env_template['id'])
self.assertIsInstance(env_template_services, list)
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service_in_env_template(self.env_template['id'], post_body)
self.assertEqual(post_body['name'], service['name'])
post_body["name"] = "updated_name"
service = self.application_catalog_client.\
update_service_from_env_template(self.env_template['id'],
service["?"]["id"],
post_body)
self.assertEqual("updated_name", service['name'])
@decorators.idempotent_id('1fe4b071-8c1f-434a-bb37-0712879df931')
def test_create_public_env_template(self):
name = utils.generate_name('create_public_env_template')
env_template = self.application_catalog_client.\
create_public_env_template(name)
self.addCleanup(self.application_catalog_client.delete_env_template,
env_template['id'])
self.assertEqual(name, env_template['name'])
env_temp = self.application_catalog_client.\
get_env_template(env_template['id'])
self.assertTrue(env_temp['is_public'])
@decorators.idempotent_id('1c79c1dc-c4ff-42d7-9382-6d523f2d9f5b')
def test_clone_env_template(self):
name = utils.generate_name('clone_env_template')
cloned_template = self.alt_client.\
clone_env_template(self.env_template['id'], name)
self.addCleanup(self.alt_client.delete_env_template,
cloned_template['id'])
self.assertEqual(name, cloned_template['name'])
template = self.alt_client.get_env_template(cloned_template['id'])
self.assertEqual(name, template['name'])
@decorators.idempotent_id('98f889cf-de5e-4cda-a97e-f2eff3b471ce')
def test_get_public_private_both_env_templates(self):
name = utils.generate_name('get_public_private_both')
public_env_template = self.application_catalog_client.\
create_public_env_template(name)
self.addCleanup(self.application_catalog_client.delete_env_template,
public_env_template['id'])
self.assertTrue(public_env_template['is_public'])
private_name = utils.generate_name('get_public_private_both')
private_env_template = self.application_catalog_client.\
create_env_template(private_name)
self.addCleanup(self.application_catalog_client.delete_env_template,
private_env_template['id'])
self.assertFalse(private_env_template['is_public'])
private_name_alt = utils.generate_name('get_public_private_both')
private_alt_env_template = self.alt_client.\
create_env_template(private_name_alt)
self.addCleanup(self.alt_client.delete_env_template,
private_alt_env_template['id'])
public_env_templates = self.application_catalog_client.\
get_public_env_templates_list()
# Deleting dates from dictionaries to skip it in assert
map(lambda x: x.pop('updated', None),
public_env_templates + [public_env_template] +
[private_env_template] + [private_alt_env_template])
map(lambda x: x.pop('created', None),
public_env_templates + [public_env_template] +
[private_env_template] + [private_alt_env_template])
self.assertIn(public_env_template, public_env_templates)
self.assertNotIn(private_env_template, public_env_templates)
self.assertNotIn(private_alt_env_template, public_env_templates)
private_env_templates = self.application_catalog_client.\
get_private_env_templates_list()
# Deleting dates from dictionaries to skip it in assert
map(lambda x: x.pop('updated', None), private_env_templates)
map(lambda x: x.pop('created', None), private_env_templates)
self.assertNotIn(public_env_template, private_env_templates)
self.assertIn(private_env_template, private_env_templates)
self.assertNotIn(private_alt_env_template, private_env_templates)
env_templates = self.application_catalog_client.\
get_env_templates_list()
# Deleting dates from dictionaries to skip it in assert
map(lambda x: x.pop('updated', None), env_templates)
map(lambda x: x.pop('created', None), env_templates)
self.assertIn(public_env_template, env_templates)
self.assertIn(private_env_template, env_templates)
self.assertNotIn(private_alt_env_template, env_templates)
alt_pub_templates = self.alt_client.get_public_env_templates_list()
# Deleting dates from dictionaries to skip it in assert
map(lambda x: x.pop('updated', None), alt_pub_templates)
map(lambda x: x.pop('created', None), alt_pub_templates)
self.assertIn(public_env_template, alt_pub_templates)
self.assertNotIn(private_env_template, alt_pub_templates)
self.assertNotIn(private_alt_env_template, alt_pub_templates)
alt_priv_templates = self.alt_client.get_private_env_templates_list()
# Deleting dates from dictionaries to skip it in assert
map(lambda x: x.pop('updated', None), alt_priv_templates)
map(lambda x: x.pop('created', None), alt_priv_templates)
self.assertNotIn(public_env_template, alt_priv_templates)
self.assertNotIn(private_env_template, alt_priv_templates)
self.assertIn(private_alt_env_template, alt_priv_templates)
alt_env_templates = self.alt_client.get_env_templates_list()
# Deleting dates from dictionaries to skip it in assert
map(lambda x: x.pop('updated', None), alt_env_templates)
map(lambda x: x.pop('created', None), alt_env_templates)
self.assertIn(public_env_template, alt_env_templates)
self.assertNotIn(private_env_template, alt_env_templates)
self.assertIn(private_alt_env_template, alt_env_templates)
@decorators.attr(type='smoke')
@decorators.idempotent_id('f7524a15-a4ad-43a5-bcb2-784fd515eb59')
def test_create_env_from_template(self):
name = utils.generate_name('create_env_from_template')
env_template = self.application_catalog_client.\
create_public_env_template(name)
self.addCleanup(self.application_catalog_client.delete_env_template,
env_template['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service_in_env_template(env_template['id'], post_body)
self.assertEqual(post_body['name'], service['name'])
env_name = utils.generate_name('create_env_from_template')
environment = self.application_catalog_client.\
create_env_from_template(env_template['id'], env_name)
self.addCleanup(self.application_catalog_client.delete_environment,
environment['environment_id'])
self.assertIsNotNone(environment)
service_from_env = self.application_catalog_client.\
get_service(environment['environment_id'],
service['?']['id'],
environment['session_id'])
self.assertEqual(service, service_from_env)

View File

@ -1,133 +0,0 @@
# Copyright (c) 2015 Telefonica I+D.
# Copyright (c) 2016 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.lib import decorators
from tempest.lib import exceptions
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestEnvironmentTemplatesNegative(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestEnvironmentTemplatesNegative, cls).resource_setup()
cls.name = utils.generate_name(cls.__name__)
cls.env_template = cls.application_catalog_client.\
create_env_template(cls.name)
cls.environment = cls.application_catalog_client.\
create_environment(cls.name)
cls.alt_client = cls.get_client_with_isolated_creds('alt')
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_env_template(cls.env_template['id'])
cls.application_catalog_client.delete_environment(
cls.environment['id'])
super(TestEnvironmentTemplatesNegative, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('022d0889-c5b3-4853-934f-533b43dfa89f')
def test_clone_env_template_private(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.clone_env_template,
self.env_template['id'], 'cloned_template')
@decorators.attr(type='negative')
@decorators.idempotent_id('1132afa7-6965-4f48-a4ed-aeedba25ad8c')
def test_delete_environment_with_wrong_env_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_env_template,
None)
@decorators.attr(type='negative')
@decorators.idempotent_id('a344b0be-d07d-4dfe-916d-900d93e44425')
def test_create_environment_with_wrong_payload(self):
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.create_env_template,
' ')
@decorators.attr(type='negative')
@decorators.idempotent_id('fa2efa91-75c0-430f-942d-f52fe208cb16')
def test_double_delete_env_template(self):
name = utils.generate_name('double_delete_env_template')
env_template = self.application_catalog_client.\
create_env_template(name)
self.application_catalog_client.delete_env_template(
env_template['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_env_template,
env_template['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('3641cfa9-e74e-4e74-af09-6d0c7d4634fc')
def test_get_deleted_env_template(self):
name = utils.generate_name('get_deleted_env_template')
env_template = self.application_catalog_client.\
create_env_template(name)
self.application_catalog_client.delete_env_template(
env_template['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_env_template,
env_template['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('106fe373-8232-4fb4-870f-290ffa3b475b')
def test_create_environment_template_with_same_name(self):
self.assertRaises(exceptions.Conflict,
self.application_catalog_client.create_env_template,
self.name)
@decorators.attr(type='negative')
@decorators.idempotent_id('07f56f09-3ca4-4d2a-8713-6306f2c3c4f8')
def test_create_env_from_template_witch_existing_name(self):
self.assertRaises(exceptions.Conflict,
self.application_catalog_client.
create_env_from_template,
self.env_template['id'],
self.name)
class TestEnvTemplatesTenantIsolation(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestEnvTemplatesTenantIsolation, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.env_template = cls.application_catalog_client.\
create_env_template(name)
cls.alt_client = cls.get_client_with_isolated_creds('alt')
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_env_template(cls.env_template['id'])
super(TestEnvTemplatesTenantIsolation, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('bdf6febf-51aa-4b0a-b0e8-645e4df2531c')
def test_get_env_template_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_env_template,
self.env_template['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('b664b388-489f-4036-918a-18fa34a2a04e')
def test_delete_env_template_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.delete_env_template,
self.env_template['id'])

View File

@ -1,128 +0,0 @@
# Copyright (c) 2016 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.lib import decorators
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestEnvironments(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestEnvironments, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.environment = cls.application_catalog_client.\
create_environment(name)
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_environment(cls.environment['id'])
super(TestEnvironments, cls).resource_cleanup()
@decorators.attr(type='smoke')
@decorators.idempotent_id('32f26f2e-6c55-4e83-9d8c-023d86299d3e')
def test_list_environments(self):
environments_list = self.application_catalog_client.\
get_environments_list()
self.assertIsInstance(environments_list, list)
@decorators.attr(type='smoke')
@decorators.idempotent_id('a4c0b2fd-2c1b-473c-80cc-d433ceec4c80')
def test_create_and_delete_environment(self):
environments_list = self.application_catalog_client.\
get_environments_list()
name = utils.generate_name('create_and_delete_env')
environment = self.application_catalog_client.create_environment(name)
self.assertEqual(name, environment['name'])
upd_environments_list = self.application_catalog_client.\
get_environments_list()
self.assertEqual(len(environments_list) + 1,
len(upd_environments_list))
self.application_catalog_client.delete_environment(environment['id'])
upd_environments_list = self.application_catalog_client.\
get_environments_list()
self.assertEqual(len(environments_list),
len(upd_environments_list))
@decorators.idempotent_id('52a06d5f-69e4-4184-a127-1bb13ce6dc7c')
def test_create_and_delete_environment_with_unicode_name(self):
environments_list = self.application_catalog_client.\
get_environments_list()
name = u'$yaql \u2665 unicode'
environment = self.application_catalog_client.create_environment(name)
self.assertEqual(name, environment['name'])
upd_environments_list = self.application_catalog_client.\
get_environments_list()
self.assertEqual(len(environments_list) + 1,
len(upd_environments_list))
self.application_catalog_client.delete_environment(environment['id'])
upd_environments_list = self.application_catalog_client.\
get_environments_list()
self.assertEqual(len(environments_list),
len(upd_environments_list))
@decorators.idempotent_id('2b45d30b-3f1d-4482-805e-7cf15d19fe38')
def test_get_environment(self):
environment = self.application_catalog_client.\
get_environment(self.environment['id'])
self.assertEqual(self.environment['name'], environment['name'])
@decorators.attr(type='smoke')
@decorators.idempotent_id('950f5bc1-3e5c-48d1-8b05-dc33303ce6f3')
def test_update_environment(self):
environment = self.application_catalog_client.\
update_environment(self.environment['id'])
self.assertIsNot(self.environment['name'], environment['name'])
@decorators.idempotent_id('61001866-e885-4dda-9ac9-5b24c67a0e25')
def test_get_environment_model(self):
model = self.application_catalog_client.\
get_environment_model(self.environment['id'])
self.assertIsInstance(model, dict)
self.assertIn('defaultNetworks', model)
self.assertEqual(self.environment['name'], model['name'])
self.assertEqual(model['?']['type'], "io.murano.Environment")
net_name = self.application_catalog_client.\
get_environment_model(self.environment['id'],
path='/defaultNetworks/environment/name')
self.assertEqual("{0}-network".format(self.environment['name']),
net_name)
@decorators.idempotent_id('23416978-9701-49ff-9bb1-d312292a7f49')
def test_update_environment_model(self):
session = self.application_catalog_client. \
create_session(self.environment['id'])
patch = [{
"op": "replace",
"path": "/defaultNetworks/flat",
"value": True
}]
new_model = self.application_catalog_client. \
update_environment_model(self.environment['id'], patch,
session['id'])
self.assertTrue(new_model['defaultNetworks']['flat'])
value_draft = self.application_catalog_client. \
get_environment_model(self.environment['id'],
'/defaultNetworks/flat',
session['id'])
self.assertTrue(value_draft)
model_current = self.application_catalog_client. \
get_environment_model(self.environment['id'])
self.assertIsNone(model_current['defaultNetworks']['flat'])

View File

@ -1,104 +0,0 @@
# Copyright (c) 2016 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.lib import decorators
from tempest.lib import exceptions
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestEnvironmentsNegative(base.BaseApplicationCatalogTest):
@decorators.attr(type='negative')
@decorators.idempotent_id('9e245625-ce24-4068-916e-20a5608f6d5a')
def test_delete_environment_with_wrong_env_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_environment,
utils.generate_uuid())
@decorators.attr(type='negative')
@decorators.idempotent_id('1dae123c-27f4-4996-871e-31c66f76ee49')
def test_double_delete_environment(self):
name = utils.generate_name('double_del_negavive')
environment = self.application_catalog_client.\
create_environment(name)
self.application_catalog_client.delete_environment(environment['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_environment,
environment['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('a8032052-5a48-48f0-b333-d1cefcfcbf5f')
def test_get_deleted_environment(self):
name = utils.generate_name('double_del_negavive')
environment = self.application_catalog_client.\
create_environment(name)
self.application_catalog_client.delete_environment(environment['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_environment,
environment['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('f0b6102c-dd22-4f4d-9775-ce0a7a53d881')
def test_update_environment_with_wrong_env_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.update_environment,
None)
@decorators.attr(type='negative')
@decorators.idempotent_id('03266970-2f9d-4b82-971f-532fe23d1027')
def test_abandon_environment_with_wrong_env_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.abandon_environment,
None)
class TestEnvironmentNegativeTenantIsolation(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestEnvironmentNegativeTenantIsolation, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.environment = cls.application_catalog_client.\
create_environment(name)
cls.alt_client = cls.get_client_with_isolated_creds(
type_of_creds='alt')
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_environment(cls.environment['id'])
super(TestEnvironmentNegativeTenantIsolation, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('0fc96a16-5df9-48b9-a681-ba5b3730e95b')
def test_get_environment_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_environment,
self.environment['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('d3c6dc81-ed60-4346-869c-0a091c2fe5b8')
def test_update_environment_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.update_environment,
self.environment['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('56aea1db-9314-4558-8b97-5fcd35fd6955')
def test_delete_environment_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.delete_environment,
self.environment['id'])

View File

@ -1,221 +0,0 @@
# Copyright (c) 2016 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 os
from tempest import config
from tempest.lib import decorators
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestRepositorySanity(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
if CONF.application_catalog.glare_backend:
msg = ("Murano using GLARE backend. "
"Repository tests will be skipped.")
raise cls.skipException(msg)
super(TestRepositorySanity, cls).resource_setup()
@decorators.attr(type='smoke')
@decorators.idempotent_id('d0f3ad6c-70b4-4ce0-90c5-e7afb20ace80')
def test_get_list_packages(self):
package_list = self.application_catalog_client.get_list_packages()
self.assertIsInstance(package_list, list)
@decorators.attr(type='smoke')
@decorators.idempotent_id('53f679d9-955f-4dc1-8cdc-1fcdcfbb07a5')
def test_upload_and_delete_package(self):
application_name = utils.generate_name('package_test_upload')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
package_list = self.application_catalog_client.get_list_packages()
self.assertIn(package['id'], {pkg['id'] for pkg in package_list})
self.application_catalog_client.delete_package(package['id'])
package_list = self.application_catalog_client.get_list_packages()
self.assertNotIn(package['id'], {pkg['id'] for pkg in package_list})
class TestRepository(base.BaseApplicationCatalogIsolatedAdminTest):
@classmethod
def resource_setup(cls):
if CONF.application_catalog.glare_backend:
msg = ("Murano using GLARE backend. "
"Repository tests will be skipped.")
raise cls.skipException(msg)
super(TestRepository, cls).resource_setup()
application_name = utils.generate_name('test_repository_class')
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
cls.package = cls.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
@classmethod
def resource_cleanup(cls):
os.remove(cls.abs_archive_path)
cls.application_catalog_client.delete_package(cls.package['id'])
super(TestRepository, cls).resource_cleanup()
@decorators.idempotent_id('5ea58ef1-1a63-403d-a57a-ef4423202993')
def test_get_package(self):
package = self.application_catalog_client.get_package(
self.package['id'])
self.assertEqual(self.package['tags'], package['tags'])
@decorators.attr(type='smoke')
@decorators.idempotent_id('daf5694d-abbf-4ab1-a6df-99540d0efc70')
def test_update_package(self):
post_body = [
{
"op": "add",
"path": "/tags",
"value": ["im a test"]
}
]
result = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertIn("im a test", result['tags'])
post_body = [
{
"op": "replace",
"path": "/tags",
"value": ["im bad:D"]
}
]
result = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertNotIn("im a test", result['tags'])
self.assertIn("im bad:D", result['tags'])
post_body = [
{
"op": "remove",
"path": "/tags",
"value": ["im bad:D"]
}
]
result = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertNotIn("im bad:D", result['tags'])
post_body = [
{
"op": "replace",
"path": "/is_public",
"value": True
}
]
result = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertTrue(result['is_public'])
post_body = [
{
"op": "replace",
"path": "/enabled",
"value": True
}
]
result = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertTrue(result['enabled'])
post_body = [
{
"op": "replace",
"path": "/description",
"value": "New description"
}
]
result = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertEqual("New description", result['description'])
post_body = [
{
"op": "replace",
"path": "/name",
"value": "New name"
}
]
result = self.application_catalog_client.update_package(
self.package['id'], post_body)
self.assertEqual("New name", result['name'])
@decorators.idempotent_id('fe4711ba-d1ee-4291-8a48-f8efcbd480ab')
def test_download_package(self):
self.application_catalog_client.download_package(self.package['id'])
@decorators.attr(type='smoke')
@decorators.idempotent_id('9e55ae34-dea4-4db5-be4a-b3b793c9c4a7')
def test_publicize_package(self):
# Given a package that isn't public
application_name = utils.generate_name('test_publicize_package')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
self.addCleanup(self.application_catalog_client.delete_package,
package['id'])
fetched_package = self.application_catalog_client.get_package(
package['id'])
self.assertFalse(fetched_package['is_public'])
# When package is publicized
post_body = [
{
"op": "replace",
"path": "/is_public",
"value": True
}
]
self.application_catalog_client.update_package(package['id'],
post_body)
# Then package becomes public
fetched_package = self.application_catalog_client.get_package(
package['id'])
self.assertTrue(fetched_package['is_public'])
@decorators.idempotent_id('1c017c1b-9efc-4498-95ff-833a9ce565a0')
def test_get_ui_definitions(self):
self.application_catalog_client.get_ui_definition(self.package['id'])
@decorators.idempotent_id('9f5ee28a-cec7-4d8b-a0fd-affbfceb0fc2')
def test_get_logo(self):
self.application_catalog_client.get_logo(self.package['id'])

View File

@ -1,193 +0,0 @@
# Copyright (c) 2016 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 os
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestRepositoryNegativeNotFound(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
if CONF.application_catalog.glare_backend:
msg = ("Murano using GLARE backend. "
"Repository tests will be skipped.")
raise cls.skipException(msg)
super(TestRepositoryNegativeNotFound, cls).resource_setup()
@decorators.attr(type='negative')
@decorators.idempotent_id('49c557f4-789c-4d9c-8f48-0ba6bea4f234')
def test_update_package_with_incorrect_id(self):
post_body = [
{
"op": "add",
"path": "/tags",
"value": ["im a test"]
}
]
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.update_package,
utils.generate_uuid(), post_body)
@decorators.attr(type='negative')
@decorators.idempotent_id('72590141-5046-424a-bed2-17e7b7aabd9a')
def test_get_package_with_incorrect_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_package,
utils.generate_uuid())
@decorators.attr(type='negative')
@decorators.idempotent_id('09e3f9d9-40ae-4d5c-a488-4137e3abd7a2')
def test_delete_package_with_incorrect_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_package,
utils.generate_uuid())
@decorators.attr(type='negative')
@decorators.idempotent_id('a3cbcb58-7e46-47e9-a633-e3fc296681a9')
def test_download_package_with_incorrect_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.download_package,
utils.generate_uuid())
@decorators.attr(type='negative')
@decorators.idempotent_id('46799c58-8fe1-4d30-91a9-6067af780b32')
def test_get_ui_definition_with_incorrect_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_ui_definition,
utils.generate_uuid())
@decorators.attr(type='negative')
@decorators.idempotent_id('062ad8ab-6b5e-43ed-8331-b4bcd849b06e')
def test_get_logo_with_incorrect_id(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_logo,
utils.generate_uuid())
class TestRepositoryNegativeForbidden(base.BaseApplicationCatalogTest):
# TODO(freerunner): I hope, that we can setup and cleanup resources
# TODO(freerunner): dramatically better.
@classmethod
def resource_setup(cls):
if CONF.application_catalog.glare_backend:
msg = ("Murano using GLARE backend. "
"Repository tests will be skipped.")
raise cls.skipException(msg)
super(TestRepositoryNegativeForbidden, cls).resource_setup()
application_name = utils.generate_name('package_test_upload')
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
cls.package = cls.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
cls.alt_client = cls.get_client_with_isolated_creds(
type_of_creds='alt')
@classmethod
def resource_cleanup(cls):
os.remove(cls.abs_archive_path)
cls.application_catalog_client.delete_package(cls.package['id'])
super(TestRepositoryNegativeForbidden, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('29f9b3f1-8e8a-4305-a593-e3055e098666')
def test_update_package_from_another_tenant(self):
post_body = [
{
"op": "add",
"path": "/tags",
"value": ["im a test"]
}
]
self.assertRaises(exceptions.Forbidden,
self.alt_client.update_package,
self.package['id'],
post_body)
@decorators.attr(type='negative')
@decorators.idempotent_id('75b57ded-6077-436f-97f8-d3087f2f3b77')
def test_get_package_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_package,
self.package['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('1d9f8f74-8aca-4ee8-be0d-ac5b9d5a7dcd')
def test_delete_package_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.delete_package,
self.package['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('a1467fed-cd6f-44dd-b79c-ea0f91e082dc')
def test_download_package_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.download_package,
self.package['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('b6074261-f981-4c15-9cd6-5811bd75127a')
def test_get_ui_definition_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_ui_definition,
self.package['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('a5a3c2bb-3fde-49cb-ae4c-c454d7eb956b')
def test_get_logo_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_logo,
self.package['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('12928ec7-bd31-415d-9260-5c488aebd4c7')
def test_publicize_package_as_non_admin_user(self):
# Given a package that isn't public
application_name = utils.generate_name('test_publicize_package_'
'as_non_admin_user')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
self.addCleanup(self.application_catalog_client.delete_package,
package['id'])
# When package is publicized, then the method throws an exception
post_body = [
{
"op": "replace",
"path": "/is_public",
"value": True
}
]
self.assertRaises(exceptions.Forbidden,
self.application_catalog_client.update_package,
package['id'],
post_body)

View File

@ -1,134 +0,0 @@
# Copyright (c) 2016 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.lib import decorators
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestServices(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestServices, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.environment = cls.application_catalog_client.\
create_environment(name)
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_environment(cls.environment['id'])
super(TestServices, cls).resource_cleanup()
@decorators.attr(type='smoke')
@decorators.idempotent_id('6cc9d2da-5aeb-4386-adf3-2ff0b737f363')
def test_get_services_list(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
services_list = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
self.assertIsInstance(services_list, list)
@decorators.attr(type='smoke')
@decorators.idempotent_id('cbdbc025-d673-4fb5-914a-baa0dd896046')
def test_create_and_delete_demo_service(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
services_list = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
services_list_ = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
self.assertEqual(len(services_list) + 1, len(services_list_))
self.application_catalog_client.\
delete_service(self.environment['id'],
session['id'],
service['?']['id'])
services_list_ = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
self.assertEqual(len(services_list), len(services_list_))
@decorators.attr(type='smoke')
@decorators.idempotent_id('431d1842-b25d-4ecd-8837-d56b89c83343')
def test_update_services_via_put(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
put_body = [self._get_demo_app()]
self.application_catalog_client.\
update_services(self.environment['id'], session['id'], put_body)
services_list = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
self.assertEqual(1, len(services_list))
@decorators.idempotent_id('fc9ef7c7-46e2-44ce-a309-bec2834c6adb')
def test_clear_services_via_put(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
services_list = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
post_body = self._get_demo_app()
self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
services_list_ = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
self.assertEqual(len(services_list) + 1, len(services_list_))
self.application_catalog_client.\
update_services(self.environment['id'], session['id'])
services_list_ = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
self.assertEqual(0, len(services_list_))
self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
services_list_ = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
self.assertEqual(1, len(services_list_))
@decorators.idempotent_id('7df86a14-3359-47c2-992e-99eaedb50456')
def test_get_service(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
services_list = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
services_list_ = self.application_catalog_client.\
get_services_list(self.environment['id'], session['id'])
self.assertEqual(len(services_list) + 1, len(services_list_))
service_ = self.application_catalog_client.\
get_service(self.environment['id'],
service['?']['id'],
session['id'])
self.assertEqual(service, service_)
@decorators.idempotent_id('d64da7cd-9fcd-42c5-9c37-766db902c801')
def test_get_services_without_sess_id(self):
services = self.application_catalog_client.\
get_services_list(self.environment['id'], None)
self.assertIsInstance(services, list)
self.assertEqual([], services)

View File

@ -1,272 +0,0 @@
# Copyright (c) 2016 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.lib import decorators
from tempest.lib import exceptions
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestServicesNegative(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestServicesNegative, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.environment = cls.application_catalog_client.\
create_environment(name)
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_environment(cls.environment['id'])
super(TestServicesNegative, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('5f1dd3f4-170f-4020-bbf6-3d7c277957a8')
def test_get_services_list_without_env_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_services_list,
None,
session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('e17972e2-4c5c-4b25-a6cd-82eb2d64897a')
def test_get_services_list_after_delete_env(self):
name = utils.generate_name("get_services_list_after_delete_env")
environment = self.application_catalog_client.create_environment(name)
session = self.application_catalog_client.\
create_session(environment['id'])
self.application_catalog_client.delete_environment(environment['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_services_list,
environment['id'],
session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('e4ffe0b1-deb0-4f33-9790-6e6dc8bcdecb')
def test_get_services_list_after_delete_session(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.application_catalog_client.\
delete_session(self.environment['id'], session['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_services_list,
self.environment['id'],
session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('d88880e2-63de-47a0-b29b-a3810b5715e6')
def test_create_service_without_env_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.create_service,
None,
session['id'],
post_body)
@decorators.attr(type='negative')
@decorators.idempotent_id('1d9311af-917a-4a29-b42f-62377369d346')
def test_create_service_without_sess_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.create_service,
self.environment['id'],
"",
post_body)
@decorators.attr(type='negative')
@decorators.idempotent_id('b22f2232-a6d3-4770-b26e-a1e0ccf62d60')
def test_delete_service_without_env_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_service,
"",
session['id'],
service['?']['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('04b4a8b7-3cf6-494a-8741-151305909893')
def test_delete_service_without_session_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.delete_service,
self.environment['id'],
"",
service['?']['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('2d040e59-3af3-47a2-8d87-eef70920cd65')
def test_double_delete_service(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
self.application_catalog_client.\
delete_service(self.environment['id'],
session['id'],
service['?']['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_service,
self.environment['id'],
session['id'],
service['?']['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('a742e411-e572-4aed-ba91-dba8db694039')
def test_get_service_without_env_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_service,
None,
session['id'],
service['?']['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('ded0b813-c36e-4108-8be2-c4b1e061f4e9')
def test_put_services_without_env_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
put_body = [self._get_demo_app()]
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.update_services,
None,
session['id'],
put_body)
@decorators.attr(type='negative')
@decorators.idempotent_id('4ab7a7ac-1939-404a-8cb7-feaadc06ae3f')
def test_put_services_without_sess_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
put_body = [self._get_demo_app()]
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.update_services,
self.environment['id'],
"",
put_body)
class TestServicesNegativeTenantIsolation(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestServicesNegativeTenantIsolation, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.environment = cls.application_catalog_client.\
create_environment(name)
cls.alt_client = cls.get_client_with_isolated_creds(
type_of_creds='alt')
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_environment(cls.environment['id'])
super(TestServicesNegativeTenantIsolation, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('014050a1-4f8d-4a9b-8332-3eb03d10ba64')
def test_get_list_services_in_env_from_another_tenant(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_services_list,
self.environment['id'],
session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('b2c70134-0537-4912-a6c7-23d477f62764')
def test_create_service_in_env_from_another_tenant(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
self.assertRaises(exceptions.Forbidden,
self.alt_client.create_service,
self.environment['id'],
session['id'],
post_body)
@decorators.attr(type='negative')
@decorators.idempotent_id('264f5854-5fce-4186-987a-98d4fbb67093')
def test_delete_service_in_env_from_another_tenant(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
self.assertRaises(exceptions.Forbidden,
self.alt_client.delete_service,
self.environment['id'],
session['id'],
service['?']['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('ff557e1f-a775-4a10-9265-2fa653179c4c')
def test_get_service_in_env_from_another_tenant(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service(self.environment['id'], session['id'], post_body)
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_service,
self.environment['id'],
session['id'],
service['?']['id'])

View File

@ -1,93 +0,0 @@
# Copyright (c) 2016 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.lib import decorators
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestSessions(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestSessions, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.environment = cls.application_catalog_client.\
create_environment(name)
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_environment(cls.environment['id'])
super(TestSessions, cls).resource_cleanup()
@decorators.attr(type='smoke')
@decorators.idempotent_id('9f8ca4dd-1159-4c12-bd97-84ee7f36775e')
def test_create_session(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
self.assertEqual(self.environment['id'], session['environment_id'])
@decorators.attr(type='smoke')
@decorators.idempotent_id('a2782f54-9f9a-443b-97be-edc17039aea5')
def test_delete_session(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.application_catalog_client.delete_session(self.environment['id'],
session['id'])
@decorators.idempotent_id('0639a8ef-f527-4a5d-b34a-4e2d46f48b30')
def test_get_session(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
session_from_resp = self.application_catalog_client.\
get_session(self.environment['id'], session['id'])
# Deleting dates from dictionaries to skip it in assert
session.pop('updated', None)
session.pop('created', None)
session_from_resp.pop('updated', None)
session_from_resp.pop('created', None)
self.assertEqual(session, session_from_resp)
@decorators.idempotent_id('30a63368-e75a-4e00-ac91-c91b17e54a62')
def test_deploy_session(self):
# Given an environment with a session
name = utils.generate_name('_create_and_deploy_env_session')
environment = self.application_catalog_client.create_environment(
name)
self.addCleanup(self.application_catalog_client.delete_environment,
environment['id'])
session = self.application_catalog_client.create_session(
environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
environment['id'], session['id'])
# When deploy session is called
self.application_catalog_client.deploy_session(environment['id'],
session['id'])
utils.wait_for_environment_deploy(self.application_catalog_client,
environment['id'])
# Then there is only one deployment and it is in a success state
fetched_deployments = self.application_catalog_client.list_deployments(
environment['id'])
self.assertEqual(1, len(fetched_deployments))
first_deployment = fetched_deployments[0]
self.assertEqual(environment['id'], first_deployment['environment_id'])
self.assertEqual('success', first_deployment['state'])

View File

@ -1,146 +0,0 @@
# Copyright (c) 2016 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.
from tempest.lib import decorators
from tempest.lib import exceptions
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
class TestSessionsNegative(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestSessionsNegative, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.environment = cls.application_catalog_client.\
create_environment(name)
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_environment(cls.environment['id'])
super(TestSessionsNegative, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('eaf51e99-ff10-45ff-8c9f-416b6a125799')
def test_create_session_before_env(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.create_session,
utils.generate_uuid())
@decorators.attr(type='negative')
@decorators.idempotent_id('1269efdf-5586-4119-80e3-e88aa20d3111')
def test_delete_session_without_env_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.delete_session,
None, session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('a96f8e67-165c-4a43-92f1-05d28275d576')
def test_get_session_without_env_id(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.get_session,
None, session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('784486ca-9645-4edc-8b23-c7ef781a85ae')
def test_get_session_after_delete_env(self):
name = utils.generate_name('get_session_after_delete_env')
environment = self.application_catalog_client.create_environment(name)
session = self.application_catalog_client.\
create_session(environment['id'])
self.application_catalog_client.delete_environment(environment['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.get_session,
environment['id'], session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('8e5e1148-0a79-4c5a-bf93-2178ff7a92fe')
def test_double_delete_session(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.application_catalog_client.delete_session(self.environment['id'],
session['id'])
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
class TestSessionsNegativeTenantIsolation(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestSessionsNegativeTenantIsolation, cls).resource_setup()
name = utils.generate_name(cls.__name__)
cls.environment = cls.application_catalog_client.\
create_environment(name)
cls.alt_client = cls.get_client_with_isolated_creds(
type_of_creds='alt')
@classmethod
def resource_cleanup(cls):
cls.application_catalog_client.\
delete_environment(cls.environment['id'])
super(TestSessionsNegativeTenantIsolation, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('72108505-3eb1-49b2-a757-a7340d18f52c')
def test_create_session_in_env_from_another_tenant(self):
self.assertRaises(exceptions.Forbidden,
self.alt_client.create_session,
self.environment['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('35ada820-67f1-4a8b-852d-f1a02c11a110')
def test_delete_session_in_env_from_another_tenant(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
self.assertRaises(exceptions.Forbidden,
self.alt_client.delete_session,
self.environment['id'], session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('62d469ac-2e91-4e50-bbe8-3f93ab79d903')
def test_get_session_in_env_from_another_tenant(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_session,
self.environment['id'], session['id'])
@decorators.attr(type='negative')
@decorators.idempotent_id('d261f060-7189-4234-9ece-06ae46127591')
def test_deploy_session_in_env_from_another_tenant(self):
session = self.application_catalog_client.\
create_session(self.environment['id'])
self.addCleanup(self.application_catalog_client.delete_session,
self.environment['id'], session['id'])
self.assertRaises(exceptions.Forbidden,
self.alt_client.deploy_session,
self.environment['id'], session['id'])

View File

@ -1,76 +0,0 @@
# Copyright (c) 2016 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 os
from tempest import config
from tempest.lib import decorators
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestStaticActions(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestStaticActions, cls).resource_setup()
application_name = utils.generate_name('test_repository_class')
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name, add_class_name=True)
if CONF.application_catalog.glare_backend:
client = cls.artifacts_client
else:
client = cls.application_catalog_client
cls.package = client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
@classmethod
def resource_cleanup(cls):
os.remove(cls.abs_archive_path)
if CONF.application_catalog.glare_backend:
client = cls.artifacts_client
else:
client = cls.application_catalog_client
client.delete_package(cls.package['id'])
super(TestStaticActions, cls).resource_cleanup()
@decorators.idempotent_id('ac3359e8-8762-417a-95c6-fb2d678850f7')
def test_call_static_action_basic(self):
action_result = self.application_catalog_client.call_static_action(
class_name=self.package['class_definitions'][0],
method_name='staticAction',
args={'myName': 'John'})
self.assertEqual('"Hello, John"', action_result)
@decorators.attr(type='smoke')
@decorators.idempotent_id('8b427735-bb73-41ab-8992-c81b3d8ebc42')
def test_call_static_action_full(self):
if CONF.application_catalog.glare_backend:
name_attr = 'name'
else:
name_attr = 'fully_qualified_name'
action_result = self.application_catalog_client.call_static_action(
class_name=self.package['class_definitions'][0],
method_name='staticAction',
package_name=self.package[name_attr],
class_version="<1", args={'myName': 'John'})
self.assertEqual('"Hello, John"', action_result)

View File

@ -1,115 +0,0 @@
# Copyright (c) 2016 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 os
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions
from murano_tempest_tests.tests.api.application_catalog import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestStaticActionsNegative(base.BaseApplicationCatalogTest):
@classmethod
def resource_setup(cls):
super(TestStaticActionsNegative, cls).resource_setup()
application_name = utils.generate_name('test_repository_class')
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name, add_class_name=True)
if CONF.application_catalog.glare_backend:
client = cls.artifacts_client
else:
client = cls.application_catalog_client
cls.package = client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': False})
@classmethod
def resource_cleanup(cls):
os.remove(cls.abs_archive_path)
if CONF.application_catalog.glare_backend:
client = cls.artifacts_client
else:
client = cls.application_catalog_client
client.delete_package(cls.package['id'])
super(TestStaticActionsNegative, cls).resource_cleanup()
@decorators.attr(type='negative')
@decorators.idempotent_id('c6d05273-b6fe-4a33-8a87-c7110c171bc2')
def test_call_static_action_no_args(self):
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.call_static_action)
@decorators.attr(type='negative')
@decorators.idempotent_id('35440618-6649-40cb-b878-b5cddd4ea0dd')
def test_call_static_action_wrong_class(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.call_static_action,
'wrong.class', 'staticAction',
args={'myName': 'John'})
@decorators.attr(type='negative')
@decorators.idempotent_id('75c6cc5e-0804-45d9-beb2-10c7ab409b70')
def test_call_static_action_wrong_method(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.call_static_action,
class_name=self.package['class_definitions'][0],
method_name='wrongMethod',
args={'myName': 'John'})
@decorators.attr(type='negative')
@decorators.idempotent_id('334c828b-3f49-49e0-97a2-534f57596bfb')
def test_call_static_action_session_method(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.call_static_action,
class_name=self.package['class_definitions'][0],
method_name='staticNotAction',
args={'myName': 'John'})
@decorators.attr(type='negative')
@decorators.idempotent_id('3ebb5009-2f61-4200-a34c-2bc506d94aed')
def test_call_static_action_wrong_args(self):
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.call_static_action,
class_name=self.package['class_definitions'][0],
method_name='staticAction',
args={'myEmail': 'John'})
@decorators.attr(type='negative')
@decorators.idempotent_id('5f4f6edc-2d66-4426-bb81-48e7570d93ef')
def test_call_static_action_wrong_package(self):
self.assertRaises(exceptions.NotFound,
self.application_catalog_client.call_static_action,
class_name=self.package['class_definitions'][0],
method_name='staticAction',
package_name='wrong.package',
args={'myName': 'John'})
@decorators.attr(type='negative')
@decorators.idempotent_id('c0854170-700f-4924-9cfe-3bff876b9e63')
def test_call_static_action_wrong_version_format(self):
self.assertRaises(exceptions.BadRequest,
self.application_catalog_client.call_static_action,
class_name=self.package['class_definitions'][0],
method_name='staticAction',
class_version='aaa',
args={'myName': 'John'})

View File

@ -1,136 +0,0 @@
# Copyright (c) 2015 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 json
import time
from tempest.common import credentials_factory as common_creds
from tempest import config
from tempest.lib import exceptions
from tempest import test
from murano_tempest_tests import clients
CONF = config.CONF
class BaseServiceBrokerTest(test.BaseTestCase):
"""Base test class for Murano Service Broker API tests."""
@classmethod
def skip_checks(cls):
super(BaseServiceBrokerTest, cls).skip_checks()
if not CONF.service_broker.run_service_broker_tests:
skip_msg = "Service Broker API tests are disabled"
raise cls.skipException(skip_msg)
if not CONF.service_available.murano_cfapi:
skip_msg = "Service Broker API is disabled"
raise cls.skipException(skip_msg)
if not CONF.service_available.murano:
skip_msg = "Murano is disabled"
raise cls.skipException(skip_msg)
@classmethod
def setup_clients(cls):
super(BaseServiceBrokerTest, cls).setup_clients()
if not hasattr(cls, "os_primary"):
cls.username = CONF.identity.username
cls.password = CONF.identity.password
cls.tenant_name = CONF.identity.tenant_name
cls.verify_nonempty(cls.username, cls.password, cls.tenant_name)
cls.os_primary = clients.Manager()
cls.service_broker_client = cls.os_primary.service_broker_client
cls.application_catalog_client = \
cls.os_primary.application_catalog_client
@classmethod
def get_client_with_isolated_creds(cls, type_of_creds="admin"):
creds = cls.get_configured_isolated_creds(type_of_creds=type_of_creds)
os = clients.Manager(credentials=creds)
client = os.application_catalog_client
return client
@classmethod
def get_configured_isolated_creds(cls, type_of_creds='admin'):
identity_version = CONF.identity.auth_version
if identity_version == 'v3':
cls.admin_role = CONF.identity.admin_role
else:
cls.admin_role = 'admin'
cls.credentials = common_creds.get_credentials_provider(
name=cls.__name__,
force_tenant_isolation=CONF.auth.use_dynamic_credentials,
identity_version=CONF.identity.auth_version)
if type_of_creds == 'primary':
creds = cls.credentials.get_primary_creds()
elif type_of_creds == 'admin':
creds = cls.credentials.get_admin_creds()
elif type_of_creds == 'alt':
creds = cls.credentials.get_alt_creds()
else:
creds = cls.credentials.get_credentials(type_of_creds)
cls.credentials.type_of_creds = type_of_creds
return creds.credentials
@classmethod
def verify_nonempty(cls, *args):
if not all(args):
msg = "Missing API credentials in configuration."
raise cls.skipException(msg)
def wait_for_result(self, instance_id, timeout):
start_time = time.time()
start_status = self.service_broker_client.get_last_status(instance_id)
while start_status:
status = self.service_broker_client.get_last_status(instance_id)
if status == start_status and time.time() - start_time > timeout:
raise exceptions.TimeoutException
elif status != start_status:
try:
parced_stat = status['state']
self.assertIn(str(parced_stat), ['succeeded', 'failed'])
result = str(parced_stat)
return result
except KeyError:
parced_stat = json.loads(status)
self.assertIsInstance(parced_stat, dict)
result = parced_stat
return result
else:
time.sleep(2)
def perform_deprovision(self, instance_id):
self.service_broker_client.deprovision(instance_id)
status = self.wait_for_result(instance_id, 30)
self.assertEqual('succeeded', status)
class BaseServiceBrokerAdminTest(BaseServiceBrokerTest):
@classmethod
def setup_clients(cls):
super(BaseServiceBrokerTest, cls).setup_clients()
if not hasattr(cls, "os_admin"):
cls.username = CONF.identity.username
cls.password = CONF.identity.password
cls.tenant_name = CONF.identity.tenant_name
cls.verify_nonempty(cls.username, cls.password, cls.tenant_name)
cls.os_admin = clients.Manager()
cls.service_broker_client = cls.os_admin.service_broker_client
cls.application_catalog_client = \
cls.os_admin.application_catalog_client

View File

@ -1,167 +0,0 @@
# Copyright (c) 2015 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 json
import os
from tempest.lib import decorators
from murano_tempest_tests.tests.api.service_broker import base
from murano_tempest_tests import utils
class ServiceBrokerActionsTest(base.BaseServiceBrokerAdminTest):
@decorators.attr(type='gate')
@decorators.idempotent_id('76cadf4b-7143-402c-975e-11d7464dd20e')
def test_applications_listing(self):
app_list = self.service_broker_client.get_applications_list()
self.assertIsInstance(app_list, list)
@decorators.attr(type=['smoke', 'gate'])
@decorators.idempotent_id('51ad86a2-b8e4-43d1-8099-75e4be293f79')
def test_provision_and_deprovision(self):
application_name = utils.generate_name('cfapi')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': True})
self.addCleanup(self.application_catalog_client.delete_package,
package['id'])
app_list = self.service_broker_client.get_applications_list()
app = self.service_broker_client.get_application(application_name,
app_list)
post_json = {}
instance_id = utils.generate_uuid()
space_id = utils.generate_uuid()
service = self.service_broker_client.provision(
instance_id, app['id'], app['plans'][0]['id'],
space_id, post_json)
self.wait_for_result(instance_id, 30)
self.addCleanup(self.perform_deprovision, instance_id)
self.assertIsInstance(json.loads(service), dict)
@decorators.attr(type=['smoke', 'gate'])
@decorators.idempotent_id('d5bd537a-7912-4916-a137-d0601157fb9e')
def test_binding_instance(self):
application_name = utils.generate_name('cfapi')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': True})
self.addCleanup(self.application_catalog_client.delete_package,
package['id'])
app_list = self.service_broker_client.get_applications_list()
app = self.service_broker_client.get_application(application_name,
app_list)
post_json = {}
instance_id = utils.generate_uuid()
space_id = utils.generate_uuid()
service = self.service_broker_client.provision(
instance_id, app['id'], app['plans'][0]['id'],
space_id, post_json)
self.wait_for_result(instance_id, 30)
self.addCleanup(self.perform_deprovision, instance_id)
self.assertIsInstance(json.loads(service), dict)
binding = self.service_broker_client.create_binding(instance_id)
self.assertIsInstance(binding, dict)
self.assertEqual({'uri': 'localhost'}, binding)
@decorators.attr(type=['smoke', 'gate'])
@decorators.idempotent_id('f738fdc2-a180-40e5-9aa6-d338d8660b88')
def test_provision_with_incorrect_input(self):
"""Test provision with restricted items in object model
Test will fail on deprovision, if parameters from '?' section
will passed through service-broker.
"""
application_name = utils.generate_name('cfapi')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': True})
self.addCleanup(self.application_catalog_client.delete_package,
package['id'])
app_list = self.service_broker_client.get_applications_list()
app = self.service_broker_client.get_application(application_name,
app_list)
# NOTE(freerunner): The '?' section should be cutted off during
# provision action.
post_json = {
'?': {
'type': 'io.murano.apps.{0}'.format(application_name),
'id': utils.generate_uuid()
}
}
instance_id = utils.generate_uuid()
space_id = utils.generate_uuid()
service = self.service_broker_client.provision(
instance_id, app['id'], app['plans'][0]['id'],
space_id, post_json)
self.wait_for_result(instance_id, 30)
self.addCleanup(self.perform_deprovision, instance_id)
self.assertIsInstance(json.loads(service), dict)
@decorators.attr(type=['smoke', 'gate'])
@decorators.idempotent_id('ef9bc7ca-21b7-480d-a3ba-32cb39b33909')
def test_double_provision_to_the_same_space(self):
application_name = utils.generate_name('cfapi')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': True})
self.addCleanup(self.application_catalog_client.delete_package,
package['id'])
app_list = self.service_broker_client.get_applications_list()
app = self.service_broker_client.get_application(application_name,
app_list)
post_json = {}
instance_id = utils.generate_uuid()
space_id = utils.generate_uuid()
service = self.service_broker_client.provision(
instance_id, app['id'], app['plans'][0]['id'],
space_id, post_json)
self.wait_for_result(instance_id, 30)
self.addCleanup(self.perform_deprovision, instance_id)
self.assertIsInstance(json.loads(service), dict)
application_name = utils.generate_name('cfapi')
abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(application_name)
self.addCleanup(os.remove, abs_archive_path)
package = self.application_catalog_client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": [], "tags": [], 'is_public': True})
self.addCleanup(self.application_catalog_client.delete_package,
package['id'])
app_list = self.service_broker_client.get_applications_list()
app = self.service_broker_client.get_application(application_name,
app_list)
post_json = {}
instance_id = utils.generate_uuid()
service = self.service_broker_client.provision(
instance_id, app['id'], app['plans'][0]['id'],
space_id, post_json)
self.wait_for_result(instance_id, 30)
self.addCleanup(self.perform_deprovision, instance_id)
self.assertIsInstance(json.loads(service), dict)

View File

@ -1,32 +0,0 @@
# Copyright (c) 2015 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.
from tempest.lib import decorators
from tempest.lib import exceptions
from murano_tempest_tests.tests.api.service_broker import base
from murano_tempest_tests import utils
class ServiceBrokerNegativeTest(base.BaseServiceBrokerAdminTest):
@decorators.attr(type=['gate', 'negative'])
@decorators.idempotent_id('3c9c14a2-1655-490a-90f0-6cb5dd6dba07')
def test_get_status_with_not_present_instance_id(self):
not_present_instance_id = utils.generate_uuid()
self.assertRaises(
exceptions.Gone,
self.service_broker_client.get_last_status,
not_present_instance_id)

View File

@ -1,406 +0,0 @@
# Copyright (c) 2016 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 requests
import socket
import time
from tempest.clients import Manager as services_manager
from tempest.common import credentials_factory as common_creds
from tempest.common import waiters
from tempest import config
from tempest.lib import exceptions
from tempest.services import orchestration
from tempest import test
from murano_tempest_tests import clients
from murano_tempest_tests import utils
CONF = config.CONF
class BaseApplicationCatalogScenarioTest(test.BaseTestCase):
"""Base test class for Murano Application Catalog Scenario tests."""
@classmethod
def skip_checks(cls):
super(BaseApplicationCatalogScenarioTest, cls).skip_checks()
if not CONF.service_available.murano:
skip_msg = "Murano is disabled"
raise cls.skipException(skip_msg)
@classmethod
def setup_clients(cls):
super(BaseApplicationCatalogScenarioTest, cls).setup_clients()
if not hasattr(cls, "os_primary"):
creds = cls.get_configured_isolated_creds(type_of_creds='primary')
cls.os_primary = clients.Manager(credentials=creds)
cls.services_manager = services_manager(creds)
cls.application_catalog_client = \
cls.os_primary.application_catalog_client
cls.artifacts_client = cls.os_primary.artifacts_client
cls.servers_client = cls.services_manager.servers_client
# NOTE(andreaf) The orchestration client is not initialised in Tempest
# by default anymore.
params = config.service_client_config('orchestration')
cls.orchestration_client = orchestration.OrchestrationClient(
cls.services_manager.auth_provider, **params)
cls.images_client = cls.services_manager.image_client_v2
@classmethod
def resource_setup(cls):
super(BaseApplicationCatalogScenarioTest, cls).resource_setup()
cls.linux_image = CONF.application_catalog.linux_image
cls.cirros_image = cls.get_required_image_name()
@classmethod
def get_client_with_isolated_creds(cls, type_of_creds="admin"):
creds = cls.get_configured_isolated_creds(type_of_creds=type_of_creds)
os = clients.Manager(credentials=creds)
client = os.application_catalog_client
return client
@classmethod
def get_configured_isolated_creds(cls, type_of_creds='admin'):
identity_version = CONF.identity.auth_version
if identity_version == 'v3':
cls.admin_role = CONF.identity.admin_role
else:
cls.admin_role = 'admin'
cls.credentials = common_creds.get_credentials_provider(
name=cls.__name__,
force_tenant_isolation=CONF.auth.use_dynamic_credentials,
identity_version=CONF.identity.auth_version)
if type_of_creds == 'primary':
creds = cls.credentials.get_primary_creds()
elif type_of_creds == 'admin':
creds = cls.credentials.get_admin_creds()
elif type_of_creds == 'alt':
creds = cls.credentials.get_alt_creds()
else:
creds = cls.credentials.get_credentials(type_of_creds)
cls.credentials.type_of_creds = type_of_creds
return creds.credentials
@classmethod
def get_required_image_name(cls):
image = cls.images_client.show_image(CONF.compute.image_ref)
return image['name']
def environment_delete(self, environment_id, timeout=180):
self.application_catalog_client.delete_environment(environment_id)
start_time = time.time()
while time.time() - start_time > timeout:
try:
self.application_catalog_client.get_environment(environment_id)
except exceptions.NotFound:
return
@classmethod
def purge_stacks(cls):
stacks = cls.orchestration_client.list_stacks()['stacks']
for stack in stacks:
cls.orchestration_client.delete_stack(stack['id'])
cls.orchestration_client.wait_for_stack_status(stack['id'],
'DELETE_COMPLETE')
def get_service(self, environment, session, service_name):
for service in self.application_catalog_client.get_services_list(
environment, session):
if service['name'] == service_name:
return service
def get_stack_id(self, environment_id):
stacks = self.orchestration_client.list_stacks()['stacks']
for stack in stacks:
if environment_id in self.orchestration_client.show_stack(
stack['id'])['stack']['description']:
return stack['id']
def get_stack_template(self, stack):
return self.orchestration_client.show_template(stack)
def get_instance_id(self, name):
instance_list = self.servers_client.list_servers()['servers']
for instance in instance_list:
if name in instance['name']:
return instance['id']
def apache(
self, attributes=None, userName=None, flavor='m1.tiny'):
post_body = {
"instance": {
"flavor": flavor,
"image": self.linux_image,
"assignFloatingIp": True,
"availabilityZone": "nova",
"volumes": attributes,
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": utils.generate_uuid()
},
"name": utils.generate_name("testMurano")
},
"name": utils.generate_name("ApacheHTTPServer"),
"userName": userName,
"?": {
"_{id}".format(id=utils.generate_uuid()): {
"name": "ApacheHTTPServer"
},
"type": "io.murano.apps.test.ApacheHttpServerCustom",
"id": utils.generate_uuid()
}
}
return post_body
def vm_cinder(
self, attributes=None, userName=None, flavor='m1.tiny'):
post_body = {
"instance": {
"flavor": flavor,
"image": self.cirros_image,
"assignFloatingIp": True,
"availabilityZone": "nova",
"volumes": attributes,
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": utils.generate_uuid()
},
"name": utils.generate_name("testMurano")
},
"name": utils.generate_name("VM"),
"userName": userName,
"?": {
"_{id}".format(id=utils.generate_uuid()): {
"name": "VM"
},
"type": "io.murano.apps.test.VM",
"id": utils.generate_uuid()
}
}
return post_body
def vm_test(self, **kwargs):
instance = {
"flavor": "m1.tiny",
"image": self.cirros_image,
"assignFloatingIp": True,
"availabilityZone": "nova",
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": utils.generate_uuid()
},
"name": utils.generate_name("testMurano")
}
if kwargs.get('securityGroups'):
instance['securityGroups'] = kwargs.get('securityGroups')
return {
"instance": instance,
"name": utils.generate_name("VM"),
"?": {
"_{id}".format(id=utils.generate_uuid()): {
"name": "VM"
},
"type": "io.murano.apps.test.VM",
"id": utils.generate_uuid()
}
}
def update_executor(self, flavor='m1.tiny'):
post_body = {
"instance": {
"flavor": flavor,
"image": self.linux_image,
"assignFloatingIp": True,
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": utils.generate_uuid()
},
"name": utils.generate_name('testMurano')
},
"name": utils.generate_name('dummy'),
"?": {
"type": "io.murano.apps.test.UpdateExecutor",
"id": utils.generate_uuid()
}
}
return post_body
def deploy_environment(self, environment, session):
self.application_catalog_client.deploy_session(environment['id'],
session['id'])
timeout = 1800
deployed_env = utils.wait_for_environment_deploy(
self.application_catalog_client, environment['id'],
timeout=timeout)
if deployed_env['status'] == 'ready':
return deployed_env
elif deployed_env['status'] == 'deploying':
self.fail('Environment deployment is not finished in {} seconds'.
format(timeout))
else:
self.fail('Environment has status {}'.format(
deployed_env['status']))
def status_check(self, environment_id, configurations):
for configuration in configurations:
inst_name = configuration[0]
ports = configuration[1:]
ip = self.get_ip_by_instance_name(environment_id, inst_name)
if ip and ports:
for port in ports:
self.check_port_access(ip, port)
else:
self.fail('Instance does not have floating IP')
def check_path(self, environment_id, path, inst_name=None):
environment = self.application_catalog_client.\
get_environment(environment_id)
if inst_name:
ip = self.get_ip_by_instance_name(environment_id, inst_name)
else:
ip = environment.services[0]['instance']['floatingIpAddress']
resp = requests.get('http://{0}/{1}'.format(ip, path))
if resp.status_code == 200:
return resp
else:
self.fail("Service path unavailable")
def get_ip_by_instance_name(self, environment_id, inst_name):
for service in self.application_catalog_client.\
get_services_list(environment_id):
if inst_name in service['instance']['name']:
return service['instance']['floatingIpAddress']
def check_port_access(self, ip, port):
result = 1
start_time = time.time()
while time.time() - start_time < 600:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((str(ip), port))
sock.close()
if result == 0:
break
time.sleep(5)
self.assertEqual(0, result, '%s port is closed on instance' % port)
@classmethod
def create_volume(cls, **kwargs):
volume = cls.volumes_client.create_volume(**kwargs)['volume']
waiters.wait_for_volume_resource_status(cls.volumes_client,
volume['id'], 'available')
return volume
@classmethod
def delete_volume(cls, volume_id):
cls.volumes_client.delete_volume(volume_id)
is_volume_deleted = False
while not is_volume_deleted:
is_volume_deleted = cls.volumes_client.\
is_resource_deleted(volume_id)
time.sleep(1)
def create_snapshot(self, volume_id):
snapshot = self.snapshots_client.\
create_snapshot(volume_id=volume_id)['snapshot']
waiters.wait_for_volume_resource_status(self.snapshots_client,
snapshot['id'], 'available')
return snapshot
def delete_snapshot(self, snapshot_id):
self.snapshots_client.delete_snapshot(snapshot_id)
is_snapshot_deleted = False
while not is_snapshot_deleted:
is_snapshot_deleted = self.snapshots_client.\
is_resource_deleted(snapshot_id)
time.sleep(1)
def create_backup(self, volume_id):
backup = self.backups_client.create_backup(
volume_id=volume_id,
force=True)['backup']
waiters.wait_for_volume_resource_status(self.backups_client,
backup['id'], 'available')
return backup
def delete_backup(self, backup_id):
self.backups_client.delete_backup(backup_id)
return self.backups_client.wait_for_resource_deletion(backup_id)
def get_volume(self, environment_id):
stack = self.get_stack_id(environment_id)
stack_outputs = self.orchestration_client.\
show_stack(stack)['stack']['outputs']
for output in stack_outputs:
if (output['output_key'].startswith('vol-') and
output['output_key'].endswith('-id')):
volume_id = output['output_value']
return self.volumes_client.show_volume(volume_id)['volume']
def get_volume_attachments(self, environment_id):
stack = self.get_stack_id(environment_id)
stack_outputs = self.orchestration_client.\
show_stack(stack)['stack']['outputs']
for output in stack_outputs:
if (output['output_key'].startswith('vol-') and
output['output_key'].endswith('-attachments')):
return output['output_value']
def check_volume_attachments(self, environment_id):
volume_attachments = self.get_volume_attachments(environment_id)
self.assertIsInstance(volume_attachments, list)
self.assertGreater(len(volume_attachments), 0)
instance_id = self.get_instance_id('testMurano')
for attachment in volume_attachments:
self.assertEqual(attachment.get('server_id'), instance_id)
self.assertTrue(attachment.get('device').startswith('/dev/'))
def check_volume_attached(self, name, volume_id):
instance_id = self.get_instance_id(name)
attached_volumes = self.servers_client.\
list_volume_attachments(instance_id)['volumeAttachments']
self.assertEqual(attached_volumes[0]['id'], volume_id)
class BaseApplicationCatalogScenarioIsolatedAdminTest(
BaseApplicationCatalogScenarioTest):
@classmethod
def setup_clients(cls):
super(BaseApplicationCatalogScenarioIsolatedAdminTest,
cls).setup_clients()
if not hasattr(cls, "os_admin"):
creds = cls.get_configured_isolated_creds(type_of_creds='admin')
cls.os_admin = clients.Manager(credentials=creds)
cls.services_manager = services_manager(creds)
cls.application_catalog_client = \
cls.os_admin.application_catalog_client
cls.artifacts_client = cls.os_admin.artifacts_client
cls.servers_client = cls.services_manager.servers_client
# NOTE(andreaf) The orchestration client is not initialised in Tempest
# by default anymore.
params = config.service_client_config('orchestration')
cls.orchestration_client = orchestration.OrchestrationClient(
cls.services_manager.auth_provider, **params)
cls.snapshots_client = cls.services_manager.snapshots_v2_client
cls.volumes_client = cls.services_manager.volumes_v2_client
cls.backups_client = cls.services_manager.backups_v2_client
cls.images_client = cls.services_manager.image_client_v2

View File

@ -1,510 +0,0 @@
# Copyright (c) 2016 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 os
import testtools
from tempest import config
from tempest.lib import decorators
from murano_tempest_tests.tests.scenario.application_catalog import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestCinderVolumes(base.BaseApplicationCatalogScenarioTest):
@classmethod
def skip_checks(cls):
super(TestCinderVolumes, cls).skip_checks()
if not CONF.service_available.cinder:
msg = "Cinder is not available. Skipping volumes tests"
raise cls.skipException(msg)
if (not CONF.volume_feature_enabled.api_v3 and
not CONF.volume_feature_enabled.api_v2):
msg = ("Neither cinder v2 nor v3 are available. Skipping"
"volumes tests")
raise cls.skipException(msg)
@classmethod
def setup_clients(cls):
super(TestCinderVolumes, cls).setup_clients()
# Prefer volume v3 which is the current version
if CONF.volume_feature_enabled.api_v3:
_volume = cls.services_manager.volume_v3
elif CONF.volume_feature_enabled.api_v2:
_volume = cls.services_manager.volume_v2
cls.volumes_client = _volume.VolumesClient()
cls.backups_client = _volume.BackupsClient()
cls.snapshots_client = _volume.SnapshotsClient()
@classmethod
def resource_setup(cls):
if not CONF.application_catalog.cinder_volume_tests:
msg = "Cinder volumes tests will be skipped."
raise cls.skipException(msg)
super(TestCinderVolumes, cls).resource_setup()
cls.linux = CONF.application_catalog.linux_image
application_name = utils.generate_name('VM')
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(
application_name,
app='io.murano.apps.test.VM',
manifest_required=False)
if CONF.application_catalog.glare_backend:
cls.client = cls.artifacts_client
else:
cls.client = cls.application_catalog_client
cls.package = cls.client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": ["Web"], "tags": ["test"]})
cls.volume = cls.create_volume(size='1')
@classmethod
def resource_cleanup(cls):
cls.delete_volume(cls.volume['id'])
cls.client.delete_package(cls.package['id'])
os.remove(cls.abs_archive_path)
super(TestCinderVolumes, cls).resource_cleanup()
@decorators.idempotent_id('241ace7d-3b6e-413e-8936-a851ff1163f8')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_boot_volume_as_image(self):
"""Test app deployment using boot volume as image
Scenario:
1. Create environment
2. Add VM application with ability to boot instance
from Cinder volume
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Check that instance is not booted from image, volume is attached
to the instance, has size 4GiB and created from image
7. Delete environment
"""
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.\
create_environment(name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.\
create_session(environment['id'])
post_body = {
"instance": {
"flavor": "m1.tiny",
"blockDevices": {
"volume": {
"?": {
"type": "io.murano.resources.CinderVolume"
},
"size": 4,
"sourceImage": self.cirros_image
},
"bootIndex": 0,
"deviceName": "vda",
"deviceType": "disk"
},
"assignFloatingIp": True,
"availabilityZone": "nova",
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": utils.generate_uuid()
},
"name": utils.generate_name("testMurano")
},
"name": utils.generate_name("VM"),
"?": {
"_{id}".format(id=utils.generate_uuid()): {
"name": "VM"
},
"type": "io.murano.apps.test.VM",
"id": utils.generate_uuid()
}
}
self.application_catalog_client.\
create_service(environment['id'], session['id'],
post_body)
self.deploy_environment(environment, session)
volume_data = self.get_volume(environment['id'])
self.check_volume_attached('testMurano', volume_data['id'])
self.assertEqual(volume_data['size'], 4)
self.assertEqual(volume_data['volume_image_metadata']['image_name'],
self.cirros_image)
server = self.get_instance_id('testMurano')
self.assertFalse(
self.servers_client.show_server(server)['server']['image'])
@decorators.idempotent_id('e10d3bad-7145-46df-8118-4040842883f6')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_existing_volume(self):
"""Test app deployment with existing volume
Scenario:
1. Create environment
2. Add VM application with ability to attach existing
Cinder volume to the instance
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Check that volume is attached to the instance
7. Delete environment
"""
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.\
create_environment(name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.\
create_session(environment['id'])
volume_attributes = {
"/dev/vdb": {
"?": {
"type": "io.murano.resources.ExistingCinderVolume"
},
"openstackId": self.volume['id']
}
}
post_body = self.vm_cinder(attributes=volume_attributes)
self.application_catalog_client.\
create_service(environment['id'], session['id'],
post_body)
self.deploy_environment(environment, session)
self.check_volume_attached('testMurano', self.volume['id'])
@decorators.idempotent_id('6338a496-7415-42a9-a514-61f6f5cb1e65')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_volume_creation(self):
"""Test app deployment with volume creation
Scenario:
1. Create environment
2. Add VM application with ability to create and
attach Cinder volume with size 1 GiB to the instance
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Check that volume is attached to the instance and has size 1GiB
7. Check that we can access some attachment info about the volume
8. Delete environment
"""
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.\
create_environment(name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.\
create_session(environment['id'])
volume_attributes = {
"/dev/vdb": {
"?": {
"type": "io.murano.resources.CinderVolume"
},
"size": 1
}
}
post_body = self.vm_cinder(attributes=volume_attributes)
self.application_catalog_client.\
create_service(environment['id'], session['id'],
post_body)
self.deploy_environment(environment, session)
volume_data = self.get_volume(environment['id'])
self.check_volume_attached('testMurano', volume_data['id'])
self.check_volume_attachments(environment['id'])
self.assertEqual(volume_data['size'], 1)
@decorators.idempotent_id('1eb9bbe4-9810-408e-86a0-78ff114aadae')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_volume_creation_from_image(self):
"""Test app deployment with volume creation from image
Scenario:
1. Create environment
2. Add VM application with ability to create Cinder
volume with size 2 GiB from image and attach it to the instance
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Check that volume is attached to the instance, has size 2GiB and
created from image
7. Delete environment
"""
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.\
create_environment(name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.\
create_session(environment['id'])
volume_attributes = {
"/dev/vdb": {
"?": {
"type": "io.murano.resources.CinderVolume"
},
"size": 4,
"sourceImage": self.cirros_image
}
}
post_body = self.vm_cinder(volume_attributes)
self.application_catalog_client.\
create_service(environment['id'], session['id'],
post_body)
self.deploy_environment(environment, session)
volume_data = self.get_volume(environment['id'])
self.check_volume_attached('testMurano', volume_data['id'])
self.assertEqual(volume_data['size'], 4)
self.assertEqual(volume_data['volume_image_metadata']['image_name'],
self.cirros_image)
@decorators.idempotent_id('bd624a9b-10ae-4079-b515-7b6031d9e725')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_volume_creation_from_volume(self):
"""Test app deployment with volume creation from volume
Scenario:
1. Create environment
2. Add VM application with ability to create Cinder
volume with size 1 GiB from existing volume and attach it to the
instance
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Check that volume is attached to the instance, has size 1GiB and
created from existing volume
7. Delete environment
"""
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.\
create_environment(name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.\
create_session(environment['id'])
volume_attributes = {
"/dev/vdb": {
"?": {
"type": "io.murano.resources.CinderVolume"
},
"size": 1,
"sourceVolume": {
"?": {
"type": "io.murano.resources.ExistingCinderVolume"
},
"openstackId": self.volume['id']
}
}
}
post_body = self.vm_cinder(volume_attributes)
self.application_catalog_client.\
create_service(environment['id'], session['id'],
post_body)
self.deploy_environment(environment, session)
volume_data = self.get_volume(environment['id'])
self.check_volume_attached('testMurano', volume_data['id'])
self.assertEqual(volume_data['size'], 1)
self.assertEqual(volume_data['source_volid'], self.volume['id'])
@decorators.idempotent_id('7a671222-160d-4594-97bf-ea47f60ad965')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_volume_creation_from_snapshot(self):
"""Test app deployment with volume creation from volume snapshot
Scenario:
1. Make snapshot from volume
2. Create environment
3. Add VM application with ability to create
Cinder volume with size 1 GiB from existing volume snapshot and
attach it to the instance
4. Deploy environment
5. Make sure that deployment finished successfully
6. Check that application is accessible
7. Check that volume is attached to the instance, has size 1GiB and
created from existing volume snapshot
8. Delete environment, snapshot
"""
snapshot = self.create_snapshot(self.volume['id'])
self.addCleanup(self.delete_snapshot, snapshot['id'])
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.\
create_environment(name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.\
create_session(environment['id'])
volume_attributes = {
"/dev/vdb": {
"?": {
"type": "io.murano.resources.CinderVolume"
},
"size": 1,
"sourceSnapshot": {
"?": {
"type": "io.murano.resources.CinderVolumeSnapshot"
},
"openstackId": snapshot['id']
}
}
}
post_body = self.vm_cinder(volume_attributes)
self.application_catalog_client.\
create_service(environment['id'], session['id'],
post_body)
self.deploy_environment(environment, session)
volume_data = self.get_volume(environment['id'])
self.check_volume_attached('testMurano', volume_data['id'])
self.assertEqual(volume_data['size'], 1)
self.assertEqual(volume_data['snapshot_id'], snapshot['id'])
class TestCinderVolumeIsolatedAdmin(
base.BaseApplicationCatalogScenarioIsolatedAdminTest):
@classmethod
def resource_setup(cls):
if not CONF.application_catalog.cinder_volume_tests:
msg = "Cinder volumes attachment tests will be skipped."
raise cls.skipException(msg)
super(TestCinderVolumeIsolatedAdmin, cls).resource_setup()
application_name = utils.generate_name('VM')
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(
application_name,
app='io.murano.apps.test.VM',
manifest_required=False)
if CONF.application_catalog.glare_backend:
cls.client = cls.artifacts_client
else:
cls.client = cls.application_catalog_client
cls.package = cls.client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": ["Web"], "tags": ["test"]})
cls.volume = cls.create_volume(size='1')
@classmethod
def resource_cleanup(cls):
cls.delete_volume(cls.volume['id'])
cls.client.delete_package(cls.package['id'])
os.remove(cls.abs_archive_path)
super(TestCinderVolumeIsolatedAdmin, cls).resource_cleanup()
@decorators.idempotent_id('4111eb94-2636-4d0b-af5c-776ed5a59b87')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_volume_creation_readonly(self):
"""Test app deploy with volume creation with readonly
Scenario:
1. Create environment
2. Add VM application with ability to create and
attach Cinder volume with size 1 GiB and readonly
properties to the instance
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Check that volume is attached to the instance, has size 1GiB,
and readonly attributes
7. Delete environment
"""
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.\
create_environment(name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.\
create_session(environment['id'])
volume_attributes = {
"/dev/vdb": {
"?": {
"type": "io.murano.resources.CinderVolume"
},
"size": 1,
"readOnly": True
}
}
post_body = self.vm_cinder(attributes=volume_attributes)
self.application_catalog_client.\
create_service(environment['id'], session['id'],
post_body)
self.deploy_environment(environment, session)
volume_data = self.get_volume(environment['id'])
self.check_volume_attached('testMurano', volume_data['id'])
self.assertEqual(volume_data['size'], 1)
self.assertEqual(volume_data['metadata']['readonly'], 'True')
@decorators.idempotent_id('5c134343-11bc-4329-ac30-9b43f32c15e2')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_volume_creation_from_backup(self):
"""Test app deployment with volume creation from volume backup
Scenario:
1. Make backup from volume
2. Create environment
3. Add VM application with ability to create Cinder
volume with size 1 GiB from existing volume backup and attach it to
the instance
4. Deploy environment
5. Make sure that deployment finished successfully
6. Check that application is accessible
7. Check that volume is attached to the instance, has size 1GiB and
restored from existing volume backup
8. Delete environment, backup
"""
if not (CONF.volume_feature_enabled.backup and
CONF.service_available.swift):
msg = ("Cinder backup driver and Swift are required. "
"Deploy app with volume restoring from backup test "
"will be skipped.")
raise self.skipException(msg)
backup = self.create_backup(self.volume['id'])
self.addCleanup(self.delete_backup, backup['id'])
name = utils.generate_name('testMurano')
environment = self.application_catalog_client. \
create_environment(name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client. \
create_session(environment['id'])
volume_attributes = {
"/dev/vdb": {
"?": {
"type": "io.murano.resources.CinderVolume"
},
"size": 1,
"name": "restore_backup_" + backup['id'],
"sourceVolumeBackup": {
"?": {
"type": "io.murano.resources.CinderVolumeBackup"
},
"openstackId": backup['id']
}
}
}
post_body = self.vm_cinder(volume_attributes)
self.application_catalog_client. \
create_service(environment['id'], session['id'],
post_body)
self.deploy_environment(environment, session)
volume_data = self.get_volume(environment['id'])
self.check_volume_attached('testMurano', volume_data['id'])
self.assertEqual(volume_data['size'], 1)
self.assertIn(backup['id'], volume_data['name'])

View File

@ -1,257 +0,0 @@
# Copyright (c) 2016 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 os
import testtools
from murano_tempest_tests.tests.scenario.application_catalog import base
from murano_tempest_tests import utils
from tempest import config
from tempest.lib import decorators
CONF = config.CONF
class TestMuranoDeployment(base.BaseApplicationCatalogScenarioTest):
@classmethod
def resource_setup(cls):
if not CONF.application_catalog.deployment_tests or \
not CONF.application_catalog.linux_image:
msg = "Application Catalog Scenario Deployment Tests will be " \
"skipped."
raise cls.skipException(msg)
super(TestMuranoDeployment, cls).resource_setup()
cls.abs_archive_path = [None]*3
cls.packages = [None]*3
application_name = utils.generate_name('Apache')
cls.abs_archive_path[0], dir_with_archive, archive_name = \
utils.prepare_package(
application_name,
app='io.murano.apps.test.ApacheHttpServerCustom',
manifest_required=False)
if CONF.application_catalog.glare_backend:
cls.client = cls.artifacts_client
else:
cls.client = cls.application_catalog_client
cls.packages[0] = cls.client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": ["Web"], "tags": ["test"]})
application_name = utils.generate_name('Lighttpd')
cls.abs_archive_path[1], dir_with_archive, archive_name = \
utils.prepare_package(
application_name,
app='io.murano.apps.test.Lighttpd',
manifest_required=False)
cls.packages[1] = cls.client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": ["Web"], "tags": ["test"]})
application_name = utils.generate_name('UpdateExecutor')
cls.abs_archive_path[2], dir_with_archive, archive_name = \
utils.prepare_package(
application_name,
app='io.murano.apps.test.UpdateExecutor',
manifest_required=False)
cls.packages[2] = cls.client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": ["Web"], "tags": ["test"]})
@classmethod
def resource_cleanup(cls):
cls.purge_stacks()
[cls.client.delete_package(package['id']) for package in cls.packages]
map(os.remove, cls.abs_archive_path)
super(TestMuranoDeployment, cls).resource_cleanup()
@decorators.idempotent_id('244c7f25-05bb-43f8-af81-563902979109')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_app_deployment(self):
"""Test app deployment
Scenario:
1. Create environment
2. Add ApacheHTTPServer application to the instance
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Delete environment
"""
post_body = self.apache()
environment_name = utils.generate_name('Test_Murano')
environment = self.application_catalog_client.create_environment(
name=environment_name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.create_session(
environment['id'])
self.assertEqual(environment['id'], session['environment_id'])
self.application_catalog_client.\
create_service(environment['id'], session['id'], post_body)
self.deploy_environment(environment, session)
self.status_check(environment['id'],
[[post_body['instance']['name'], 22, 80]])
@decorators.idempotent_id('f161ac2f-69b8-4c0b-89ee-225459e7f113')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_resources_deallocation(self):
"""Test resources deallocation
Scenario:
1. Create environment
2. Add ApacheHTTPServer application to the instance
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Remove application from environment
7. Deploy environment
8. Check that application is accessible
9. Check that resources aren't used
10. Delete environment
"""
app_1_post_body = self.apache()
app_2_post_body = self.apache()
environment_name = utils.generate_name('Test_Murano')
environment = self.application_catalog_client.create_environment(
name=environment_name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.create_session(
environment['id'])
self.assertEqual(environment['id'], session['environment_id'])
self.application_catalog_client.create_service(
environment['id'], session['id'], app_1_post_body)
self.application_catalog_client.create_service(
environment['id'], session['id'], app_2_post_body)
self.deploy_environment(environment, session)
self.status_check(environment['id'],
[[app_1_post_body['instance']['name'], 22, 80]])
environment = self.application_catalog_client.get_environment(
environment['id'])
app_for_remove = self.get_service(
environment['id'], session['id'], app_1_post_body['name'])
session = self.application_catalog_client.create_session(
environment['id'])
self.application_catalog_client.delete_service(
environment['id'], session['id'], app_for_remove['?']['id'])
environment = self.application_catalog_client.get_environment(
environment['id'])
self.deploy_environment(environment, session)
self.status_check(environment['id'],
[[app_2_post_body['instance']['name'], 22, 80]])
instance_name = app_1_post_body['instance']['name']
stack = self.get_stack_id(environment['id'])
template = self.get_stack_template(stack)
ip_addresses = '{0}-assigned-ip'.format(instance_name)
floating_ip = '{0}-FloatingIPaddress'.format(instance_name)
self.assertNotIn(ip_addresses, template['outputs'])
self.assertNotIn(floating_ip, template['outputs'])
self.assertNotIn(instance_name, template['resources'])
@decorators.idempotent_id('5f0f1326-83b4-4ebb-a80d-312a744851b1')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_dependent_app(self):
"""Test dependent application
Scenario:
1. Create environment
2. Add Update Executor application to the instance
3. Add Dependent application
4. Deploy environment
5. Make sure that deployment finished successfully
6. Check that application is accessible
7. Delete environment
"""
post_body = self.update_executor()
environment_name = utils.generate_name('Test_Murano')
environment = self.application_catalog_client.create_environment(
name=environment_name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.create_session(
environment['id'])
self.assertEqual(environment['id'], session['environment_id'])
updater = self.application_catalog_client.\
create_service(environment['id'], session['id'], post_body)
post_body = {
"name": utils.generate_name("lighttest"),
"updater": updater,
"?": {
"type": "io.murano.apps.test.Lighttpd",
"id": utils.generate_uuid()
}
}
self.application_catalog_client.create_service(
environment['id'], session['id'], post_body)
self.deploy_environment(environment, session)
self.status_check(environment['id'],
[[updater['instance']['name'], 22, 80]])
@decorators.idempotent_id('3a1fbca7-f5b3-4274-b4dd-3a66822bad77')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_simple_software_configuration(self):
"""Test simple software configuration
Scenario:
1. Create environment with name specified
2. Add ApacheHTTPServer application to the instance with specific
user name
3. Deploy environment
4. Make sure that deployment finished successfully
5. Check that application is accessible
6. Check that environment deployed with specific user name
7. Delete environment
"""
post_body = self.apache(userName=utils.generate_name('user'))
username = post_body["userName"]
environment_name = utils.generate_name('SSC-murano')
environment = self.application_catalog_client.create_environment(
name=environment_name)
self.addCleanup(self.environment_delete, environment['id'])
session = self.application_catalog_client.create_session(
environment['id'])
self.assertEqual(environment['id'], session['environment_id'])
self.application_catalog_client.\
create_service(environment['id'], session['id'], post_body)
self.deploy_environment(environment, session)
self.status_check(environment['id'],
[[post_body['instance']['name'], 22, 80]])
resp = self.check_path(
environment['id'], '', post_body['instance']['name'])
self.assertIn(username, resp.text, "Required information not found in "
"response from server")

View File

@ -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.
import os
import testtools
from tempest import config
from tempest.lib import decorators
from murano_tempest_tests.tests.scenario.application_catalog import base
from murano_tempest_tests import utils
CONF = config.CONF
class TestSecurityGroups(base.BaseApplicationCatalogScenarioTest):
@classmethod
def resource_setup(cls):
super(TestSecurityGroups, cls).resource_setup()
cls.linux = CONF.application_catalog.linux_image
application_name = utils.generate_name('VM')
cls.abs_archive_path, dir_with_archive, archive_name = \
utils.prepare_package(
application_name,
app='io.murano.apps.test.VM',
manifest_required=False)
if CONF.application_catalog.glare_backend:
cls.client = cls.artifacts_client
else:
cls.client = cls.application_catalog_client
cls.package = cls.client.upload_package(
application_name, archive_name, dir_with_archive,
{"categories": ["Web"], "tags": ["test"]})
@classmethod
def resource_cleanup(cls):
cls.client.delete_package(cls.package['id'])
os.remove(cls.abs_archive_path)
super(TestSecurityGroups, cls).resource_cleanup()
@decorators.idempotent_id('1344f041-3f7a-4e75-acfc-36b050ccec82')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_murano_defined_security_group(self):
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.create_environment(name)
session = self.application_catalog_client.create_session(
environment['id'])
self.application_catalog_client.create_service(
environment['id'], session['id'], self.vm_test())
self.deploy_environment(environment, session)
instance_id = self.get_instance_id('testMurano')
security_groups = self.servers_client.list_security_groups_by_server(
instance_id).get('security_groups')
self.assertEqual(len(security_groups), 1)
self.assertEqual(len(security_groups[0].get('rules')), 4)
@decorators.idempotent_id('c52cb4a2-53dd-44c3-95d5-7e1606954caa')
@testtools.testcase.attr('smoke')
@testtools.testcase.attr('scenario')
def test_deploy_app_with_user_defined_security_group(self):
name = utils.generate_name('testMurano')
environment = self.application_catalog_client.create_environment(name)
session = self.application_catalog_client.create_session(
environment['id'])
self.application_catalog_client.create_service(
environment['id'], session['id'],
self.vm_test(securityGroups=['default']))
self.deploy_environment(environment, session)
instance_id = self.get_instance_id('testMurano')
security_groups = self.servers_client.list_security_groups_by_server(
instance_id).get('security_groups')
self.assertEqual(len(security_groups), 1)
self.assertEqual('default', security_groups[0].get('name'))

View File

@ -1,512 +0,0 @@
# Copyright (c) 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.
import collections
import os
import shutil
import tempfile
import time
import uuid
import yaml
import zipfile
from oslo_log import log as logging
import requests
import six
from six.moves import urllib
LOG = logging.getLogger(__name__)
MANIFEST = {'Format': 'MuranoPL/1.0',
'Type': 'Application',
'Description': 'MockApp for API tests',
'Author': 'Mirantis, Inc'}
def compose_package(app_name, package_dir,
require=None, archive_dir=None, add_class_name=False,
manifest_required=True, version=None):
"""Composes a murano package
Composes package `app_name` manifest and files from `package_dir`.
Includes `require` section if any in the manifest file.
Puts the resulting .zip file into `archive_dir` if present or in the
`package_dir`.
"""
tmp_package_dir = os.path.join(archive_dir, os.path.basename(package_dir))
shutil.copytree(package_dir, tmp_package_dir)
package_dir = tmp_package_dir
if manifest_required:
manifest = os.path.join(package_dir, "manifest.yaml")
with open(manifest, 'w') as f:
fqn = 'io.murano.apps.' + app_name
mfest_copy = MANIFEST.copy()
mfest_copy['FullName'] = fqn
mfest_copy['Name'] = app_name
mfest_copy['Classes'] = {fqn: 'mock_muranopl.yaml'}
if require:
mfest_copy['Require'] = {str(name): version
for name, version in require}
if version:
mfest_copy['Version'] = version
f.write(yaml.dump(mfest_copy, default_flow_style=False))
if add_class_name:
class_file = os.path.join(package_dir, 'Classes', 'mock_muranopl.yaml')
with open(class_file, 'r') as f:
contents = f.read()
index = contents.index('Extends')
contents = "{0}Name: {1}\n\n{2}".format(contents[:index], app_name,
contents[index:])
with open(class_file, 'w') as f:
f.write(contents)
if require:
class_file = os.path.join(package_dir, 'Classes', 'mock_muranopl.yaml')
with open(class_file, 'r') as f:
content = f.read()
index_string = 'deploy:\n Body:\n '
index = content.index(index_string) + len(index_string)
class_names = [req[0][req[0].rfind('.') + 1:] for req in require]
addition = "".join(["- new({})\n".format(name) + ' ' * 6
for name in class_names])
content = content[:index] + addition + content[index:]
with open(class_file, 'w') as f:
f.write(content)
name = app_name + '.zip'
if not archive_dir:
archive_dir = os.path.dirname(os.path.abspath(__file__))
archive_path = os.path.join(archive_dir, name)
with zipfile.ZipFile(archive_path, 'w') as zip_file:
for root, dirs, files in os.walk(package_dir):
for f in files:
zip_file.write(
os.path.join(root, f),
arcname=os.path.join(os.path.relpath(root, package_dir), f)
)
return archive_path, name
def prepare_package(name, require=None, add_class_name=False,
app='MockApp', manifest_required=True,
version=None):
"""Prepare package.
:param name: Package name to compose
:param require: Parameter 'require' for manifest
:param add_class_name: Option to write class name to class file
:return: Path to archive, directory with archive, filename of archive
"""
app_dir = acquire_package_directory(app=app)
target_arc_path = tempfile.mkdtemp()
arc_path, filename = compose_package(
name, app_dir, require=require, archive_dir=target_arc_path,
add_class_name=add_class_name, manifest_required=manifest_required,
version=version)
return arc_path, target_arc_path, filename
def generate_uuid():
"""Generate uuid for objects."""
return uuid.uuid4().hex
def generate_name(prefix):
"""Generate name for objects."""
suffix = generate_uuid()[:8]
return '{0}_{1}'.format(prefix, suffix)
def acquire_package_directory(app='MockApp'):
"""Obtain absolutely directory with package files.
Should be called inside tests dir.
:return: Package path
"""
top_plugin_dir = os.path.realpath(os.path.join(os.getcwd(),
os.path.dirname(__file__)))
expected_package_dir = '/extras/' + app
app_dir = top_plugin_dir + expected_package_dir
return app_dir
def to_url(filename, base_url, version='', path='/', extension=''):
if urllib.parse.urlparse(filename).scheme in ('http', 'https'):
return filename
if not base_url:
raise ValueError("No base_url for repository supplied")
if '/' in filename or filename in ('.', '..'):
raise ValueError("Invalid filename path supplied: {0}".format(
filename))
version = '.' + version if version else ''
return urllib.parse.urljoin(base_url,
path + filename + version + extension)
# ----------------------Murano client common functions-------------------------
class NoCloseProxy(object):
"""A proxy object, that does nothing on close."""
def __init__(self, obj):
self.obj = obj
def close(self):
return
def __getattr__(self, name):
return getattr(self.obj, name)
class File(object):
def __init__(self, name, binary=True):
self.name = name
self.binary = binary
def open(self):
mode = 'rb' if self.binary else 'r'
if hasattr(self.name, 'read'):
# NOTE(kzaitsev) We do not want to close a file object
# passed to File wrapper. The caller should be responsible
# for closing it
return NoCloseProxy(self.name)
else:
if os.path.isfile(self.name):
return open(self.name, mode)
url = urllib.parse.urlparse(self.name)
if url.scheme in ('http', 'https'):
resp = requests.get(self.name, stream=True)
if not resp.ok:
raise ValueError("Got non-ok status({0}) "
"while connecting to {1}".format(
resp.status_code, self.name))
temp_file = tempfile.NamedTemporaryFile(mode='w+b')
for chunk in resp.iter_content(1024 * 1024):
temp_file.write(chunk)
temp_file.flush()
return open(temp_file.name, mode)
raise ValueError("Can't open {0}".format(self.name))
class FileWrapperMixin(object):
def __init__(self, file_wrapper):
self.file_wrapper = file_wrapper
try:
self._file = self.file_wrapper.open()
except Exception:
# NOTE(kzaitsev): We need to have _file available at __del__ time.
self._file = None
raise
def file(self):
self._file.seek(0)
return self._file
def close(self):
if self._file and not self._file.closed:
self._file.close()
def save(self, dst, binary=True):
file_name = self.file_wrapper.name
if urllib.parse.urlparse(file_name).scheme:
file_name = file_name.split('/')[-1]
dst = os.path.join(dst, file_name)
mode = 'wb' if binary else 'w'
with open(dst, mode) as dst_file:
self._file.seek(0)
shutil.copyfileobj(self._file, dst_file)
def __del__(self):
self.close()
class Package(FileWrapperMixin):
"""Represents murano package contents."""
@staticmethod
def from_file(file_obj):
if not isinstance(file_obj, File):
file_obj = File(file_obj)
return Package(file_obj)
@staticmethod
def from_location(name, base_url='', version='', url='', path=None):
"""Open file using one of three possible options
If path is supplied search for name file in the path, otherwise
if url is supplied - open that url and finally search murano
repository for the package.
"""
if path:
pkg_name = os.path.join(path, name)
file_name = None
for f in [pkg_name, pkg_name + '.zip']:
if os.path.exists(f):
file_name = f
if file_name:
return Package.from_file(file_name)
LOG.error("Couldn't find file for package {0}, tried {1}".format(
name, [pkg_name, pkg_name + '.zip']))
if url:
return Package.from_file(url)
return Package.from_file(to_url(
name,
base_url=base_url,
version=version,
path='apps/',
extension='.zip')
)
@property
def contents(self):
"""Contents of a package."""
if not hasattr(self, '_contents'):
try:
self._file.seek(0)
self._zip_obj = zipfile.ZipFile(
six.BytesIO(self._file.read()))
except Exception as e:
LOG.error("Error {0} occurred,"
" while parsing the package".format(e))
raise
return self._zip_obj
@property
def manifest(self):
"""Parsed manifest file of a package."""
if not hasattr(self, '_manifest'):
try:
self._manifest = yaml.safe_load(
self.contents.open('manifest.yaml'))
except Exception as e:
LOG.error("Error {0} occurred, while extracting "
"manifest from package".format(e))
raise
return self._manifest
def images(self):
"""Returns a list of required image specifications."""
if 'images.lst' not in self.contents.namelist():
return []
try:
return yaml.safe_load(
self.contents.open('images.lst')).get('Images', [])
except Exception:
return []
@property
def classes(self):
if not hasattr(self, '_classes'):
self._classes = {}
for class_name, class_file in (
self.manifest.get('Classes', {}).items()):
filename = "Classes/%s" % class_file
if filename not in self.contents.namelist():
continue
klass = yaml.safe_load(self.contents.open(filename))
self._classes[class_name] = klass
return self._classes
@property
def ui(self):
if not hasattr(self, '_ui'):
if 'UI/ui.yaml' in self.contents.namelist():
self._ui = self.contents.open('UI/ui.yaml')
else:
self._ui = None
return self._ui
@property
def logo(self):
if not hasattr(self, '_logo'):
if 'logo.png' in self.contents.namelist():
self._logo = self.contents.open('logo.png')
else:
self._logo = None
return self._logo
def _get_package_order(self, packages_graph):
"""Sorts packages according to dependencies between them
Murano allows cyclic dependencies. It is impossible
to do topological sort for graph with cycles, so at first
graph condensation should be built.
For condensation building Kosaraju's algorithm is used.
Packages in strongly connected components can be situated
in random order to each other.
"""
def topological_sort(graph, start_node):
order = []
not_seen = set(graph)
def dfs(node):
not_seen.discard(node)
for dep_node in graph[node]:
if dep_node in not_seen:
dfs(dep_node)
order.append(node)
dfs(start_node)
return order
def transpose_graph(graph):
transposed = collections.defaultdict(list)
for node, deps in six.viewitems(graph):
for dep in deps:
transposed[dep].append(node)
return transposed
order = topological_sort(packages_graph, self.manifest['FullName'])
order.reverse()
transposed = transpose_graph(packages_graph)
def top_sort_by_components(graph, component_order):
result = []
seen = set()
def dfs(node):
seen.add(node)
result.append(node)
for dep_node in graph[node]:
if dep_node not in seen:
dfs(dep_node)
for item in component_order:
if item not in seen:
dfs(item)
return reversed(result)
return top_sort_by_components(transposed, order)
def requirements(self, base_url, path=None, dep_dict=None):
"""Scans Require section of manifests of all the dependencies.
Returns a dict with FQPNs as keys and respective Package objects
as values, ordered by topological sort.
:param base_url: url of packages location
:param path: local path of packages location
:param dep_dict: unused. Left for backward compatibility
"""
unordered_requirements = {}
requirements_graph = collections.defaultdict(list)
dep_queue = collections.deque([(self.manifest['FullName'], self)])
while dep_queue:
dep_name, dep_file = dep_queue.popleft()
unordered_requirements[dep_name] = dep_file
direct_deps = Package._get_direct_deps(dep_file, base_url, path)
for name, file in direct_deps:
if name not in unordered_requirements:
dep_queue.append((name, file))
requirements_graph[dep_name] = [dep[0] for dep in direct_deps]
ordered_reqs_names = self._get_package_order(requirements_graph)
ordered_reqs_dict = collections.OrderedDict()
for name in ordered_reqs_names:
ordered_reqs_dict[name] = unordered_requirements[name]
return ordered_reqs_dict
@staticmethod
def _get_direct_deps(package, base_url, path):
result = []
if 'Require' in package.manifest:
for dep_name, ver in package.manifest['Require'].items():
try:
req_file = Package.from_location(
dep_name,
version=ver,
path=path,
base_url=base_url,
)
except Exception as e:
LOG.error("Error {0} occurred while parsing package {1}, "
"required by {2} package".format(
e, dep_name,
package.manifest['FullName']))
continue
result.append((req_file.manifest['FullName'], req_file))
return result
class NamespaceResolver(object):
"""Copied from main murano repo
original at murano/dsl/namespace_resolver.py
"""
def __init__(self, namespaces):
self._namespaces = namespaces
self._namespaces[''] = ''
def resolve_name(self, name, relative=None):
if name is None:
raise ValueError()
if name and name.startswith(':'):
return name[1:]
if ':' in name:
parts = name.split(':')
if len(parts) != 2 or not parts[1]:
raise NameError('Incorrectly formatted name ' + name)
if parts[0] not in self._namespaces:
raise KeyError('Unknown namespace prefix ' + parts[0])
return '.'.join((self._namespaces[parts[0]], parts[1]))
if not relative and '=' in self._namespaces and '.' not in name:
return '.'.join((self._namespaces['='], name))
if relative and '.' not in name:
return '.'.join((relative, name))
return name
def get_local_inheritance(classes):
result = {}
for class_name, klass in classes.items():
if 'Extends' not in klass:
continue
ns = klass.get('Namespaces')
if ns:
resolver = NamespaceResolver(ns)
else:
resolver = None
if isinstance(klass['Extends'], list):
bases = klass['Extends']
else:
bases = [klass['Extends']]
for base_class in bases:
if resolver:
base_fqn = resolver.resolve_name(base_class)
else:
base_fqn = base_class
result.setdefault(base_fqn, []).append(class_name)
return result
def wait_for_environment_deploy(client, environment_id,
timeout=1800, interval=10):
start_time = time.time()
while client.get_environment(environment_id)['status'] == 'deploying':
if time.time() - start_time > timeout:
break
time.sleep(interval)
return client.get_environment(environment_id)