summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhurong <aaronzhu1121@gmail.com>2017-08-28 13:55:34 +0800
committerzhurong <aaronzhu1121@gmail.com>2017-08-28 17:27:26 +0800
commitec4a098af9ca9e76875a9608a4ce096725b348b4 (patch)
tree2f5a619b68b949257dfda38533698d838839cb9a
parentf5a48364e3b5fe6c03fda068f941983d0bdda069 (diff)
Move tempest tests from solum repo to solum-tempest-plugin
Notes
Notes (review): Code-Review+2: zhurong <aaronzhu1121@gmail.com> Workflow+1: zhurong <aaronzhu1121@gmail.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Mon, 28 Aug 2017 10:37:05 +0000 Reviewed-on: https://review.openstack.org/498317 Project: openstack/solum-tempest-plugin Branch: refs/heads/master
-rw-r--r--solum_tempest_plugin/__init__.py19
-rw-r--r--solum_tempest_plugin/base.py269
-rw-r--r--solum_tempest_plugin/camp/__init__.py (renamed from solum_tempest_plugin/tests/__init__.py)0
-rw-r--r--solum_tempest_plugin/camp/test_platform_endpoints.py54
-rw-r--r--solum_tempest_plugin/camp/v1_1/__init__.py0
-rw-r--r--solum_tempest_plugin/camp/v1_1/test_assemblies.py156
-rw-r--r--solum_tempest_plugin/camp/v1_1/test_formats.py53
-rw-r--r--solum_tempest_plugin/camp/v1_1/test_parameter_definitions.py98
-rw-r--r--solum_tempest_plugin/camp/v1_1/test_plans.py423
-rw-r--r--solum_tempest_plugin/camp/v1_1/test_platform.py73
-rw-r--r--solum_tempest_plugin/camp/v1_1/test_type_definitions.py58
-rw-r--r--solum_tempest_plugin/common/__init__.py0
-rw-r--r--solum_tempest_plugin/common/apputils.py38
-rw-r--r--solum_tempest_plugin/test_release.py22
-rw-r--r--solum_tempest_plugin/test_versions.py88
-rw-r--r--solum_tempest_plugin/v1/__init__.py0
-rw-r--r--solum_tempest_plugin/v1/public/__init__.py0
-rw-r--r--solum_tempest_plugin/v1/public/test_trigger.py59
-rw-r--r--solum_tempest_plugin/v1/test_app.py154
-rw-r--r--solum_tempest_plugin/v1/test_assembly.py212
-rw-r--r--solum_tempest_plugin/v1/test_component.py153
-rw-r--r--solum_tempest_plugin/v1/test_extension.py (renamed from solum_tempest_plugin/tests/test_solum_tempest_plugin.py)23
-rw-r--r--solum_tempest_plugin/v1/test_language_pack.py143
-rw-r--r--solum_tempest_plugin/v1/test_operation.py27
-rw-r--r--solum_tempest_plugin/v1/test_plan.py232
-rw-r--r--solum_tempest_plugin/v1/test_root.py77
-rw-r--r--solum_tempest_plugin/v1/test_sensor.py (renamed from solum_tempest_plugin/tests/base.py)18
-rw-r--r--solum_tempest_plugin/v1/test_service.py132
28 files changed, 2543 insertions, 38 deletions
diff --git a/solum_tempest_plugin/__init__.py b/solum_tempest_plugin/__init__.py
index 8ed5e59..e69de29 100644
--- a/solum_tempest_plugin/__init__.py
+++ b/solum_tempest_plugin/__init__.py
@@ -1,19 +0,0 @@
1# -*- coding: utf-8 -*-
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import pbr.version
16
17
18__version__ = pbr.version.VersionInfo(
19 'solum-tempest-plugin').version_string()
diff --git a/solum_tempest_plugin/base.py b/solum_tempest_plugin/base.py
new file mode 100644
index 0000000..3904393
--- /dev/null
+++ b/solum_tempest_plugin/base.py
@@ -0,0 +1,269 @@
1# Copyright 2013 - Noorul Islam K M
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import copy
16import json
17import os
18import random
19import string
20import time
21
22from tempest.common import credentials_factory as common_creds
23from tempest import config
24from tempest.lib import auth
25from tempest.lib.common import http
26from tempest.lib.common import rest_client
27import testtools
28import yaml
29
30from solum_tempest_plugin.common import apputils
31
32
33CONF = config.CONF
34
35assembly_sample_data = {"name": "test_assembly",
36 "description": "A test to create assembly",
37 "project_id": "project_id",
38 "user_id": "user_id",
39 "status": "status",
40 "application_uri": "http://localhost:5000"}
41
42plan_sample_data = {"version": "1",
43 "name": "test_plan",
44 "description": "A test to create plan",
45 "project_id": "project_id",
46 "user_id": "user_id",
47 "artifacts": [{
48 "name": "No deus",
49 "artifact_type": "heroku",
50 "content": {
51 "href": "https://example.com/git/a.git",
52 "private": False
53 },
54 "language_pack": "auto",
55 }]}
56
57solum_group = config.cfg.OptGroup(name='solum', title='Solum test options')
58SolumGroup = [
59 config.cfg.BoolOpt('barbican_enabled',
60 default=False,
61 help="Defaults to false. Determines whether Barbican"
62 "is enabled."),
63 config.cfg.BoolOpt('camp_enabled',
64 default=True,
65 help="Defaults to true. Determines whether CAMP"
66 "is enabled.")
67]
68
69CONF.register_group(solum_group)
70CONF.register_opts(SolumGroup, group=solum_group.name)
71
72
73class SolumClient(rest_client.RestClient):
74
75 def __init__(self, auth_provider, service='application_deployment',
76 region='RegionOne'):
77 super(SolumClient, self).__init__(auth_provider, service, region)
78 self.endpoint_url = 'publicURL'
79 self.created_assemblies = []
80 self.created_plans = []
81 self.created_apps = []
82 self.created_lps = []
83
84 def request_without_auth(self, resource, method, headers=None, body=None):
85 if headers is None:
86 headers = {}
87 dscv = CONF.identity.disable_ssl_certificate_validation
88 http_obj = http.ClosingHttp(disable_ssl_certificate_validation=dscv)
89 url = '%s/%s' % (self.base_url, resource)
90 return http_obj.request(url, method, headers=headers, body=body)
91
92 def assembly_delete_done(self, assembly_uuid):
93 wait_interval = 1
94 growth_factor = 1.2
95 max_attempts = 5
96
97 for count in range(max_attempts):
98 try:
99 resp, body = self.get('v1/assemblies/%s' % assembly_uuid)
100 except Exception:
101 return True
102 time.sleep(wait_interval)
103 wait_interval *= growth_factor
104
105 return False
106
107 def create_assembly(self, plan_uuid, data=None):
108 assembly_data = copy.deepcopy(data or assembly_sample_data)
109 assembly_data['plan_uri'] = "%s/v1/plans/%s" % (self.base_url,
110 plan_uuid)
111 jsondata = json.dumps(assembly_data)
112 resp, body = self.post('v1/assemblies', jsondata)
113 assembly_resp = SolumResponse(resp=resp, body=body, body_type='json')
114 uuid = assembly_resp.uuid
115 if uuid is not None:
116 self.created_assemblies.append(uuid)
117 return assembly_resp
118
119 def create_plan(self, data=None):
120 plan_data = copy.deepcopy(data or plan_sample_data)
121 yaml_data = yaml.dump(plan_data)
122 resp, body = self.post('v1/plans', yaml_data,
123 headers={'content-type': 'application/x-yaml'})
124 plan_resp = SolumResponse(resp=resp, body=body, body_type='yaml')
125 uuid = plan_resp.uuid
126 if uuid is not None:
127 self.created_plans.append(uuid)
128 return plan_resp
129
130 def create_lp(self, data=None):
131 sample_lp = dict()
132 s = string.lowercase
133 sample_lp["name"] = "lp" + ''.join(random.sample(s, 5))
134 lp_url = "https://github.com/murali44/Solum-lp-Go.git"
135 sample_lp["source_uri"] = lp_url
136 jsondata = json.dumps(sample_lp)
137 resp, body = self.post('v1/language_packs', jsondata)
138 return sample_lp["name"]
139
140 def create_app(self, data=None):
141 app_data = copy.deepcopy(data) or apputils.get_sample_data()
142 json_data = json.dumps(app_data)
143 resp, body = self.post('v1/apps', json_data)
144
145 app_resp = SolumResponse(resp=resp, body=body, body_type='yaml')
146 if app_resp.id is not None:
147 self.created_apps.append(app_resp.id)
148 return app_resp
149
150 def delete_created_assemblies(self):
151 [self.delete_assembly(uuid) for uuid in list(self.created_assemblies)]
152 self.created_assemblies = []
153
154 def delete_assembly(self, uuid):
155 resp, body = self.delete('v1/assemblies/%s' % uuid)
156 if self.assembly_delete_done(uuid):
157 self.created_assemblies.remove(uuid)
158 return resp, body
159
160 def delete_created_plans(self):
161 self.delete_created_assemblies()
162 [self.delete_plan(uuid) for uuid in list(self.created_plans)]
163 self.created_plans = []
164
165 def delete_created_lps(self):
166 resp, body = self.get('v1/language_packs')
167 data = json.loads(body)
168 [self._delete_language_pack(pl['uuid']) for pl in data]
169
170 def _delete_language_pack(self, uuid):
171 resp, _ = self.delete('v1/language_packs/%s' % uuid)
172
173 def delete_language_pack(self, name):
174 resp, _ = self.delete('v1/language_packs/%s' % name)
175
176 def delete_created_apps(self):
177 self.delete_created_assemblies()
178 [self.delete_app(id) for id in list(self.created_apps)]
179 self.created_apps = []
180
181 def delete_app(self, id):
182 resp, body = self.delete(
183 'v1/apps/%s' % id,
184 headers={'content-type': 'application/json'})
185 if id in self.created_apps:
186 self.created_apps.remove(id)
187 return resp, body
188
189 def delete_plan(self, uuid):
190 resp, body = self.delete(
191 'v1/plans/%s' % uuid,
192 headers={'content-type': 'application/x-yaml'})
193 self.created_plans.remove(uuid)
194 return resp, body
195
196
197class SolumResponse(object):
198 def __init__(self, resp, body, body_type):
199 self.resp = resp
200 self.body = body
201 if body_type == 'json':
202 self.data = json.loads(self.body)
203 elif body_type == 'yaml':
204 self.data = yaml.safe_load(self.body)
205 if self.data.get('uuid'):
206 self.uuid = self.data.get('uuid')
207 if self.data.get('id'):
208 self.id = self.data.get('id')
209
210 @property
211 def status(self):
212 return self.resp.status
213
214 @property
215 def yaml_data(self):
216 return yaml.safe_load(self.body)
217
218 @property
219 def json_data(self):
220 return json.loads(self.body)
221
222
223class TestCase(testtools.TestCase):
224 def setUp(self):
225 super(TestCase, self).setUp()
226
227 credentials = common_creds.get_configured_admin_credentials(
228 'identity_admin')
229
230 auth_provider = get_auth_provider(credentials)
231 self.client = SolumClient(auth_provider)
232 self.builderclient = SolumClient(auth_provider, 'image_builder')
233
234 def tearDown(self):
235 super(TestCase, self).tearDown()
236 self.client.delete_created_apps()
237
238
239def get_auth_provider(credentials, scope='project'):
240 default_params = {
241 'disable_ssl_certificate_validation':
242 CONF.identity.disable_ssl_certificate_validation,
243 'ca_certs': CONF.identity.ca_certificates_file,
244 'trace_requests': CONF.debug.trace_requests
245 }
246
247 if isinstance(credentials, auth.KeystoneV3Credentials):
248 auth_provider_class, auth_url = \
249 auth.KeystoneV3AuthProvider, CONF.identity.uri_v3
250 else:
251 auth_provider_class, auth_url = \
252 auth.KeystoneV2AuthProvider, CONF.identity.uri
253
254 _auth_provider = auth_provider_class(credentials, auth_url,
255 scope=scope,
256 **default_params)
257 _auth_provider.set_auth()
258 return _auth_provider
259
260
261def is_fedora():
262 if os.path.exists("/etc/redhat-release"):
263 return True
264 return False
265
266
267def config_set_as(config, target_value):
268 value = getattr(CONF.solum, config)
269 return value == target_value
diff --git a/solum_tempest_plugin/tests/__init__.py b/solum_tempest_plugin/camp/__init__.py
index e69de29..e69de29 100644
--- a/solum_tempest_plugin/tests/__init__.py
+++ b/solum_tempest_plugin/camp/__init__.py
diff --git a/solum_tempest_plugin/camp/test_platform_endpoints.py b/solum_tempest_plugin/camp/test_platform_endpoints.py
new file mode 100644
index 0000000..7110090
--- /dev/null
+++ b/solum_tempest_plugin/camp/test_platform_endpoints.py
@@ -0,0 +1,54 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import json
14
15from solum_tempest_plugin import base
16
17
18class PlatformDiscoveryTestCase(base.TestCase):
19
20 def test_get_root_discovers_camp_v1_1(self):
21 if base.config_set_as('camp_enabled', False):
22 self.skipTest('CAMP not enabled.')
23 # get our platform_endpoints container
24 resp, body = (self.client.
25 request_without_auth('camp/platform_endpoints',
26 'GET'))
27 self.assertEqual(200, resp.status)
28 endpoints = json.loads(body)
29 self.assertEqual('platform_endpoints', endpoints['type'])
30 self.assertEqual('Solum_CAMP_endpoints', endpoints['name'])
31 pe_links = endpoints['platform_endpoint_links']
32
33 # there should be one element in the Link array
34 self.assertEqual(1, len(pe_links))
35 camp_v1_1_link = pe_links[0]
36 self.assertEqual('Solum_CAMP_v1_1_endpoint',
37 camp_v1_1_link['target_name'])
38
39 # get the URL of the platform_endpoint and strip the base URL
40 rel_ep_url = camp_v1_1_link['href'][len(self.client.base_url) + 1:]
41
42 # get our lone platform_endpoint resource
43 resp, body = (self.client.
44 request_without_auth(rel_ep_url,
45 'GET'))
46 self.assertEqual(200, resp.status)
47 endpoint = json.loads(body)
48 self.assertEqual('platform_endpoint', endpoint['type'])
49 self.assertEqual('Solum_CAMP_v1_1_endpoint', endpoint['name'])
50 self.assertEqual('CAMP 1.1', endpoint['specification_version'])
51 self.assertEqual('Solum CAMP 1.1', endpoint['implementation_version'])
52 self.assertEqual('KEYSTONE-2.0', endpoint['auth_scheme'])
53 self.assertEqual('%s/camp/v1_1/platform' % self.client.base_url,
54 endpoint['platform_uri'])
diff --git a/solum_tempest_plugin/camp/v1_1/__init__.py b/solum_tempest_plugin/camp/v1_1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/solum_tempest_plugin/camp/v1_1/__init__.py
diff --git a/solum_tempest_plugin/camp/v1_1/test_assemblies.py b/solum_tempest_plugin/camp/v1_1/test_assemblies.py
new file mode 100644
index 0000000..5324e04
--- /dev/null
+++ b/solum_tempest_plugin/camp/v1_1/test_assemblies.py
@@ -0,0 +1,156 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import json
14
15from tempest.lib import exceptions as tempest_exceptions
16import yaml
17
18from solum_tempest_plugin import base
19from solum_tempest_plugin.camp.v1_1 import test_plans
20
21
22class TestAssembliesController(base.TestCase):
23
24 def tearDown(self):
25 super(TestAssembliesController, self).tearDown()
26 self.client.delete_created_assemblies()
27 self.client.delete_created_plans()
28
29 # TODO(gpilz) - this is a dup of a method in test_plans.TestPlansController
30 def _create_camp_plan(self, data):
31 yaml_data = yaml.dump(data)
32 resp, body = self.client.post('camp/v1_1/plans', yaml_data,
33 headers={'content-type':
34 'application/x-yaml'})
35 plan_resp = base.SolumResponse(resp=resp,
36 body=body,
37 body_type='json')
38 uuid = plan_resp.uuid
39 if uuid is not None:
40 # share the Solum client's list of created plans
41 self.client.created_plans.append(uuid)
42 return plan_resp
43
44 def test_get_solum_assembly(self):
45 """Test the CAMP assemblies collection resource.
46
47 Test that an assembly resource created through the Solum API is
48 visible via the CAMP API.
49 """
50 if base.config_set_as('camp_enabled', False):
51 self.skipTest('CAMP not enabled.')
52
53 # create an assembly using Solum
54 p_resp = self.client.create_plan()
55 self.assertEqual(201, p_resp.status)
56 a_resp = self.client.create_assembly(plan_uuid=p_resp.uuid)
57 self.assertEqual(201, a_resp.status)
58 new_uuid = a_resp.uuid
59
60 # try to get to the newly created assembly through the CAMP assemblies
61 # resource. it would be more efficient to simply take the UUID of the
62 # newly created resource and create a CAMP API URI
63 # (../camp/v1_1/assemblies/<uuid>) from that, but we want to test that
64 # a link to the Solum-created assembly appears in in the list of links
65 # in the CAMP plans resource.
66 resp, body = self.client.get('camp/v1_1/assemblies')
67 self.assertEqual(200, resp.status, 'GET assemblies resource')
68
69 # pick out the assemebly link for our new assembly uuid
70 assemblies_dct = json.loads(body)
71 camp_link = None
72 for link in assemblies_dct['assembly_links']:
73 link_uuid = link['href'].split("/")[-1]
74 if link_uuid == new_uuid:
75 camp_link = link
76
77 msg = 'Unable to find link to newly created plan in CAMP plans'
78 self.assertIsNotNone(camp_link, msg)
79
80 url = camp_link['href'][len(self.client.base_url) + 1:]
81 msg = ("GET Solum assembly resource for %s" %
82 camp_link['target_name'])
83 resp, body = self.client.get(url)
84 self.assertEqual(200, resp.status, msg)
85
86 assembly = json.loads(body)
87 self.assertEqual('assembly', assembly['type'])
88 self.assertEqual(base.assembly_sample_data['name'], assembly['name'])
89
90 def test_create_camp_assembly(self):
91 """Test creating a CAMP assembly from a local plan resource.
92
93 Creates a plan resource then uses that to create an assembly resource.
94
95 """
96 if base.config_set_as('camp_enabled', False):
97 self.skipTest('CAMP not enabled.')
98
99 # create a plan using the CAMP API
100 resp = self._create_camp_plan(data=test_plans.sample_data)
101 self.assertEqual(201, resp.status)
102 uri = (resp.data['uri']
103 [len(self.client.base_url):])
104
105 ref_obj = json.dumps({'plan_uri': uri})
106
107 resp, body = self.client.post(
108 'camp/v1_1/assemblies',
109 ref_obj,
110 headers={'content-type': 'application/json'})
111 self.assertEqual(201, resp.status)
112
113 assem_resp = base.SolumResponse(resp=resp,
114 body=body,
115 body_type='json')
116 uuid = assem_resp.uuid
117 if uuid is not None:
118 # share the Solum client's list of created assemblies
119 self.client.created_assemblies.append(uuid)
120
121 def test_delete_plan_with_assemblies(self):
122 """Test deleting a plan that has assemblies associated with it.
123
124 Creates a plan, an assembly, then tries to delete the plan.
125 """
126 if base.config_set_as('camp_enabled', False):
127 self.skipTest('CAMP not enabled.')
128
129 # create a plan using the CAMP API
130 resp = self._create_camp_plan(data=test_plans.sample_data)
131 self.assertEqual(201, resp.status)
132 plan_uri = (resp.data['uri']
133 [len(self.client.base_url):])
134
135 ref_obj = json.dumps({'plan_uri': plan_uri})
136
137 resp, body = self.client.post(
138 'camp/v1_1/assemblies',
139 ref_obj,
140 headers={'content-type': 'application/json'})
141 self.assertEqual(201, resp.status)
142
143 assem_resp = base.SolumResponse(resp=resp,
144 body=body,
145 body_type='json')
146 uuid = assem_resp.uuid
147 if uuid is not None:
148 # share the Solum client's list of created assemblies
149 self.client.created_assemblies.append(uuid)
150
151 # try to delete the plan before deleting the assembly
152# resp, body = self.client.delete(plan_uri[1:])
153# self.assertEqual(409, resp.status)
154
155 self.assertRaises(tempest_exceptions.Conflict,
156 self.client.delete, plan_uri[1:])
diff --git a/solum_tempest_plugin/camp/v1_1/test_formats.py b/solum_tempest_plugin/camp/v1_1/test_formats.py
new file mode 100644
index 0000000..d1927b7
--- /dev/null
+++ b/solum_tempest_plugin/camp/v1_1/test_formats.py
@@ -0,0 +1,53 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import json
14
15from solum_tempest_plugin import base
16
17
18class TestSupportedFormats(base.TestCase):
19
20 def test_formats(self):
21 """Tests normative statement RE-42 from the CAMP v1.1 specification:
22
23 http://docs.oasis-open.org/camp/camp-spec/v1.1/csprd02/
24 camp-spec-v1.1-csprd02.pdf
25 """
26 if base.config_set_as('camp_enabled', False):
27 self.skipTest('CAMP not enabled.')
28 resp, body = self.client.get('camp/v1_1/formats/')
29 self.assertEqual(200, resp.status, 'GET formats resource')
30 formats = json.loads(body)
31 self.assertEqual('formats', formats['type'])
32 self.assertEqual('Solum_CAMP_formats', formats['name'])
33 format_links = formats['format_links']
34
35 # there should be one element in the Link array
36 self.assertEqual(1, len(format_links), 'RE-42')
37 json_link = format_links[0]
38 self.assertEqual('JSON', json_link['target_name'])
39
40 # get the URL of the platform_endpoint and strip the base URL
41 url = json_link['href'][len(self.client.base_url) + 1:]
42
43 # get our lone platform_endpoint resource
44 resp, body = self.client.get(url)
45 self.assertEqual(200, resp.status, 'GET JSON format resource')
46 formatr = json.loads(body)
47 self.assertEqual('format', formatr['type'])
48 self.assertEqual('JSON', formatr['name'], 'RE-42')
49 self.assertEqual('application/json', formatr['mime_type'], 'RE-42')
50 self.assertEqual('RFC4627', formatr['version'], 'RE-42')
51 self.assertEqual('http://www.ietf.org/rfc/rfc4627.txt',
52 formatr['documentation'],
53 'RE-42')
diff --git a/solum_tempest_plugin/camp/v1_1/test_parameter_definitions.py b/solum_tempest_plugin/camp/v1_1/test_parameter_definitions.py
new file mode 100644
index 0000000..030fdb6
--- /dev/null
+++ b/solum_tempest_plugin/camp/v1_1/test_parameter_definitions.py
@@ -0,0 +1,98 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import json
14
15from solum_tempest_plugin import base
16
17
18class TestParameterDefinitions(base.TestCase):
19
20 def test_assembly_parameter_definitions(self):
21 """Tests normative statement RMR-03 from the CAMP v1.1 specification:
22
23 http://docs.oasis-open.org/camp/camp-spec/v1.1/csprd02/
24 camp-spec-v1.1-csprd02.pdf
25 """
26 if base.config_set_as('camp_enabled', False):
27 self.skipTest('CAMP not enabled.')
28 resp, body = self.client.get('camp/v1_1/assemblies/')
29 self.assertEqual(200, resp.status, 'GET assemblies resource')
30 assemblies = json.loads(body)
31
32 # get the URL of the parameter_definitions resource
33 url = (assemblies['parameter_definitions_uri']
34 [len(self.client.base_url) + 1:])
35
36 # get the parameter_definitions resource
37 resp, body = self.client.get(url)
38 self.assertEqual(200, resp.status,
39 'GET assembly parameter_definitions resource')
40 pd_resc = json.loads(body)
41 self.assertEqual('parameter_definitions', pd_resc['type'])
42 self.assertIn('parameter_definition_links', pd_resc)
43 pd_links = pd_resc['parameter_definition_links']
44
45 # The assembly resource must reference parameter definitions for
46 # the pdp_uri, plan_uri, pdp_file, and plan_file parameters. It
47 # can reference additional parameter definitions.
48 self.assertLessEqual(4,
49 len(pd_links),
50 "too few parameter definition links")
51 expected_pds = ['pdp_uri', 'plan_uri', 'pdp_file', 'plan_file']
52 for pd_link in pd_links:
53 expected_pds.remove(pd_link['target_name'])
54
55 self.assertEqual(0,
56 len(expected_pds),
57 ('Missing parameter_definition from %s' %
58 pd_resc['name']))
59
60 def test_plan_parameter_definitions(self):
61 """Tests normative statement RMR-06 from the CAMP v1.1 specification:
62
63 http://docs.oasis-open.org/camp/camp-spec/v1.1/csprd02/
64 camp-spec-v1.1-csprd02.pdf
65 """
66 if base.config_set_as('camp_enabled', False):
67 self.skipTest('CAMP not enabled.')
68 resp, body = self.client.get('camp/v1_1/plans/')
69 self.assertEqual(200, resp.status, 'GET plans resource')
70 plans = json.loads(body)
71
72 # get the URL of the parameter_definitions resource
73 url = (plans['parameter_definitions_uri']
74 [len(self.client.base_url) + 1:])
75
76 # get the parameter_definitions resource
77 resp, body = self.client.get(url)
78 self.assertEqual(200, resp.status,
79 'GET plans parameter_definitions resource')
80 pd_resc = json.loads(body)
81 self.assertEqual('parameter_definitions', pd_resc['type'])
82 self.assertIn('parameter_definition_links', pd_resc)
83 pd_links = pd_resc['parameter_definition_links']
84
85 # The plan resource must reference parameter definitions for
86 # the pdp_uri, plan_uri, pdp_file, and plan_file parameters. It
87 # can reference additional parameter definitions.
88 self.assertLessEqual(4,
89 len(pd_links),
90 "too few parameter definition links")
91 expected_pds = ['pdp_uri', 'plan_uri', 'pdp_file', 'plan_file']
92 for pd_link in pd_links:
93 expected_pds.remove(pd_link['target_name'])
94
95 self.assertEqual(0,
96 len(expected_pds),
97 ('Missing parameter_definition from %s' %
98 pd_resc['name']))
diff --git a/solum_tempest_plugin/camp/v1_1/test_plans.py b/solum_tempest_plugin/camp/v1_1/test_plans.py
new file mode 100644
index 0000000..c85fef7
--- /dev/null
+++ b/solum_tempest_plugin/camp/v1_1/test_plans.py
@@ -0,0 +1,423 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import copy
14import json
15
16from tempest.lib import exceptions as tempest_exceptions
17import yaml
18
19from solum_tempest_plugin import base
20from solum_tempest_plugin.v1 import test_plan as solum_tests
21
22
23sample_data = {"camp_version": "CAMP 1.1",
24 "name": "camp_test_plan",
25 "description": "A test to create CAMP plan",
26 "artifacts": [{
27 "name": "train spotter service",
28 "artifact_type": "org.python:python",
29 "language_pack": "python1",
30 "content": {"href": "https://sporgil.com/git/spotter.git"},
31 "requirements": [{
32 "requirement_type": "org.python:runtime",
33 "fulfillment": {
34 "name": "python runtime",
35 "description": "python 2.7.x runtime",
36 "characteristics": [{
37 "characteristic_type": "org.python:version",
38 "version": "[2.7, 3,0)"
39 }]
40 }
41 }]
42 }]}
43
44
45class TestPlansController(base.TestCase):
46
47 def setUp(self):
48 super(TestPlansController, self).setUp()
49
50 def tearDown(self):
51 super(TestPlansController, self).tearDown()
52 self.client.delete_created_plans()
53
54 def _assert_output_expected(self, body_data, data):
55 self.assertEqual(body_data['name'], data['name'])
56 self.assertEqual(body_data['description'], data['description'])
57 if body_data['artifacts']:
58 self.assertEqual(body_data['artifacts'][0]['content']['href'],
59 data['artifacts'][0]['content']['href'])
60 self.assertIsNotNone(body_data['uuid'])
61
62 def _create_camp_plan(self, data):
63 yaml_data = yaml.dump(data)
64 resp, body = self.client.post('camp/v1_1/plans', yaml_data,
65 headers={'content-type':
66 'application/x-yaml'})
67 plan_resp = base.SolumResponse(resp=resp,
68 body=body,
69 body_type='json')
70 uuid = plan_resp.uuid
71 if uuid is not None:
72 # share the Solum client's list of created plans
73 self.client.created_plans.append(uuid)
74 return plan_resp
75
76 def test_get_solum_plan(self):
77 """Test the visibility of Solum-created plans
78
79 Test that an plan resource created through the Solum API is
80 visible via the CAMP API.
81 """
82 if base.config_set_as('camp_enabled', False):
83 self.skipTest('CAMP not enabled.')
84
85 # create a plan using Solum
86 p_resp = self.client.create_plan()
87 self.assertEqual(201, p_resp.status)
88 new_plan = p_resp.yaml_data
89 new_uuid = new_plan['uuid']
90
91 # try to get to the newly plan created through the CAMP plans
92 # resource. it would be more efficient to simply take the UUID of the
93 # newly created resource and create a CAMP API URI
94 # (../camp/v1_1/plans/<uuid>) from that, but we want to test that a
95 # link to the Solum-created plan appears in in the list of links in
96 # the CAMP plans resource.
97 resp, body = self.client.get('camp/v1_1/plans')
98 self.assertEqual(200, resp.status, 'GET plans resource')
99
100 # pick out the plan link for our new plan uuid
101 plans_dct = json.loads(body)
102 camp_link = None
103 for link in plans_dct['plan_links']:
104 link_uuid = link['href'].split("/")[-1]
105 if link_uuid == new_uuid:
106 camp_link = link
107
108 msg = 'Unable to find link to newly created plan in CAMP plans'
109 self.assertIsNotNone(camp_link, msg)
110
111 url = camp_link['href'][len(self.client.base_url) + 1:]
112 msg = ("GET Solum plan resource for %s" %
113 camp_link['target_name'])
114 resp, body = self.client.get(url)
115 self.assertEqual(200, resp.status, msg)
116
117 # CAMP plans are rendered in JSON
118 plan = json.loads(body)
119 self.assertEqual(base.plan_sample_data['name'], plan['name'])
120 self.assertEqual(base.plan_sample_data['description'],
121 plan['description'])
122
123 def test_create_camp_plan(self):
124 """Test the visibility of CAMP-created plans
125
126 Test that an plan resource created through the CAMP API is
127 visible through the Solum API.
128 """
129 if base.config_set_as('camp_enabled', False):
130 self.skipTest('CAMP not enabled.')
131
132 # create a plan using the CAMP API
133 resp = self._create_camp_plan(data=sample_data)
134 self.assertEqual(201, resp.status)
135 self._assert_output_expected(resp.data, sample_data)
136
137 uuid = resp.data['uuid']
138
139 # get the plan using the Solum API
140 resp, body = self.client.get(
141 'v1/plans/%s' % uuid,
142 headers={'content-type': 'application/x-yaml'})
143 self.assertEqual(200, resp.status)
144 yaml_data = yaml.safe_load(body)
145 self._assert_output_expected(yaml_data, sample_data)
146
147 def test_create_camp_plan_with_private_github_repo(self):
148 """Test CAMP support for private git repos
149
150 Test that CAMP support the Solum private github case.
151 """
152 if base.config_set_as('camp_enabled', False):
153 self.skipTest('CAMP not enabled.')
154
155 # copy the Solum test data and add a camp_version
156 camp_data = copy.copy(solum_tests.sample_data_private)
157 camp_data['camp_version'] = 'CAMP 1.1'
158
159 resp = self._create_camp_plan(data=camp_data)
160 self.assertEqual(201, resp.status)
161 self._assert_output_expected(resp.data, camp_data)
162
163 def test_get_no_plan(self):
164 """Try to GET a CAMP plan that doesn't exist
165
166 Test the CAMP API's ability to respond with an HTTP 404 when doing a
167 GET on a non-existent plan.
168 """
169 if base.config_set_as('camp_enabled', False):
170 self.skipTest('CAMP not enabled.')
171
172 self.assertRaises(tempest_exceptions.NotFound,
173 self.client.get, 'camp/v1_1/plans/no_plan')
174
175 def test_create_bad_content_type(self):
176 """Try to create a CAMP plan with a bogus Content-Type
177
178 Test that an attempt to create a plan with an incorrect Content-Type
179 header results in the proper error.
180 """
181 if base.config_set_as('camp_enabled', False):
182 self.skipTest('CAMP not enabled.')
183
184 yaml_data = yaml.dump(sample_data)
185 self.assertRaises(tempest_exceptions.InvalidContentType,
186 self.client.post, 'camp/v1_1/plans', yaml_data,
187 headers={'content-type': 'image/jpeg'})
188
189 def test_create_no_camp_version(self):
190 """Try to create a CAMP plan from input lacking 'camp_version'
191
192 Test that an attempt to create a plan with no 'camp_version' results
193 in the proper error.
194 """
195 if base.config_set_as('camp_enabled', False):
196 self.skipTest('CAMP not enabled.')
197
198 no_version_data = copy.copy(sample_data)
199 del no_version_data['camp_version']
200 no_version_str = yaml.dump(no_version_data)
201
202 self.assertRaises(tempest_exceptions.BadRequest,
203 self.client.post, 'camp/v1_1/plans',
204 no_version_str,
205 headers={'content-type': 'application/x-yaml'})
206
207 def test_create_bad_camp_version(self):
208 """Try to create a CAMP plan from input with incorrect 'camp_version'
209
210 Test that an attempt to create a plan with an incorrect 'camp_version'
211 results in the proper error.
212 """
213 if base.config_set_as('camp_enabled', False):
214 self.skipTest('CAMP not enabled.')
215
216 bad_version_data = copy.copy(sample_data)
217 bad_version_data['camp_version'] = 'CAMP 8.1'
218 bad_version_str = yaml.dump(bad_version_data)
219
220 self.assertRaises(tempest_exceptions.BadRequest,
221 self.client.post, 'camp/v1_1/plans',
222 bad_version_str,
223 headers={'content-type': 'application/x-yaml'})
224
225 def test_create_empty_yaml(self):
226 """Try to create a CAMP plan from an empty YAML document
227
228 Test that an attempt to create a plan using an empty yaml document
229 results in the proper error.
230 """
231 if base.config_set_as('camp_enabled', False):
232 self.skipTest('CAMP not enabled.')
233
234 self.assertRaises(tempest_exceptions.BadRequest,
235 self.client.post, 'camp/v1_1/plans', '{}',
236 headers={'content-type': 'application/x-yaml'})
237
238 def test_create_invalid_yaml(self):
239 """Try to create a CAMP plan from invalid YAML
240
241 Test that an attempt to create a plan using an invalid document
242 results in the proper error.
243 """
244 if base.config_set_as('camp_enabled', False):
245 self.skipTest('CAMP not enabled.')
246
247 self.assertRaises(tempest_exceptions.BadRequest,
248 self.client.post, 'camp/v1_1/plans', 'invalid type',
249 headers={'content-type': 'application/x-yaml'})
250
251 def test_create_invalid_syntax(self):
252 """Try to create a CAMP plan from garbled YAML
253
254 Test that an attempt to create a plan using yaml with an invalid syntax
255 results in the proper error.
256 """
257 if base.config_set_as('camp_enabled', False):
258 self.skipTest('CAMP not enabled.')
259
260 self.assertRaises(tempest_exceptions.BadRequest,
261 self.client.post, 'camp/v1_1/plans',
262 "}invalid: y'm'l3!",
263 headers={'content-type': 'application/x-yaml'})
264
265 def test_delete_solum_plan_from_camp(self):
266 """Test the ability to DELETE a Solum-created plan
267
268 Test that an plan resource created through the Solum API can
269 be deleted through the CAMP API.
270 """
271 if base.config_set_as('camp_enabled', False):
272 self.skipTest('CAMP not enabled.')
273
274 # create a plan using Solum
275 create_resp = self.client.create_plan()
276 self.assertEqual(201, create_resp.status)
277 uuid = create_resp.uuid
278
279 # delete the plan using CAMP
280 resp, body = self.client.delete('camp/v1_1/plans/%s' % uuid)
281 self.assertEqual(204, resp.status)
282
283 # remove the plan from the list of plans so we don't try to remove it
284 # twice
285 self.client.created_plans.remove(uuid)
286
287 def test_delete_camp_plan_from_solum(self):
288 """Test the ability of the Solum API to delete a CAMP-created plan
289
290 Test that an plan resource created through the CAMP API can
291 be deleted through the Solum API.
292 """
293 if base.config_set_as('camp_enabled', False):
294 self.skipTest('CAMP not enabled.')
295
296 # create a plan using the CAMP API
297 resp = self._create_camp_plan(data=sample_data)
298 self.assertEqual(201, resp.status)
299 self._assert_output_expected(resp.data, sample_data)
300
301 uuid = resp.data['uuid']
302
303 # delete the plan using the Solum API
304 resp, body = self.client.delete('v1/plans/%s' % uuid)
305 self.assertEqual(202, resp.status)
306
307 # remove the plan from the list of plans so we don't try to remove it
308 # twice
309 self.client.created_plans.remove(uuid)
310
311 def test_delete_no_plan(self):
312 """Try to DELTE a plan that doesn't exist
313
314 Test the ability of CAMP to respond with an HTTP 404 when the client
315 tries to DELETE a plan that doesn' exist
316 """
317 if base.config_set_as('camp_enabled', False):
318 self.skipTest('CAMP not enabled.')
319
320 self.assertRaises(tempest_exceptions.NotFound,
321 self.client.delete, 'camp/v1_1/plans/no_plan')
322
323 def test_patch_plan(self):
324 """PATCH a CAMP plan.
325
326 Test the ability to modify a CAMP plan using the HTTP PATCH
327 method with a JSON Patch request.
328 """
329 if base.config_set_as('camp_enabled', False):
330 self.skipTest('CAMP not enabled.')
331
332 # create a plan using the CAMP API
333 resp = self._create_camp_plan(data=sample_data)
334 self.assertEqual(201, resp.status)
335 uri = (resp.data['uri']
336 [len(self.client.base_url) + 1:])
337
338 patch_data = [
339 {"op": "add", "path": "/tags", "value": ["foo", "baz"]}
340 ]
341 patch_json = json.dumps(patch_data)
342
343 resp, body = self.client.patch(
344 uri, patch_json,
345 headers={'content-type': 'application/json-patch+json'})
346 self.assertEqual(200, resp.status)
347 json_data = json.loads(body)
348 self.assertIn('tags', json_data)
349 tags = json_data['tags']
350 self.assertEqual(2, len(tags))
351 self.assertEqual('foo', tags[0])
352 self.assertEqual('baz', tags[1])
353
354 def test_patch_no_plan(self):
355 """Try to PATCH a non-existent CAMP plan
356
357 Test that an attempt to PATCH a plan that doesn't exist results in
358 an HTTP 404 "Not Found" error
359 """
360 if base.config_set_as('camp_enabled', False):
361 self.skipTest('CAMP not enabled.')
362
363 # use an invalid JSON Patch document to test correct error precedence
364 patch_data = [
365 {"op": "add", "value": ["foo", "baz"]}
366 ]
367 patch_json = json.dumps(patch_data)
368
369 # use a bad Content-Type to further test correct error precedence
370 self.assertRaises(tempest_exceptions.NotFound,
371 self.client.patch, 'camp/v1_1/plans/no_plan',
372 patch_json,
373 headers={'content-type':
374 'application/x-not-a-type'})
375
376 def test_patch_bad_content_type(self):
377 """PATCH a CAMP plan using an incorrect content-type
378
379 Test that an attempt to patch a plan with an incorrect Content-Type
380 results in the proper error.
381 """
382 if base.config_set_as('camp_enabled', False):
383 self.skipTest('CAMP not enabled.')
384
385 # create a plan using the CAMP API
386 resp = self._create_camp_plan(data=sample_data)
387 self.assertEqual(201, resp.status)
388 uri = (resp.data['uri']
389 [len(self.client.base_url) + 1:])
390
391 patch_data = [
392 {"op": "add", "path": "/tags", "value": ["foo", "baz"]}
393 ]
394 patch_json = json.dumps(patch_data)
395
396 self.assertRaises(tempest_exceptions.InvalidContentType,
397 self.client.patch, uri, patch_json,
398 headers={'content-type': 'application/x-not-a-type'})
399
400 def test_patch_bad_json_patch(self):
401 """PATCH a CAMP plan using invalid JSON Patch document
402
403 Test that an attempt to patch a plan with a mal-formed JSON Patch
404 request (missing 'path') results in the proper error.
405 """
406 if base.config_set_as('camp_enabled', False):
407 self.skipTest('CAMP not enabled.')
408
409 # create a plan using the CAMP API
410 resp = self._create_camp_plan(data=sample_data)
411 self.assertEqual(201, resp.status)
412 uri = (resp.data['uri']
413 [len(self.client.base_url) + 1:])
414
415 patch_data = [
416 {"op": "add", "value": ["foo", "baz"]}
417 ]
418 patch_json = json.dumps(patch_data)
419
420 self.assertRaises(tempest_exceptions.BadRequest,
421 self.client.patch, uri, patch_json,
422 headers={'content-type':
423 'application/json-patch+json'})
diff --git a/solum_tempest_plugin/camp/v1_1/test_platform.py b/solum_tempest_plugin/camp/v1_1/test_platform.py
new file mode 100644
index 0000000..20e2a00
--- /dev/null
+++ b/solum_tempest_plugin/camp/v1_1/test_platform.py
@@ -0,0 +1,73 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import json
14
15from solum_tempest_plugin import base
16
17
18class TestPlatformAndContainers(base.TestCase):
19
20 def _test_get_resource(self, url, rtype, name):
21 resp, body = self.client.get(url)
22 self.assertEqual(200, resp.status, 'GET %s resource' % rtype)
23 resource = json.loads(body)
24 self.assertEqual(rtype, resource['type'])
25 self.assertEqual(name, resource['name'])
26
27 def test_get_platform_and_containers(self):
28 if base.config_set_as('camp_enabled', False):
29 self.skipTest('CAMP not enabled.')
30 # get and test our platform resource
31 resp, body = self.client.get('camp/v1_1/platform/')
32 self.assertEqual(200, resp.status, 'GET platform resource')
33 platform = json.loads(body)
34 self.assertEqual('platform', platform['type'])
35 self.assertEqual('Solum_CAMP_v1_1_platform', platform['name'])
36 self.assertEqual('CAMP 1.1', platform['specification_version'])
37 self.assertEqual('Solum CAMP 1.1', platform['implementation_version'])
38
39 # get and test the supported formats resource
40 url = (platform['supported_formats_uri']
41 [len(self.client.base_url) + 1:])
42 self._test_get_resource(url, 'formats', 'Solum_CAMP_formats')
43
44 # get and test the extensions resource
45 url = (platform['extensions_uri']
46 [len(self.client.base_url) + 1:])
47 self._test_get_resource(url, 'extensions', 'Solum_CAMP_extensions')
48
49 # get and test the type_definitions resource
50 url = (platform['type_definitions_uri']
51 [len(self.client.base_url) + 1:])
52 self._test_get_resource(url,
53 'type_definitions',
54 'Solum_CAMP_type_definitions')
55
56 # get and test the platform_endpoints resource
57 url = (platform['platform_endpoints_uri']
58 [len(self.client.base_url) + 1:])
59 self._test_get_resource(url,
60 'platform_endpoints',
61 'Solum_CAMP_endpoints')
62
63 # get and test the assemblies collection resource
64 url = platform['assemblies_uri'][len(self.client.base_url) + 1:]
65 self._test_get_resource(url, 'assemblies', 'Solum_CAMP_assemblies')
66
67 # get and test the services collection resource
68 url = platform['services_uri'][len(self.client.base_url) + 1:]
69 self._test_get_resource(url, 'services', 'Solum_CAMP_services')
70
71 # get and test the plans collection resource
72 url = platform['plans_uri'][len(self.client.base_url) + 1:]
73 self._test_get_resource(url, 'plans', 'Solum_CAMP_plans')
diff --git a/solum_tempest_plugin/camp/v1_1/test_type_definitions.py b/solum_tempest_plugin/camp/v1_1/test_type_definitions.py
new file mode 100644
index 0000000..476c52d
--- /dev/null
+++ b/solum_tempest_plugin/camp/v1_1/test_type_definitions.py
@@ -0,0 +1,58 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import json
14
15from solum_tempest_plugin import base
16
17
18class TestTypeDefinitions(base.TestCase):
19
20 def _test_get_resource(self, abs_url, msg, rtype, name):
21 url = abs_url[len(self.client.base_url) + 1:]
22 resp, body = self.client.get(url)
23 self.assertEqual(200, resp.status, msg)
24 resource = json.loads(body)
25 self.assertEqual(rtype, resource['type'])
26 self.assertEqual(name, resource['name'])
27 return body
28
29 def test_type_definitions(self):
30 """Test the CAMP type_definition metadata.
31
32 Crawls tree rooted in type_definitions and verifies that all the
33 resources exist and that all the links to the attribute_definition
34 resources are valid and the attribute_definitions resources exist.
35 """
36 if base.config_set_as('camp_enabled', False):
37 self.skipTest('CAMP not enabled.')
38
39 resp, body = self.client.get('camp/v1_1/type_definitions')
40 self.assertEqual(200, resp.status, 'GET type_definitions resource')
41
42 defs_dct = json.loads(body)
43 for link_dct in defs_dct['type_definition_links']:
44 msg = ("GET type_definition resource for %s" %
45 link_dct['target_name'])
46 body = self._test_get_resource(link_dct['href'],
47 msg,
48 'type_definition',
49 link_dct['target_name'])
50
51 def_dct = json.loads(body)
52 for adl_dct in def_dct['attribute_definition_links']:
53 msg = ("GET attribute_definition resource for %s" %
54 link_dct['target_name'])
55 self._test_get_resource(adl_dct['href'],
56 msg,
57 'attribute_definition',
58 adl_dct['target_name'])
diff --git a/solum_tempest_plugin/common/__init__.py b/solum_tempest_plugin/common/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/solum_tempest_plugin/common/__init__.py
diff --git a/solum_tempest_plugin/common/apputils.py b/solum_tempest_plugin/common/apputils.py
new file mode 100644
index 0000000..e28ffe4
--- /dev/null
+++ b/solum_tempest_plugin/common/apputils.py
@@ -0,0 +1,38 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import random
14import string
15
16
17def get_sample_data(languagepack=''):
18 data = dict()
19 s = string.lowercase
20 data["name"] = "test_app" + ''.join(random.sample(s, 5))
21 data["description"] = "descp"
22 data["languagepack"] = languagepack
23 data["trigger_actions"] = ["test", "build", "deploy"]
24 data["ports"] = [80]
25
26 source = {}
27 source['repository'] = "https://github.com/a/b.git"
28 source['revision'] = "master"
29 data["source"] = source
30
31 workflow = {}
32 workflow["test_cmd"] = "./unit_tests.sh"
33 workflow["run_cmd"] = "python app.py"
34 data["workflow_config"] = workflow
35
36 data["repo_token"] = 'abc'
37
38 return data
diff --git a/solum_tempest_plugin/test_release.py b/solum_tempest_plugin/test_release.py
new file mode 100644
index 0000000..d7d36ee
--- /dev/null
+++ b/solum_tempest_plugin/test_release.py
@@ -0,0 +1,22 @@
1# Copyright 2015 - Rackspace Hosting
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from solum_tempest_plugin import base
16
17
18class ReleaseVersionTests(base.TestCase):
19 def test_release_reported(self):
20 resp, body = self.client.get('/')
21 release_version = resp.get('x-solum-release')
22 self.assertTrue(release_version is not None)
diff --git a/solum_tempest_plugin/test_versions.py b/solum_tempest_plugin/test_versions.py
new file mode 100644
index 0000000..f4b822f
--- /dev/null
+++ b/solum_tempest_plugin/test_versions.py
@@ -0,0 +1,88 @@
1#
2# Copyright 2013 - Red Hat, Inc.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import json
17
18from solum_tempest_plugin import base
19
20
21class VersionDiscoveryTestCase(base.TestCase):
22 def test_get_root_discovers_v1(self):
23 resp, body = self.client.get('/')
24 body = json.loads(body)
25 self.assertEqual(200, resp.status)
26 self.assertEqual(1, len(body))
27 v1 = body[0]
28 self.assertEqual('v1.0', v1['id'])
29 self.assertEqual('CURRENT', v1['status'])
30 self.assertEqual('v1', v1['link']['target_name'])
31 self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
32
33 def test_delete_root_discovers_v1(self):
34 resp, body = self.client.delete('/')
35 body = json.loads(body)
36 self.assertEqual(200, resp.status)
37 self.assertEqual(1, len(body))
38 v1 = body[0]
39 self.assertEqual('v1.0', v1['id'])
40 self.assertEqual('CURRENT', v1['status'])
41 self.assertEqual('v1', v1['link']['target_name'])
42 self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
43
44 def test_post_root_discovers_v1(self):
45 resp, body = self.client.post('/', '{}')
46 body = json.loads(body)
47 self.assertEqual(200, resp.status)
48 self.assertEqual(1, len(body))
49 v1 = body[0]
50 self.assertEqual('v1.0', v1['id'])
51 self.assertEqual('CURRENT', v1['status'])
52 self.assertEqual('v1', v1['link']['target_name'])
53 self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
54
55 def test_put_root_discovers_v1(self):
56 resp, body = self.client.put('/', '{}')
57 body = json.loads(body)
58 self.assertEqual(200, resp.status)
59 self.assertEqual(1, len(body))
60 v1 = body[0]
61 self.assertEqual('v1.0', v1['id'])
62 self.assertEqual('CURRENT', v1['status'])
63 self.assertEqual('v1', v1['link']['target_name'])
64 self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
65
66 def test_post_no_body_root_discovers_v1(self):
67 self.skipTest("POST without body will hang request: #1367470")
68 resp, body = self.client.post('/', None)
69 body = json.loads(body)
70 self.assertEqual(200, resp.status)
71 self.assertEqual(1, len(body))
72 v1 = body[0]
73 self.assertEqual('v1.0', v1['id'])
74 self.assertEqual('CURRENT', v1['status'])
75 self.assertEqual('v1', v1['link']['target_name'])
76 self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
77
78 def test_put_no_body_root_discovers_v1(self):
79 self.skipTest("PUT without body will hang request: #1367470")
80 resp, body = self.client.put('/', None)
81 body = json.loads(body)
82 self.assertEqual(200, resp.status)
83 self.assertEqual(1, len(body))
84 v1 = body[0]
85 self.assertEqual('v1.0', v1['id'])
86 self.assertEqual('CURRENT', v1['status'])
87 self.assertEqual('v1', v1['link']['target_name'])
88 self.assertEqual('%s/v1' % self.client.base_url, v1['link']['href'])
diff --git a/solum_tempest_plugin/v1/__init__.py b/solum_tempest_plugin/v1/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/solum_tempest_plugin/v1/__init__.py
diff --git a/solum_tempest_plugin/v1/public/__init__.py b/solum_tempest_plugin/v1/public/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/solum_tempest_plugin/v1/public/__init__.py
diff --git a/solum_tempest_plugin/v1/public/test_trigger.py b/solum_tempest_plugin/v1/public/test_trigger.py
new file mode 100644
index 0000000..149f3b8
--- /dev/null
+++ b/solum_tempest_plugin/v1/public/test_trigger.py
@@ -0,0 +1,59 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import json
14import time
15
16import requests
17
18from solum_tempest_plugin import base
19from solum_tempest_plugin.common import apputils
20
21
22class TestTriggerController(base.TestCase):
23
24 def test_trigger_post(self):
25 lp_name = self.client.create_lp()
26 data = apputils.get_sample_data(languagepack=lp_name)
27 resp = self.client.create_app(data=data)
28 bdy = json.loads(resp.body)
29 trigger_uri = bdy['trigger_uri']
30 # Using requests instead of self.client to test unauthenticated request
31 status_url = 'https://api.github.com/repos/u/r/statuses/{sha}'
32 body_dict = {'sender': {'url': 'https://api.github.com'},
33 'pull_request': {'head': {'sha': 'asdf'}},
34 'repository': {'statuses_url': status_url}}
35 body = json.dumps(body_dict)
36 resp = requests.post(trigger_uri, data=body)
37 self.assertEqual(202, resp.status_code)
38 self.client.delete_created_apps()
39 # since app delete is an async operation, wait few seconds for app
40 # delete and then delete language pack (otherwise language pack
41 # cannot be deleted)
42 time.sleep(2)
43 self.client.delete_created_lps()
44
45 def test_trigger_post_with_empty_body(self):
46 lp_name = self.client.create_lp()
47 data = apputils.get_sample_data(languagepack=lp_name)
48 resp = self.client.create_app(data=data)
49 bdy = json.loads(resp.body)
50 trigger_uri = bdy['trigger_uri']
51 # Using requests instead of self.client to test unauthenticated request
52 resp = requests.post(trigger_uri)
53 self.assertEqual(400, resp.status_code)
54 self.client.delete_created_apps()
55 # since app delete is an async operation, wait few seconds for app
56 # delete and then delete language pack (otherwise language pack
57 # cannot be deleted)
58 time.sleep(2)
59 self.client.delete_created_lps()
diff --git a/solum_tempest_plugin/v1/test_app.py b/solum_tempest_plugin/v1/test_app.py
new file mode 100644
index 0000000..071df06
--- /dev/null
+++ b/solum_tempest_plugin/v1/test_app.py
@@ -0,0 +1,154 @@
1#
2# Copyright 2015 - Rackspace US, Inc
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import json
17import time
18
19from tempest.lib import exceptions as tempest_exceptions
20import yaml
21
22from solum_tempest_plugin import base
23from solum_tempest_plugin.common import apputils
24
25
26class TestAppController(base.TestCase):
27
28 def _assert_app_data(self, actual, expected):
29 self.assertEqual(expected["name"], actual["name"])
30 self.assertEqual(expected["description"], actual["description"])
31 self.assertEqual(expected["languagepack"], actual["languagepack"])
32 self.assertEqual(expected["trigger_actions"],
33 actual["trigger_actions"])
34
35 self.assertEqual(expected["ports"], actual["ports"])
36 self.assertEqual(expected["source"]["repository"],
37 actual["source"]["repository"])
38
39 self.assertEqual(expected["source"]["revision"],
40 actual["source"]["revision"])
41
42 self.assertEqual(expected["workflow_config"]["test_cmd"],
43 actual["workflow_config"]["test_cmd"])
44
45 self.assertEqual(expected["workflow_config"]["run_cmd"],
46 actual["workflow_config"]["run_cmd"])
47
48 def setUp(self):
49 super(TestAppController, self).setUp()
50
51 def tearDown(self):
52 super(TestAppController, self).tearDown()
53
54 def test_app_create(self):
55 lp_name = self.client.create_lp()
56 data = apputils.get_sample_data(languagepack=lp_name)
57 resp = self.client.create_app(data=data)
58 self.assertEqual(201, resp.status)
59 self.client.delete_app(resp.id)
60 time.sleep(2)
61 self.client.delete_language_pack(lp_name)
62
63 def test_app_create_bad_port_data(self):
64 try:
65 bad_data = apputils.get_sample_data()
66 bad_data["ports"][0] = -1
67 self.client.create_plan(data=bad_data)
68 except tempest_exceptions.BadRequest:
69 self.assertTrue(True)
70
71 def test_app_create_empty_body(self):
72 self.assertRaises(tempest_exceptions.BadRequest,
73 self.client.post, 'v1/apps', '{}',
74 headers={'content-type': 'application/json'})
75
76 def test_app_patch(self):
77 lp_name = self.client.create_lp()
78 data = apputils.get_sample_data(languagepack=lp_name)
79 create_resp = self.client.create_app(data=data)
80 self.assertEqual(201, create_resp.status)
81
82 json_update = {
83 'name': 'newfakeappname',
84 'workflow_config': {
85 'run_cmd': 'newruncmd',
86 },
87 'source': {
88 'repository': 'newrepo',
89 },
90 }
91
92 uri = 'v1/apps/%s' % create_resp.id
93
94 resp, body = self.client.patch(
95 uri, json.dumps(json_update),
96 headers={'content-type': 'application/json'})
97
98 self.assertEqual(200, resp.status)
99 app_body = json.loads(body)
100 self.assertEqual('newfakeappname', app_body["name"])
101 self.assertEqual("newruncmd", app_body["workflow_config"]["run_cmd"])
102 self.assertEqual("newrepo", app_body["source"]["repository"])
103 self.client.delete_app(create_resp.id)
104 time.sleep(2)
105 self.client.delete_language_pack(lp_name)
106
107 def test_app_get(self):
108 lp_name = self.client.create_lp()
109 data = apputils.get_sample_data(languagepack=lp_name)
110 create_resp = self.client.create_app(data=data)
111 self.assertEqual(201, create_resp.status)
112 id = create_resp.id
113
114 resp, body = self.client.get(
115 'v1/apps/%s' % id,
116 headers={'content-type': 'application/json'})
117 self.assertEqual(200, resp.status)
118 yaml_data = yaml.safe_load(body)
119 self._assert_app_data(yaml_data, data)
120 self.client.delete_app(create_resp.id)
121 time.sleep(2)
122 self.client.delete_language_pack(lp_name)
123
124 def test_apps_get_all(self):
125 lp_name = self.client.create_lp()
126 data = apputils.get_sample_data(languagepack=lp_name)
127 create_resp = self.client.create_app(data)
128 self.assertEqual(201, create_resp.status)
129 resp, body = self.client.get(
130 'v1/apps', headers={'content-type': 'application/json'})
131 resp_data = yaml.safe_load(body)
132 self.assertEqual(200, resp.status)
133 id = create_resp.id
134 filtered = [app for app in resp_data if app['id'] == id]
135 self.assertEqual(filtered[0]['id'], id)
136 self.client.delete_app(id)
137 time.sleep(2)
138 self.client.delete_language_pack(lp_name)
139
140 def test_app_delete(self):
141 lp_name = self.client.create_lp()
142 data = apputils.get_sample_data(languagepack=lp_name)
143 create_resp = self.client.create_app(data)
144 self.assertEqual(201, create_resp.status)
145 id = create_resp.id
146 resp, body = self.client.delete_app(id)
147 self.assertEqual(202, resp.status)
148 self.assertEqual('', body)
149 time.sleep(2)
150 self.client.delete_language_pack(lp_name)
151
152 def test_app_delete_not_found(self):
153 self.assertRaises(tempest_exceptions.NotFound,
154 self.client.delete, 'v1/apps/not_found')
diff --git a/solum_tempest_plugin/v1/test_assembly.py b/solum_tempest_plugin/v1/test_assembly.py
new file mode 100644
index 0000000..ba0d67d
--- /dev/null
+++ b/solum_tempest_plugin/v1/test_assembly.py
@@ -0,0 +1,212 @@
1#
2# Copyright 2013 - Noorul Islam K M
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import json
17
18from tempest.lib import exceptions as tempest_exceptions
19
20from solum_tempest_plugin import base
21
22sample_data = {"name": "test_assembly",
23 "description": "A test to create assembly",
24 "project_id": "project_id",
25 "user_id": "user_id",
26 "status": "QUEUED",
27 "application_uri": "http://localhost:5000"}
28
29plan_sample_data = {"version": "1",
30 "name": "test_plan",
31 "description": "A test to create plan",
32 "project_id": "project_id",
33 "user_id": "user_id"}
34
35
36class TestAssemblyController(base.TestCase):
37
38 def setUp(self):
39 super(TestAssemblyController, self).setUp()
40
41 def tearDown(self):
42 super(TestAssemblyController, self).tearDown()
43 self.client.delete_created_assemblies()
44 self.client.delete_created_plans()
45
46 def _assert_output_expected(self, body_data, data):
47 self.assertEqual(body_data['description'], data['description'])
48 self.assertEqual(body_data['plan_uri'], data['plan_uri'])
49 self.assertEqual(body_data['name'], data['name'])
50 self.assertIsNotNone(body_data['uuid'])
51 self.assertEqual(body_data['status'], data['status'])
52 self.assertEqual(body_data['application_uri'], data['application_uri'])
53
54 def test_assemblies_get_all(self):
55 # Create assemblies to find
56 p_resp_1 = self.client.create_plan()
57 self.assertEqual(201, p_resp_1.status)
58 a_resp_1 = self.client.create_assembly(data=sample_data,
59 plan_uuid=p_resp_1.uuid)
60 self.assertEqual(201, a_resp_1.status)
61
62 p_resp_2 = self.client.create_plan()
63 self.assertEqual(201, p_resp_2.status)
64 a_resp_2 = self.client.create_assembly(data=sample_data,
65 plan_uuid=p_resp_2.uuid)
66 self.assertEqual(201, a_resp_2.status)
67
68 # Get list of all assemblies
69 resp, body = self.client.get('v1/assemblies')
70 self.assertEqual(200, resp.status)
71
72 # Search for uuids of created assemblies
73 assembly_list = json.loads(body)
74 found_uuid_1 = False
75 found_uuid_2 = False
76 for assembly in assembly_list:
77 uuid = json.dumps(assembly['uuid'])
78 if a_resp_1.uuid in uuid:
79 found_uuid_1 = True
80 elif a_resp_2.uuid in uuid:
81 found_uuid_2 = True
82
83 self.assertTrue(found_uuid_1,
84 'Cannot find assembly [%s] in list of all assemblies.'
85 % a_resp_1.uuid)
86 self.assertTrue(found_uuid_2,
87 'Cannot find assembly [%s] in list of all assemblies.'
88 % a_resp_2.uuid)
89
90 def test_assemblies_create(self):
91 plan_resp = self.client.create_plan()
92 self.assertEqual(201, plan_resp.status)
93 assembly_resp = self.client.create_assembly(
94 plan_uuid=plan_resp.uuid,
95 data=sample_data)
96 self.assertEqual(201, assembly_resp.status)
97 sample_data['plan_uri'] = "%s/v1/plans/%s" % (self.client.base_url,
98 plan_resp.uuid)
99 self._assert_output_expected(assembly_resp.data, sample_data)
100
101 def test_assemblies_create_none(self):
102 self.assertRaises(tempest_exceptions.BadRequest,
103 self.client.post, 'v1/assemblies', "{}")
104
105 def test_assemblies_get(self):
106 plan_resp = self.client.create_plan(data=plan_sample_data)
107 self.assertEqual(201, plan_resp.status)
108 plan_uuid = plan_resp.uuid
109 assembly_resp = self.client.create_assembly(
110 plan_uuid=plan_uuid,
111 data=sample_data)
112 self.assertEqual(201, assembly_resp.status)
113 uuid = assembly_resp.uuid
114 sample_data['plan_uri'] = "%s/v1/plans/%s" % (self.client.base_url,
115 plan_uuid)
116 resp, body = self.client.get('v1/assemblies/%s' % uuid)
117 self.assertEqual(200, resp.status)
118 json_data = json.loads(body)
119 self._assert_output_expected(json_data, sample_data)
120
121 # Now check that HTTPS is respected. No new assemblies are created.
122 for k in ['plan_uri', 'trigger_uri']:
123 if k in sample_data:
124 sample_data[k] = sample_data[k].replace('http:', 'https:', 1)
125 use_https = {'X-Forwarded-Proto': 'https'}
126 resp, body = self.client.get('v1/assemblies/%s' % uuid,
127 headers=use_https)
128 self.assertEqual(200, resp.status)
129 json_data = json.loads(body)
130 self._assert_output_expected(json_data, sample_data)
131
132 def test_assemblies_get_not_found(self):
133 self.assertRaises(tempest_exceptions.NotFound,
134 self.client.get, 'v1/assemblies/not_found')
135
136 def test_assemblies_put(self):
137 plan_resp = self.client.create_plan()
138 self.assertEqual(201, plan_resp.status)
139 plan_uuid = plan_resp.uuid
140 assembly_resp = self.client.create_assembly(
141 plan_uuid=plan_uuid,
142 data=sample_data)
143 self.assertEqual(201, assembly_resp.status)
144 uuid = assembly_resp.uuid
145 uri = "%s/v1/plans/%s" % (self.client.base_url, plan_uuid)
146 updated_data = {"name": "test_assembly_updated",
147 "description": "A test to create assembly updated",
148 "plan_uri": uri,
149 "user_id": "user_id updated",
150 "status": "new_status",
151 "application_uri": "new_uri"}
152 updated_json = json.dumps(updated_data)
153 resp, body = self.client.put('v1/assemblies/%s' % uuid, updated_json)
154 self.assertEqual(200, resp.status)
155 json_data = json.loads(body)
156 self._assert_output_expected(json_data, updated_data)
157
158 def test_assemblies_put_not_found(self):
159 updated_data = {"name": "test_assembly_updated",
160 "description": "A test to create assembly updated",
161 "plan_uri": 'fake_uri',
162 "project_id": "project_id updated",
163 "user_id": "user_id updated",
164 "status": "new_status",
165 "application_uri": "new_uri"}
166 updated_json = json.dumps(updated_data)
167 self.assertRaises(tempest_exceptions.NotFound,
168 self.client.put, 'v1/assemblies/not_found',
169 updated_json)
170
171 def test_assemblies_put_none(self):
172 self.assertRaises(tempest_exceptions.BadRequest,
173 self.client.put, 'v1/assemblies/any', "{}")
174
175 def test_assemblies_put_cannot_update(self):
176 plan_resp = self.client.create_plan()
177 self.assertEqual(201, plan_resp.status)
178 plan_uuid = plan_resp.uuid
179 assembly_resp = self.client.create_assembly(
180 plan_uuid=plan_uuid,
181 data=sample_data)
182 self.assertEqual(201, assembly_resp.status)
183 uuid = assembly_resp.uuid
184 immutables = [
185 ('id', 'new_assembly_id'),
186 ('uuid', 'new_assembly_uuid'),
187 ('project_id', 'new_project_id'),
188 ]
189 for key_value in immutables:
190 updated_data = dict([key_value])
191 updated_json = json.dumps(updated_data)
192 self.assertRaises(tempest_exceptions.BadRequest,
193 self.client.put,
194 'v1/assemblies/%s' % uuid,
195 updated_json)
196
197 def test_assemblies_delete(self):
198 plan_resp = self.client.create_plan()
199 self.assertEqual(201, plan_resp.status)
200 assembly_resp = self.client.create_assembly(
201 plan_uuid=plan_resp.uuid,
202 data=sample_data)
203 self.assertEqual(201, assembly_resp.status)
204 uuid = assembly_resp.uuid
205
206 resp, body = self.client.delete_assembly(uuid)
207 self.assertEqual(204, resp.status)
208 self.assertEqual('', body)
209
210 def test_assemblies_delete_not_found(self):
211 self.assertRaises(tempest_exceptions.NotFound,
212 self.client.delete, 'v1/assemblies/not_found')
diff --git a/solum_tempest_plugin/v1/test_component.py b/solum_tempest_plugin/v1/test_component.py
new file mode 100644
index 0000000..648d2f3
--- /dev/null
+++ b/solum_tempest_plugin/v1/test_component.py
@@ -0,0 +1,153 @@
1#
2# Copyright 2013 - Noorul Islam K M
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import json
17
18from tempest.lib import exceptions as tempest_exceptions
19
20from solum_tempest_plugin import base
21
22sample_data = {'name': 'test_component',
23 'description': 'desc'}
24
25assembly_sample_data = {'name': 'test_assembly',
26 'description': 'desc assembly'}
27
28plan_sample_data = {'version': '1',
29 'name': 'test_plan',
30 'description': 'A test to create plan'}
31
32
33class TestComponentController(base.TestCase):
34
35 def setUp(self):
36 super(TestComponentController, self).setUp()
37
38 def tearDown(self):
39 super(TestComponentController, self).tearDown()
40 self.client.delete_created_assemblies()
41 self.client.delete_created_plans()
42
43 def _assert_output_expected(self, body_data, data):
44 self.assertEqual(body_data['name'], data['name'])
45 self.assertEqual(body_data['assembly_uuid'], data['assembly_uuid'])
46 self.assertIsNotNone(body_data['uuid'])
47 self.assertIsNotNone(body_data['project_id'])
48 self.assertIsNotNone(body_data['user_id'])
49
50 def _delete_component(self, uuid):
51 resp, body = self.client.delete('v1/components/%s' % uuid)
52 self.assertEqual(204, resp.status)
53
54 def _create_component(self):
55 plan_resp = self.client.create_plan()
56 self.assertEqual(201, plan_resp.status,)
57 assembly_resp = self.client.create_assembly(plan_uuid=plan_resp.uuid)
58 self.assertEqual(201, assembly_resp.status)
59 plan_uuid = plan_resp.uuid
60 assembly_uuid = assembly_resp.uuid
61 sample_data['assembly_uuid'] = assembly_uuid
62 data = json.dumps(sample_data)
63 resp, body = self.client.post('v1/components', data)
64 self.assertEqual(201, resp.status)
65 out_data = json.loads(body)
66 uuid = out_data['uuid']
67 self.assertIsNotNone(uuid)
68 return uuid, assembly_uuid, plan_uuid
69
70 def test_components_get_all(self):
71 uuid, assembly_uuid, plan_uuid = self._create_component()
72 resp, body = self.client.get('v1/components')
73 data = json.loads(body)
74 self.assertEqual(200, resp.status)
75 filtered = [com for com in data if com['uuid'] == uuid]
76 self.assertEqual(1, len(filtered))
77 self.assertEqual(uuid, filtered[0]['uuid'])
78 self._delete_component(uuid)
79
80 def test_components_create(self):
81 plan_resp = self.client.create_plan()
82 self.assertEqual(201, plan_resp.status)
83 assembly_resp = self.client.create_assembly(plan_uuid=plan_resp.uuid)
84 self.assertEqual(201, assembly_resp.status)
85 plan_uuid = plan_resp.uuid
86 assembly_uuid = assembly_resp.uuid
87
88 sample_data['assembly_uuid'] = assembly_uuid
89 sample_data['plan_uri'] = "%s/v1/plans/%s" % (self.client.base_url,
90 plan_uuid)
91 sample_json = json.dumps(sample_data)
92 resp, body = self.client.post('v1/components', sample_json)
93 self.assertEqual(201, resp.status)
94 json_data = json.loads(body)
95 self._assert_output_expected(json_data, sample_data)
96 self._delete_component(json_data['uuid'])
97
98 def test_components_create_none(self):
99 self.assertRaises(tempest_exceptions.BadRequest,
100 self.client.post, 'v1/components', "{}")
101
102 def test_components_get(self):
103 uuid, assembly_uuid, plan_uuid = self._create_component()
104 sample_data['plan_uri'] = "%s/v1/plans/%s" % (self.client.base_url,
105 plan_uuid)
106 resp, body = self.client.get('v1/components/%s' % uuid)
107 self.assertEqual(200, resp.status)
108 json_data = json.loads(body)
109 self._assert_output_expected(json_data, sample_data)
110 self._delete_component(uuid)
111
112 def test_components_get_not_found(self):
113 self.assertRaises(tempest_exceptions.NotFound,
114 self.client.get, 'v1/components/not_found')
115
116 def test_components_put(self):
117 uuid, assembly_uuid, plan_uuid = self._create_component()
118 updated_data = {'name': 'test_service_updated',
119 'description': 'desc updated',
120 'plan_uri': "%s/v1/plans/%s" % (self.client.base_url,
121 plan_uuid),
122 'assembly_uuid': assembly_uuid}
123 updated_json = json.dumps(updated_data)
124 resp, body = self.client.put('v1/components/%s' % uuid, updated_json)
125 self.assertEqual(200, resp.status)
126 json_data = json.loads(body)
127 self._assert_output_expected(json_data, updated_data)
128 self._delete_component(uuid)
129
130 def test_components_put_not_found(self):
131 updated_data = {'name': 'test_service_updated',
132 'description': 'desc updated',
133 'plan_uri': "%s/v1/plans/%s" % (self.client.base_url,
134 'not_found'),
135 'assembly_uuid': 'not_found'}
136 updated_json = json.dumps(updated_data)
137 self.assertRaises(tempest_exceptions.NotFound,
138 self.client.put, 'v1/components/not_found',
139 updated_json)
140
141 def test_components_put_none(self):
142 self.assertRaises(tempest_exceptions.BadRequest,
143 self.client.put, 'v1/components/any', "{}")
144
145 def test_components_delete(self):
146 uuid, assembly_uuid, plan_uuid = self._create_component()
147 resp, body = self.client.delete('v1/components/%s' % uuid)
148 self.assertEqual(204, resp.status)
149 self.assertEqual('', body)
150
151 def test_components_delete_not_found(self):
152 self.assertRaises(tempest_exceptions.NotFound,
153 self.client.delete, 'v1/components/not_found')
diff --git a/solum_tempest_plugin/tests/test_solum_tempest_plugin.py b/solum_tempest_plugin/v1/test_extension.py
index 5060123..c593609 100644
--- a/solum_tempest_plugin/tests/test_solum_tempest_plugin.py
+++ b/solum_tempest_plugin/v1/test_extension.py
@@ -1,5 +1,6 @@
1# -*- coding: utf-8 -*- 1#
2 2# Copyright 2013 - Noorul Islam K M
3#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may 4# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain 5# not use this file except in compliance with the License. You may obtain
5# a copy of the License at 6# a copy of the License at
@@ -12,17 +13,15 @@
12# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
13# under the License. 14# under the License.
14 15
15""" 16import json
16test_solum_tempest_plugin
17----------------------------------
18
19Tests for `solum_tempest_plugin` module.
20"""
21 17
22from solum_tempest_plugin.tests import base 18from solum_tempest_plugin import base
23 19
24 20
25class TestSolum_tempest_plugin(base.TestCase): 21class TestExtensionController(base.TestCase):
26 22
27 def test_something(self): 23 def test_extensions_get_all(self):
28 pass 24 resp, body = self.client.get('v1/extensions')
25 data = json.loads(body)
26 self.assertEqual(200, resp.status)
27 self.assertEqual([], data)
diff --git a/solum_tempest_plugin/v1/test_language_pack.py b/solum_tempest_plugin/v1/test_language_pack.py
new file mode 100644
index 0000000..23ff646
--- /dev/null
+++ b/solum_tempest_plugin/v1/test_language_pack.py
@@ -0,0 +1,143 @@
1# Copyright 2014 - Rackspace
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import json
16import random
17import string
18import time
19
20from tempest.lib import exceptions as tempest_exceptions
21
22from solum_tempest_plugin import base
23from solum_tempest_plugin.common import apputils
24
25sample_plan = {"version": "1",
26 "name": "test_plan",
27 "artifacts": [{
28 "name": "No deus",
29 "language_pack": "language_pack_name"
30 }]}
31
32
33class TestLanguagePackController(base.TestCase):
34
35 def _get_sample_languagepack(self):
36 sample_lp = dict()
37 s = string.lowercase
38 sample_lp["name"] = "lp" + ''.join(random.sample(s, 5))
39 lp_url = "https://github.com/murali44/Solum-lp-Go.git"
40 sample_lp["source_uri"] = lp_url
41 return sample_lp
42
43 def setUp(self):
44 super(TestLanguagePackController, self).setUp()
45
46 def _delete_all(self):
47 resp, body = self.client.get('v1/language_packs')
48 data = json.loads(body)
49 self.assertEqual(200, resp.status)
50 [self._delete_language_pack(pl['uuid']) for pl in data]
51
52 def _delete_language_pack(self, uuid):
53 resp, _ = self.client.delete('v1/language_packs/%s' % uuid)
54 self.assertEqual(204, resp.status)
55
56 def _create_language_pack(self):
57 sample_lp = self._get_sample_languagepack()
58 jsondata = json.dumps(sample_lp)
59 resp, body = self.client.post('v1/language_packs', jsondata)
60 self.assertEqual(201, resp.status)
61 out_data = json.loads(body)
62 uuid = out_data['uuid']
63 self.assertIsNotNone(uuid)
64 return uuid, sample_lp
65
66 def test_language_packs_get_all(self):
67 uuid, sample_lp = self._create_language_pack()
68 resp, body = self.client.get('v1/language_packs')
69 data = json.loads(body)
70 self.assertEqual(200, resp.status)
71 filtered = [pl for pl in data if pl['uuid'] == uuid]
72 self.assertEqual(uuid, filtered[0]['uuid'])
73 self._delete_language_pack(uuid)
74
75 def test_language_packs_create(self):
76 sample_lp = self._get_sample_languagepack()
77 sample_json = json.dumps(sample_lp)
78 resp, body = self.client.post('v1/language_packs', sample_json)
79 self.assertEqual(201, resp.status)
80 json_data = json.loads(body)
81 self.assertEqual("QUEUED", json_data["status"])
82 self.assertEqual(sample_lp['name'], json_data["name"])
83 self._delete_language_pack(json_data["uuid"])
84
85 def test_language_packs_create_none(self):
86 self.assertRaises(tempest_exceptions.BadRequest,
87 self.client.post, 'v1/language_packs', "{}")
88
89 def test_language_packs_get(self):
90 uuid, sample_lp = self._create_language_pack()
91 resp, body = self.client.get('v1/language_packs/%s' % uuid)
92 self.assertEqual(200, resp.status)
93 json_data = json.loads(body)
94 self.assertEqual(sample_lp['source_uri'], json_data['source_uri'])
95 self.assertEqual(sample_lp['name'], json_data['name'])
96 self._delete_language_pack(uuid)
97
98 def test_language_packs_get_not_found(self):
99 self.assertRaises(tempest_exceptions.NotFound,
100 self.client.get, 'v1/language_packs/not_found')
101
102 def test_language_packs_delete(self):
103 uuid, sample_lp = self._create_language_pack()
104 resp, body = self.client.delete('v1/language_packs/%s' % uuid)
105 self.assertEqual(204, resp.status)
106 self.assertEqual('', body)
107
108 def test_language_packs_delete_not_found(self):
109 self.assertRaises(tempest_exceptions.NotFound,
110 self.client.delete, 'v1/language_packs/not_found')
111
112 def test_language_packs_delete_used_by_plan(self):
113 uuid, sample_lp = self._create_language_pack()
114
115 artifacts = sample_plan['artifacts']
116 artifacts[0]['language_pack'] = sample_lp['name']
117 sample_plan['artifacts'] = artifacts
118 resp = self.client.create_plan(data=sample_plan)
119
120 self.assertRaises(tempest_exceptions.Conflict,
121 self.client.delete, 'v1/language_packs/%s' % uuid)
122 self.client.delete_plan(resp.uuid)
123 # Sleep for a few seconds to make sure plans are deleted.
124 time.sleep(5)
125 self._delete_language_pack(uuid)
126
127 def test_language_packs_delete_used_by_app(self):
128 uuid, sample_lp = self._create_language_pack()
129
130 sample_app = apputils.get_sample_data()
131
132 sample_app["languagepack"] = sample_lp["name"]
133
134 resp = self.client.create_app(data=sample_app)
135
136 self.assertRaises(tempest_exceptions.Conflict,
137 self.client.delete, 'v1/language_packs/%s' % uuid)
138 bdy = json.loads(resp.body)
139
140 self.client.delete_app(bdy["id"])
141 # Sleep for a few seconds to make sure plans are deleted.
142 time.sleep(5)
143 self._delete_language_pack(uuid)
diff --git a/solum_tempest_plugin/v1/test_operation.py b/solum_tempest_plugin/v1/test_operation.py
new file mode 100644
index 0000000..b1836e0
--- /dev/null
+++ b/solum_tempest_plugin/v1/test_operation.py
@@ -0,0 +1,27 @@
1#
2# Copyright 2013 - Noorul Islam K M
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import json
17
18from solum_tempest_plugin import base
19
20
21class TestOperationController(base.TestCase):
22
23 def test_operations_get_all(self):
24 resp, body = self.client.get('v1/operations')
25 data = json.loads(body)
26 self.assertEqual(200, resp.status)
27 self.assertEqual([], data)
diff --git a/solum_tempest_plugin/v1/test_plan.py b/solum_tempest_plugin/v1/test_plan.py
new file mode 100644
index 0000000..30228e8
--- /dev/null
+++ b/solum_tempest_plugin/v1/test_plan.py
@@ -0,0 +1,232 @@
1#
2# Copyright 2013 - Rackspace US, Inc
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16from tempest.lib import exceptions as tempest_exceptions
17import yaml
18
19from solum_tempest_plugin import base
20
21sample_data = {"version": "1",
22 "name": "test_plan",
23 "description": "A test to create plan",
24 "artifacts": [{
25 "name": "No deus",
26 "artifact_type": "heroku",
27 "content": {
28 "href": "https://example.com/git/a.git",
29 "private": False,
30 },
31 "language_pack": "auto",
32 "ports": 123
33 }]}
34
35bad_data = {"version": "1",
36 "name": "test_plan",
37 "description": "A test to create plan",
38 "artifacts": [{
39 "name": "No deus",
40 "artifact_type": "heroku",
41 "content": {
42 "href": "https://example.com/git/a.git",
43 "private": False,
44 },
45 "language_pack": "auto",
46 "ports": -1
47 }]}
48
49sample_data_private = {"version": "1",
50 "name": "test_plan",
51 "description": "A test to create plan",
52 "artifacts": [{
53 "name": "No deus",
54 "artifact_type": "heroku",
55 "content": {
56 "href": "https://example.com/git/a.git",
57 "private": True,
58 },
59 "language_pack": "auto",
60 }]}
61
62
63class TestPlanController(base.TestCase):
64 def setUp(self):
65 super(TestPlanController, self).setUp()
66
67 def tearDown(self):
68 super(TestPlanController, self).tearDown()
69 self.client.delete_created_plans()
70
71 def _delete_all(self):
72 resp, body = self.client.get(
73 'v1/plans', headers={'accept-type': 'application/x-yaml'})
74 data = yaml.safe_load(body)
75 self.assertEqual(200, resp.status)
76 [self._delete_plan(pl['uuid']) for pl in data]
77
78 def _assert_output_expected(self, body_data, data):
79 self.assertEqual(body_data['description'], data['description'])
80 self.assertEqual(body_data['name'], data['name'])
81 if body_data['artifacts']:
82 self.assertEqual(body_data['artifacts'][0]['content']['href'],
83 data['artifacts'][0]['content']['href'])
84 self.assertIsNotNone(body_data['uuid'])
85
86 def test_plans_get_all(self):
87 create_resp = self.client.create_plan()
88 self.assertEqual(201, create_resp.status)
89 resp, body = self.client.get(
90 'v1/plans', headers={'content-type': 'application/x-yaml'})
91 data = yaml.safe_load(body)
92 self.assertEqual(200, resp.status)
93 uuid = create_resp.uuid
94 filtered = [pl for pl in data if pl['uuid'] == uuid]
95 self.assertEqual(uuid, filtered[0]['uuid'])
96
97 def test_plans_create(self):
98 resp = self.client.create_plan(data=sample_data)
99 self.assertEqual(201, resp.status)
100 self._assert_output_expected(resp.data, sample_data)
101
102 def test_plans_create_bad_port_data(self):
103 try:
104 self.client.create_plan(data=bad_data)
105 except tempest_exceptions.BadRequest:
106 self.assertTrue(True)
107
108 def test_plans_create_with_private_github_repo(self):
109 resp = self.client.create_plan(data=sample_data_private)
110 self.assertEqual(201, resp.status)
111 self._assert_output_expected(resp.data, sample_data)
112
113 def test_plans_create_empty_yaml(self):
114 self.assertRaises(tempest_exceptions.BadRequest,
115 self.client.post, 'v1/plans', '{}',
116 headers={'content-type': 'application/x-yaml'})
117
118 def test_plans_create_invalid_yaml_type(self):
119 self.assertRaises(tempest_exceptions.BadRequest,
120 self.client.post, 'v1/plans', 'invalid type',
121 headers={'content-type': 'application/x-yaml'})
122
123 def test_plans_create_invalid_yaml_syntax(self):
124 self.assertRaises(tempest_exceptions.BadRequest,
125 self.client.post, 'v1/plans', "}invalid: y'm'l3!",
126 headers={'content-type': 'application/x-yaml'})
127
128 def test_plans_get(self):
129 create_resp = self.client.create_plan(data=sample_data)
130 self.assertEqual(201, create_resp.status)
131 uuid = create_resp.uuid
132
133 resp, body = self.client.get(
134 'v1/plans/%s' % uuid,
135 headers={'content-type': 'application/x-yaml'})
136 self.assertEqual(200, resp.status, )
137 yaml_data = yaml.safe_load(body)
138 self._assert_output_expected(yaml_data, sample_data)
139
140 def test_plans_get_with_private_github_repo(self):
141 create_resp = self.client.create_plan(data=sample_data_private)
142 self.assertEqual(201, create_resp.status)
143 uuid = create_resp.uuid
144
145 resp, body = self.client.get(
146 'v1/plans/%s' % uuid,
147 headers={'content-type': 'application/x-yaml'})
148 self.assertEqual(200, resp.status)
149 yaml_data = yaml.safe_load(body)
150 public_key = yaml_data['artifacts'][0]['content']['public_key']
151 self.assertIsNotNone(public_key)
152 self._assert_output_expected(yaml_data, sample_data)
153
154 def test_plans_get_not_found(self):
155 self.assertRaises(tempest_exceptions.NotFound,
156 self.client.get, 'v1/plans/not_found',
157 headers={'content-type': 'application/x-yaml'})
158
159 def test_plans_put(self):
160 create_resp = self.client.create_plan()
161 self.assertEqual(201, create_resp.status)
162 uuid = create_resp.uuid
163 updated_data = {"version": "1",
164 "name": "test_plan_updated",
165 "description": "A test to create plan updated",
166 "type": "plan",
167 "artifacts": []}
168 updated_yaml = yaml.dump(updated_data)
169 resp, body = self.client.put(
170 'v1/plans/%s' % uuid, updated_yaml,
171 headers={'content-type': 'application/x-yaml'})
172 self.assertEqual(200, resp.status)
173 yaml_data = yaml.safe_load(body)
174 self._assert_output_expected(yaml_data, updated_data)
175
176 def test_plans_put_not_found(self):
177 updated_data = {"name": "test_plan updated",
178 "description": "A test to create plan updated",
179 "type": "plan",
180 "artifacts": []}
181 updated_yaml = yaml.dump(updated_data)
182 self.assertRaises(tempest_exceptions.NotFound,
183 self.client.put, 'v1/plans/not_found', updated_yaml,
184 headers={'content-type': 'application/x-yaml'})
185
186 def test_plans_put_empty_yaml(self):
187 create_resp = self.client.create_plan()
188 self.assertEqual(201, create_resp.status)
189
190 # get the URI of the newly created plan
191 uri = (create_resp.data['uri']
192 [len(self.client.base_url) + 1:])
193
194 self.assertRaises(tempest_exceptions.BadRequest,
195 self.client.put, uri, '{}',
196 headers={'content-type': 'application/x-yaml'})
197
198 def test_plans_put_invalid_yaml_type(self):
199 create_resp = self.client.create_plan()
200 self.assertEqual(201, create_resp.status)
201
202 # get the URI of the newly created plan
203 uri = (create_resp.data['uri']
204 [len(self.client.base_url) + 1:])
205
206 self.assertRaises(tempest_exceptions.BadRequest,
207 self.client.put, uri, 'invalid type',
208 headers={'content-type': 'application/x-yaml'})
209
210 def test_plans_put_invalid_yaml_syntax(self):
211 create_resp = self.client.create_plan()
212 self.assertEqual(201, create_resp.status)
213
214 # get the URI of the newly created plan
215 uri = (create_resp.data['uri']
216 [len(self.client.base_url) + 1:])
217
218 self.assertRaises(tempest_exceptions.BadRequest,
219 self.client.put, uri, "}invalid: y'm'l3!",
220 headers={'content-type': 'application/x-yaml'})
221
222 def test_plans_delete(self):
223 create_resp = self.client.create_plan()
224 self.assertEqual(201, create_resp.status)
225 uuid = create_resp.uuid
226 resp, body = self.client.delete_plan(uuid)
227 self.assertEqual(202, resp.status)
228 self.assertEqual('', body)
229
230 def test_plans_delete_not_found(self):
231 self.assertRaises(tempest_exceptions.NotFound,
232 self.client.delete, 'v1/plans/not_found')
diff --git a/solum_tempest_plugin/v1/test_root.py b/solum_tempest_plugin/v1/test_root.py
new file mode 100644
index 0000000..43550b9
--- /dev/null
+++ b/solum_tempest_plugin/v1/test_root.py
@@ -0,0 +1,77 @@
1#
2# Copyright 2013 - Noorul Islam K M
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import json
17
18from solum import version
19from solum_tempest_plugin import base
20
21
22class TestRootController(base.TestCase):
23
24 def test_index(self):
25 resp, body = self.client.request_without_auth('', 'GET')
26 self.assertEqual(200, resp.status)
27 data = json.loads(body)
28 self.assertEqual(data[0]['id'], 'v1.0')
29 self.assertEqual(data[0]['status'], 'CURRENT')
30 self.assertEqual(data[0]['link'],
31 {'href': '%s/v1' % self.client.base_url,
32 'target_name': 'v1'})
33
34 def test_platform(self):
35 resp, body = self.client.request_without_auth('v1', 'GET')
36 self.assertEqual(200, resp.status)
37 data = json.loads(body)
38 self.assertEqual(data['uri'], '%s/v1' % self.client.base_url)
39 self.assertEqual(data['type'], 'platform')
40 self.assertEqual(data['name'], 'solum')
41 self.assertEqual(data['description'], 'solum native implementation')
42 self.assertEqual(data['implementation_version'],
43 version.version_string())
44 self.assertEqual(data['plans_uri'],
45 '%s/v1/plans' % self.client.base_url)
46 self.assertEqual(data['assemblies_uri'],
47 '%s/v1/assemblies' % self.client.base_url)
48 self.assertEqual(data['services_uri'],
49 '%s/v1/services' % self.client.base_url)
50 self.assertEqual(data['components_uri'],
51 '%s/v1/components' % self.client.base_url)
52 self.assertEqual(data['extensions_uri'],
53 '%s/v1/extensions' % self.client.base_url)
54 self.assertEqual(data['operations_uri'],
55 '%s/v1/operations' % self.client.base_url)
56 self.assertEqual(data['sensors_uri'],
57 '%s/v1/sensors' % self.client.base_url)
58 self.assertEqual(data['language_packs_uri'],
59 '%s/v1/language_packs' % self.client.base_url)
60 self.assertEqual(data['pipelines_uri'],
61 '%s/v1/pipelines' % self.client.base_url)
62 self.assertEqual(data['triggers_uri'],
63 '%s/v1/triggers' % self.client.base_url)
64 self.assertEqual(data['infrastructure_uri'],
65 '%s/v1/infrastructure' % self.client.base_url)
66
67 def test_request_without_auth(self):
68 resp, body = self.client.request_without_auth('v1', 'GET')
69 self.assertEqual(200, resp.status)
70 resp, body = self.client.get('v1')
71 self.assertEqual(200, resp.status)
72 resp, body = self.client.request_without_auth(
73 'v1/plans', 'GET', headers={'content-type': 'application/x-yaml'})
74 self.assertEqual(401, resp.status)
75 resp, body = self.client.get(
76 'v1/plans', headers={'content-type': 'application/x-yaml'})
77 self.assertEqual(200, resp.status)
diff --git a/solum_tempest_plugin/tests/base.py b/solum_tempest_plugin/v1/test_sensor.py
index 1c30cdb..6e5f23d 100644
--- a/solum_tempest_plugin/tests/base.py
+++ b/solum_tempest_plugin/v1/test_sensor.py
@@ -1,7 +1,5 @@
1# -*- coding: utf-8 -*- 1#
2 2# Copyright 2013 - Noorul Islam K M
3# Copyright 2010-2011 OpenStack Foundation
4# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
5# 3#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may 4# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain 5# not use this file except in compliance with the License. You may obtain
@@ -15,9 +13,15 @@
15# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
16# under the License. 14# under the License.
17 15
18from oslotest import base 16import json
17
18from solum_tempest_plugin import base
19 19
20 20
21class TestCase(base.BaseTestCase): 21class TestSensorController(base.TestCase):
22 22
23 """Test case base class for all unit tests.""" 23 def test_sensors_get_all(self):
24 resp, body = self.client.get('v1/sensors')
25 data = json.loads(body)
26 self.assertEqual(200, resp.status)
27 self.assertEqual([], data)
diff --git a/solum_tempest_plugin/v1/test_service.py b/solum_tempest_plugin/v1/test_service.py
new file mode 100644
index 0000000..2acf669
--- /dev/null
+++ b/solum_tempest_plugin/v1/test_service.py
@@ -0,0 +1,132 @@
1#
2# Copyright 2013 - Noorul Islam K M
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16import json
17
18from tempest.lib import exceptions as tempest_exceptions
19
20from solum_tempest_plugin import base
21
22sample_data = {"name": "test_service",
23 "description": "A test to create service",
24 "project_id": "project_id",
25 "user_id": "user_id",
26 "service_type": "mysql",
27 "read_only": True,
28 "type": "service"}
29
30
31class TestServiceController(base.TestCase):
32 def setUp(self):
33 super(TestServiceController, self).setUp()
34 self.addCleanup(self._delete_all)
35
36 def _delete_all(self):
37 resp, body = self.client.get('v1/services')
38 data = json.loads(body)
39 self.assertEqual(resp.status, 200)
40 [self._delete_service(ser['uuid']) for ser in data]
41
42 def _assert_output_expected(self, body_data, data):
43 self.assertEqual(body_data['description'], data['description'])
44 self.assertEqual(body_data['name'], data['name'])
45 self.assertEqual(body_data['service_type'], data['service_type'])
46 self.assertEqual(body_data['read_only'], data['read_only'])
47 self.assertEqual(body_data['type'], 'service')
48 self.assertIsNotNone(body_data['uuid'])
49
50 def _delete_service(self, uuid):
51 resp, _ = self.client.delete('v1/services/%s' % uuid)
52 self.assertEqual(resp.status, 204)
53
54 def _create_service(self):
55 jsondata = json.dumps(sample_data)
56 resp, body = self.client.post('v1/services', jsondata)
57 self.assertEqual(resp.status, 201)
58 out_data = json.loads(body)
59 uuid = out_data['uuid']
60 self.assertIsNotNone(uuid)
61 return uuid
62
63 def test_services_get_all(self):
64 uuid = self._create_service()
65 resp, body = self.client.get('v1/services')
66 data = json.loads(body)
67 self.assertEqual(resp.status, 200)
68 filtered = [ser for ser in data if ser['uuid'] == uuid]
69 self.assertEqual(filtered[0]['uuid'], uuid)
70
71 def test_services_create(self):
72 sample_json = json.dumps(sample_data)
73 resp, body = self.client.post('v1/services', sample_json)
74 self.assertEqual(resp.status, 201)
75 json_data = json.loads(body)
76 self._assert_output_expected(json_data, sample_data)
77 self._delete_service(json_data['uuid'])
78
79 def test_services_create_none(self):
80 self.assertRaises(tempest_exceptions.BadRequest,
81 self.client.post, 'v1/services', "{}")
82
83 def test_services_get(self):
84 uuid = self._create_service()
85 resp, body = self.client.get('v1/services/%s' % uuid)
86 self.assertEqual(resp.status, 200)
87 json_data = json.loads(body)
88 self._assert_output_expected(json_data, sample_data)
89 self._delete_service(uuid)
90
91 def test_services_get_not_found(self):
92 self.assertRaises(tempest_exceptions.NotFound,
93 self.client.get, 'v1/services/not_found')
94
95 def test_services_put(self):
96 uuid = self._create_service()
97 updated_data = {"name": "test_service_updated",
98 "description": "A test to create service updated",
99 "user_id": "user_id updated",
100 "service_type": "mysql updated",
101 "read_only": False}
102 updated_json = json.dumps(updated_data)
103 resp, body = self.client.put('v1/services/%s' % uuid, updated_json)
104 self.assertEqual(resp.status, 200)
105 json_data = json.loads(body)
106 self._assert_output_expected(json_data, updated_data)
107 self._delete_service(uuid)
108
109 def test_services_put_not_found(self):
110 updated_data = {"name": "test_service_updated",
111 "description": "A test to create service updated",
112 "user_id": "user_id updated",
113 "service_type": "mysql updated",
114 "read_only": False}
115 updated_json = json.dumps(updated_data)
116 self.assertRaises(tempest_exceptions.NotFound,
117 self.client.put, 'v1/services/not_found',
118 updated_json)
119
120 def test_services_put_none(self):
121 self.assertRaises(tempest_exceptions.BadRequest,
122 self.client.put, 'v1/services/any', "{}")
123
124 def test_services_delete(self):
125 uuid = self._create_service()
126 resp, body = self.client.delete('v1/services/%s' % uuid)
127 self.assertEqual(resp.status, 204)
128 self.assertEqual(body, '')
129
130 def test_services_delete_not_found(self):
131 self.assertRaises(tempest_exceptions.NotFound,
132 self.client.delete, 'v1/services/not_found')