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:
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 @@
|
||||
========================
|
||||
Team and repository tags
|
||||
========================
|
||||
This project is no longer maintained.
|
||||
|
||||
.. image:: https://governance.openstack.org/tc/badges/solum-tempest-plugin.svg
|
||||
:target: https://governance.openstack.org/tc/reference/tags/index.html
|
||||
The contents of this repository are still available in the Git
|
||||
source code management system. To see the contents of this
|
||||
repository before it reached its end of life, please check out the
|
||||
previous commit with "git checkout HEAD^1".
|
||||
|
||||
============================
|
||||
Tempest Integration of Solum
|
||||
============================
|
||||
|
||||
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
|
||||
For any further questions, please email
|
||||
openstack-discuss@lists.openstack.org or join #openstack-dev on
|
||||
OFTC.
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user