Retire Solum: remove repo content
Solum project is retiring - https://review.opendev.org/c/openstack/governance/+/919211 this commit remove the content of this project repo Change-Id: Iea55401c4f7e253db8dc969eea0e956bcd977e8e
This commit is contained in:
committed by
Ghanshyam
parent
ddd6d9f7a9
commit
da9b61f57b
@@ -1,6 +0,0 @@
|
|||||||
[run]
|
|
||||||
branch = True
|
|
||||||
source = solum-tempest-plugin
|
|
||||||
|
|
||||||
[report]
|
|
||||||
ignore_errors = True
|
|
||||||
58
.gitignore
vendored
58
.gitignore
vendored
@@ -1,58 +0,0 @@
|
|||||||
*.py[cod]
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Packages
|
|
||||||
*.egg*
|
|
||||||
*.egg-info
|
|
||||||
dist
|
|
||||||
build
|
|
||||||
eggs
|
|
||||||
parts
|
|
||||||
bin
|
|
||||||
var
|
|
||||||
sdist
|
|
||||||
develop-eggs
|
|
||||||
.installed.cfg
|
|
||||||
lib
|
|
||||||
lib64
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
cover/
|
|
||||||
.coverage*
|
|
||||||
!.coveragerc
|
|
||||||
.tox
|
|
||||||
nosetests.xml
|
|
||||||
.stestr/
|
|
||||||
.venv
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
|
|
||||||
# Mr Developer
|
|
||||||
.mr.developer.cfg
|
|
||||||
.project
|
|
||||||
.pydevproject
|
|
||||||
|
|
||||||
# Complexity
|
|
||||||
output/*.html
|
|
||||||
output/*/index.html
|
|
||||||
|
|
||||||
# Sphinx
|
|
||||||
doc/build
|
|
||||||
|
|
||||||
# pbr generates these
|
|
||||||
AUTHORS
|
|
||||||
ChangeLog
|
|
||||||
|
|
||||||
# Editors
|
|
||||||
*~
|
|
||||||
.*.swp
|
|
||||||
.*sw?
|
|
||||||
|
|
||||||
# Files created by releasenotes build
|
|
||||||
releasenotes/build
|
|
||||||
3
.mailmap
3
.mailmap
@@ -1,3 +0,0 @@
|
|||||||
# Format is:
|
|
||||||
# <preferred e-mail> <other e-mail 1>
|
|
||||||
# <preferred e-mail> <other e-mail 2>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[DEFAULT]
|
|
||||||
test_path=./
|
|
||||||
top_dir=./
|
|
||||||
34
.zuul.yaml
34
.zuul.yaml
@@ -1,34 +0,0 @@
|
|||||||
- project:
|
|
||||||
queue: solum
|
|
||||||
templates:
|
|
||||||
- check-requirements
|
|
||||||
- tempest-plugin-jobs
|
|
||||||
check:
|
|
||||||
jobs:
|
|
||||||
- solum-devstack-yoga
|
|
||||||
- solum-devstack-xena
|
|
||||||
- solum-devstack-wallaby
|
|
||||||
|
|
||||||
- job:
|
|
||||||
name: solum-devstack-zed
|
|
||||||
parent: solum-devstack
|
|
||||||
nodeset: openstack-single-node-focal
|
|
||||||
override-checkout: stable/zed
|
|
||||||
|
|
||||||
- job:
|
|
||||||
name: solum-devstack-yoga
|
|
||||||
parent: solum-devstack
|
|
||||||
nodeset: openstack-single-node-focal
|
|
||||||
override-checkout: stable/yoga
|
|
||||||
|
|
||||||
- job:
|
|
||||||
name: solum-devstack-xena
|
|
||||||
parent: solum-devstack
|
|
||||||
nodeset: openstack-single-node-focal
|
|
||||||
override-checkout: stable/xena
|
|
||||||
|
|
||||||
- job:
|
|
||||||
name: solum-devstack-wallaby
|
|
||||||
parent: solum-devstack
|
|
||||||
nodeset: openstack-single-node-focal
|
|
||||||
override-checkout: stable/wallaby
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
If you would like to contribute to the development of OpenStack, you must
|
|
||||||
follow the steps in this page:
|
|
||||||
|
|
||||||
http://docs.openstack.org/infra/manual/developers.html
|
|
||||||
|
|
||||||
If you already have a good understanding of how the system works and your
|
|
||||||
OpenStack accounts are set up, you can skip to the development workflow
|
|
||||||
section of this documentation to learn how changes to OpenStack should be
|
|
||||||
submitted for review via the Gerrit tool:
|
|
||||||
|
|
||||||
http://docs.openstack.org/infra/manual/developers.html#development-workflow
|
|
||||||
|
|
||||||
Pull requests submitted through GitHub will be ignored.
|
|
||||||
|
|
||||||
Bugs should be filed on Launchpad, not GitHub:
|
|
||||||
|
|
||||||
https://bugs.launchpad.net/solum
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
solum-tempest-plugin Style Commandments
|
|
||||||
===============================================
|
|
||||||
|
|
||||||
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/
|
|
||||||
176
LICENSE
176
LICENSE
@@ -1,176 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
44
README.rst
44
README.rst
@@ -1,38 +1,10 @@
|
|||||||
========================
|
This project is no longer maintained.
|
||||||
Team and repository tags
|
|
||||||
========================
|
|
||||||
|
|
||||||
.. image:: https://governance.openstack.org/tc/badges/solum-tempest-plugin.svg
|
The contents of this repository are still available in the Git
|
||||||
:target: https://governance.openstack.org/tc/reference/tags/index.html
|
source code management system. To see the contents of this
|
||||||
|
repository before it reached its end of life, please check out the
|
||||||
|
previous commit with "git checkout HEAD^1".
|
||||||
|
|
||||||
============================
|
For any further questions, please email
|
||||||
Tempest Integration of Solum
|
openstack-discuss@lists.openstack.org or join #openstack-dev on
|
||||||
============================
|
OFTC.
|
||||||
|
|
||||||
This directory contains Tempest tests to cover the Solum project, as well
|
|
||||||
as a plugin to automatically load these tests into tempest.
|
|
||||||
|
|
||||||
See the Tempest plugin docs for information on using it:
|
|
||||||
https://docs.openstack.org/tempest/latest/#using-plugins
|
|
||||||
|
|
||||||
* Free software: Apache license
|
|
||||||
* Documentation: https://docs.openstack.org/solum/latest/
|
|
||||||
* Source: https://opendev.org/openstack/solum-tempest-plugin
|
|
||||||
* Bugs: https://bugs.launchpad.net/solum
|
|
||||||
|
|
||||||
Running the tests
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
To run all tests from this plugin, install Solum into your environment and
|
|
||||||
navigate to tempest directory and run::
|
|
||||||
|
|
||||||
$ cd /opt/stack/tempest
|
|
||||||
$ tox -e venv-tempest -- pip install (path to the solum-tempest-plugin directory)
|
|
||||||
|
|
||||||
To run all tests from the solumn-tempest-plugin, run this command::
|
|
||||||
|
|
||||||
$ tox -e all -- solum_tempest_plugin
|
|
||||||
|
|
||||||
To run a single test case, run with the test case name, for example::
|
|
||||||
|
|
||||||
$ tox -e all -- solum_tempest_plugin.camp.v1_1.test_plans.TestPlansController.test_create_camp_plan
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
# The order of packages is significant, because pip processes them in the order
|
|
||||||
# of appearance. Changing the order has an impact on the overall integration
|
|
||||||
# process, which may cause wedges in the gate later.
|
|
||||||
|
|
||||||
sphinx>=2.0.0,!=2.1.0 # BSD
|
|
||||||
openstackdocstheme>=2.0.0 # Apache-2.0
|
|
||||||
# releasenotes
|
|
||||||
reno>=2.5.0 # Apache-2.0
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
# implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.abspath('../..'))
|
|
||||||
# -- General configuration ----------------------------------------------------
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
|
||||||
extensions = [
|
|
||||||
'sphinx.ext.autodoc',
|
|
||||||
'openstackdocstheme',
|
|
||||||
#'sphinx.ext.intersphinx',
|
|
||||||
]
|
|
||||||
|
|
||||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
|
||||||
# text edit cycles.
|
|
||||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
|
||||||
|
|
||||||
# The suffix of source filenames.
|
|
||||||
source_suffix = '.rst'
|
|
||||||
|
|
||||||
# The master toctree document.
|
|
||||||
master_doc = 'index'
|
|
||||||
|
|
||||||
# General information about the project.
|
|
||||||
project = u'solum-tempest-plugin'
|
|
||||||
copyright = u'2017, OpenStack Developers'
|
|
||||||
|
|
||||||
# openstackdocstheme options
|
|
||||||
repository_name = 'openstack/solum-tempest-plugin'
|
|
||||||
bug_project = 'solum'
|
|
||||||
bug_tag = ''
|
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
|
||||||
add_function_parentheses = True
|
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
|
||||||
# unit titles (such as .. function::).
|
|
||||||
add_module_names = True
|
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
|
||||||
pygments_style = 'sphinx'
|
|
||||||
|
|
||||||
# -- Options for HTML output --------------------------------------------------
|
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
|
||||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
|
||||||
# html_theme_path = ["."]
|
|
||||||
# html_theme = '_theme'
|
|
||||||
# html_static_path = ['static']
|
|
||||||
html_theme = 'openstackdocs'
|
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
|
||||||
htmlhelp_basename = '%sdoc' % project
|
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
|
||||||
# (source start file, target name, title, author, documentclass
|
|
||||||
# [howto/manual]).
|
|
||||||
latex_documents = [
|
|
||||||
('index',
|
|
||||||
'%s.tex' % project,
|
|
||||||
u'%s Documentation' % project,
|
|
||||||
u'OpenStack Developers', 'manual'),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Example configuration for intersphinx: refer to the Python standard library.
|
|
||||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
.. solum-tempest-plugin documentation master file, created by
|
|
||||||
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
|
|
||||||
You can adapt this file completely to your liking, but it should at least
|
|
||||||
contain the root `toctree` directive.
|
|
||||||
|
|
||||||
====================================================
|
|
||||||
Welcome to the documentation of solum_tempest_plugin
|
|
||||||
====================================================
|
|
||||||
|
|
||||||
Contents:
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
readme
|
|
||||||
|
|
||||||
Indices and tables
|
|
||||||
==================
|
|
||||||
|
|
||||||
* :ref:`genindex`
|
|
||||||
* :ref:`modindex`
|
|
||||||
* :ref:`search`
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
.. include:: ../../README.rst
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
upgrade:
|
|
||||||
- |
|
|
||||||
Python 2.7 support has been dropped. Last release of solum-tempest-plugin
|
|
||||||
to support python 2.7 is OpenStack Train. The minimum version of Python now
|
|
||||||
supported by solum-tempest-plugin is Python 3.6.
|
|
||||||
@@ -1,280 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
# implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# This file is execfile()d with the current directory set to its
|
|
||||||
# containing dir.
|
|
||||||
#
|
|
||||||
# Note that not all possible configuration values are present in this
|
|
||||||
# autogenerated file.
|
|
||||||
#
|
|
||||||
# All configuration values have a default; values that are commented out
|
|
||||||
# serve to show the default.
|
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
|
||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
|
||||||
|
|
||||||
# -- General configuration ------------------------------------------------
|
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
|
||||||
# needs_sphinx = '1.0'
|
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
|
||||||
# ones.
|
|
||||||
extensions = [
|
|
||||||
'openstackdocstheme',
|
|
||||||
'reno.sphinxext',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
|
||||||
templates_path = ['_templates']
|
|
||||||
|
|
||||||
# The suffix of source filenames.
|
|
||||||
source_suffix = '.rst'
|
|
||||||
|
|
||||||
# The encoding of source files.
|
|
||||||
# source_encoding = 'utf-8-sig'
|
|
||||||
|
|
||||||
# The master toctree document.
|
|
||||||
master_doc = 'index'
|
|
||||||
|
|
||||||
# General information about the project.
|
|
||||||
project = u'solum_tempest_plugin Release Notes'
|
|
||||||
copyright = u'2017, OpenStack Developers'
|
|
||||||
|
|
||||||
# openstackdocstheme options
|
|
||||||
repository_name = 'openstack/solum-tempest-plugin'
|
|
||||||
bug_project = 'solum'
|
|
||||||
bug_tag = ''
|
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
|
||||||
# |version| and |release|, also used in various other places throughout the
|
|
||||||
# built documents.
|
|
||||||
#
|
|
||||||
# The short X.Y version.
|
|
||||||
# The full version, including alpha/beta/rc tags.
|
|
||||||
release = ''
|
|
||||||
# The short X.Y version.
|
|
||||||
version = ''
|
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
|
||||||
# for a list of supported languages.
|
|
||||||
# language = None
|
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
|
||||||
# non-false value, then it is used:
|
|
||||||
# today = ''
|
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
|
||||||
# today_fmt = '%B %d, %Y'
|
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
|
||||||
# directories to ignore when looking for source files.
|
|
||||||
exclude_patterns = []
|
|
||||||
|
|
||||||
# The reST default role (used for this markup: `text`) to use for all
|
|
||||||
# documents.
|
|
||||||
# default_role = None
|
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
|
||||||
# add_function_parentheses = True
|
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
|
||||||
# unit titles (such as .. function::).
|
|
||||||
# add_module_names = True
|
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
|
||||||
# output. They are ignored by default.
|
|
||||||
# show_authors = False
|
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
|
||||||
pygments_style = 'sphinx'
|
|
||||||
|
|
||||||
# A list of ignored prefixes for module index sorting.
|
|
||||||
# modindex_common_prefix = []
|
|
||||||
|
|
||||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
|
||||||
# keep_warnings = False
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output ----------------------------------------------
|
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
|
||||||
# a list of builtin themes.
|
|
||||||
html_theme = 'openstackdocs'
|
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
|
||||||
# further. For a list of options available for each theme, see the
|
|
||||||
# documentation.
|
|
||||||
# html_theme_options = {}
|
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
|
||||||
# html_theme_path = []
|
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
|
||||||
# "<project> v<release> documentation".
|
|
||||||
# html_title = None
|
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
|
||||||
# html_short_title = None
|
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top
|
|
||||||
# of the sidebar.
|
|
||||||
# html_logo = None
|
|
||||||
|
|
||||||
# The name of an image file (within the static path) to use as favicon of the
|
|
||||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
|
||||||
# pixels large.
|
|
||||||
# html_favicon = None
|
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
|
||||||
html_static_path = ['_static']
|
|
||||||
|
|
||||||
# Add any extra paths that contain custom files (such as robots.txt or
|
|
||||||
# .htaccess) here, relative to this directory. These files are copied
|
|
||||||
# directly to the root of the documentation.
|
|
||||||
# html_extra_path = []
|
|
||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
|
||||||
# using the given strftime format.
|
|
||||||
# html_last_updated_fmt = '%b %d, %Y'
|
|
||||||
|
|
||||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
|
||||||
# typographically correct entities.
|
|
||||||
# html_use_smartypants = True
|
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
|
||||||
# html_sidebars = {}
|
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names to
|
|
||||||
# template names.
|
|
||||||
# html_additional_pages = {}
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# html_domain_indices = True
|
|
||||||
|
|
||||||
# If false, no index is generated.
|
|
||||||
# html_use_index = True
|
|
||||||
|
|
||||||
# If true, the index is split into individual pages for each letter.
|
|
||||||
# html_split_index = False
|
|
||||||
|
|
||||||
# If true, links to the reST sources are added to the pages.
|
|
||||||
# html_show_sourcelink = True
|
|
||||||
|
|
||||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
|
||||||
# html_show_sphinx = True
|
|
||||||
|
|
||||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
|
||||||
# html_show_copyright = True
|
|
||||||
|
|
||||||
# If true, an OpenSearch description file will be output, and all pages will
|
|
||||||
# contain a <link> tag referring to it. The value of this option must be the
|
|
||||||
# base URL from which the finished HTML is served.
|
|
||||||
# html_use_opensearch = ''
|
|
||||||
|
|
||||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
|
||||||
# html_file_suffix = None
|
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
|
||||||
htmlhelp_basename = 'solum_tempest_pluginReleaseNotesdoc'
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output ---------------------------------------------
|
|
||||||
|
|
||||||
latex_elements = {
|
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
|
||||||
# 'papersize': 'letterpaper',
|
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
|
||||||
# 'pointsize': '10pt',
|
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
# 'preamble': '',
|
|
||||||
}
|
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
|
||||||
# (source start file, target name, title,
|
|
||||||
# author, documentclass [howto, manual, or own class]).
|
|
||||||
latex_documents = [
|
|
||||||
('index', 'solum_tempest_pluginReleaseNotes.tex',
|
|
||||||
u'solum_tempest_plugin Release Notes Documentation',
|
|
||||||
u'OpenStack Foundation', 'manual'),
|
|
||||||
]
|
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
|
||||||
# the title page.
|
|
||||||
# latex_logo = None
|
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
|
||||||
# not chapters.
|
|
||||||
# latex_use_parts = False
|
|
||||||
|
|
||||||
# If true, show page references after internal links.
|
|
||||||
# latex_show_pagerefs = False
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
|
||||||
# latex_show_urls = False
|
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
|
||||||
# latex_appendices = []
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# latex_domain_indices = True
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ---------------------------------------
|
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
|
||||||
# (source start file, name, description, authors, manual section).
|
|
||||||
man_pages = [
|
|
||||||
('index', 'solum_tempest_pluginrereleasenotes',
|
|
||||||
u'solum_tempest_plugin Release Notes Documentation',
|
|
||||||
[u'OpenStack Foundation'], 1)
|
|
||||||
]
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
|
||||||
# man_show_urls = False
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output -------------------------------------------
|
|
||||||
|
|
||||||
# Grouping the document tree into Texinfo files. List of tuples
|
|
||||||
# (source start file, target name, title, author,
|
|
||||||
# dir menu entry, description, category)
|
|
||||||
texinfo_documents = [
|
|
||||||
('index', 'solum_tempest_plugin ReleaseNotes',
|
|
||||||
u'solum_tempest_plugin Release Notes Documentation',
|
|
||||||
u'OpenStack Foundation', 'solum_tempest_pluginReleaseNotes',
|
|
||||||
'One line description of project.',
|
|
||||||
'Miscellaneous'),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
|
||||||
# texinfo_appendices = []
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
|
||||||
# texinfo_domain_indices = True
|
|
||||||
|
|
||||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
|
||||||
# texinfo_show_urls = 'footnote'
|
|
||||||
|
|
||||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
|
||||||
# texinfo_no_detailmenu = False
|
|
||||||
|
|
||||||
# -- Options for Internationalization output ------------------------------
|
|
||||||
locale_dirs = ['locale/']
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
============================================
|
|
||||||
solum_tempest_plugin Release Notes
|
|
||||||
============================================
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 1
|
|
||||||
|
|
||||||
unreleased
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
==============================
|
|
||||||
Current Series Release Notes
|
|
||||||
==============================
|
|
||||||
|
|
||||||
.. release-notes::
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# The order of packages is significant, because pip processes them in the order
|
|
||||||
# of appearance. Changing the order has an impact on the overall integration
|
|
||||||
# process, which may cause wedges in the gate later.
|
|
||||||
|
|
||||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
|
||||||
29
setup.cfg
29
setup.cfg
@@ -1,29 +0,0 @@
|
|||||||
[metadata]
|
|
||||||
name = solum-tempest-plugin
|
|
||||||
summary = Tempest plugin for the solum project.
|
|
||||||
description-file =
|
|
||||||
README.rst
|
|
||||||
author = OpenStack
|
|
||||||
author-email = openstack-discuss@lists.openstack.org
|
|
||||||
home-page = https://docs.openstack.org/solum/latest/
|
|
||||||
python-requires = >=3.6
|
|
||||||
classifier =
|
|
||||||
Environment :: OpenStack
|
|
||||||
Intended Audience :: Information Technology
|
|
||||||
Intended Audience :: System Administrators
|
|
||||||
License :: OSI Approved :: Apache Software License
|
|
||||||
Operating System :: POSIX :: Linux
|
|
||||||
Programming Language :: Python
|
|
||||||
Programming Language :: Python :: Implementation :: CPython
|
|
||||||
Programming Language :: Python :: 3 :: Only
|
|
||||||
Programming Language :: Python :: 3
|
|
||||||
Programming Language :: Python :: 3.6
|
|
||||||
Programming Language :: Python :: 3.7
|
|
||||||
|
|
||||||
[files]
|
|
||||||
packages =
|
|
||||||
solum_tempest_plugin
|
|
||||||
|
|
||||||
[entry_points]
|
|
||||||
tempest.test_plugins =
|
|
||||||
solum_tests = solum_tempest_plugin.plugin:SolumTempestPlugin
|
|
||||||
20
setup.py
20
setup.py
@@ -1,20 +0,0 @@
|
|||||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
# implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import setuptools
|
|
||||||
|
|
||||||
setuptools.setup(
|
|
||||||
setup_requires=['pbr>=2.0.0'],
|
|
||||||
pbr=True)
|
|
||||||
@@ -1,273 +0,0 @@
|
|||||||
# Copyright 2013 - Noorul Islam K M
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import copy
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
import string
|
|
||||||
import time
|
|
||||||
|
|
||||||
from tempest.common import credentials_factory as common_creds
|
|
||||||
from tempest import config
|
|
||||||
from tempest.lib import auth
|
|
||||||
from tempest.lib.common import http
|
|
||||||
from tempest.lib.common import rest_client
|
|
||||||
import testtools
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from solum_tempest_plugin.common import apputils
|
|
||||||
|
|
||||||
|
|
||||||
CONF = config.CONF
|
|
||||||
|
|
||||||
assembly_sample_data = {"name": "test_assembly",
|
|
||||||
"description": "A test to create assembly",
|
|
||||||
"project_id": "project_id",
|
|
||||||
"user_id": "user_id",
|
|
||||||
"status": "status",
|
|
||||||
"application_uri": "http://localhost:5000"}
|
|
||||||
|
|
||||||
plan_sample_data = {"version": "1",
|
|
||||||
"name": "test_plan",
|
|
||||||
"description": "A test to create plan",
|
|
||||||
"project_id": "project_id",
|
|
||||||
"user_id": "user_id",
|
|
||||||
"artifacts": [{
|
|
||||||
"name": "No deus",
|
|
||||||
"artifact_type": "heroku",
|
|
||||||
"content": {
|
|
||||||
"href": "https://example.com/git/a.git",
|
|
||||||
"private": False
|
|
||||||
},
|
|
||||||
"language_pack": "auto",
|
|
||||||
}]}
|
|
||||||
|
|
||||||
solum_group = config.cfg.OptGroup(name='solum', title='Solum test options')
|
|
||||||
SolumGroup = [
|
|
||||||
config.cfg.BoolOpt('barbican_enabled',
|
|
||||||
default=False,
|
|
||||||
help="Defaults to false. Determines whether Barbican"
|
|
||||||
"is enabled."),
|
|
||||||
config.cfg.BoolOpt('camp_enabled',
|
|
||||||
default=False,
|
|
||||||
help="Defaults to true. Determines whether CAMP"
|
|
||||||
"is enabled.")
|
|
||||||
]
|
|
||||||
|
|
||||||
CONF.register_group(solum_group)
|
|
||||||
CONF.register_opts(SolumGroup, group=solum_group.name)
|
|
||||||
|
|
||||||
|
|
||||||
class SolumClient(rest_client.RestClient):
|
|
||||||
|
|
||||||
def __init__(self, auth_provider, service='application_deployment',
|
|
||||||
region='RegionOne'):
|
|
||||||
super(SolumClient, self).__init__(auth_provider, service, region)
|
|
||||||
self.endpoint_url = 'publicURL'
|
|
||||||
self.created_assemblies = []
|
|
||||||
self.created_plans = []
|
|
||||||
self.created_apps = []
|
|
||||||
self.created_lps = []
|
|
||||||
|
|
||||||
def request_without_auth(self, resource, method, headers=None, body=None):
|
|
||||||
if headers is None:
|
|
||||||
headers = {}
|
|
||||||
dscv = CONF.identity.disable_ssl_certificate_validation
|
|
||||||
http_obj = http.ClosingHttp(disable_ssl_certificate_validation=dscv)
|
|
||||||
url = '%s/%s' % (self.base_url, resource)
|
|
||||||
return http_obj.request(url, method, headers=headers, body=body)
|
|
||||||
|
|
||||||
def assembly_delete_done(self, assembly_uuid):
|
|
||||||
wait_interval = 1
|
|
||||||
growth_factor = 1.2
|
|
||||||
max_attempts = 5
|
|
||||||
|
|
||||||
for count in range(max_attempts):
|
|
||||||
try:
|
|
||||||
resp, body = self.get('v1/assemblies/%s' % assembly_uuid)
|
|
||||||
except Exception:
|
|
||||||
return True
|
|
||||||
time.sleep(wait_interval)
|
|
||||||
wait_interval *= growth_factor
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def create_assembly(self, plan_uuid, data=None):
|
|
||||||
assembly_data = copy.deepcopy(data or assembly_sample_data)
|
|
||||||
assembly_data['plan_uri'] = "%s/v1/plans/%s" % (self.base_url,
|
|
||||||
plan_uuid)
|
|
||||||
jsondata = json.dumps(assembly_data)
|
|
||||||
resp, body = self.post('v1/assemblies', jsondata)
|
|
||||||
assembly_resp = SolumResponse(resp=resp, body=body, body_type='json')
|
|
||||||
uuid = assembly_resp.uuid
|
|
||||||
if uuid is not None:
|
|
||||||
self.created_assemblies.append(uuid)
|
|
||||||
return assembly_resp
|
|
||||||
|
|
||||||
def create_plan(self, data=None):
|
|
||||||
plan_data = copy.deepcopy(data or plan_sample_data)
|
|
||||||
yaml_data = yaml.dump(plan_data)
|
|
||||||
resp, body = self.post('v1/plans', yaml_data,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
plan_resp = SolumResponse(resp=resp, body=body, body_type='yaml')
|
|
||||||
uuid = plan_resp.uuid
|
|
||||||
if uuid is not None:
|
|
||||||
self.created_plans.append(uuid)
|
|
||||||
return plan_resp
|
|
||||||
|
|
||||||
def create_lp(self, data=None):
|
|
||||||
sample_lp = dict()
|
|
||||||
s = string.ascii_lowercase
|
|
||||||
sample_lp["name"] = "lp" + ''.join(random.sample(s, 5))
|
|
||||||
lp_url = "https://github.com/murali44/Solum-lp-Go.git"
|
|
||||||
sample_lp["source_uri"] = lp_url
|
|
||||||
jsondata = json.dumps(sample_lp)
|
|
||||||
resp, body = self.post('v1/language_packs', jsondata)
|
|
||||||
return sample_lp["name"]
|
|
||||||
|
|
||||||
def create_app(self, data=None):
|
|
||||||
app_data = copy.deepcopy(data) or apputils.get_sample_data()
|
|
||||||
json_data = json.dumps(app_data)
|
|
||||||
resp, body = self.post('v1/apps', json_data)
|
|
||||||
|
|
||||||
app_resp = SolumResponse(resp=resp, body=body, body_type='yaml')
|
|
||||||
if app_resp.id is not None:
|
|
||||||
self.created_apps.append(app_resp.id)
|
|
||||||
return app_resp
|
|
||||||
|
|
||||||
def delete_created_assemblies(self):
|
|
||||||
[self.delete_assembly(uuid) for uuid in list(self.created_assemblies)]
|
|
||||||
self.created_assemblies = []
|
|
||||||
|
|
||||||
def delete_assembly(self, uuid):
|
|
||||||
resp, body = self.delete('v1/assemblies/%s' % uuid)
|
|
||||||
if self.assembly_delete_done(uuid):
|
|
||||||
self.created_assemblies.remove(uuid)
|
|
||||||
return resp, body
|
|
||||||
|
|
||||||
def delete_created_plans(self):
|
|
||||||
self.delete_created_assemblies()
|
|
||||||
[self.delete_plan(uuid) for uuid in list(self.created_plans)]
|
|
||||||
self.created_plans = []
|
|
||||||
|
|
||||||
def delete_created_lps(self):
|
|
||||||
resp, body = self.get('v1/language_packs')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
[self._delete_language_pack(pl['uuid']) for pl in data]
|
|
||||||
|
|
||||||
def _delete_language_pack(self, uuid):
|
|
||||||
resp, _ = self.delete('v1/language_packs/%s' % uuid)
|
|
||||||
|
|
||||||
def delete_language_pack(self, name):
|
|
||||||
resp, _ = self.delete('v1/language_packs/%s' % name)
|
|
||||||
|
|
||||||
def delete_created_apps(self):
|
|
||||||
self.delete_created_assemblies()
|
|
||||||
[self.delete_app(id) for id in list(self.created_apps)]
|
|
||||||
self.created_apps = []
|
|
||||||
|
|
||||||
def delete_app(self, id):
|
|
||||||
resp, body = self.delete(
|
|
||||||
'v1/apps/%s' % id,
|
|
||||||
headers={'content-type': 'application/json'})
|
|
||||||
if id in self.created_apps:
|
|
||||||
self.created_apps.remove(id)
|
|
||||||
return resp, body
|
|
||||||
|
|
||||||
def delete_plan(self, uuid):
|
|
||||||
resp, body = self.delete(
|
|
||||||
'v1/plans/%s' % uuid,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
self.created_plans.remove(uuid)
|
|
||||||
return resp, body
|
|
||||||
|
|
||||||
|
|
||||||
class SolumResponse(object):
|
|
||||||
def __init__(self, resp, body, body_type):
|
|
||||||
self.resp = resp
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
self.body = body
|
|
||||||
if body_type == 'json':
|
|
||||||
self.data = json.loads(self.body)
|
|
||||||
elif body_type == 'yaml':
|
|
||||||
self.data = yaml.safe_load(self.body)
|
|
||||||
if self.data.get('uuid'):
|
|
||||||
self.uuid = self.data.get('uuid')
|
|
||||||
if self.data.get('id'):
|
|
||||||
self.id = self.data.get('id')
|
|
||||||
|
|
||||||
@property
|
|
||||||
def status(self):
|
|
||||||
return self.resp.status
|
|
||||||
|
|
||||||
@property
|
|
||||||
def yaml_data(self):
|
|
||||||
return yaml.safe_load(self.body)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def json_data(self):
|
|
||||||
return json.loads(self.body)
|
|
||||||
|
|
||||||
|
|
||||||
class TestCase(testtools.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestCase, self).setUp()
|
|
||||||
|
|
||||||
credentials = common_creds.get_configured_admin_credentials(
|
|
||||||
'identity_admin')
|
|
||||||
|
|
||||||
auth_provider = get_auth_provider(credentials)
|
|
||||||
self.client = SolumClient(auth_provider)
|
|
||||||
self.builderclient = SolumClient(auth_provider, 'image_builder')
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
super(TestCase, self).tearDown()
|
|
||||||
self.client.delete_created_apps()
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def is_fedora():
|
|
||||||
if os.path.exists("/etc/redhat-release"):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def config_set_as(config, target_value):
|
|
||||||
value = getattr(CONF.solum, config)
|
|
||||||
return value == target_value
|
|
||||||
@@ -1,38 +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 random
|
|
||||||
import string
|
|
||||||
|
|
||||||
|
|
||||||
def get_sample_data(languagepack=''):
|
|
||||||
data = dict()
|
|
||||||
s = string.ascii_lowercase
|
|
||||||
data["name"] = "test_app" + ''.join(random.sample(s, 5))
|
|
||||||
data["description"] = "descp"
|
|
||||||
data["languagepack"] = languagepack
|
|
||||||
data["trigger_actions"] = ["test", "build", "deploy"]
|
|
||||||
data["ports"] = [80]
|
|
||||||
|
|
||||||
source = {}
|
|
||||||
source['repository'] = "https://github.com/a/b.git"
|
|
||||||
source['revision'] = "master"
|
|
||||||
data["source"] = source
|
|
||||||
|
|
||||||
workflow = {}
|
|
||||||
workflow["test_cmd"] = "./unit_tests.sh"
|
|
||||||
workflow["run_cmd"] = "python app.py"
|
|
||||||
data["workflow_config"] = workflow
|
|
||||||
|
|
||||||
data["repo_token"] = 'abc'
|
|
||||||
|
|
||||||
return data
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
# implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
|
||||||
|
|
||||||
|
|
||||||
service_option = cfg.BoolOpt("solum",
|
|
||||||
default=True,
|
|
||||||
help="Whether or not solum is expected to be "
|
|
||||||
"available")
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from tempest.test_discover import plugins
|
|
||||||
|
|
||||||
from solum_tempest_plugin import config as solum_config
|
|
||||||
|
|
||||||
|
|
||||||
class SolumTempestPlugin(plugins.TempestPlugin):
|
|
||||||
def load_tests(self):
|
|
||||||
base_path = os.path.split(os.path.dirname(
|
|
||||||
os.path.abspath(__file__)))[0]
|
|
||||||
test_dir = "solum_tempest_plugin/tests"
|
|
||||||
full_test_dir = os.path.join(base_path, test_dir)
|
|
||||||
return full_test_dir, base_path
|
|
||||||
|
|
||||||
def register_opts(self, conf):
|
|
||||||
conf.register_opt(solum_config.service_option,
|
|
||||||
group='service_available')
|
|
||||||
|
|
||||||
def get_opt_lists(self):
|
|
||||||
return [('service_available', [solum_config.service_option])]
|
|
||||||
@@ -1,58 +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 json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class PlatformDiscoveryTestCase(base.TestCase):
|
|
||||||
|
|
||||||
def test_get_root_discovers_camp_v1_1(self):
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
# get our platform_endpoints container
|
|
||||||
resp, body = (self.client.
|
|
||||||
request_without_auth('camp/platform_endpoints',
|
|
||||||
'GET'))
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
endpoints = json.loads(body)
|
|
||||||
self.assertEqual('platform_endpoints', endpoints['type'])
|
|
||||||
self.assertEqual('Solum_CAMP_endpoints', endpoints['name'])
|
|
||||||
pe_links = endpoints['platform_endpoint_links']
|
|
||||||
|
|
||||||
# there should be one element in the Link array
|
|
||||||
self.assertEqual(1, len(pe_links))
|
|
||||||
camp_v1_1_link = pe_links[0]
|
|
||||||
self.assertEqual('Solum_CAMP_v1_1_endpoint',
|
|
||||||
camp_v1_1_link['target_name'])
|
|
||||||
|
|
||||||
# get the URL of the platform_endpoint and strip the base URL
|
|
||||||
rel_ep_url = camp_v1_1_link['href'][len(self.client.base_url) + 1:]
|
|
||||||
|
|
||||||
# get our lone platform_endpoint resource
|
|
||||||
resp, body = (self.client.
|
|
||||||
request_without_auth(rel_ep_url,
|
|
||||||
'GET'))
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
endpoint = json.loads(body)
|
|
||||||
self.assertEqual('platform_endpoint', endpoint['type'])
|
|
||||||
self.assertEqual('Solum_CAMP_v1_1_endpoint', endpoint['name'])
|
|
||||||
self.assertEqual('CAMP 1.1', endpoint['specification_version'])
|
|
||||||
self.assertEqual('Solum CAMP 1.1', endpoint['implementation_version'])
|
|
||||||
self.assertEqual('KEYSTONE-2.0', endpoint['auth_scheme'])
|
|
||||||
self.assertEqual('%s/camp/v1_1/platform' % self.client.base_url,
|
|
||||||
endpoint['platform_uri'])
|
|
||||||
@@ -1,161 +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 json
|
|
||||||
|
|
||||||
from tempest.lib import exceptions as tempest_exceptions
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
from solum_tempest_plugin.tests.application_deployment.camp.v1_1 \
|
|
||||||
import test_plans
|
|
||||||
|
|
||||||
|
|
||||||
class TestAssembliesController(base.TestCase):
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
super(TestAssembliesController, self).tearDown()
|
|
||||||
self.client.delete_created_assemblies()
|
|
||||||
self.client.delete_created_plans()
|
|
||||||
|
|
||||||
# TODO(gpilz) - this is a dup of a method in test_plans.TestPlansController
|
|
||||||
def _create_camp_plan(self, data):
|
|
||||||
yaml_data = yaml.dump(data)
|
|
||||||
resp, body = self.client.post('camp/v1_1/plans', yaml_data,
|
|
||||||
headers={'content-type':
|
|
||||||
'application/x-yaml'})
|
|
||||||
plan_resp = base.SolumResponse(resp=resp,
|
|
||||||
body=body,
|
|
||||||
body_type='json')
|
|
||||||
uuid = plan_resp.uuid
|
|
||||||
if uuid is not None:
|
|
||||||
# share the Solum client's list of created plans
|
|
||||||
self.client.created_plans.append(uuid)
|
|
||||||
return plan_resp
|
|
||||||
|
|
||||||
def test_get_solum_assembly(self):
|
|
||||||
"""Test the CAMP assemblies collection resource.
|
|
||||||
|
|
||||||
Test that an assembly resource created through the Solum API is
|
|
||||||
visible via the CAMP API.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create an assembly using Solum
|
|
||||||
p_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, p_resp.status)
|
|
||||||
a_resp = self.client.create_assembly(plan_uuid=p_resp.uuid)
|
|
||||||
self.assertEqual(201, a_resp.status)
|
|
||||||
new_uuid = a_resp.uuid
|
|
||||||
|
|
||||||
# try to get to the newly created assembly through the CAMP assemblies
|
|
||||||
# resource. it would be more efficient to simply take the UUID of the
|
|
||||||
# newly created resource and create a CAMP API URI
|
|
||||||
# (../camp/v1_1/assemblies/<uuid>) from that, but we want to test that
|
|
||||||
# a link to the Solum-created assembly appears in in the list of links
|
|
||||||
# in the CAMP plans resource.
|
|
||||||
resp, body = self.client.get('camp/v1_1/assemblies')
|
|
||||||
self.assertEqual(200, resp.status, 'GET assemblies resource')
|
|
||||||
|
|
||||||
# pick out the assemebly link for our new assembly uuid
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
assemblies_dct = json.loads(body)
|
|
||||||
camp_link = None
|
|
||||||
for link in assemblies_dct['assembly_links']:
|
|
||||||
link_uuid = link['href'].split("/")[-1]
|
|
||||||
if link_uuid == new_uuid:
|
|
||||||
camp_link = link
|
|
||||||
|
|
||||||
msg = 'Unable to find link to newly created plan in CAMP plans'
|
|
||||||
self.assertIsNotNone(camp_link, msg)
|
|
||||||
|
|
||||||
url = camp_link['href'][len(self.client.base_url) + 1:]
|
|
||||||
msg = ("GET Solum assembly resource for %s" %
|
|
||||||
camp_link['target_name'])
|
|
||||||
resp, body = self.client.get(url)
|
|
||||||
self.assertEqual(200, resp.status, msg)
|
|
||||||
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
assembly = json.loads(body)
|
|
||||||
self.assertEqual('assembly', assembly['type'])
|
|
||||||
self.assertEqual(base.assembly_sample_data['name'], assembly['name'])
|
|
||||||
|
|
||||||
def test_create_camp_assembly(self):
|
|
||||||
"""Test creating a CAMP assembly from a local plan resource.
|
|
||||||
|
|
||||||
Creates a plan resource then uses that to create an assembly resource.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using the CAMP API
|
|
||||||
resp = self._create_camp_plan(data=test_plans.sample_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
uri = (resp.data['uri']
|
|
||||||
[len(self.client.base_url):])
|
|
||||||
|
|
||||||
ref_obj = json.dumps({'plan_uri': uri})
|
|
||||||
|
|
||||||
resp, body = self.client.post(
|
|
||||||
'camp/v1_1/assemblies',
|
|
||||||
ref_obj,
|
|
||||||
headers={'content-type': 'application/json'})
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
|
|
||||||
assem_resp = base.SolumResponse(resp=resp,
|
|
||||||
body=body,
|
|
||||||
body_type='json')
|
|
||||||
uuid = assem_resp.uuid
|
|
||||||
if uuid is not None:
|
|
||||||
# share the Solum client's list of created assemblies
|
|
||||||
self.client.created_assemblies.append(uuid)
|
|
||||||
|
|
||||||
def test_delete_plan_with_assemblies(self):
|
|
||||||
"""Test deleting a plan that has assemblies associated with it.
|
|
||||||
|
|
||||||
Creates a plan, an assembly, then tries to delete the plan.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using the CAMP API
|
|
||||||
resp = self._create_camp_plan(data=test_plans.sample_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
plan_uri = (resp.data['uri']
|
|
||||||
[len(self.client.base_url):])
|
|
||||||
|
|
||||||
ref_obj = json.dumps({'plan_uri': plan_uri})
|
|
||||||
|
|
||||||
resp, body = self.client.post(
|
|
||||||
'camp/v1_1/assemblies',
|
|
||||||
ref_obj,
|
|
||||||
headers={'content-type': 'application/json'})
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
|
|
||||||
assem_resp = base.SolumResponse(resp=resp,
|
|
||||||
body=body,
|
|
||||||
body_type='json')
|
|
||||||
uuid = assem_resp.uuid
|
|
||||||
if uuid is not None:
|
|
||||||
# share the Solum client's list of created assemblies
|
|
||||||
self.client.created_assemblies.append(uuid)
|
|
||||||
|
|
||||||
# try to delete the plan before deleting the assembly
|
|
||||||
# resp, body = self.client.delete(plan_uri[1:])
|
|
||||||
# self.assertEqual(409, resp.status)
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.Conflict,
|
|
||||||
self.client.delete, plan_uri[1:])
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestSupportedFormats(base.TestCase):
|
|
||||||
|
|
||||||
def test_formats(self):
|
|
||||||
"""Tests normative statement RE-42 from the CAMP v1.1 specification:
|
|
||||||
|
|
||||||
http://docs.oasis-open.org/camp/camp-spec/v1.1/csprd02/
|
|
||||||
camp-spec-v1.1-csprd02.pdf
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
resp, body = self.client.get('camp/v1_1/formats/')
|
|
||||||
self.assertEqual(200, resp.status, 'GET formats resource')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
formats = json.loads(body)
|
|
||||||
self.assertEqual('formats', formats['type'])
|
|
||||||
self.assertEqual('Solum_CAMP_formats', formats['name'])
|
|
||||||
format_links = formats['format_links']
|
|
||||||
|
|
||||||
# there should be one element in the Link array
|
|
||||||
self.assertEqual(1, len(format_links), 'RE-42')
|
|
||||||
json_link = format_links[0]
|
|
||||||
self.assertEqual('JSON', json_link['target_name'])
|
|
||||||
|
|
||||||
# get the URL of the platform_endpoint and strip the base URL
|
|
||||||
url = json_link['href'][len(self.client.base_url) + 1:]
|
|
||||||
|
|
||||||
# get our lone platform_endpoint resource
|
|
||||||
resp, body = self.client.get(url)
|
|
||||||
self.assertEqual(200, resp.status, 'GET JSON format resource')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
formatr = json.loads(body)
|
|
||||||
self.assertEqual('format', formatr['type'])
|
|
||||||
self.assertEqual('JSON', formatr['name'], 'RE-42')
|
|
||||||
self.assertEqual('application/json', formatr['mime_type'], 'RE-42')
|
|
||||||
self.assertEqual('RFC4627', formatr['version'], 'RE-42')
|
|
||||||
self.assertEqual('http://www.ietf.org/rfc/rfc4627.txt',
|
|
||||||
formatr['documentation'],
|
|
||||||
'RE-42')
|
|
||||||
@@ -1,106 +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 json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestParameterDefinitions(base.TestCase):
|
|
||||||
|
|
||||||
def test_assembly_parameter_definitions(self):
|
|
||||||
"""Tests normative statement RMR-03 from the CAMP v1.1 specification:
|
|
||||||
|
|
||||||
http://docs.oasis-open.org/camp/camp-spec/v1.1/csprd02/
|
|
||||||
camp-spec-v1.1-csprd02.pdf
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
resp, body = self.client.get('camp/v1_1/assemblies/')
|
|
||||||
self.assertEqual(200, resp.status, 'GET assemblies resource')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
assemblies = json.loads(body)
|
|
||||||
|
|
||||||
# get the URL of the parameter_definitions resource
|
|
||||||
url = (assemblies['parameter_definitions_uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
|
|
||||||
# get the parameter_definitions resource
|
|
||||||
resp, body = self.client.get(url)
|
|
||||||
self.assertEqual(200, resp.status,
|
|
||||||
'GET assembly parameter_definitions resource')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
pd_resc = json.loads(body)
|
|
||||||
self.assertEqual('parameter_definitions', pd_resc['type'])
|
|
||||||
self.assertIn('parameter_definition_links', pd_resc)
|
|
||||||
pd_links = pd_resc['parameter_definition_links']
|
|
||||||
|
|
||||||
# The assembly resource must reference parameter definitions for
|
|
||||||
# the pdp_uri, plan_uri, pdp_file, and plan_file parameters. It
|
|
||||||
# can reference additional parameter definitions.
|
|
||||||
self.assertLessEqual(4,
|
|
||||||
len(pd_links),
|
|
||||||
"too few parameter definition links")
|
|
||||||
expected_pds = ['pdp_uri', 'plan_uri', 'pdp_file', 'plan_file']
|
|
||||||
for pd_link in pd_links:
|
|
||||||
expected_pds.remove(pd_link['target_name'])
|
|
||||||
|
|
||||||
self.assertEqual(0,
|
|
||||||
len(expected_pds),
|
|
||||||
('Missing parameter_definition from %s' %
|
|
||||||
pd_resc['name']))
|
|
||||||
|
|
||||||
def test_plan_parameter_definitions(self):
|
|
||||||
"""Tests normative statement RMR-06 from the CAMP v1.1 specification:
|
|
||||||
|
|
||||||
http://docs.oasis-open.org/camp/camp-spec/v1.1/csprd02/
|
|
||||||
camp-spec-v1.1-csprd02.pdf
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
resp, body = self.client.get('camp/v1_1/plans/')
|
|
||||||
self.assertEqual(200, resp.status, 'GET plans resource')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
plans = json.loads(body)
|
|
||||||
|
|
||||||
# get the URL of the parameter_definitions resource
|
|
||||||
url = (plans['parameter_definitions_uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
|
|
||||||
# get the parameter_definitions resource
|
|
||||||
resp, body = self.client.get(url)
|
|
||||||
self.assertEqual(200, resp.status,
|
|
||||||
'GET plans parameter_definitions resource')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
pd_resc = json.loads(body)
|
|
||||||
self.assertEqual('parameter_definitions', pd_resc['type'])
|
|
||||||
self.assertIn('parameter_definition_links', pd_resc)
|
|
||||||
pd_links = pd_resc['parameter_definition_links']
|
|
||||||
|
|
||||||
# The plan resource must reference parameter definitions for
|
|
||||||
# the pdp_uri, plan_uri, pdp_file, and plan_file parameters. It
|
|
||||||
# can reference additional parameter definitions.
|
|
||||||
self.assertLessEqual(4,
|
|
||||||
len(pd_links),
|
|
||||||
"too few parameter definition links")
|
|
||||||
expected_pds = ['pdp_uri', 'plan_uri', 'pdp_file', 'plan_file']
|
|
||||||
for pd_link in pd_links:
|
|
||||||
expected_pds.remove(pd_link['target_name'])
|
|
||||||
|
|
||||||
self.assertEqual(0,
|
|
||||||
len(expected_pds),
|
|
||||||
('Missing parameter_definition from %s' %
|
|
||||||
pd_resc['name']))
|
|
||||||
@@ -1,430 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import copy
|
|
||||||
import json
|
|
||||||
|
|
||||||
from tempest.lib import exceptions as tempest_exceptions
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
from solum_tempest_plugin.tests.application_deployment.v1 import test_plan \
|
|
||||||
as solum_tests
|
|
||||||
|
|
||||||
|
|
||||||
sample_data = {"camp_version": "CAMP 1.1",
|
|
||||||
"name": "camp_test_plan",
|
|
||||||
"description": "A test to create CAMP plan",
|
|
||||||
"artifacts": [{
|
|
||||||
"name": "train spotter service",
|
|
||||||
"artifact_type": "org.python:python",
|
|
||||||
"language_pack": "python1",
|
|
||||||
"content": {"href": "https://sporgil.com/git/spotter.git"},
|
|
||||||
"requirements": [{
|
|
||||||
"requirement_type": "org.python:runtime",
|
|
||||||
"fulfillment": {
|
|
||||||
"name": "python runtime",
|
|
||||||
"description": "python 2.7.x runtime",
|
|
||||||
"characteristics": [{
|
|
||||||
"characteristic_type": "org.python:version",
|
|
||||||
"version": "[2.7, 3,0)"
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}]}
|
|
||||||
|
|
||||||
|
|
||||||
class TestPlansController(base.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestPlansController, self).setUp()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
super(TestPlansController, self).tearDown()
|
|
||||||
self.client.delete_created_plans()
|
|
||||||
|
|
||||||
def _assert_output_expected(self, body_data, data):
|
|
||||||
self.assertEqual(body_data['name'], data['name'])
|
|
||||||
self.assertEqual(body_data['description'], data['description'])
|
|
||||||
if body_data['artifacts']:
|
|
||||||
self.assertEqual(body_data['artifacts'][0]['content']['href'],
|
|
||||||
data['artifacts'][0]['content']['href'])
|
|
||||||
self.assertIsNotNone(body_data['uuid'])
|
|
||||||
|
|
||||||
def _create_camp_plan(self, data):
|
|
||||||
yaml_data = yaml.dump(data)
|
|
||||||
resp, body = self.client.post('camp/v1_1/plans', yaml_data,
|
|
||||||
headers={'content-type':
|
|
||||||
'application/x-yaml'})
|
|
||||||
plan_resp = base.SolumResponse(resp=resp,
|
|
||||||
body=body,
|
|
||||||
body_type='json')
|
|
||||||
uuid = plan_resp.uuid
|
|
||||||
if uuid is not None:
|
|
||||||
# share the Solum client's list of created plans
|
|
||||||
self.client.created_plans.append(uuid)
|
|
||||||
return plan_resp
|
|
||||||
|
|
||||||
def test_get_solum_plan(self):
|
|
||||||
"""Test the visibility of Solum-created plans
|
|
||||||
|
|
||||||
Test that an plan resource created through the Solum API is
|
|
||||||
visible via the CAMP API.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using Solum
|
|
||||||
p_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, p_resp.status)
|
|
||||||
new_plan = p_resp.yaml_data
|
|
||||||
new_uuid = new_plan['uuid']
|
|
||||||
|
|
||||||
# try to get to the newly plan created through the CAMP plans
|
|
||||||
# resource. it would be more efficient to simply take the UUID of the
|
|
||||||
# newly created resource and create a CAMP API URI
|
|
||||||
# (../camp/v1_1/plans/<uuid>) from that, but we want to test that a
|
|
||||||
# link to the Solum-created plan appears in in the list of links in
|
|
||||||
# the CAMP plans resource.
|
|
||||||
resp, body = self.client.get('camp/v1_1/plans')
|
|
||||||
self.assertEqual(200, resp.status, 'GET plans resource')
|
|
||||||
|
|
||||||
# pick out the plan link for our new plan uuid
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
plans_dct = json.loads(body)
|
|
||||||
camp_link = None
|
|
||||||
for link in plans_dct['plan_links']:
|
|
||||||
link_uuid = link['href'].split("/")[-1]
|
|
||||||
if link_uuid == new_uuid:
|
|
||||||
camp_link = link
|
|
||||||
|
|
||||||
msg = 'Unable to find link to newly created plan in CAMP plans'
|
|
||||||
self.assertIsNotNone(camp_link, msg)
|
|
||||||
|
|
||||||
url = camp_link['href'][len(self.client.base_url) + 1:]
|
|
||||||
msg = ("GET Solum plan resource for %s" %
|
|
||||||
camp_link['target_name'])
|
|
||||||
resp, body = self.client.get(url)
|
|
||||||
self.assertEqual(200, resp.status, msg)
|
|
||||||
|
|
||||||
# CAMP plans are rendered in JSON
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
plan = json.loads(body)
|
|
||||||
self.assertEqual(base.plan_sample_data['name'], plan['name'])
|
|
||||||
self.assertEqual(base.plan_sample_data['description'],
|
|
||||||
plan['description'])
|
|
||||||
|
|
||||||
def test_create_camp_plan(self):
|
|
||||||
"""Test the visibility of CAMP-created plans
|
|
||||||
|
|
||||||
Test that an plan resource created through the CAMP API is
|
|
||||||
visible through the Solum API.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using the CAMP API
|
|
||||||
resp = self._create_camp_plan(data=sample_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
self._assert_output_expected(resp.data, sample_data)
|
|
||||||
|
|
||||||
uuid = resp.data['uuid']
|
|
||||||
|
|
||||||
# get the plan using the Solum API
|
|
||||||
resp, body = self.client.get(
|
|
||||||
'v1/plans/%s' % uuid,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
yaml_data = yaml.safe_load(body)
|
|
||||||
self._assert_output_expected(yaml_data, sample_data)
|
|
||||||
|
|
||||||
def test_create_camp_plan_with_private_github_repo(self):
|
|
||||||
"""Test CAMP support for private git repos
|
|
||||||
|
|
||||||
Test that CAMP support the Solum private github case.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# copy the Solum test data and add a camp_version
|
|
||||||
camp_data = copy.copy(solum_tests.sample_data_private)
|
|
||||||
camp_data['camp_version'] = 'CAMP 1.1'
|
|
||||||
|
|
||||||
resp = self._create_camp_plan(data=camp_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
self._assert_output_expected(resp.data, camp_data)
|
|
||||||
|
|
||||||
def test_get_no_plan(self):
|
|
||||||
"""Try to GET a CAMP plan that doesn't exist
|
|
||||||
|
|
||||||
Test the CAMP API's ability to respond with an HTTP 404 when doing a
|
|
||||||
GET on a non-existent plan.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.get, 'camp/v1_1/plans/no_plan')
|
|
||||||
|
|
||||||
def test_create_bad_content_type(self):
|
|
||||||
"""Try to create a CAMP plan with a bogus Content-Type
|
|
||||||
|
|
||||||
Test that an attempt to create a plan with an incorrect Content-Type
|
|
||||||
header results in the proper error.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
yaml_data = yaml.dump(sample_data)
|
|
||||||
self.assertRaises(tempest_exceptions.InvalidContentType,
|
|
||||||
self.client.post, 'camp/v1_1/plans', yaml_data,
|
|
||||||
headers={'content-type': 'image/jpeg'})
|
|
||||||
|
|
||||||
def test_create_no_camp_version(self):
|
|
||||||
"""Try to create a CAMP plan from input lacking 'camp_version'
|
|
||||||
|
|
||||||
Test that an attempt to create a plan with no 'camp_version' results
|
|
||||||
in the proper error.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
no_version_data = copy.copy(sample_data)
|
|
||||||
del no_version_data['camp_version']
|
|
||||||
no_version_str = yaml.dump(no_version_data)
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'camp/v1_1/plans',
|
|
||||||
no_version_str,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_create_bad_camp_version(self):
|
|
||||||
"""Try to create a CAMP plan from input with incorrect 'camp_version'
|
|
||||||
|
|
||||||
Test that an attempt to create a plan with an incorrect 'camp_version'
|
|
||||||
results in the proper error.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
bad_version_data = copy.copy(sample_data)
|
|
||||||
bad_version_data['camp_version'] = 'CAMP 8.1'
|
|
||||||
bad_version_str = yaml.dump(bad_version_data)
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'camp/v1_1/plans',
|
|
||||||
bad_version_str,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_create_empty_yaml(self):
|
|
||||||
"""Try to create a CAMP plan from an empty YAML document
|
|
||||||
|
|
||||||
Test that an attempt to create a plan using an empty yaml document
|
|
||||||
results in the proper error.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'camp/v1_1/plans', '{}',
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_create_invalid_yaml(self):
|
|
||||||
"""Try to create a CAMP plan from invalid YAML
|
|
||||||
|
|
||||||
Test that an attempt to create a plan using an invalid document
|
|
||||||
results in the proper error.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'camp/v1_1/plans', 'invalid type',
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_create_invalid_syntax(self):
|
|
||||||
"""Try to create a CAMP plan from garbled YAML
|
|
||||||
|
|
||||||
Test that an attempt to create a plan using yaml with an invalid syntax
|
|
||||||
results in the proper error.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'camp/v1_1/plans',
|
|
||||||
"}invalid: y'm'l3!",
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_delete_solum_plan_from_camp(self):
|
|
||||||
"""Test the ability to DELETE a Solum-created plan
|
|
||||||
|
|
||||||
Test that an plan resource created through the Solum API can
|
|
||||||
be deleted through the CAMP API.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using Solum
|
|
||||||
create_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
uuid = create_resp.uuid
|
|
||||||
|
|
||||||
# delete the plan using CAMP
|
|
||||||
resp, body = self.client.delete('camp/v1_1/plans/%s' % uuid)
|
|
||||||
self.assertEqual(204, resp.status)
|
|
||||||
|
|
||||||
# remove the plan from the list of plans so we don't try to remove it
|
|
||||||
# twice
|
|
||||||
self.client.created_plans.remove(uuid)
|
|
||||||
|
|
||||||
def test_delete_camp_plan_from_solum(self):
|
|
||||||
"""Test the ability of the Solum API to delete a CAMP-created plan
|
|
||||||
|
|
||||||
Test that an plan resource created through the CAMP API can
|
|
||||||
be deleted through the Solum API.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using the CAMP API
|
|
||||||
resp = self._create_camp_plan(data=sample_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
self._assert_output_expected(resp.data, sample_data)
|
|
||||||
|
|
||||||
uuid = resp.data['uuid']
|
|
||||||
|
|
||||||
# delete the plan using the Solum API
|
|
||||||
resp, body = self.client.delete('v1/plans/%s' % uuid)
|
|
||||||
self.assertEqual(202, resp.status)
|
|
||||||
|
|
||||||
# remove the plan from the list of plans so we don't try to remove it
|
|
||||||
# twice
|
|
||||||
self.client.created_plans.remove(uuid)
|
|
||||||
|
|
||||||
def test_delete_no_plan(self):
|
|
||||||
"""Try to DELTE a plan that doesn't exist
|
|
||||||
|
|
||||||
Test the ability of CAMP to respond with an HTTP 404 when the client
|
|
||||||
tries to DELETE a plan that doesn' exist
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.delete, 'camp/v1_1/plans/no_plan')
|
|
||||||
|
|
||||||
def test_patch_plan(self):
|
|
||||||
"""PATCH a CAMP plan.
|
|
||||||
|
|
||||||
Test the ability to modify a CAMP plan using the HTTP PATCH
|
|
||||||
method with a JSON Patch request.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using the CAMP API
|
|
||||||
resp = self._create_camp_plan(data=sample_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
uri = (resp.data['uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
|
|
||||||
patch_data = [
|
|
||||||
{"op": "add", "path": "/tags", "value": ["foo", "baz"]}
|
|
||||||
]
|
|
||||||
patch_json = json.dumps(patch_data)
|
|
||||||
|
|
||||||
resp, body = self.client.patch(
|
|
||||||
uri, patch_json,
|
|
||||||
headers={'content-type': 'application/json-patch+json'})
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self.assertIn('tags', json_data)
|
|
||||||
tags = json_data['tags']
|
|
||||||
self.assertEqual(2, len(tags))
|
|
||||||
self.assertEqual('foo', tags[0])
|
|
||||||
self.assertEqual('baz', tags[1])
|
|
||||||
|
|
||||||
def test_patch_no_plan(self):
|
|
||||||
"""Try to PATCH a non-existent CAMP plan
|
|
||||||
|
|
||||||
Test that an attempt to PATCH a plan that doesn't exist results in
|
|
||||||
an HTTP 404 "Not Found" error
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# use an invalid JSON Patch document to test correct error precedence
|
|
||||||
patch_data = [
|
|
||||||
{"op": "add", "value": ["foo", "baz"]}
|
|
||||||
]
|
|
||||||
patch_json = json.dumps(patch_data)
|
|
||||||
|
|
||||||
# use a bad Content-Type to further test correct error precedence
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.patch, 'camp/v1_1/plans/no_plan',
|
|
||||||
patch_json,
|
|
||||||
headers={'content-type':
|
|
||||||
'application/x-not-a-type'})
|
|
||||||
|
|
||||||
def test_patch_bad_content_type(self):
|
|
||||||
"""PATCH a CAMP plan using an incorrect content-type
|
|
||||||
|
|
||||||
Test that an attempt to patch a plan with an incorrect Content-Type
|
|
||||||
results in the proper error.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using the CAMP API
|
|
||||||
resp = self._create_camp_plan(data=sample_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
uri = (resp.data['uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
|
|
||||||
patch_data = [
|
|
||||||
{"op": "add", "path": "/tags", "value": ["foo", "baz"]}
|
|
||||||
]
|
|
||||||
patch_json = json.dumps(patch_data)
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.InvalidContentType,
|
|
||||||
self.client.patch, uri, patch_json,
|
|
||||||
headers={'content-type': 'application/x-not-a-type'})
|
|
||||||
|
|
||||||
def test_patch_bad_json_patch(self):
|
|
||||||
"""PATCH a CAMP plan using invalid JSON Patch document
|
|
||||||
|
|
||||||
Test that an attempt to patch a plan with a mal-formed JSON Patch
|
|
||||||
request (missing 'path') results in the proper error.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
# create a plan using the CAMP API
|
|
||||||
resp = self._create_camp_plan(data=sample_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
uri = (resp.data['uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
|
|
||||||
patch_data = [
|
|
||||||
{"op": "add", "value": ["foo", "baz"]}
|
|
||||||
]
|
|
||||||
patch_json = json.dumps(patch_data)
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.patch, uri, patch_json,
|
|
||||||
headers={'content-type':
|
|
||||||
'application/json-patch+json'})
|
|
||||||
@@ -1,77 +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 json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestPlatformAndContainers(base.TestCase):
|
|
||||||
|
|
||||||
def _test_get_resource(self, url, rtype, name):
|
|
||||||
resp, body = self.client.get(url)
|
|
||||||
self.assertEqual(200, resp.status, 'GET %s resource' % rtype)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
resource = json.loads(body)
|
|
||||||
self.assertEqual(rtype, resource['type'])
|
|
||||||
self.assertEqual(name, resource['name'])
|
|
||||||
|
|
||||||
def test_get_platform_and_containers(self):
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
# get and test our platform resource
|
|
||||||
resp, body = self.client.get('camp/v1_1/platform/')
|
|
||||||
self.assertEqual(200, resp.status, 'GET platform resource')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
platform = json.loads(body)
|
|
||||||
self.assertEqual('platform', platform['type'])
|
|
||||||
self.assertEqual('Solum_CAMP_v1_1_platform', platform['name'])
|
|
||||||
self.assertEqual('CAMP 1.1', platform['specification_version'])
|
|
||||||
self.assertEqual('Solum CAMP 1.1', platform['implementation_version'])
|
|
||||||
|
|
||||||
# get and test the supported formats resource
|
|
||||||
url = (platform['supported_formats_uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
self._test_get_resource(url, 'formats', 'Solum_CAMP_formats')
|
|
||||||
|
|
||||||
# get and test the extensions resource
|
|
||||||
url = (platform['extensions_uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
self._test_get_resource(url, 'extensions', 'Solum_CAMP_extensions')
|
|
||||||
|
|
||||||
# get and test the type_definitions resource
|
|
||||||
url = (platform['type_definitions_uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
self._test_get_resource(url,
|
|
||||||
'type_definitions',
|
|
||||||
'Solum_CAMP_type_definitions')
|
|
||||||
|
|
||||||
# get and test the platform_endpoints resource
|
|
||||||
url = (platform['platform_endpoints_uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
self._test_get_resource(url,
|
|
||||||
'platform_endpoints',
|
|
||||||
'Solum_CAMP_endpoints')
|
|
||||||
|
|
||||||
# get and test the assemblies collection resource
|
|
||||||
url = platform['assemblies_uri'][len(self.client.base_url) + 1:]
|
|
||||||
self._test_get_resource(url, 'assemblies', 'Solum_CAMP_assemblies')
|
|
||||||
|
|
||||||
# get and test the services collection resource
|
|
||||||
url = platform['services_uri'][len(self.client.base_url) + 1:]
|
|
||||||
self._test_get_resource(url, 'services', 'Solum_CAMP_services')
|
|
||||||
|
|
||||||
# get and test the plans collection resource
|
|
||||||
url = platform['plans_uri'][len(self.client.base_url) + 1:]
|
|
||||||
self._test_get_resource(url, 'plans', 'Solum_CAMP_plans')
|
|
||||||
@@ -1,62 +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 json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestTypeDefinitions(base.TestCase):
|
|
||||||
|
|
||||||
def _test_get_resource(self, abs_url, msg, rtype, name):
|
|
||||||
url = abs_url[len(self.client.base_url) + 1:]
|
|
||||||
resp, body = self.client.get(url)
|
|
||||||
self.assertEqual(200, resp.status, msg)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
resource = json.loads(body)
|
|
||||||
self.assertEqual(rtype, resource['type'])
|
|
||||||
self.assertEqual(name, resource['name'])
|
|
||||||
return body
|
|
||||||
|
|
||||||
def test_type_definitions(self):
|
|
||||||
"""Test the CAMP type_definition metadata.
|
|
||||||
|
|
||||||
Crawls tree rooted in type_definitions and verifies that all the
|
|
||||||
resources exist and that all the links to the attribute_definition
|
|
||||||
resources are valid and the attribute_definitions resources exist.
|
|
||||||
"""
|
|
||||||
if base.config_set_as('camp_enabled', False):
|
|
||||||
self.skipTest('CAMP not enabled.')
|
|
||||||
|
|
||||||
resp, body = self.client.get('camp/v1_1/type_definitions')
|
|
||||||
self.assertEqual(200, resp.status, 'GET type_definitions resource')
|
|
||||||
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
defs_dct = json.loads(body)
|
|
||||||
for link_dct in defs_dct['type_definition_links']:
|
|
||||||
msg = ("GET type_definition resource for %s" %
|
|
||||||
link_dct['target_name'])
|
|
||||||
body = self._test_get_resource(link_dct['href'],
|
|
||||||
msg,
|
|
||||||
'type_definition',
|
|
||||||
link_dct['target_name'])
|
|
||||||
|
|
||||||
def_dct = json.loads(body)
|
|
||||||
for adl_dct in def_dct['attribute_definition_links']:
|
|
||||||
msg = ("GET attribute_definition resource for %s" %
|
|
||||||
link_dct['target_name'])
|
|
||||||
self._test_get_resource(adl_dct['href'],
|
|
||||||
msg,
|
|
||||||
'attribute_definition',
|
|
||||||
adl_dct['target_name'])
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class VersionDiscoveryTestCase(base.TestCase):
|
|
||||||
def test_get_root_discovers_v1(self):
|
|
||||||
resp, body = self.client.get('/')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
body = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual(1, len(body))
|
|
||||||
v1 = body[0]
|
|
||||||
self.assertEqual('v1.0', v1['id'])
|
|
||||||
self.assertEqual('CURRENT', v1['status'])
|
|
||||||
self.assertEqual('v1', v1['link']['target_name'])
|
|
||||||
self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
|
|
||||||
|
|
||||||
def test_delete_root_discovers_v1(self):
|
|
||||||
resp, body = self.client.delete('/')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
body = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual(1, len(body))
|
|
||||||
v1 = body[0]
|
|
||||||
self.assertEqual('v1.0', v1['id'])
|
|
||||||
self.assertEqual('CURRENT', v1['status'])
|
|
||||||
self.assertEqual('v1', v1['link']['target_name'])
|
|
||||||
self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
|
|
||||||
|
|
||||||
def test_post_root_discovers_v1(self):
|
|
||||||
resp, body = self.client.post('/', '{}')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
body = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual(1, len(body))
|
|
||||||
v1 = body[0]
|
|
||||||
self.assertEqual('v1.0', v1['id'])
|
|
||||||
self.assertEqual('CURRENT', v1['status'])
|
|
||||||
self.assertEqual('v1', v1['link']['target_name'])
|
|
||||||
self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
|
|
||||||
|
|
||||||
def test_put_root_discovers_v1(self):
|
|
||||||
resp, body = self.client.put('/', '{}')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
body = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual(1, len(body))
|
|
||||||
v1 = body[0]
|
|
||||||
self.assertEqual('v1.0', v1['id'])
|
|
||||||
self.assertEqual('CURRENT', v1['status'])
|
|
||||||
self.assertEqual('v1', v1['link']['target_name'])
|
|
||||||
self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
|
|
||||||
|
|
||||||
def test_post_no_body_root_discovers_v1(self):
|
|
||||||
self.skipTest("POST without body will hang request: #1367470")
|
|
||||||
resp, body = self.client.post('/', None)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
body = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual(1, len(body))
|
|
||||||
v1 = body[0]
|
|
||||||
self.assertEqual('v1.0', v1['id'])
|
|
||||||
self.assertEqual('CURRENT', v1['status'])
|
|
||||||
self.assertEqual('v1', v1['link']['target_name'])
|
|
||||||
self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
|
|
||||||
|
|
||||||
def test_put_no_body_root_discovers_v1(self):
|
|
||||||
self.skipTest("PUT without body will hang request: #1367470")
|
|
||||||
resp, body = self.client.put('/', None)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
body = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual(1, len(body))
|
|
||||||
v1 = body[0]
|
|
||||||
self.assertEqual('v1.0', v1['id'])
|
|
||||||
self.assertEqual('CURRENT', v1['status'])
|
|
||||||
self.assertEqual('v1', v1['link']['target_name'])
|
|
||||||
self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
|
|
||||||
@@ -1,67 +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 json
|
|
||||||
import time
|
|
||||||
|
|
||||||
import requests
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
from solum_tempest_plugin.common import apputils
|
|
||||||
|
|
||||||
|
|
||||||
class TestTriggerController(base.TestCase):
|
|
||||||
|
|
||||||
def test_trigger_post(self):
|
|
||||||
self.skipTest("Will enable after fix this")
|
|
||||||
lp_name = self.client.create_lp()
|
|
||||||
data = apputils.get_sample_data(languagepack=lp_name)
|
|
||||||
resp = self.client.create_app(data=data)
|
|
||||||
body = resp.body
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
bdy = json.loads(body)
|
|
||||||
trigger_uri = bdy['trigger_uri']
|
|
||||||
# Using requests instead of self.client to test unauthenticated request
|
|
||||||
status_url = 'https://api.github.com/repos/u/r/statuses/{sha}'
|
|
||||||
body_dict = {'sender': {'url': 'https://api.github.com'},
|
|
||||||
'pull_request': {'head': {'sha': 'asdf'}},
|
|
||||||
'repository': {'statuses_url': status_url}}
|
|
||||||
body = json.dumps(body_dict)
|
|
||||||
resp = requests.post(trigger_uri, data=body)
|
|
||||||
self.assertEqual(202, resp.status_code)
|
|
||||||
self.client.delete_created_apps()
|
|
||||||
# since app delete is an async operation, wait few seconds for app
|
|
||||||
# delete and then delete language pack (otherwise language pack
|
|
||||||
# cannot be deleted)
|
|
||||||
time.sleep(2)
|
|
||||||
self.client.delete_created_lps()
|
|
||||||
|
|
||||||
def test_trigger_post_with_empty_body(self):
|
|
||||||
self.skipTest("Will enable after fix this")
|
|
||||||
lp_name = self.client.create_lp()
|
|
||||||
data = apputils.get_sample_data(languagepack=lp_name)
|
|
||||||
resp = self.client.create_app(data=data)
|
|
||||||
body = resp.body
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
bdy = json.loads(body)
|
|
||||||
trigger_uri = bdy['trigger_uri']
|
|
||||||
# Using requests instead of self.client to test unauthenticated request
|
|
||||||
resp = requests.post(trigger_uri)
|
|
||||||
self.assertEqual(400, resp.status_code)
|
|
||||||
self.client.delete_created_apps()
|
|
||||||
# since app delete is an async operation, wait few seconds for app
|
|
||||||
# delete and then delete language pack (otherwise language pack
|
|
||||||
# cannot be deleted)
|
|
||||||
time.sleep(2)
|
|
||||||
self.client.delete_created_lps()
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2015 - Rackspace US, Inc
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
import time
|
|
||||||
|
|
||||||
from tempest.lib import exceptions as tempest_exceptions
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
from solum_tempest_plugin.common import apputils
|
|
||||||
|
|
||||||
|
|
||||||
class TestAppController(base.TestCase):
|
|
||||||
|
|
||||||
def _assert_app_data(self, actual, expected):
|
|
||||||
self.assertEqual(expected["name"], actual["name"])
|
|
||||||
self.assertEqual(expected["description"], actual["description"])
|
|
||||||
self.assertEqual(expected["languagepack"], actual["languagepack"])
|
|
||||||
self.assertEqual(expected["trigger_actions"],
|
|
||||||
actual["trigger_actions"])
|
|
||||||
|
|
||||||
self.assertEqual(expected["ports"], actual["ports"])
|
|
||||||
self.assertEqual(expected["source"]["repository"],
|
|
||||||
actual["source"]["repository"])
|
|
||||||
|
|
||||||
self.assertEqual(expected["source"]["revision"],
|
|
||||||
actual["source"]["revision"])
|
|
||||||
|
|
||||||
self.assertEqual(expected["workflow_config"]["test_cmd"],
|
|
||||||
actual["workflow_config"]["test_cmd"])
|
|
||||||
|
|
||||||
self.assertEqual(expected["workflow_config"]["run_cmd"],
|
|
||||||
actual["workflow_config"]["run_cmd"])
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestAppController, self).setUp()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
super(TestAppController, self).tearDown()
|
|
||||||
|
|
||||||
def test_app_create(self):
|
|
||||||
self.skipTest("Will enable after fix this")
|
|
||||||
lp_name = self.client.create_lp()
|
|
||||||
data = apputils.get_sample_data(languagepack=lp_name)
|
|
||||||
resp = self.client.create_app(data=data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
self.client.delete_app(resp.id)
|
|
||||||
time.sleep(2)
|
|
||||||
self.client.delete_language_pack(lp_name)
|
|
||||||
|
|
||||||
def test_app_create_bad_port_data(self):
|
|
||||||
self.skipTest("Will enable after fix this")
|
|
||||||
try:
|
|
||||||
bad_data = apputils.get_sample_data()
|
|
||||||
bad_data["ports"][0] = -1
|
|
||||||
self.client.create_plan(data=bad_data)
|
|
||||||
except tempest_exceptions.BadRequest:
|
|
||||||
self.assertTrue(True)
|
|
||||||
|
|
||||||
def test_app_create_empty_body(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'v1/apps', '{}',
|
|
||||||
headers={'content-type': 'application/json'})
|
|
||||||
|
|
||||||
def test_app_patch(self):
|
|
||||||
lp_name = self.client.create_lp()
|
|
||||||
data = apputils.get_sample_data(languagepack=lp_name)
|
|
||||||
create_resp = self.client.create_app(data=data)
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
|
|
||||||
json_update = {
|
|
||||||
'name': 'newfakeappname',
|
|
||||||
'workflow_config': {
|
|
||||||
'run_cmd': 'newruncmd',
|
|
||||||
},
|
|
||||||
'source': {
|
|
||||||
'repository': 'newrepo',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
uri = 'v1/apps/%s' % create_resp.id
|
|
||||||
|
|
||||||
resp, body = self.client.patch(
|
|
||||||
uri, json.dumps(json_update),
|
|
||||||
headers={'content-type': 'application/json'})
|
|
||||||
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
app_body = json.loads(body)
|
|
||||||
self.assertEqual('newfakeappname', app_body["name"])
|
|
||||||
self.assertEqual("newruncmd", app_body["workflow_config"]["run_cmd"])
|
|
||||||
self.assertEqual("newrepo", app_body["source"]["repository"])
|
|
||||||
self.client.delete_app(create_resp.id)
|
|
||||||
time.sleep(2)
|
|
||||||
self.client.delete_language_pack(lp_name)
|
|
||||||
|
|
||||||
def test_app_get(self):
|
|
||||||
lp_name = self.client.create_lp()
|
|
||||||
data = apputils.get_sample_data(languagepack=lp_name)
|
|
||||||
create_resp = self.client.create_app(data=data)
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
id = create_resp.id
|
|
||||||
|
|
||||||
resp, body = self.client.get(
|
|
||||||
'v1/apps/%s' % id,
|
|
||||||
headers={'content-type': 'application/json'})
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
yaml_data = yaml.safe_load(body)
|
|
||||||
self._assert_app_data(yaml_data, data)
|
|
||||||
self.client.delete_app(create_resp.id)
|
|
||||||
time.sleep(2)
|
|
||||||
self.client.delete_language_pack(lp_name)
|
|
||||||
|
|
||||||
def test_apps_get_all(self):
|
|
||||||
lp_name = self.client.create_lp()
|
|
||||||
data = apputils.get_sample_data(languagepack=lp_name)
|
|
||||||
create_resp = self.client.create_app(data)
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
resp, body = self.client.get(
|
|
||||||
'v1/apps', headers={'content-type': 'application/json'})
|
|
||||||
resp_data = yaml.safe_load(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
id = create_resp.id
|
|
||||||
filtered = [app for app in resp_data if app['id'] == id]
|
|
||||||
self.assertEqual(filtered[0]['id'], id)
|
|
||||||
self.client.delete_app(id)
|
|
||||||
time.sleep(2)
|
|
||||||
self.client.delete_language_pack(lp_name)
|
|
||||||
|
|
||||||
def test_app_delete(self):
|
|
||||||
lp_name = self.client.create_lp()
|
|
||||||
data = apputils.get_sample_data(languagepack=lp_name)
|
|
||||||
create_resp = self.client.create_app(data)
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
id = create_resp.id
|
|
||||||
resp, body = self.client.delete_app(id)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
self.assertEqual(202, resp.status)
|
|
||||||
self.assertEqual('', body)
|
|
||||||
time.sleep(2)
|
|
||||||
self.client.delete_language_pack(lp_name)
|
|
||||||
|
|
||||||
def test_app_delete_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.delete, 'v1/apps/not_found')
|
|
||||||
@@ -1,222 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Noorul Islam K M
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from tempest.lib import exceptions as tempest_exceptions
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
sample_data = {"name": "test_assembly",
|
|
||||||
"description": "A test to create assembly",
|
|
||||||
"project_id": "project_id",
|
|
||||||
"user_id": "user_id",
|
|
||||||
"status": "QUEUED",
|
|
||||||
"application_uri": "http://localhost:5000"}
|
|
||||||
|
|
||||||
plan_sample_data = {"version": "1",
|
|
||||||
"name": "test_plan",
|
|
||||||
"description": "A test to create plan",
|
|
||||||
"project_id": "project_id",
|
|
||||||
"user_id": "user_id"}
|
|
||||||
|
|
||||||
|
|
||||||
class TestAssemblyController(base.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestAssemblyController, self).setUp()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
super(TestAssemblyController, self).tearDown()
|
|
||||||
self.client.delete_created_assemblies()
|
|
||||||
self.client.delete_created_plans()
|
|
||||||
|
|
||||||
def _assert_output_expected(self, body_data, data):
|
|
||||||
self.assertEqual(body_data['description'], data['description'])
|
|
||||||
self.assertEqual(body_data['plan_uri'], data['plan_uri'])
|
|
||||||
self.assertEqual(body_data['name'], data['name'])
|
|
||||||
self.assertIsNotNone(body_data['uuid'])
|
|
||||||
self.assertEqual(body_data['status'], data['status'])
|
|
||||||
self.assertEqual(body_data['application_uri'], data['application_uri'])
|
|
||||||
|
|
||||||
def test_assemblies_get_all(self):
|
|
||||||
# Create assemblies to find
|
|
||||||
p_resp_1 = self.client.create_plan()
|
|
||||||
self.assertEqual(201, p_resp_1.status)
|
|
||||||
a_resp_1 = self.client.create_assembly(data=sample_data,
|
|
||||||
plan_uuid=p_resp_1.uuid)
|
|
||||||
self.assertEqual(201, a_resp_1.status)
|
|
||||||
|
|
||||||
p_resp_2 = self.client.create_plan()
|
|
||||||
self.assertEqual(201, p_resp_2.status)
|
|
||||||
a_resp_2 = self.client.create_assembly(data=sample_data,
|
|
||||||
plan_uuid=p_resp_2.uuid)
|
|
||||||
self.assertEqual(201, a_resp_2.status)
|
|
||||||
|
|
||||||
# Get list of all assemblies
|
|
||||||
resp, body = self.client.get('v1/assemblies')
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
|
|
||||||
# Search for uuids of created assemblies
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
assembly_list = json.loads(body)
|
|
||||||
found_uuid_1 = False
|
|
||||||
found_uuid_2 = False
|
|
||||||
for assembly in assembly_list:
|
|
||||||
uuid = json.dumps(assembly['uuid'])
|
|
||||||
if a_resp_1.uuid in uuid:
|
|
||||||
found_uuid_1 = True
|
|
||||||
elif a_resp_2.uuid in uuid:
|
|
||||||
found_uuid_2 = True
|
|
||||||
|
|
||||||
self.assertTrue(found_uuid_1,
|
|
||||||
'Cannot find assembly [%s] in list of all assemblies.'
|
|
||||||
% a_resp_1.uuid)
|
|
||||||
self.assertTrue(found_uuid_2,
|
|
||||||
'Cannot find assembly [%s] in list of all assemblies.'
|
|
||||||
% a_resp_2.uuid)
|
|
||||||
|
|
||||||
def test_assemblies_create(self):
|
|
||||||
plan_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, plan_resp.status)
|
|
||||||
assembly_resp = self.client.create_assembly(
|
|
||||||
plan_uuid=plan_resp.uuid,
|
|
||||||
data=sample_data)
|
|
||||||
self.assertEqual(201, assembly_resp.status)
|
|
||||||
sample_data['plan_uri'] = "%s/v1/plans/%s" % (self.client.base_url,
|
|
||||||
plan_resp.uuid)
|
|
||||||
self._assert_output_expected(assembly_resp.data, sample_data)
|
|
||||||
|
|
||||||
def test_assemblies_create_none(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'v1/assemblies', "{}")
|
|
||||||
|
|
||||||
def test_assemblies_get(self):
|
|
||||||
plan_resp = self.client.create_plan(data=plan_sample_data)
|
|
||||||
self.assertEqual(201, plan_resp.status)
|
|
||||||
plan_uuid = plan_resp.uuid
|
|
||||||
assembly_resp = self.client.create_assembly(
|
|
||||||
plan_uuid=plan_uuid,
|
|
||||||
data=sample_data)
|
|
||||||
self.assertEqual(201, assembly_resp.status)
|
|
||||||
uuid = assembly_resp.uuid
|
|
||||||
sample_data['plan_uri'] = "%s/v1/plans/%s" % (self.client.base_url,
|
|
||||||
plan_uuid)
|
|
||||||
resp, body = self.client.get('v1/assemblies/%s' % uuid)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, sample_data)
|
|
||||||
|
|
||||||
# Now check that HTTPS is respected. No new assemblies are created.
|
|
||||||
for k in ['plan_uri', 'trigger_uri']:
|
|
||||||
if k in sample_data:
|
|
||||||
sample_data[k] = sample_data[k].replace('http:', 'https:', 1)
|
|
||||||
use_https = {'X-Forwarded-Proto': 'https'}
|
|
||||||
resp, body = self.client.get('v1/assemblies/%s' % uuid,
|
|
||||||
headers=use_https)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, sample_data)
|
|
||||||
|
|
||||||
def test_assemblies_get_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.get, 'v1/assemblies/not_found')
|
|
||||||
|
|
||||||
def test_assemblies_put(self):
|
|
||||||
plan_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, plan_resp.status)
|
|
||||||
plan_uuid = plan_resp.uuid
|
|
||||||
assembly_resp = self.client.create_assembly(
|
|
||||||
plan_uuid=plan_uuid,
|
|
||||||
data=sample_data)
|
|
||||||
self.assertEqual(201, assembly_resp.status)
|
|
||||||
uuid = assembly_resp.uuid
|
|
||||||
uri = "%s/v1/plans/%s" % (self.client.base_url, plan_uuid)
|
|
||||||
updated_data = {"name": "test_assembly_updated",
|
|
||||||
"description": "A test to create assembly updated",
|
|
||||||
"plan_uri": uri,
|
|
||||||
"user_id": "user_id updated",
|
|
||||||
"status": "new_status",
|
|
||||||
"application_uri": "new_uri"}
|
|
||||||
updated_json = json.dumps(updated_data)
|
|
||||||
resp, body = self.client.put('v1/assemblies/%s' % uuid, updated_json)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, updated_data)
|
|
||||||
|
|
||||||
def test_assemblies_put_not_found(self):
|
|
||||||
updated_data = {"name": "test_assembly_updated",
|
|
||||||
"description": "A test to create assembly updated",
|
|
||||||
"plan_uri": 'fake_uri',
|
|
||||||
"project_id": "project_id updated",
|
|
||||||
"user_id": "user_id updated",
|
|
||||||
"status": "new_status",
|
|
||||||
"application_uri": "new_uri"}
|
|
||||||
updated_json = json.dumps(updated_data)
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.put, 'v1/assemblies/not_found',
|
|
||||||
updated_json)
|
|
||||||
|
|
||||||
def test_assemblies_put_none(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.put, 'v1/assemblies/any', "{}")
|
|
||||||
|
|
||||||
def test_assemblies_put_cannot_update(self):
|
|
||||||
plan_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, plan_resp.status)
|
|
||||||
plan_uuid = plan_resp.uuid
|
|
||||||
assembly_resp = self.client.create_assembly(
|
|
||||||
plan_uuid=plan_uuid,
|
|
||||||
data=sample_data)
|
|
||||||
self.assertEqual(201, assembly_resp.status)
|
|
||||||
uuid = assembly_resp.uuid
|
|
||||||
immutables = [
|
|
||||||
('id', 'new_assembly_id'),
|
|
||||||
('uuid', 'new_assembly_uuid'),
|
|
||||||
('project_id', 'new_project_id'),
|
|
||||||
]
|
|
||||||
for key_value in immutables:
|
|
||||||
updated_data = dict([key_value])
|
|
||||||
updated_json = json.dumps(updated_data)
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.put,
|
|
||||||
'v1/assemblies/%s' % uuid,
|
|
||||||
updated_json)
|
|
||||||
|
|
||||||
def test_assemblies_delete(self):
|
|
||||||
plan_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, plan_resp.status)
|
|
||||||
assembly_resp = self.client.create_assembly(
|
|
||||||
plan_uuid=plan_resp.uuid,
|
|
||||||
data=sample_data)
|
|
||||||
self.assertEqual(201, assembly_resp.status)
|
|
||||||
uuid = assembly_resp.uuid
|
|
||||||
|
|
||||||
resp, body = self.client.delete_assembly(uuid)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
self.assertEqual(204, resp.status)
|
|
||||||
self.assertEqual('', body)
|
|
||||||
|
|
||||||
def test_assemblies_delete_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.delete, 'v1/assemblies/not_found')
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Noorul Islam K M
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from tempest.lib import exceptions as tempest_exceptions
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
sample_data = {'name': 'test_component',
|
|
||||||
'description': 'desc'}
|
|
||||||
|
|
||||||
assembly_sample_data = {'name': 'test_assembly',
|
|
||||||
'description': 'desc assembly'}
|
|
||||||
|
|
||||||
plan_sample_data = {'version': '1',
|
|
||||||
'name': 'test_plan',
|
|
||||||
'description': 'A test to create plan'}
|
|
||||||
|
|
||||||
|
|
||||||
class TestComponentController(base.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestComponentController, self).setUp()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
super(TestComponentController, self).tearDown()
|
|
||||||
self.client.delete_created_assemblies()
|
|
||||||
self.client.delete_created_plans()
|
|
||||||
|
|
||||||
def _assert_output_expected(self, body_data, data):
|
|
||||||
self.assertEqual(body_data['name'], data['name'])
|
|
||||||
self.assertEqual(body_data['assembly_uuid'], data['assembly_uuid'])
|
|
||||||
self.assertIsNotNone(body_data['uuid'])
|
|
||||||
self.assertIsNotNone(body_data['project_id'])
|
|
||||||
self.assertIsNotNone(body_data['user_id'])
|
|
||||||
|
|
||||||
def _delete_component(self, uuid):
|
|
||||||
resp, body = self.client.delete('v1/components/%s' % uuid)
|
|
||||||
self.assertEqual(204, resp.status)
|
|
||||||
|
|
||||||
def _create_component(self):
|
|
||||||
plan_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, plan_resp.status,)
|
|
||||||
assembly_resp = self.client.create_assembly(plan_uuid=plan_resp.uuid)
|
|
||||||
self.assertEqual(201, assembly_resp.status)
|
|
||||||
plan_uuid = plan_resp.uuid
|
|
||||||
assembly_uuid = assembly_resp.uuid
|
|
||||||
sample_data['assembly_uuid'] = assembly_uuid
|
|
||||||
data = json.dumps(sample_data)
|
|
||||||
resp, body = self.client.post('v1/components', data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
out_data = json.loads(body)
|
|
||||||
uuid = out_data['uuid']
|
|
||||||
self.assertIsNotNone(uuid)
|
|
||||||
return uuid, assembly_uuid, plan_uuid
|
|
||||||
|
|
||||||
def test_components_get_all(self):
|
|
||||||
uuid, assembly_uuid, plan_uuid = self._create_component()
|
|
||||||
resp, body = self.client.get('v1/components')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
filtered = [com for com in data if com['uuid'] == uuid]
|
|
||||||
self.assertEqual(1, len(filtered))
|
|
||||||
self.assertEqual(uuid, filtered[0]['uuid'])
|
|
||||||
self._delete_component(uuid)
|
|
||||||
|
|
||||||
def test_components_create(self):
|
|
||||||
plan_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, plan_resp.status)
|
|
||||||
assembly_resp = self.client.create_assembly(plan_uuid=plan_resp.uuid)
|
|
||||||
self.assertEqual(201, assembly_resp.status)
|
|
||||||
plan_uuid = plan_resp.uuid
|
|
||||||
assembly_uuid = assembly_resp.uuid
|
|
||||||
|
|
||||||
sample_data['assembly_uuid'] = assembly_uuid
|
|
||||||
sample_data['plan_uri'] = "%s/v1/plans/%s" % (self.client.base_url,
|
|
||||||
plan_uuid)
|
|
||||||
sample_json = json.dumps(sample_data)
|
|
||||||
resp, body = self.client.post('v1/components', sample_json)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, sample_data)
|
|
||||||
self._delete_component(json_data['uuid'])
|
|
||||||
|
|
||||||
def test_components_create_none(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'v1/components', "{}")
|
|
||||||
|
|
||||||
def test_components_get(self):
|
|
||||||
uuid, assembly_uuid, plan_uuid = self._create_component()
|
|
||||||
sample_data['plan_uri'] = "%s/v1/plans/%s" % (self.client.base_url,
|
|
||||||
plan_uuid)
|
|
||||||
resp, body = self.client.get('v1/components/%s' % uuid)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, sample_data)
|
|
||||||
self._delete_component(uuid)
|
|
||||||
|
|
||||||
def test_components_get_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.get, 'v1/components/not_found')
|
|
||||||
|
|
||||||
def test_components_put(self):
|
|
||||||
uuid, assembly_uuid, plan_uuid = self._create_component()
|
|
||||||
updated_data = {'name': 'test_service_updated',
|
|
||||||
'description': 'desc updated',
|
|
||||||
'plan_uri': "%s/v1/plans/%s" % (self.client.base_url,
|
|
||||||
plan_uuid),
|
|
||||||
'assembly_uuid': assembly_uuid}
|
|
||||||
updated_json = json.dumps(updated_data)
|
|
||||||
resp, body = self.client.put('v1/components/%s' % uuid, updated_json)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, updated_data)
|
|
||||||
self._delete_component(uuid)
|
|
||||||
|
|
||||||
def test_components_put_not_found(self):
|
|
||||||
updated_data = {'name': 'test_service_updated',
|
|
||||||
'description': 'desc updated',
|
|
||||||
'plan_uri': "%s/v1/plans/%s" % (self.client.base_url,
|
|
||||||
'not_found'),
|
|
||||||
'assembly_uuid': 'not_found'}
|
|
||||||
updated_json = json.dumps(updated_data)
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.put, 'v1/components/not_found',
|
|
||||||
updated_json)
|
|
||||||
|
|
||||||
def test_components_put_none(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.put, 'v1/components/any', "{}")
|
|
||||||
|
|
||||||
def test_components_delete(self):
|
|
||||||
uuid, assembly_uuid, plan_uuid = self._create_component()
|
|
||||||
resp, body = self.client.delete('v1/components/%s' % uuid)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
self.assertEqual(204, resp.status)
|
|
||||||
self.assertEqual('', body)
|
|
||||||
|
|
||||||
def test_components_delete_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.delete, 'v1/components/not_found')
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Noorul Islam K M
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestExtensionController(base.TestCase):
|
|
||||||
|
|
||||||
def test_extensions_get_all(self):
|
|
||||||
resp, body = self.client.get('v1/extensions')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual([], data)
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
# Copyright 2014 - Rackspace
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
import random
|
|
||||||
import string
|
|
||||||
import time
|
|
||||||
|
|
||||||
from tempest.lib import exceptions as tempest_exceptions
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
from solum_tempest_plugin.common import apputils
|
|
||||||
|
|
||||||
sample_plan = {"version": "1",
|
|
||||||
"name": "test_plan",
|
|
||||||
"artifacts": [{
|
|
||||||
"name": "No deus",
|
|
||||||
"language_pack": "language_pack_name"
|
|
||||||
}]}
|
|
||||||
|
|
||||||
|
|
||||||
class TestLanguagePackController(base.TestCase):
|
|
||||||
|
|
||||||
def _get_sample_languagepack(self):
|
|
||||||
sample_lp = dict()
|
|
||||||
s = string.ascii_lowercase
|
|
||||||
sample_lp["name"] = "lp" + ''.join(random.sample(s, 5))
|
|
||||||
lp_url = "https://github.com/murali44/Solum-lp-Go.git"
|
|
||||||
sample_lp["source_uri"] = lp_url
|
|
||||||
return sample_lp
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(TestLanguagePackController, self).setUp()
|
|
||||||
|
|
||||||
def _delete_all(self):
|
|
||||||
resp, body = self.client.get('v1/language_packs')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
[self._delete_language_pack(pl['uuid']) for pl in data]
|
|
||||||
|
|
||||||
def _delete_language_pack(self, uuid):
|
|
||||||
resp, _ = self.client.delete('v1/language_packs/%s' % uuid)
|
|
||||||
self.assertEqual(204, resp.status)
|
|
||||||
|
|
||||||
def _create_language_pack(self):
|
|
||||||
sample_lp = self._get_sample_languagepack()
|
|
||||||
jsondata = json.dumps(sample_lp)
|
|
||||||
resp, body = self.client.post('v1/language_packs', jsondata)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
out_data = json.loads(body)
|
|
||||||
uuid = out_data['uuid']
|
|
||||||
self.assertIsNotNone(uuid)
|
|
||||||
return uuid, sample_lp
|
|
||||||
|
|
||||||
def test_language_packs_get_all(self):
|
|
||||||
uuid, sample_lp = self._create_language_pack()
|
|
||||||
resp, body = self.client.get('v1/language_packs')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
filtered = [pl for pl in data if pl['uuid'] == uuid]
|
|
||||||
self.assertEqual(uuid, filtered[0]['uuid'])
|
|
||||||
self._delete_language_pack(uuid)
|
|
||||||
|
|
||||||
def test_language_packs_create(self):
|
|
||||||
sample_lp = self._get_sample_languagepack()
|
|
||||||
sample_json = json.dumps(sample_lp)
|
|
||||||
resp, body = self.client.post('v1/language_packs', sample_json)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self.assertEqual("QUEUED", json_data["status"])
|
|
||||||
self.assertEqual(sample_lp['name'], json_data["name"])
|
|
||||||
self._delete_language_pack(json_data["uuid"])
|
|
||||||
|
|
||||||
def test_language_packs_create_none(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'v1/language_packs', "{}")
|
|
||||||
|
|
||||||
def test_language_packs_get(self):
|
|
||||||
uuid, sample_lp = self._create_language_pack()
|
|
||||||
resp, body = self.client.get('v1/language_packs/%s' % uuid)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self.assertEqual(sample_lp['source_uri'], json_data['source_uri'])
|
|
||||||
self.assertEqual(sample_lp['name'], json_data['name'])
|
|
||||||
self._delete_language_pack(uuid)
|
|
||||||
|
|
||||||
def test_language_packs_get_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.get, 'v1/language_packs/not_found')
|
|
||||||
|
|
||||||
def test_language_packs_delete(self):
|
|
||||||
uuid, sample_lp = self._create_language_pack()
|
|
||||||
resp, body = self.client.delete('v1/language_packs/%s' % uuid)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
self.assertEqual(204, resp.status)
|
|
||||||
self.assertEqual('', body)
|
|
||||||
|
|
||||||
def test_language_packs_delete_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.delete, 'v1/language_packs/not_found')
|
|
||||||
|
|
||||||
def test_language_packs_delete_used_by_plan(self):
|
|
||||||
uuid, sample_lp = self._create_language_pack()
|
|
||||||
|
|
||||||
artifacts = sample_plan['artifacts']
|
|
||||||
artifacts[0]['language_pack'] = sample_lp['name']
|
|
||||||
sample_plan['artifacts'] = artifacts
|
|
||||||
resp = self.client.create_plan(data=sample_plan)
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.Conflict,
|
|
||||||
self.client.delete, 'v1/language_packs/%s' % uuid)
|
|
||||||
self.client.delete_plan(resp.uuid)
|
|
||||||
# Sleep for a few seconds to make sure plans are deleted.
|
|
||||||
time.sleep(5)
|
|
||||||
self._delete_language_pack(uuid)
|
|
||||||
|
|
||||||
def test_language_packs_delete_used_by_app(self):
|
|
||||||
uuid, sample_lp = self._create_language_pack()
|
|
||||||
|
|
||||||
sample_app = apputils.get_sample_data()
|
|
||||||
|
|
||||||
sample_app["languagepack"] = sample_lp["name"]
|
|
||||||
|
|
||||||
resp = self.client.create_app(data=sample_app)
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.Conflict,
|
|
||||||
self.client.delete, 'v1/language_packs/%s' % uuid)
|
|
||||||
body = resp.body
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
bdy = json.loads(body)
|
|
||||||
|
|
||||||
self.client.delete_app(bdy["id"])
|
|
||||||
# Sleep for a few seconds to make sure plans are deleted.
|
|
||||||
time.sleep(5)
|
|
||||||
self._delete_language_pack(uuid)
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Noorul Islam K M
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestOperationController(base.TestCase):
|
|
||||||
|
|
||||||
def test_operations_get_all(self):
|
|
||||||
resp, body = self.client.get('v1/operations')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual([], data)
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Rackspace US, 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 exceptions as tempest_exceptions
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
sample_data = {"version": "1",
|
|
||||||
"name": "test_plan",
|
|
||||||
"description": "A test to create plan",
|
|
||||||
"artifacts": [{
|
|
||||||
"name": "No deus",
|
|
||||||
"artifact_type": "heroku",
|
|
||||||
"content": {
|
|
||||||
"href": "https://example.com/git/a.git",
|
|
||||||
"private": False,
|
|
||||||
},
|
|
||||||
"language_pack": "auto",
|
|
||||||
"ports": 123
|
|
||||||
}]}
|
|
||||||
|
|
||||||
bad_data = {"version": "1",
|
|
||||||
"name": "test_plan",
|
|
||||||
"description": "A test to create plan",
|
|
||||||
"artifacts": [{
|
|
||||||
"name": "No deus",
|
|
||||||
"artifact_type": "heroku",
|
|
||||||
"content": {
|
|
||||||
"href": "https://example.com/git/a.git",
|
|
||||||
"private": False,
|
|
||||||
},
|
|
||||||
"language_pack": "auto",
|
|
||||||
"ports": -1
|
|
||||||
}]}
|
|
||||||
|
|
||||||
sample_data_private = {"version": "1",
|
|
||||||
"name": "test_plan",
|
|
||||||
"description": "A test to create plan",
|
|
||||||
"artifacts": [{
|
|
||||||
"name": "No deus",
|
|
||||||
"artifact_type": "heroku",
|
|
||||||
"content": {
|
|
||||||
"href": "https://example.com/git/a.git",
|
|
||||||
"private": True,
|
|
||||||
},
|
|
||||||
"language_pack": "auto",
|
|
||||||
}]}
|
|
||||||
|
|
||||||
|
|
||||||
class TestPlanController(base.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestPlanController, self).setUp()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
super(TestPlanController, self).tearDown()
|
|
||||||
self.client.delete_created_plans()
|
|
||||||
|
|
||||||
def _delete_all(self):
|
|
||||||
resp, body = self.client.get(
|
|
||||||
'v1/plans', headers={'accept-type': 'application/x-yaml'})
|
|
||||||
data = yaml.safe_load(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
[self._delete_plan(pl['uuid']) for pl in data]
|
|
||||||
|
|
||||||
def _assert_output_expected(self, body_data, data):
|
|
||||||
self.assertEqual(body_data['description'], data['description'])
|
|
||||||
self.assertEqual(body_data['name'], data['name'])
|
|
||||||
if body_data['artifacts']:
|
|
||||||
self.assertEqual(body_data['artifacts'][0]['content']['href'],
|
|
||||||
data['artifacts'][0]['content']['href'])
|
|
||||||
self.assertIsNotNone(body_data['uuid'])
|
|
||||||
|
|
||||||
def test_plans_get_all(self):
|
|
||||||
create_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
resp, body = self.client.get(
|
|
||||||
'v1/plans', headers={'content-type': 'application/x-yaml'})
|
|
||||||
data = yaml.safe_load(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
uuid = create_resp.uuid
|
|
||||||
filtered = [pl for pl in data if pl['uuid'] == uuid]
|
|
||||||
self.assertEqual(uuid, filtered[0]['uuid'])
|
|
||||||
|
|
||||||
def test_plans_create(self):
|
|
||||||
resp = self.client.create_plan(data=sample_data)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
self._assert_output_expected(resp.data, sample_data)
|
|
||||||
|
|
||||||
def test_plans_create_bad_port_data(self):
|
|
||||||
try:
|
|
||||||
self.client.create_plan(data=bad_data)
|
|
||||||
except tempest_exceptions.BadRequest:
|
|
||||||
self.assertTrue(True)
|
|
||||||
|
|
||||||
def test_plans_create_with_private_github_repo(self):
|
|
||||||
resp = self.client.create_plan(data=sample_data_private)
|
|
||||||
self.assertEqual(201, resp.status)
|
|
||||||
self._assert_output_expected(resp.data, sample_data)
|
|
||||||
|
|
||||||
def test_plans_create_empty_yaml(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'v1/plans', '{}',
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_plans_create_invalid_yaml_type(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'v1/plans', 'invalid type',
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_plans_create_invalid_yaml_syntax(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'v1/plans', "}invalid: y'm'l3!",
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_plans_get(self):
|
|
||||||
create_resp = self.client.create_plan(data=sample_data)
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
uuid = create_resp.uuid
|
|
||||||
|
|
||||||
resp, body = self.client.get(
|
|
||||||
'v1/plans/%s' % uuid,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
self.assertEqual(200, resp.status, )
|
|
||||||
yaml_data = yaml.safe_load(body)
|
|
||||||
self._assert_output_expected(yaml_data, sample_data)
|
|
||||||
|
|
||||||
def test_plans_get_with_private_github_repo(self):
|
|
||||||
create_resp = self.client.create_plan(data=sample_data_private)
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
uuid = create_resp.uuid
|
|
||||||
|
|
||||||
resp, body = self.client.get(
|
|
||||||
'v1/plans/%s' % uuid,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
yaml_data = yaml.safe_load(body)
|
|
||||||
public_key = yaml_data['artifacts'][0]['content']['public_key']
|
|
||||||
self.assertIsNotNone(public_key)
|
|
||||||
self._assert_output_expected(yaml_data, sample_data)
|
|
||||||
|
|
||||||
def test_plans_get_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.get, 'v1/plans/not_found',
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_plans_put(self):
|
|
||||||
create_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
uuid = create_resp.uuid
|
|
||||||
updated_data = {"version": "1",
|
|
||||||
"name": "test_plan_updated",
|
|
||||||
"description": "A test to create plan updated",
|
|
||||||
"type": "plan",
|
|
||||||
"artifacts": []}
|
|
||||||
updated_yaml = yaml.dump(updated_data)
|
|
||||||
resp, body = self.client.put(
|
|
||||||
'v1/plans/%s' % uuid, updated_yaml,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
yaml_data = yaml.safe_load(body)
|
|
||||||
self._assert_output_expected(yaml_data, updated_data)
|
|
||||||
|
|
||||||
def test_plans_put_not_found(self):
|
|
||||||
updated_data = {"name": "test_plan updated",
|
|
||||||
"description": "A test to create plan updated",
|
|
||||||
"type": "plan",
|
|
||||||
"artifacts": []}
|
|
||||||
updated_yaml = yaml.dump(updated_data)
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.put, 'v1/plans/not_found', updated_yaml,
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_plans_put_empty_yaml(self):
|
|
||||||
create_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
|
|
||||||
# get the URI of the newly created plan
|
|
||||||
uri = (create_resp.data['uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.put, uri, '{}',
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_plans_put_invalid_yaml_type(self):
|
|
||||||
create_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
|
|
||||||
# get the URI of the newly created plan
|
|
||||||
uri = (create_resp.data['uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.put, uri, 'invalid type',
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_plans_put_invalid_yaml_syntax(self):
|
|
||||||
create_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
|
|
||||||
# get the URI of the newly created plan
|
|
||||||
uri = (create_resp.data['uri']
|
|
||||||
[len(self.client.base_url) + 1:])
|
|
||||||
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.put, uri, "}invalid: y'm'l3!",
|
|
||||||
headers={'content-type': 'application/x-yaml'})
|
|
||||||
|
|
||||||
def test_plans_delete(self):
|
|
||||||
create_resp = self.client.create_plan()
|
|
||||||
self.assertEqual(201, create_resp.status)
|
|
||||||
uuid = create_resp.uuid
|
|
||||||
resp, body = self.client.delete_plan(uuid)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
self.assertEqual(202, resp.status)
|
|
||||||
self.assertEqual('', body)
|
|
||||||
|
|
||||||
def test_plans_delete_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.delete, 'v1/plans/not_found')
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Noorul Islam K M
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestRootController(base.TestCase):
|
|
||||||
|
|
||||||
def test_index(self):
|
|
||||||
resp, body = self.client.request_without_auth('', 'GET')
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(data[0]['id'], 'v1.0')
|
|
||||||
self.assertEqual(data[0]['status'], 'CURRENT')
|
|
||||||
self.assertEqual(data[0]['link'],
|
|
||||||
{'href': '%s/v1' % self.client.base_url,
|
|
||||||
'target_name': 'v1'})
|
|
||||||
|
|
||||||
def test_platform(self):
|
|
||||||
resp, body = self.client.request_without_auth('v1', 'GET')
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(data['uri'], '%s/v1' % self.client.base_url)
|
|
||||||
self.assertEqual(data['type'], 'platform')
|
|
||||||
self.assertEqual(data['name'], 'solum')
|
|
||||||
self.assertEqual(data['description'], 'solum native implementation')
|
|
||||||
self.assertEqual(data['plans_uri'],
|
|
||||||
'%s/v1/plans' % self.client.base_url)
|
|
||||||
self.assertEqual(data['assemblies_uri'],
|
|
||||||
'%s/v1/assemblies' % self.client.base_url)
|
|
||||||
self.assertEqual(data['services_uri'],
|
|
||||||
'%s/v1/services' % self.client.base_url)
|
|
||||||
self.assertEqual(data['components_uri'],
|
|
||||||
'%s/v1/components' % self.client.base_url)
|
|
||||||
self.assertEqual(data['extensions_uri'],
|
|
||||||
'%s/v1/extensions' % self.client.base_url)
|
|
||||||
self.assertEqual(data['operations_uri'],
|
|
||||||
'%s/v1/operations' % self.client.base_url)
|
|
||||||
self.assertEqual(data['sensors_uri'],
|
|
||||||
'%s/v1/sensors' % self.client.base_url)
|
|
||||||
self.assertEqual(data['language_packs_uri'],
|
|
||||||
'%s/v1/language_packs' % self.client.base_url)
|
|
||||||
self.assertEqual(data['pipelines_uri'],
|
|
||||||
'%s/v1/pipelines' % self.client.base_url)
|
|
||||||
self.assertEqual(data['triggers_uri'],
|
|
||||||
'%s/v1/triggers' % self.client.base_url)
|
|
||||||
self.assertEqual(data['infrastructure_uri'],
|
|
||||||
'%s/v1/infrastructure' % self.client.base_url)
|
|
||||||
|
|
||||||
def test_request_without_auth(self):
|
|
||||||
resp, body = self.client.request_without_auth('v1', 'GET')
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
resp, body = self.client.get('v1')
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
resp, body = self.client.request_without_auth(
|
|
||||||
'v1/plans', 'GET', headers={'content-type': 'application/x-yaml'})
|
|
||||||
self.assertEqual(401, resp.status)
|
|
||||||
resp, body = self.client.get(
|
|
||||||
'v1/plans', headers={'content-type': 'application/x-yaml'})
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Noorul Islam K M
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestSensorController(base.TestCase):
|
|
||||||
|
|
||||||
def test_sensors_get_all(self):
|
|
||||||
resp, body = self.client.get('v1/sensors')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(200, resp.status)
|
|
||||||
self.assertEqual([], data)
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2013 - Noorul Islam K M
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
from tempest.lib import exceptions as tempest_exceptions
|
|
||||||
|
|
||||||
from solum_tempest_plugin import base
|
|
||||||
|
|
||||||
sample_data = {"name": "test_service",
|
|
||||||
"description": "A test to create service",
|
|
||||||
"project_id": "project_id",
|
|
||||||
"user_id": "user_id",
|
|
||||||
"service_type": "mysql",
|
|
||||||
"read_only": True,
|
|
||||||
"type": "service"}
|
|
||||||
|
|
||||||
|
|
||||||
class TestServiceController(base.TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestServiceController, self).setUp()
|
|
||||||
self.addCleanup(self._delete_all)
|
|
||||||
|
|
||||||
def _delete_all(self):
|
|
||||||
resp, body = self.client.get('v1/services')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(resp.status, 200)
|
|
||||||
[self._delete_service(ser['uuid']) for ser in data]
|
|
||||||
|
|
||||||
def _assert_output_expected(self, body_data, data):
|
|
||||||
self.assertEqual(body_data['description'], data['description'])
|
|
||||||
self.assertEqual(body_data['name'], data['name'])
|
|
||||||
self.assertEqual(body_data['service_type'], data['service_type'])
|
|
||||||
self.assertEqual(body_data['read_only'], data['read_only'])
|
|
||||||
self.assertEqual(body_data['type'], 'service')
|
|
||||||
self.assertIsNotNone(body_data['uuid'])
|
|
||||||
|
|
||||||
def _delete_service(self, uuid):
|
|
||||||
resp, _ = self.client.delete('v1/services/%s' % uuid)
|
|
||||||
self.assertEqual(resp.status, 204)
|
|
||||||
|
|
||||||
def _create_service(self):
|
|
||||||
jsondata = json.dumps(sample_data)
|
|
||||||
resp, body = self.client.post('v1/services', jsondata)
|
|
||||||
self.assertEqual(resp.status, 201)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
out_data = json.loads(body)
|
|
||||||
uuid = out_data['uuid']
|
|
||||||
self.assertIsNotNone(uuid)
|
|
||||||
return uuid
|
|
||||||
|
|
||||||
def test_services_get_all(self):
|
|
||||||
uuid = self._create_service()
|
|
||||||
resp, body = self.client.get('v1/services')
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
data = json.loads(body)
|
|
||||||
self.assertEqual(resp.status, 200)
|
|
||||||
filtered = [ser for ser in data if ser['uuid'] == uuid]
|
|
||||||
self.assertEqual(filtered[0]['uuid'], uuid)
|
|
||||||
|
|
||||||
def test_services_create(self):
|
|
||||||
sample_json = json.dumps(sample_data)
|
|
||||||
resp, body = self.client.post('v1/services', sample_json)
|
|
||||||
self.assertEqual(resp.status, 201)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, sample_data)
|
|
||||||
self._delete_service(json_data['uuid'])
|
|
||||||
|
|
||||||
def test_services_create_none(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.post, 'v1/services', "{}")
|
|
||||||
|
|
||||||
def test_services_get(self):
|
|
||||||
uuid = self._create_service()
|
|
||||||
resp, body = self.client.get('v1/services/%s' % uuid)
|
|
||||||
self.assertEqual(resp.status, 200)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, sample_data)
|
|
||||||
self._delete_service(uuid)
|
|
||||||
|
|
||||||
def test_services_get_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.get, 'v1/services/not_found')
|
|
||||||
|
|
||||||
def test_services_put(self):
|
|
||||||
uuid = self._create_service()
|
|
||||||
updated_data = {"name": "test_service_updated",
|
|
||||||
"description": "A test to create service updated",
|
|
||||||
"user_id": "user_id updated",
|
|
||||||
"service_type": "mysql updated",
|
|
||||||
"read_only": False}
|
|
||||||
updated_json = json.dumps(updated_data)
|
|
||||||
resp, body = self.client.put('v1/services/%s' % uuid, updated_json)
|
|
||||||
self.assertEqual(resp.status, 200)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
json_data = json.loads(body)
|
|
||||||
self._assert_output_expected(json_data, updated_data)
|
|
||||||
self._delete_service(uuid)
|
|
||||||
|
|
||||||
def test_services_put_not_found(self):
|
|
||||||
updated_data = {"name": "test_service_updated",
|
|
||||||
"description": "A test to create service updated",
|
|
||||||
"user_id": "user_id updated",
|
|
||||||
"service_type": "mysql updated",
|
|
||||||
"read_only": False}
|
|
||||||
updated_json = json.dumps(updated_data)
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.put, 'v1/services/not_found',
|
|
||||||
updated_json)
|
|
||||||
|
|
||||||
def test_services_put_none(self):
|
|
||||||
self.assertRaises(tempest_exceptions.BadRequest,
|
|
||||||
self.client.put, 'v1/services/any', "{}")
|
|
||||||
|
|
||||||
def test_services_delete(self):
|
|
||||||
uuid = self._create_service()
|
|
||||||
resp, body = self.client.delete('v1/services/%s' % uuid)
|
|
||||||
if isinstance(body, bytes):
|
|
||||||
body = body.decode('utf-8')
|
|
||||||
self.assertEqual(resp.status, 204)
|
|
||||||
self.assertEqual(body, '')
|
|
||||||
|
|
||||||
def test_services_delete_not_found(self):
|
|
||||||
self.assertRaises(tempest_exceptions.NotFound,
|
|
||||||
self.client.delete, 'v1/services/not_found')
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
# The order of packages is significant, because pip processes them in the order
|
|
||||||
# of appearance. Changing the order has an impact on the overall integration
|
|
||||||
# process, which may cause wedges in the gate later.
|
|
||||||
|
|
||||||
hacking>=3.0.1,<3.1.0 # Apache-2.0
|
|
||||||
|
|
||||||
coverage!=4.4,>=4.0 # Apache-2.0
|
|
||||||
python-subunit>=1.0.0 # Apache-2.0/BSD
|
|
||||||
oslotest>=3.2.0 # Apache-2.0
|
|
||||||
stestr>=2.0.0 # Apache-2.0
|
|
||||||
testtools>=2.2.0 # MIT
|
|
||||||
55
tox.ini
55
tox.ini
@@ -1,55 +0,0 @@
|
|||||||
[tox]
|
|
||||||
minversion = 2.0
|
|
||||||
envlist = py37,py36,pep8
|
|
||||||
skipsdist = True
|
|
||||||
ignore_basepython_conflict = True
|
|
||||||
|
|
||||||
[testenv]
|
|
||||||
basepython = python3
|
|
||||||
usedevelop = True
|
|
||||||
setenv =
|
|
||||||
VIRTUAL_ENV={envdir}
|
|
||||||
PYTHONWARNINGS=default::DeprecationWarning
|
|
||||||
deps =
|
|
||||||
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
|
||||||
-r{toxinidir}/test-requirements.txt
|
|
||||||
commands = stestr run --slowest {posargs}
|
|
||||||
|
|
||||||
[testenv:pep8]
|
|
||||||
commands = flake8 {posargs}
|
|
||||||
|
|
||||||
[testenv:venv]
|
|
||||||
commands = {posargs}
|
|
||||||
|
|
||||||
[testenv:cover]
|
|
||||||
setenv =
|
|
||||||
{[testenv]setenv}
|
|
||||||
PYTHON=coverage run --source solum_tempest_plugin --parallel-mode
|
|
||||||
commands =
|
|
||||||
stestr run {posargs}
|
|
||||||
coverage combine
|
|
||||||
coverage html -d cover
|
|
||||||
coverage xml -o cover/coverage.xml
|
|
||||||
coverage report
|
|
||||||
|
|
||||||
[testenv:docs]
|
|
||||||
deps =
|
|
||||||
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
|
|
||||||
-r{toxinidir}/doc/requirements.txt
|
|
||||||
commands = sphinx-build -W -b html doc/source doc/build/html
|
|
||||||
|
|
||||||
[testenv:releasenotes]
|
|
||||||
deps = {[testenv:docs]deps}
|
|
||||||
commands =
|
|
||||||
sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
|
|
||||||
|
|
||||||
[testenv:debug]
|
|
||||||
commands = oslo_debug_helper {posargs}
|
|
||||||
|
|
||||||
[flake8]
|
|
||||||
# E123, E125 skipped as they are invalid PEP-8.
|
|
||||||
|
|
||||||
show-source = True
|
|
||||||
ignore = E123,E125
|
|
||||||
builtins = _
|
|
||||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
|
||||||
Reference in New Issue
Block a user