Fix creating objects with the same names

* Fixed unit-tests
 * Added new unit-tests
 * default project_id = <default_project>

Closes-bug #1385275

Change-Id: I65e239fe471117f5b11cfb56fec92e90083fe50b
This commit is contained in:
Nikolay Mahotkin 2014-10-24 17:38:22 +04:00
parent 39a6b0c725
commit 5966eee08b
6 changed files with 92 additions and 34 deletions

View File

@ -28,6 +28,7 @@ LOG = logging.getLogger(__name__)
options.set_defaults(cfg.CONF, sqlite_db="mistral.sqlite")
_DB_SESSION_THREAD_LOCAL_NAME = "db_sql_alchemy_session"
DEFAULT_PROJECT_ID = "<default-project>"
_facade = None

View File

@ -17,6 +17,7 @@
import contextlib
import sys
from oslo.config import cfg
from oslo.db import exception as db_exc
import sqlalchemy as sa
@ -27,6 +28,7 @@ from mistral import exceptions as exc
from mistral.openstack.common import log as logging
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
@ -84,6 +86,13 @@ def transaction():
end_tx()
def _get_project_id():
if CONF.pecan.auth_enable and context.has_ctx():
return context.ctx().project_id
else:
return b.DEFAULT_PROJECT_ID
def _delete_all(model, session=None, **kwargs):
query = b.model_query(model).filter_by(**kwargs)
query.delete()
@ -92,7 +101,7 @@ def _delete_all(model, session=None, **kwargs):
def _get_collection_sorted_by_name(model, **kwargs):
query = b.model_query(model)
proj = query.filter_by(project_id=context.ctx().project_id, **kwargs)
proj = query.filter_by(project_id=_get_project_id(), **kwargs)
public = query.filter_by(scope='public', **kwargs)
return proj.union(public).order_by(model.name).all()
@ -172,9 +181,7 @@ def delete_workbook(name, session=None):
def _get_workbook(name):
query = b.model_query(models.Workbook)
project_id = context.ctx().project_id if context.has_ctx() else None
proj = query.filter_by(name=name, project_id=project_id)
proj = query.filter_by(name=name, project_id=_get_project_id())
public = query.filter_by(name=name, scope='public')
return proj.union(public).first()
@ -210,7 +217,7 @@ def create_workflow(values, session=None):
wf = models.Workflow()
wf.update(values.copy())
wf['project_id'] = context.ctx().project_id if context.has_ctx() else None
wf['project_id'] = _get_project_id()
try:
wf.save(session=session)
@ -230,7 +237,7 @@ def update_workflow(name, values, session=None):
"Workflow not found [workflow_name=%s]" % name)
wf.update(values.copy())
wf['project_id'] = context.ctx().project_id if context.has_ctx() else None
wf['project_id'] = _get_project_id()
return wf
@ -264,9 +271,7 @@ def delete_workflows(**kwargs):
def _get_workflow(name):
query = b.model_query(models.Workflow)
project_id = context.ctx().project_id if context.has_ctx() else None
proj = query.filter_by(name=name, project_id=project_id)
proj = query.filter_by(name=name, project_id=_get_project_id())
public = query.filter_by(name=name, scope='public')
return proj.union(public).first()
@ -568,13 +573,10 @@ def delete_actions(**kwargs):
def _get_action(name):
query = b.model_query(models.Action)
return query.filter_by(name=name).first()
proj = query.filter_by(name=name, project_id=_get_project_id())
public = query.filter_by(name=name, scope='public')
def _get_actions(**kwargs):
query = b.model_query(models.Action)
return query.filter_by(**kwargs).all()
return proj.union(public).first()
# Cron triggers.
@ -664,7 +666,10 @@ def delete_cron_triggers(**kwargs):
def _get_cron_trigger(name):
query = b.model_query(models.CronTrigger)
return query.filter_by(name=name).first()
proj = query.filter_by(name=name, project_id=_get_project_id())
public = query.filter_by(name=name, scope='public')
return proj.union(public).first()
def _get_cron_triggers(**kwargs):

View File

@ -18,6 +18,7 @@ import json
import sqlalchemy as sa
from sqlalchemy.orm import relationship
from mistral.db.sqlalchemy import base
from mistral.db.sqlalchemy import model_base as mb
from mistral.db.sqlalchemy import types as st
@ -39,7 +40,7 @@ class Workbook(mb.MistralModelBase):
# Security properties.
scope = sa.Column(sa.String(80))
project_id = sa.Column(sa.String(80))
project_id = sa.Column(sa.String(80), default=base.DEFAULT_PROJECT_ID)
trust_id = sa.Column(sa.String(80))
@ -60,7 +61,7 @@ class Workflow(mb.MistralModelBase):
# Security properties.
scope = sa.Column(sa.String(80))
project_id = sa.Column(sa.String(80))
project_id = sa.Column(sa.String(80), default=base.DEFAULT_PROJECT_ID)
trust_id = sa.Column(sa.String(80))
@ -162,7 +163,7 @@ class Action(mb.MistralModelBase):
# Security properties.
scope = sa.Column(sa.String(80))
project_id = sa.Column(sa.String(80))
project_id = sa.Column(sa.String(80), default=base.DEFAULT_PROJECT_ID)
trust_id = sa.Column(sa.String(80))
@ -188,7 +189,7 @@ class CronTrigger(mb.MistralModelBase):
# Security properties.
scope = sa.Column(sa.String(80))
project_id = sa.Column(sa.String(80))
project_id = sa.Column(sa.String(80), default=base.DEFAULT_PROJECT_ID)
trust_id = sa.Column(sa.String(80))
def to_dict(self):

View File

@ -221,7 +221,7 @@ class DbTestCase(BaseTest):
self.ctx = auth_context.MistralContext(
user_id='1-2-3-4',
project_id='5-6-7-8',
project_id='<default-project>',
user_name='test-user',
project_name='test-project',
is_admin=False

View File

@ -18,6 +18,8 @@
import copy
from oslo.config import cfg
from mistral import context as auth_context
from mistral.db.v2.sqlalchemy import api as db_api
from mistral import exceptions as exc
@ -50,7 +52,16 @@ WORKBOOKS = [
]
class WorkbookTest(test_base.DbTestCase):
class SQLAlchemyTest(test_base.DbTestCase):
def setUp(self):
super(SQLAlchemyTest, self).setUp()
cfg.CONF.set_default('auth_enable', True, group='pecan')
self.addCleanup(cfg.CONF.set_default, 'auth_enable', False,
group='pecan')
class WorkbookTest(SQLAlchemyTest):
def test_create_and_get_and_load_workbook(self):
created = db_api.create_workbook(WORKBOOKS[0])
@ -64,6 +75,16 @@ class WorkbookTest(test_base.DbTestCase):
self.assertIsNone(db_api.load_workbook("not-existing-wb"))
def test_create_workbook_duplicate_without_auth(self):
cfg.CONF.set_default('auth_enable', False, group='pecan')
db_api.create_workbook(WORKBOOKS[0])
self.assertRaises(
exc.DBDuplicateEntry,
db_api.create_workbook,
WORKBOOKS[0]
)
def test_update_workbook(self):
created = db_api.create_workbook(WORKBOOKS[0])
@ -238,7 +259,7 @@ WORKFLOWS = [
]
class WorkflowTest(test_base.DbTestCase):
class WorkflowTest(SQLAlchemyTest):
def test_create_and_get_and_load_workflow(self):
created = db_api.create_workflow(WORKFLOWS[0])
@ -252,6 +273,16 @@ class WorkflowTest(test_base.DbTestCase):
self.assertIsNone(db_api.load_workflow("not-existing-wf"))
def test_create_workflow_duplicate_without_auth(self):
cfg.CONF.set_default('auth_enable', False, group='pecan')
db_api.create_workflow(WORKFLOWS[0])
self.assertRaises(
exc.DBDuplicateEntry,
db_api.create_workflow,
WORKFLOWS[0]
)
def test_update_workflow(self):
created = db_api.create_workflow(WORKFLOWS[0])
@ -403,7 +434,7 @@ EXECUTIONS = [
]
class ExecutionTest(test_base.DbTestCase):
class ExecutionTest(SQLAlchemyTest):
def test_create_and_get_and_load_execution(self):
created = db_api.create_execution(EXECUTIONS[0])
@ -527,7 +558,7 @@ TASKS = [
]
class TaskTest(test_base.DbTestCase):
class TaskTest(SQLAlchemyTest):
def test_create_and_get_and_load_task(self):
ex = db_api.create_execution(EXECUTIONS[0])
@ -654,7 +685,7 @@ ACTIONS = [
'is_system': True,
'action_class': 'mypackage.my_module.Action1',
'attributes': None,
'project_id': '5-6-7-8'
'project_id': '<default-project>'
},
{
'name': 'action2',
@ -662,12 +693,12 @@ ACTIONS = [
'is_system': True,
'action_class': 'mypackage.my_module.Action2',
'attributes': None,
'project_id': '5-6-7-8'
'project_id': '<default-project>'
},
]
class ActionTest(test_base.DbTestCase):
class ActionTest(SQLAlchemyTest):
def setUp(self):
super(ActionTest, self).setUp()
@ -686,6 +717,16 @@ class ActionTest(test_base.DbTestCase):
self.assertIsNone(db_api.load_action("not-existing-id"))
def test_create_action_duplicate_without_auth(self):
cfg.CONF.set_default('auth_enable', False, group='pecan')
db_api.create_action(ACTIONS[0])
self.assertRaises(
exc.DBDuplicateEntry,
db_api.create_action,
ACTIONS[0]
)
def test_update_action(self):
created = db_api.create_action(ACTIONS[0])
@ -767,7 +808,7 @@ CRON_TRIGGERS = [
'workflow_input': {},
'next_execution_time': timeutils.utcnow(),
'scope': 'private',
'project_id': '5-6-7-8'
'project_id': '<default-project>'
},
{
'name': 'trigger2',
@ -777,12 +818,12 @@ CRON_TRIGGERS = [
'workflow_input': {},
'next_execution_time': timeutils.utcnow(),
'scope': 'private',
'project_id': '5-6-7-8'
'project_id': '<default-project>'
},
]
class CronTriggerTest(test_base.DbTestCase):
class CronTriggerTest(SQLAlchemyTest):
def setUp(self):
super(CronTriggerTest, self).setUp()
@ -804,6 +845,16 @@ class CronTriggerTest(test_base.DbTestCase):
self.assertIsNone(db_api.load_cron_trigger("not-existing-trigger"))
def test_create_cron_trigger_duplicate_without_auth(self):
cfg.CONF.set_default('auth_enable', False, group='pecan')
db_api.create_cron_trigger(CRON_TRIGGERS[0])
self.assertRaises(
exc.DBDuplicateEntry,
db_api.create_cron_trigger,
CRON_TRIGGERS[0]
)
def test_update_cron_trigger(self):
created = db_api.create_cron_trigger(CRON_TRIGGERS[0])
@ -872,7 +923,7 @@ class CronTriggerTest(test_base.DbTestCase):
self.assertIn("'name': 'trigger1'", s)
class TXTest(test_base.DbTestCase):
class TXTest(SQLAlchemyTest):
def test_rollback(self):
db_api.start_tx()

View File

@ -17,7 +17,7 @@ from oslo.config import cfg
from mistral.db.v2 import api as db_api
from mistral.openstack.common import log as logging
from mistral.services import workbooks as wb_service
from mistral.tests.unit.engine1 import base
from mistral.tests import base
from mistral.workbook import parser as spec_parser
LOG = logging.getLogger(__name__)
@ -106,7 +106,7 @@ workflows:
"""
class WorkbookServiceTest(base.EngineTestCase):
class WorkbookServiceTest(base.DbTestCase):
def test_create_workbook(self):
wb_db = wb_service.create_workbook_v2({'definition': WORKBOOK})