Merge "Put, post operations implemented for environments"
This commit is contained in:
commit
2903aa30a2
|
@ -11,6 +11,7 @@
|
|||
# under the License.
|
||||
|
||||
LOG_LEVEL = 'DEBUG'
|
||||
PROPAGATE_EXCEPTIONS = True
|
||||
|
||||
SQLALCHEMY_DATABASE_URI = \
|
||||
'postgresql://tuningbox:tuningbox@localhost/tuningbox'
|
||||
|
|
|
@ -15,24 +15,33 @@ import itertools
|
|||
|
||||
import flask
|
||||
import flask_restful
|
||||
from flask_restful import fields
|
||||
from sqlalchemy import exc as sa_exc
|
||||
from werkzeug import exceptions
|
||||
|
||||
from tuning_box import converters
|
||||
from tuning_box import db
|
||||
from tuning_box import errors
|
||||
from tuning_box.library import components
|
||||
from tuning_box.library import environments
|
||||
from tuning_box import logger
|
||||
from tuning_box.middleware import keystone
|
||||
|
||||
# These handlers work if PROPAGATE_EXCEPTIONS is off (non-Nailgun case)
|
||||
api_errors = {
|
||||
'IntegrityError': {'status': 409}, # sqlalchemy IntegrityError
|
||||
'TuningboxIntegrityError': {'status': 409},
|
||||
'TuningboxNotFound': {'status': 404}
|
||||
}
|
||||
api = flask_restful.Api(errors=api_errors)
|
||||
|
||||
api.add_resource(components.ComponentsCollection, '/components')
|
||||
api.add_resource(components.Component, '/components/<int:component_id>')
|
||||
api.add_resource(environments.EnvironmentsCollection, '/environments')
|
||||
api.add_resource(
|
||||
environments.Environment,
|
||||
'/environments/<int:environment_id>', # Backward compatibility support
|
||||
'/environment/<int:environment_id>'
|
||||
)
|
||||
|
||||
|
||||
def with_transaction(f):
|
||||
|
@ -44,55 +53,6 @@ def with_transaction(f):
|
|||
return inner
|
||||
|
||||
|
||||
environment_fields = {
|
||||
'id': fields.Integer,
|
||||
'components': fields.List(fields.Integer(attribute='id')),
|
||||
'hierarchy_levels': fields.List(fields.String(attribute='name')),
|
||||
}
|
||||
|
||||
|
||||
@api.resource('/environments')
|
||||
class EnvironmentsCollection(flask_restful.Resource):
|
||||
method_decorators = [flask_restful.marshal_with(environment_fields)]
|
||||
|
||||
def get(self):
|
||||
return db.Environment.query.all()
|
||||
|
||||
@with_transaction
|
||||
def post(self):
|
||||
component_ids = flask.request.json['components']
|
||||
# TODO(yorik-sar): verify that resource names do not clash
|
||||
components = [db.Component.query.get_by_id_or_name(i)
|
||||
for i in component_ids]
|
||||
|
||||
hierarchy_levels = []
|
||||
level = None
|
||||
for name in flask.request.json['hierarchy_levels']:
|
||||
level = db.EnvironmentHierarchyLevel(name=name, parent=level)
|
||||
hierarchy_levels.append(level)
|
||||
|
||||
environment = db.Environment(components=components,
|
||||
hierarchy_levels=hierarchy_levels)
|
||||
if 'id' in flask.request.json:
|
||||
environment.id = flask.request.json['id']
|
||||
db.db.session.add(environment)
|
||||
return environment, 201
|
||||
|
||||
|
||||
@api.resource('/environments/<int:environment_id>')
|
||||
class Environment(flask_restful.Resource):
|
||||
method_decorators = [flask_restful.marshal_with(environment_fields)]
|
||||
|
||||
def get(self, environment_id):
|
||||
return db.Environment.query.get_or_404(environment_id)
|
||||
|
||||
@with_transaction
|
||||
def delete(self, environment_id):
|
||||
environment = db.Environment.query.get_or_404(environment_id)
|
||||
db.db.session.delete(environment)
|
||||
return None, 204
|
||||
|
||||
|
||||
def iter_environment_level_values(environment, levels):
|
||||
env_levels = db.EnvironmentHierarchyLevel.get_for_environment(environment)
|
||||
level_pairs = zip(env_levels, levels)
|
||||
|
@ -250,6 +210,12 @@ def handle_integrity_error(exc):
|
|||
return response
|
||||
|
||||
|
||||
def handle_object_not_found(exc):
|
||||
response = flask.jsonify(msg=exc.args[0])
|
||||
response.status_code = 404
|
||||
return response
|
||||
|
||||
|
||||
def build_app(configure_logging=True, with_keystone=True):
|
||||
app = flask.Flask(__name__)
|
||||
app.url_map.converters.update(converters.ALL)
|
||||
|
@ -259,6 +225,10 @@ def build_app(configure_logging=True, with_keystone=True):
|
|||
app.config.from_envvar('TUNINGBOX_SETTINGS', silent=True)
|
||||
# These handlers work if PROPAGATE_EXCEPTIONS is on (Nailgun case)
|
||||
app.register_error_handler(sa_exc.IntegrityError, handle_integrity_error)
|
||||
app.register_error_handler(errors.TuningboxIntegrityError,
|
||||
handle_integrity_error)
|
||||
app.register_error_handler(errors.TuningboxNotFound,
|
||||
handle_object_not_found)
|
||||
db.db.init_app(app)
|
||||
if configure_logging:
|
||||
log_level = app.config.get('LOG_LEVEL', 'INFO')
|
||||
|
|
|
@ -47,12 +47,12 @@ def fk(cls, **kwargs):
|
|||
|
||||
|
||||
class BaseQuery(flask_sqlalchemy.BaseQuery):
|
||||
def get_by_id_or_name(self, id_or_name):
|
||||
def get_by_id_or_name(self, id_or_name, fail_on_none=True):
|
||||
if isinstance(id_or_name, int):
|
||||
result = self.get(id_or_name)
|
||||
else:
|
||||
result = self.filter_by(name=id_or_name).one_or_none()
|
||||
if result is None:
|
||||
if fail_on_none and result is None:
|
||||
flask.abort(404)
|
||||
return result
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class BaseTuningboxError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TuningboxIntegrityError(BaseTuningboxError):
|
||||
pass
|
||||
|
||||
|
||||
class TuningboxNotFound(BaseTuningboxError):
|
||||
pass
|
|
@ -0,0 +1,44 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tuning_box import errors
|
||||
|
||||
|
||||
def load_objects(model, ids):
|
||||
if ids is None:
|
||||
return None
|
||||
result = []
|
||||
for obj_id in ids:
|
||||
obj = model.query.filter_by(id=obj_id).one_or_none()
|
||||
if obj is None:
|
||||
raise errors.TuningboxNotFound(
|
||||
"{0} not found by identifier: "
|
||||
"{1}".format(model.__tablename__, obj_id)
|
||||
)
|
||||
result.append(obj)
|
||||
return result
|
||||
|
||||
|
||||
def load_objects_by_id_or_name(model, identifiers):
|
||||
if identifiers is None:
|
||||
return None
|
||||
result = []
|
||||
for identifier in identifiers:
|
||||
obj = model.query.get_by_id_or_name(
|
||||
identifier, fail_on_none=False)
|
||||
if obj is None:
|
||||
raise errors.TuningboxNotFound(
|
||||
"{0} not found by identifier: "
|
||||
"{1}".format(model.__tablename__, identifier)
|
||||
)
|
||||
result.append(obj)
|
||||
return result
|
|
@ -16,7 +16,7 @@ import flask_restful
|
|||
from flask_restful import fields
|
||||
|
||||
from tuning_box import db
|
||||
|
||||
from tuning_box import library
|
||||
|
||||
resource_definition_fields = {
|
||||
'id': fields.Integer,
|
||||
|
@ -64,14 +64,8 @@ class Component(flask_restful.Resource):
|
|||
component.name = update_by.get('name', component.name)
|
||||
resource_definitions = update_by.get('resource_definitions')
|
||||
if resource_definitions is not None:
|
||||
resources = []
|
||||
for resource_data in resource_definitions:
|
||||
resource = db.ResourceDefinition.query.filter_by(
|
||||
id=resource_data.get('id')
|
||||
).one()
|
||||
resource.component_id = component.id
|
||||
db.db.session.add(resource)
|
||||
resources.append(resource)
|
||||
ids = [data['id'] for data in resource_definitions]
|
||||
resources = library.load_objects(db.ResourceDefinition, ids)
|
||||
component.resource_definitions = resources
|
||||
|
||||
def put(self, component_id):
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import flask
|
||||
import flask_restful
|
||||
from flask_restful import fields
|
||||
|
||||
from tuning_box import db
|
||||
from tuning_box import errors
|
||||
from tuning_box import library
|
||||
|
||||
environment_fields = {
|
||||
'id': fields.Integer,
|
||||
'components': fields.List(fields.Integer(attribute='id')),
|
||||
'hierarchy_levels': fields.List(fields.String(attribute='name')),
|
||||
}
|
||||
|
||||
|
||||
class EnvironmentsCollection(flask_restful.Resource):
|
||||
method_decorators = [flask_restful.marshal_with(environment_fields)]
|
||||
|
||||
def get(self):
|
||||
return db.Environment.query.all()
|
||||
|
||||
def _check_components(self, components):
|
||||
identities = set()
|
||||
duplicates = set()
|
||||
id_names = ('id', 'name')
|
||||
for component in components:
|
||||
for id_name in id_names:
|
||||
value = getattr(component, id_name)
|
||||
|
||||
if value not in identities:
|
||||
identities.add(value)
|
||||
else:
|
||||
duplicates.add(value)
|
||||
if duplicates:
|
||||
raise errors.TuningboxIntegrityError(
|
||||
"Components duplicates: {0}".format(duplicates))
|
||||
|
||||
@db.with_transaction
|
||||
def post(self):
|
||||
component_ids = flask.request.json['components']
|
||||
components = [db.Component.query.get_by_id_or_name(i)
|
||||
for i in component_ids]
|
||||
self._check_components(components)
|
||||
|
||||
hierarchy_levels = []
|
||||
level = None
|
||||
for name in flask.request.json['hierarchy_levels']:
|
||||
level = db.EnvironmentHierarchyLevel(name=name, parent=level)
|
||||
hierarchy_levels.append(level)
|
||||
|
||||
environment = db.Environment(components=components,
|
||||
hierarchy_levels=hierarchy_levels)
|
||||
if 'id' in flask.request.json:
|
||||
environment.id = flask.request.json['id']
|
||||
db.db.session.add(environment)
|
||||
return environment, 201
|
||||
|
||||
|
||||
class Environment(flask_restful.Resource):
|
||||
method_decorators = [flask_restful.marshal_with(environment_fields)]
|
||||
|
||||
def get(self, environment_id):
|
||||
return db.Environment.query.get_or_404(environment_id)
|
||||
|
||||
def _update_components(self, environment, components):
|
||||
if components is not None:
|
||||
new_components = library.load_objects_by_id_or_name(
|
||||
db.Component, components)
|
||||
environment.components = new_components
|
||||
|
||||
def _update_hierarchy_levels(self, environment, hierarchy_levels):
|
||||
if hierarchy_levels is not None:
|
||||
new_hierarchy_levels = library.load_objects_by_id_or_name(
|
||||
db.EnvironmentHierarchyLevel, hierarchy_levels)
|
||||
parent = None
|
||||
for level in new_hierarchy_levels:
|
||||
level.parent = parent
|
||||
parent = level
|
||||
environment.hierarchy_levels = new_hierarchy_levels
|
||||
|
||||
@db.with_transaction
|
||||
def _perform_update(self, environment_id):
|
||||
environment = db.Environment.query.get_or_404(environment_id)
|
||||
update_by = flask.request.json
|
||||
|
||||
components = update_by.get('components')
|
||||
self._update_components(environment, components)
|
||||
|
||||
hierarchy_levels = update_by.get('hierarchy_levels')
|
||||
self._update_hierarchy_levels(environment, hierarchy_levels)
|
||||
|
||||
def put(self, environment_id):
|
||||
return self.patch(environment_id)
|
||||
|
||||
def patch(self, env_id):
|
||||
self._perform_update(env_id)
|
||||
return None, 204
|
||||
|
||||
@db.with_transaction
|
||||
def delete(self, environment_id):
|
||||
environment = db.Environment.query.get_or_404(environment_id)
|
||||
db.db.session.delete(environment)
|
||||
return None, 204
|
|
@ -10,6 +10,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from tuning_box import db
|
||||
from tuning_box.library import components
|
||||
|
@ -156,6 +157,21 @@ class TestComponents(BaseTest):
|
|||
self.assertItemsEqual(initial_data['resource_definitions'],
|
||||
actual_component['resource_definitions'])
|
||||
|
||||
def test_put_component_resource_not_found(self):
|
||||
self._fixture()
|
||||
component_url = '/components/7'
|
||||
initial_data = self._component_json
|
||||
|
||||
resource_definition = copy.deepcopy(
|
||||
initial_data['resource_definitions'][0])
|
||||
resource_definition['id'] = None
|
||||
|
||||
res = self.client.put(
|
||||
component_url,
|
||||
data={'resource_definitions': [resource_definition]}
|
||||
)
|
||||
self.assertEqual(404, res.status_code)
|
||||
|
||||
def test_put_component_ignore_changing_id(self):
|
||||
self._fixture()
|
||||
component_url = '/components/7'
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tuning_box import db
|
||||
from tuning_box import library
|
||||
from tuning_box.library import environments
|
||||
from tuning_box.tests.test_app import BaseTest
|
||||
|
||||
|
||||
class TestEnvironments(BaseTest):
|
||||
|
||||
def test_get_environments_empty(self):
|
||||
res = self.client.get('/environments')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(res.json, [])
|
||||
|
||||
def test_get_environments(self):
|
||||
self._fixture()
|
||||
res = self.client.get('/environments')
|
||||
self.assertEqual(200, res.status_code)
|
||||
self.assertEqual(1, len(res.json))
|
||||
self.assertItemsEqual(
|
||||
{'id': 9, 'components': [7], 'hierarchy_levels': ['lvl1', 'lvl2']},
|
||||
res.json[0]
|
||||
)
|
||||
|
||||
def test_get_one_environment(self):
|
||||
self._fixture()
|
||||
res = self.client.get('/environments/9')
|
||||
self.assertEqual(200, res.status_code)
|
||||
self.assertItemsEqual(
|
||||
{'id': 9, 'components': [7], 'hierarchy_levels': ['lvl1', 'lvl2']},
|
||||
res.json
|
||||
)
|
||||
|
||||
def test_get_one_environment_404(self):
|
||||
res = self.client.get('/environments/9')
|
||||
self.assertEqual(res.status_code, 404)
|
||||
|
||||
def test_post_environment(self):
|
||||
self._fixture()
|
||||
json = {'components': [7], 'hierarchy_levels': ['lvla', 'lvlb']}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 201)
|
||||
json['id'] = res.json['id']
|
||||
self.assertItemsEqual(json, res.json)
|
||||
self._assert_db_effect(
|
||||
db.Environment, res.json['id'],
|
||||
environments.environment_fields, json)
|
||||
|
||||
def test_post_environment_preserve_id(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'id': 42,
|
||||
'components': [7],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(201, res.status_code)
|
||||
self.assertItemsEqual(json, res.json)
|
||||
self._assert_db_effect(
|
||||
db.Environment, 42, environments.environment_fields, json)
|
||||
|
||||
def test_post_environment_preserve_id_conflict(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'id': 9,
|
||||
'components': [7],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 409)
|
||||
|
||||
def test_post_environment_preserve_id_conflict_propagate_exc(self):
|
||||
self.app.config["PROPAGATE_EXCEPTIONS"] = True
|
||||
self._fixture()
|
||||
json = {
|
||||
'id': 9,
|
||||
'components': [7],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 409)
|
||||
|
||||
def test_post_environment_by_component_name(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'components': ['component1'],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 201)
|
||||
json['id'] = res.json['id']
|
||||
json['components'] = [7]
|
||||
self.assertItemsEqual(json, res.json)
|
||||
self._assert_db_effect(
|
||||
db.Environment, res.json['id'],
|
||||
environments.environment_fields, json)
|
||||
|
||||
def test_post_components_duplication(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'components': ['component1', 7],
|
||||
'hierarchy_levels': ['lvl'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(409, res.status_code)
|
||||
|
||||
def test_post_components_no_duplication(self):
|
||||
self._fixture()
|
||||
components_url = '/components'
|
||||
res = self.client.get(components_url)
|
||||
self.assertEqual(200, res.status_code)
|
||||
component = res.json[0]
|
||||
|
||||
# Creating component with name equal to id of existed component
|
||||
res = self.client.post(
|
||||
components_url,
|
||||
data={
|
||||
'name': component['id'],
|
||||
'resource_definitions': []
|
||||
}
|
||||
)
|
||||
self.assertEqual(201, res.status_code)
|
||||
new_component = res.json
|
||||
|
||||
# Checking no components duplication detected
|
||||
json = {
|
||||
'components': [component['id'], new_component['name']],
|
||||
'hierarchy_levels': ['lvl'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(201, res.status_code)
|
||||
|
||||
def test_post_environment_404(self):
|
||||
self._fixture()
|
||||
json = {'components': [8], 'hierarchy_levels': ['lvla', 'lvlb']}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 404)
|
||||
self._assert_not_in_db(db.Environment, 10)
|
||||
|
||||
def test_post_environment_by_component_name_404(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'components': ['component2'],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 404)
|
||||
self._assert_not_in_db(db.Environment, 10)
|
||||
|
||||
def test_delete_environment(self):
|
||||
self._fixture()
|
||||
res = self.client.delete('/environments/9')
|
||||
self.assertEqual(res.status_code, 204)
|
||||
self.assertEqual(res.data, b'')
|
||||
self._assert_not_in_db(db.Environment, 9)
|
||||
|
||||
def test_delete_environment_404(self):
|
||||
res = self.client.delete('/environments/9')
|
||||
self.assertEqual(res.status_code, 404)
|
||||
|
||||
def test_put_environment_404(self):
|
||||
res = self.client.put('/environments/7')
|
||||
self.assertEqual(res.status_code, 404)
|
||||
|
||||
def test_put_environment_components(self):
|
||||
self._fixture()
|
||||
environment_url = '/environment/9'
|
||||
initial = self.client.get(environment_url).json
|
||||
|
||||
# Updating components
|
||||
res = self.client.put(environment_url,
|
||||
data={'components': []})
|
||||
self.assertEqual(204, res.status_code)
|
||||
actual = self.client.get(environment_url).json
|
||||
self.assertEqual([], actual['components'])
|
||||
|
||||
# Restoring components
|
||||
res = self.client.put(
|
||||
environment_url,
|
||||
data={'components': initial['components']}
|
||||
)
|
||||
self.assertEqual(204, res.status_code)
|
||||
actual = self.client.get(environment_url).json
|
||||
self.assertItemsEqual(initial, actual)
|
||||
|
||||
def test_put_environment_component_not_found(self):
|
||||
self._fixture()
|
||||
environment_url = '/environment/9'
|
||||
res = self.client.put(
|
||||
environment_url,
|
||||
data={'components': [None]}
|
||||
)
|
||||
self.assertEqual(404, res.status_code)
|
||||
|
||||
def check_hierarchy_levels(self, hierarchy_levels_names):
|
||||
with self.app.app_context():
|
||||
hierarchy_levels = library.load_objects_by_id_or_name(
|
||||
db.EnvironmentHierarchyLevel, hierarchy_levels_names)
|
||||
parent_id = None
|
||||
for level in hierarchy_levels:
|
||||
self.assertEqual(parent_id, level.parent_id)
|
||||
parent_id = level.id
|
||||
|
||||
def test_put_environment_hierarchy_levels(self):
|
||||
self._fixture()
|
||||
environment_url = '/environment/9'
|
||||
initial = self.client.get(environment_url).json
|
||||
|
||||
# Updating hierarchy levels
|
||||
res = self.client.put(environment_url,
|
||||
data={'hierarchy_levels': []})
|
||||
self.assertEqual(204, res.status_code)
|
||||
actual = self.client.get(environment_url).json
|
||||
self.assertEqual([], actual['hierarchy_levels'])
|
||||
|
||||
# Restoring levels
|
||||
res = self.client.put(
|
||||
environment_url,
|
||||
data={'hierarchy_levels': initial['hierarchy_levels']}
|
||||
)
|
||||
self.assertEqual(204, res.status_code)
|
||||
actual = self.client.get(environment_url).json
|
||||
self.assertItemsEqual(initial, actual)
|
||||
self.check_hierarchy_levels(actual['hierarchy_levels'])
|
||||
|
||||
def test_put_environment_hierarchy_levels_remove_level(self):
|
||||
self._fixture()
|
||||
environment_url = '/environment/9'
|
||||
initial = self.client.get(environment_url).json
|
||||
expected_levels = initial['hierarchy_levels'][1:]
|
||||
|
||||
# Updating hierarchy levels
|
||||
res = self.client.put(
|
||||
environment_url,
|
||||
data={'hierarchy_levels': expected_levels}
|
||||
)
|
||||
self.assertEqual(204, res.status_code)
|
||||
actual = self.client.get(environment_url).json
|
||||
self.assertEqual(expected_levels, actual['hierarchy_levels'])
|
||||
self.check_hierarchy_levels(actual['hierarchy_levels'])
|
||||
|
||||
def test_put_environment_level_not_found(self):
|
||||
self._fixture()
|
||||
environment_url = '/environment/9'
|
||||
res = self.client.put(
|
||||
environment_url,
|
||||
data={'hierarchy_levels': [None]}
|
||||
)
|
||||
self.assertEqual(404, res.status_code)
|
|
@ -88,120 +88,6 @@ class BaseTest(base.TestCase):
|
|||
|
||||
class TestApp(BaseTest):
|
||||
|
||||
def test_get_environments_empty(self):
|
||||
res = self.client.get('/environments')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(res.json, [])
|
||||
|
||||
def test_get_environments(self):
|
||||
self._fixture()
|
||||
res = self.client.get('/environments')
|
||||
self.assertEqual(200, res.status_code)
|
||||
self.assertEqual(1, len(res.json))
|
||||
self.assertItemsEqual(
|
||||
{'id': 9, 'components': [7], 'hierarchy_levels': ['lvl1', 'lvl2']},
|
||||
res.json[0]
|
||||
)
|
||||
|
||||
def test_get_one_environment(self):
|
||||
self._fixture()
|
||||
res = self.client.get('/environments/9')
|
||||
self.assertEqual(200, res.status_code)
|
||||
self.assertItemsEqual(
|
||||
{'id': 9, 'components': [7], 'hierarchy_levels': ['lvl1', 'lvl2']},
|
||||
res.json
|
||||
)
|
||||
|
||||
def test_get_one_environment_404(self):
|
||||
res = self.client.get('/environments/9')
|
||||
self.assertEqual(res.status_code, 404)
|
||||
|
||||
def test_post_environment(self):
|
||||
self._fixture()
|
||||
json = {'components': [7], 'hierarchy_levels': ['lvla', 'lvlb']}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 201)
|
||||
json['id'] = res.json['id']
|
||||
self.assertItemsEqual(json, res.json)
|
||||
self._assert_db_effect(
|
||||
db.Environment, res.json['id'], app.environment_fields, json)
|
||||
|
||||
def test_post_environment_preserve_id(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'id': 42,
|
||||
'components': [7],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(201, res.status_code)
|
||||
self.assertItemsEqual(json, res.json)
|
||||
self._assert_db_effect(
|
||||
db.Environment, 42, app.environment_fields, json)
|
||||
|
||||
def test_post_environment_preserve_id_conflict(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'id': 9,
|
||||
'components': [7],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 409)
|
||||
|
||||
def test_post_environment_preserve_id_conflict_propagate_exc(self):
|
||||
self.app.config["PROPAGATE_EXCEPTIONS"] = True
|
||||
self._fixture()
|
||||
json = {
|
||||
'id': 9,
|
||||
'components': [7],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 409)
|
||||
|
||||
def test_post_environment_by_component_name(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'components': ['component1'],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 201)
|
||||
json['id'] = res.json['id']
|
||||
json['components'] = [7]
|
||||
self.assertItemsEqual(json, res.json)
|
||||
self._assert_db_effect(
|
||||
db.Environment, res.json['id'], app.environment_fields, json)
|
||||
|
||||
def test_post_environment_404(self):
|
||||
self._fixture()
|
||||
json = {'components': [8], 'hierarchy_levels': ['lvla', 'lvlb']}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 404)
|
||||
self._assert_not_in_db(db.Environment, 10)
|
||||
|
||||
def test_post_environment_by_component_name_404(self):
|
||||
self._fixture()
|
||||
json = {
|
||||
'components': ['component2'],
|
||||
'hierarchy_levels': ['lvla', 'lvlb'],
|
||||
}
|
||||
res = self.client.post('/environments', data=json)
|
||||
self.assertEqual(res.status_code, 404)
|
||||
self._assert_not_in_db(db.Environment, 10)
|
||||
|
||||
def test_delete_environment(self):
|
||||
self._fixture()
|
||||
res = self.client.delete('/environments/9')
|
||||
self.assertEqual(res.status_code, 204)
|
||||
self.assertEqual(res.data, b'')
|
||||
self._assert_not_in_db(db.Environment, 9)
|
||||
|
||||
def test_delete_environment_404(self):
|
||||
res = self.client.delete('/environments/9')
|
||||
self.assertEqual(res.status_code, 404)
|
||||
|
||||
def test_get_environment_level_value_root(self):
|
||||
self._fixture()
|
||||
with self.app.app_context(), db.db.session.begin():
|
||||
|
|
Loading…
Reference in New Issue