1 from cubicweb.devtools.apptest import EnvBasedTC |
1 from cubicweb.devtools.apptest import EnvBasedTC |
2 from cubicweb import ValidationError |
2 from cubicweb import ValidationError |
3 |
3 |
4 def add_wf(self, etype, name=None): |
4 def add_wf(self, etype, name=None, default=False): |
5 if name is None: |
5 if name is None: |
6 name = unicode(etype) |
6 name = etype |
7 wf = self.execute('INSERT Workflow X: X name %(n)s', {'n': name}).get_entity(0, 0) |
7 wf = self.execute('INSERT Workflow X: X name %(n)s', {'n': unicode(name)}).get_entity(0, 0) |
8 self.execute('SET WF workflow_of ET WHERE WF eid %(wf)s, ET name %(et)s', |
8 self.execute('SET WF workflow_of ET WHERE WF eid %(wf)s, ET name %(et)s', |
9 {'wf': wf.eid, 'et': etype}) |
9 {'wf': wf.eid, 'et': etype}) |
|
10 if default: |
|
11 self.execute('SET ET default_workflow WF WHERE WF eid %(wf)s, ET name %(et)s', |
|
12 {'wf': wf.eid, 'et': etype}) |
10 return wf |
13 return wf |
11 |
14 |
12 def parse_hist(wfhist): |
15 def parse_hist(wfhist): |
13 return [(ti.previous_state.name, ti.new_state.name, |
16 return [(ti.previous_state.name, ti.new_state.name, |
14 ti.transition and ti.transition.name, ti.comment) |
17 ti.transition and ti.transition.name, ti.comment) |
153 self.execute('INSERT RQLExpression X: X exprtype "ERQLExpression", ' |
156 self.execute('INSERT RQLExpression X: X exprtype "ERQLExpression", ' |
154 'X expression "U has_update_permission X", T condition X ' |
157 'X expression "U has_update_permission X", T condition X ' |
155 'WHERE T name "deactivate"') |
158 'WHERE T name "deactivate"') |
156 self._test_stduser_deactivate() |
159 self._test_stduser_deactivate() |
157 |
160 |
|
161 def test_subworkflow_base(self): |
|
162 """subworkflow |
|
163 |
|
164 +-----------+ tr1 +-----------+ |
|
165 | swfstate1 | ------>| swfstate2 | |
|
166 +-----------+ +-----------+ |
|
167 | tr2 +-----------+ |
|
168 `------>| swfstate3 | |
|
169 +-----------+ |
|
170 |
|
171 main workflow |
|
172 |
|
173 +--------+ swftr1 +--------+ |
|
174 | state1 | -------[swfstate2]->| state2 | |
|
175 +--------+ | +--------+ |
|
176 | +--------+ |
|
177 `-[swfstate3]-->| state3 | |
|
178 +--------+ |
|
179 """ |
|
180 # sub-workflow |
|
181 swf = add_wf(self, 'CWGroup', name='subworkflow') |
|
182 swfstate1 = swf.add_state(u'swfstate1', initial=True) |
|
183 swfstate2 = swf.add_state(u'swfstate2') |
|
184 swfstate3 = swf.add_state(u'swfstate3') |
|
185 tr1 = swf.add_transition(u'tr1', (swfstate1,), swfstate2) |
|
186 tr2 = swf.add_transition(u'tr2', (swfstate1,), swfstate3) |
|
187 # main workflow |
|
188 mwf = add_wf(self, 'CWGroup', name='main workflow', default=True) |
|
189 state1 = mwf.add_state(u'state1', initial=True) |
|
190 state2 = mwf.add_state(u'state2') |
|
191 state3 = mwf.add_state(u'state3') |
|
192 swftr1 = mwf.add_wftransition(u'swftr1', swf, state1, |
|
193 [(swfstate2, state2), (swfstate3, state3)]) |
|
194 self.assertEquals(swftr1.destination().eid, swfstate1.eid) |
|
195 # workflows built, begin test |
|
196 self.group = self.add_entity('CWGroup', name=u'grp1') |
|
197 self.commit() |
|
198 self.assertEquals(self.group.current_state.eid, state1.eid) |
|
199 self.assertEquals(self.group.current_workflow.eid, mwf.eid) |
|
200 self.assertEquals(self.group.main_workflow.eid, mwf.eid) |
|
201 self.assertEquals(self.group.subworkflow_input_transition(), None) |
|
202 self.group.fire_transition('swftr1', u'go') |
|
203 self.commit() |
|
204 self.group.clear_all_caches() |
|
205 self.assertEquals(self.group.current_state.eid, swfstate1.eid) |
|
206 self.assertEquals(self.group.current_workflow.eid, swf.eid) |
|
207 self.assertEquals(self.group.main_workflow.eid, mwf.eid) |
|
208 self.assertEquals(self.group.subworkflow_input_transition().eid, swftr1.eid) |
|
209 self.group.fire_transition('tr1', u'go') |
|
210 self.commit() |
|
211 self.group.clear_all_caches() |
|
212 self.assertEquals(self.group.current_state.eid, state2.eid) |
|
213 self.assertEquals(self.group.current_workflow.eid, mwf.eid) |
|
214 self.assertEquals(self.group.main_workflow.eid, mwf.eid) |
|
215 self.assertEquals(self.group.subworkflow_input_transition(), None) |
|
216 # force back to swfstate1 is impossible since we can't any more find |
|
217 # subworkflow input transition |
|
218 ex = self.assertRaises(ValidationError, |
|
219 self.group.change_state, swfstate1, u'gadget') |
|
220 self.assertEquals(ex.errors, {'to_state': "state doesn't belong to entity's current workflow"}) |
|
221 self.rollback() |
|
222 # force back to state1 |
|
223 self.group.change_state('state1', u'gadget') |
|
224 self.group.fire_transition('swftr1', u'au') |
|
225 self.group.clear_all_caches() |
|
226 self.group.fire_transition('tr2', u'chapeau') |
|
227 self.commit() |
|
228 self.group.clear_all_caches() |
|
229 self.assertEquals(self.group.current_state.eid, state3.eid) |
|
230 self.assertEquals(self.group.current_workflow.eid, mwf.eid) |
|
231 self.assertEquals(self.group.main_workflow.eid, mwf.eid) |
|
232 self.assertListEquals(parse_hist(self.group.workflow_history), |
|
233 [('state1', 'swfstate1', 'swftr1', 'go'), |
|
234 ('swfstate1', 'swfstate2', 'tr1', 'go'), |
|
235 ('swfstate2', 'state2', 'swftr1', 'exiting from subworkflow subworkflow'), |
|
236 ('state2', 'state1', None, 'gadget'), |
|
237 ('state1', 'swfstate1', 'swftr1', 'au'), |
|
238 ('swfstate1', 'swfstate3', 'tr2', 'chapeau'), |
|
239 ('swfstate3', 'state3', 'swftr1', 'exiting from subworkflow subworkflow'), |
|
240 ]) |
|
241 |
|
242 def test_subworkflow_exit_consistency(self): |
|
243 # sub-workflow |
|
244 swf = add_wf(self, 'CWGroup', name='subworkflow') |
|
245 swfstate1 = swf.add_state(u'swfstate1', initial=True) |
|
246 swfstate2 = swf.add_state(u'swfstate2') |
|
247 tr1 = swf.add_transition(u'tr1', (swfstate1,), swfstate2) |
|
248 # main workflow |
|
249 mwf = add_wf(self, 'CWGroup', name='main workflow', default=True) |
|
250 state1 = mwf.add_state(u'state1', initial=True) |
|
251 state2 = mwf.add_state(u'state2') |
|
252 state3 = mwf.add_state(u'state3') |
|
253 mwf.add_wftransition(u'swftr1', swf, state1, |
|
254 [(swfstate2, state2), (swfstate2, state3)]) |
|
255 ex = self.assertRaises(ValidationError, self.commit) |
|
256 self.assertEquals(ex.errors, {'subworkflow_exit': u"can't have multiple exits on the same state"}) |
158 |
257 |
159 |
258 |
160 class CustomWorkflowTC(EnvBasedTC): |
259 class CustomWorkflowTC(EnvBasedTC): |
161 |
260 |
162 def setup_database(self): |
261 def setup_database(self): |