# HG changeset patch # User Sylvain Thénault # Date 1250787804 -7200 # Node ID a613cc003ab75c92c129aca360a063aad9d705cc # Parent e5cef8ff5857c2a68430eaa22858b2ea063355f1 make state/transition name unique within a workflow diff -r e5cef8ff5857 -r a613cc003ab7 entities/test/unittest_wfobjs.py --- a/entities/test/unittest_wfobjs.py Thu Aug 20 18:37:33 2009 +0200 +++ b/entities/test/unittest_wfobjs.py Thu Aug 20 19:03:24 2009 +0200 @@ -1,6 +1,41 @@ from cubicweb.devtools.apptest import EnvBasedTC from cubicweb import ValidationError +class WorkflowBuildingTC(EnvBasedTC): + + def test_wf_construction(self): + wf = self.execute('INSERT Workflow X: X name "test"').get_entity(0, 0) + self.execute('SET WF workflow_of ET WHERE ET name "Company"') + foo = wf.add_state(u'foo', initial=True) + bar = wf.add_state(u'bar') + self.assertEquals(wf.state_by_name('bar').eid, bar.eid) + self.assertEquals(wf.state_by_name('barrr'), None) + baz = wf.add_transition(u'baz', (foo,), bar, ('managers',)) + self.assertEquals(wf.transition_by_name('baz').eid, baz.eid) + self.assertEquals(len(baz.require_group), 1) + self.assertEquals(baz.require_group[0].name, 'managers') + + def test_duplicated_state(self): + wf = self.execute('INSERT Workflow X: X name "test"').get_entity(0, 0) + self.execute('SET WF workflow_of ET WHERE ET name "Company"') + wf.add_state(u'foo', initial=True) + wf.add_state(u'foo') + ex = self.assertRaises(ValidationError, self.commit) + # XXX enhance message + self.assertEquals(ex.errors, {'state_of': 'unique constraint S name N, Y state_of O, Y name N failed'}) + + def test_duplicated_transition(self): + wf = self.execute('INSERT Workflow X: X name "test"').get_entity(0, 0) + self.execute('SET WF workflow_of ET WHERE ET name "Company"') + foo = wf.add_state(u'foo', initial=True) + bar = wf.add_state(u'bar') + wf.add_transition(u'baz', (foo,), bar, ('managers',)) + wf.add_transition(u'baz', (bar,), foo) + ex = self.assertRaises(ValidationError, self.commit) + # XXX enhance message + self.assertEquals(ex.errors, {'transition_of': 'unique constraint S name N, Y transition_of O, Y name N failed'}) + + class WorkflowTC(EnvBasedTC): def setup_database(self): @@ -23,17 +58,6 @@ ['deactivate 1', 'activate 1', 'deactivate 2']) self.assertEquals(e.latest_trinfo().comment, 'deactivate 2') - # def test_wf_construction(self): # XXX update or kill me - # bar = self.mh.cmd_add_state(u'bar', ('Personne', 'Email'), initial=True) - # baz = self.mh.cmd_add_transition(u'baz', ('Personne', 'Email'), - # (foo,), bar, ('managers',)) - # for etype in ('Personne', 'Email'): - # t1 = self.mh.rqlexec('Any N WHERE T transition_of ET, ET name "%s", T name N' % - # etype)[0][0] - # self.assertEquals(t1, "baz") - # gn = self.mh.rqlexec('Any GN WHERE T require_group G, G name GN, T eid %s' % baz)[0][0] - # self.assertEquals(gn, 'managers') - def test_possible_transitions(self): user = self.entity('CWUser X') trs = list(user.possible_transitions()) diff -r e5cef8ff5857 -r a613cc003ab7 schemas/workflow.py --- a/schemas/workflow.py Thu Aug 20 18:37:33 2009 +0200 +++ b/schemas/workflow.py Thu Aug 20 19:03:24 2009 +0200 @@ -10,8 +10,9 @@ from yams.buildobjs import (EntityType, RelationType, SubjectRelation, ObjectRelation, RichString, String) -from cubicweb.schema import RQLConstraint -from cubicweb.schemas import META_ETYPE_PERMS, META_RTYPE_PERMS, HOOKS_RTYPE_PERMS +from cubicweb.schema import RQLConstraint, RQLUniqueConstraint +from cubicweb.schemas import (META_ETYPE_PERMS, META_RTYPE_PERMS, + HOOKS_RTYPE_PERMS) class Workflow(EntityType): permissions = META_ETYPE_PERMS @@ -34,7 +35,6 @@ constraints=[RQLConstraint('O state_of S')], description=_('initial state for this workflow')) -# XXX ensure state/transition name is unique in a given workflow class State(EntityType): """used to associate simple states to an entity type and/or to define @@ -47,13 +47,14 @@ description = RichString(fulltextindexed=True, default_format='text/rest', description=_('semantic description of this state')) - state_of = SubjectRelation('Workflow', cardinality='+*', - description=_('workflow to which this state belongs')) # XXX should be on BaseTransition w/ AND/OR selectors when we will # implements #345274 allowed_transition = SubjectRelation('BaseTransition', cardinality='**', constraints=[RQLConstraint('S state_of WF, O transition_of WF')], description=_('allowed transitions from this state')) + state_of = SubjectRelation('Workflow', cardinality='+*', + description=_('workflow to which this state belongs'), + constraints=[RQLUniqueConstraint('S name N, Y state_of O, Y name N')]) class BaseTransition(EntityType): @@ -75,7 +76,8 @@ description=_('group in which a user should be to be ' 'allowed to pass this transition')) transition_of = SubjectRelation('Workflow', cardinality='+*', - description=_('workflow to which this transition belongs')) + description=_('workflow to which this transition belongs'), + constraints=[RQLUniqueConstraint('S name N, Y transition_of O, Y name N')]) class Transition(BaseTransition):