001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.tests.embedded;
034:
035: import com.flexive.shared.*;
036: import static com.flexive.shared.CacheAdmin.getEnvironment;
037: import com.flexive.shared.exceptions.FxApplicationException;
038: import com.flexive.shared.exceptions.FxRuntimeException;
039: import com.flexive.shared.interfaces.*;
040: import com.flexive.shared.security.ACL;
041: import com.flexive.shared.security.Role;
042: import com.flexive.shared.security.UserGroup;
043: import com.flexive.shared.value.FxString;
044: import com.flexive.shared.workflow.*;
045: import static com.flexive.tests.embedded.FxTestUtils.*;
046: import org.apache.commons.lang.StringUtils;
047: import org.testng.annotations.AfterClass;
048: import org.testng.annotations.BeforeClass;
049: import org.testng.annotations.Test;
050:
051: import java.util.ArrayList;
052: import java.util.Arrays;
053: import java.util.Collections;
054: import java.util.List;
055:
056: /**
057: * Workflow tests.
058: *
059: * @author Daniel Lichtenberger (daniel.lichtenberger@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
060: */
061: @Test(groups={"ejb","workflow"})
062: public class WorkflowTest {
063:
064: private static final String WORKFLOW_NAME = "Cactus test workflow";
065: private static final String WORKFLOW_DESCRIPTION = "Test description";
066: private static final String STEPDEF_NAME = "Cactus test step definition";
067: private static final String STEPDEF_DESCRIPTION = "Cactus test step definition description";
068: private static final String ACL_NAME = "Cactus test ACL";
069: private static final String ACL_LABEL = "Cactus test label";
070:
071: private ACLEngine aclEngine = null;
072: private WorkflowEngine workflowEngine = null;
073: private StepEngine stepEngine = null;
074: private StepDefinitionEngine stepDefinitionEngine = null;
075: private RouteEngine routeEngine = null;
076:
077: private ACL myWorkflowACL = null;
078: private static int ctr = 0;
079:
080: /**
081: * Create test ACLs.
082: *
083: * @throws Exception if an error occurs
084: */
085: @BeforeClass
086: public void beforeClass() throws Exception {
087: // EJB lookup
088: aclEngine = EJBLookup.getACLEngine();
089: workflowEngine = EJBLookup.getWorkflowEngine();
090: stepEngine = EJBLookup.getWorkflowStepEngine();
091: stepDefinitionEngine = EJBLookup
092: .getWorkflowStepDefinitionEngine();
093: routeEngine = EJBLookup.getWorkflowRouteEngine();
094: // create test ACL
095: login(TestUsers.SUPERVISOR);
096: myWorkflowACL = aclEngine.load(aclEngine.create(
097: "CACTUS_TEST_WORKFLOW", new FxString("Test workflow"),
098: getUserTicket().getMandatorId(), "#000000",
099: "cactus test ACL (ignore)", ACL.Category.WORKFLOW));
100: aclEngine.assign(myWorkflowACL.getId(),
101: UserGroup.GROUP_EVERYONE, true, true, true, true, true,
102: true);
103: }
104:
105: /**
106: * Remove test ACLs.
107: *
108: * @throws Exception if an error occurs
109: */
110: @AfterClass
111: public void afterClass() throws Exception {
112: // remove test ACL
113: aclEngine.unassign(myWorkflowACL.getId(),
114: UserGroup.GROUP_EVERYONE);
115: aclEngine.remove(myWorkflowACL.getId());
116: logout();
117: }
118:
119: /**
120: * Test creation and loading of workflows.
121: *
122: * @throws Exception if an error occured
123: */
124: @Test
125: public void createWorkflow() throws Exception {
126: long workflowId = -1;
127: try {
128: workflowId = createTestWorkflow();
129: try {
130: createTestWorkflow();
131: assert false : "Workflows must have unique names";
132: } catch (Exception e) {
133: //ok
134: }
135: assert getUserTicket().isInRole(Role.WorkflowManagement) : "User is not in role workflow management - call should have failed.";
136: Workflow workflow = getEnvironment()
137: .getWorkflow(workflowId);
138: assert workflowId == workflow.getId() : "Workflow ID not set/returned correctly.";
139: assert WORKFLOW_NAME.equals(workflow.getName()) : "Workflow name was not stored correctly.";
140: assert WORKFLOW_DESCRIPTION.equals(workflow
141: .getDescription()) : "Workflow description was not stored correctly.";
142: } finally {
143: // cleanup
144: if (workflowId != -1) {
145: workflowEngine.remove(workflowId);
146: }
147: }
148: }
149:
150: /**
151: * Tests if a workflow is deleted properly.
152: *
153: * @throws Exception if an error occured
154: */
155: @Test
156: public void deleteWorkflow() throws Exception {
157: long workflowId = createTestWorkflow();
158: workflowEngine.remove(workflowId);
159: assert getUserTicket().isInRole(Role.WorkflowManagement) : "User is not in role workflow management - call should have failed.";
160: try {
161: getEnvironment().getWorkflow(workflowId);
162: assert false : "Able to retrieve deleted workflow.";
163: } catch (Exception e) {
164: // succeed
165: }
166: }
167:
168: /**
169: * Tests if workflows are updated properly.
170: *
171: * @throws Exception if an error occured
172: */
173: @Test
174: public void updateWorkflow() throws Exception {
175: long workflowId = createTestWorkflow();
176: try {
177: WorkflowEdit editWorkflow = new WorkflowEdit(
178: getEnvironment().getWorkflow(workflowId));
179: editWorkflow.setName(StringUtils.reverse(WORKFLOW_NAME));
180: editWorkflow.setDescription(StringUtils
181: .reverse(WORKFLOW_DESCRIPTION));
182: editWorkflow.getSteps().add(
183: new StepEdit(new Step(-1,
184: StepDefinition.EDIT_STEP_ID, editWorkflow
185: .getId(), myWorkflowACL.getId())));
186: editWorkflow.getSteps().add(
187: new StepEdit(new Step(-2,
188: StepDefinition.LIVE_STEP_ID, editWorkflow
189: .getId(), myWorkflowACL.getId())));
190: editWorkflow.getRoutes().add(
191: new Route(-1, UserGroup.GROUP_EVERYONE, -1, -2));
192: workflowEngine.update(editWorkflow);
193: Workflow workflow = getEnvironment()
194: .getWorkflow(workflowId);
195: assert getUserTicket().isInRole(Role.WorkflowManagement) : "User is not in role workflow management - call should have failed.";
196: assert StringUtils.reverse(WORKFLOW_NAME).equals(
197: workflow.getName()) : "Workflow name not updated properly.";
198: assert StringUtils.reverse(WORKFLOW_DESCRIPTION).equals(
199: workflow.getDescription()) : "Workflow description not updated properly.";
200: assert workflow.getSteps().size() == 2 : "Unexpected number of workflow steps: "
201: + workflow.getSteps().size();
202: assert workflow.getRoutes().size() == 1 : "Unexpected number of workflow routes: "
203: + workflow.getRoutes();
204: } finally {
205: // cleanup
206: workflowEngine.remove(workflowId);
207: }
208: }
209:
210: /**
211: * Do some tests that caching works with transaction rollbacks
212: *
213: * @throws FxApplicationException if an error occured
214: */
215: @Test
216: public void updateWorkflowCaching() throws FxApplicationException {
217: long workflowId = createTestWorkflow();
218: try {
219: WorkflowEdit editWorkflow = new WorkflowEdit(
220: getEnvironment().getWorkflow(workflowId));
221: // add two valid steps
222: editWorkflow.getSteps().add(
223: new StepEdit(new Step(-1,
224: StepDefinition.EDIT_STEP_ID, editWorkflow
225: .getId(), myWorkflowACL.getId())));
226: editWorkflow.getSteps().add(
227: new StepEdit(new Step(-2,
228: StepDefinition.LIVE_STEP_ID, editWorkflow
229: .getId(), myWorkflowACL.getId())));
230: // ... and an invalid route (which will cause a rollback after the steps have been added)
231: editWorkflow.getRoutes().add(
232: new Route(-1, UserGroup.GROUP_EVERYONE, -1, -10));
233:
234: List<Step> cachedSteps = getEnvironment().getSteps();
235: try {
236: workflowEngine.update(editWorkflow);
237: assert false : "Should not be able to successfully create workflows with invalid routes.";
238: } catch (Exception e) {
239: assert cachedSteps.equals(getEnvironment().getSteps()) : "Steps should have been rollbacked.\nSteps before update: "
240: + cachedSteps.toString()
241: + "\nEnvironment: "
242: + getEnvironment().getSteps();
243: }
244: } finally {
245: workflowEngine.remove(workflowId);
246: }
247: }
248:
249: /**
250: * Tests workflow step creation, editing and updating.
251: *
252: * @throws Exception if an error occured
253: */
254: @Test
255: public void createEditUpdateStep() throws Exception {
256: long workflowId = -1;
257: long stepDefinitionId = -1;
258: long aclId = -1;
259: long acl2Id = -1;
260: Workflow workflow;
261: try {
262: stepDefinitionId = createStepDefinition(null);
263: try {
264: createStepDefinition(null);
265: assert false : "Step definitions must have unique names for a specific language";
266: } catch (Exception e) {
267: //ok
268: }
269: aclId = createAcl();
270: List<Step> steps = new ArrayList<Step>();
271: steps.add(new Step(-1, stepDefinitionId, -1, aclId));
272: workflow = new Workflow(-1, WORKFLOW_NAME,
273: WORKFLOW_DESCRIPTION, steps, new ArrayList<Route>());
274: workflowId = workflowEngine.create(workflow);
275: workflow = getEnvironment().getWorkflow(workflowId);
276: // try to remove previously created step
277: assert 1 == workflow.getSteps().size() : "Step initialized with workflow not created automatically";
278:
279: // update step
280: acl2Id = createAcl();
281: long stepId = workflow.getSteps().get(0).getId();
282: stepEngine.updateStep(stepId, acl2Id);
283: assert getEnvironment().getStep(stepId).getAclId() == acl2Id;
284:
285: stepEngine.removeStep(stepId);
286: workflow = getEnvironment().getWorkflow(workflowId);
287: assert 0 == workflow.getSteps().size() : "Step not removed in CacheAdmin.getEnvironment().";
288: // generate some steps...
289: List<StepDefinition> stepDefinitions = getEnvironment()
290: .getStepDefinitions();
291: for (StepDefinition stepDefinition : stepDefinitions) {
292: stepEngine.createStep(new Step(-1, stepDefinition
293: .getId(), workflow.getId(), aclId));
294: }
295: // check if structure was updated properly
296: workflow = getEnvironment().getWorkflow(workflowId);
297: assert stepDefinitions.size() == workflow.getSteps().size() : "Created steps not reflected in CacheAdmin.getEnvironment().";
298: // create some routes...
299: steps = workflow.getSteps();
300: int routes = 0;
301: for (int i = 0; i < steps.size() - 1; i++) {
302: for (int j = 0; j < steps.size() - 1; j++) {
303: if (i != j) {
304: // add route from step i to step j
305: long routeId = routeEngine.create(steps.get(i)
306: .getId(), steps.get(j).getId(),
307: j % 2 == 0 ? UserGroup.GROUP_EVERYONE
308: : UserGroup.GROUP_OWNER);
309: Route route = getEnvironment()
310: .getRoute(routeId);
311: Step[] targets = routeEngine.getTargets(route
312: .getFromStepId());
313: boolean found = false;
314: for (Step step : targets) {
315: if (step.getId() == route.getToStepId()) {
316: found = true;
317: break;
318: }
319: }
320: if (!found) {
321: assert false : "Created route target not found with getTargets().";
322: }
323: routes++;
324: }
325: }
326: }
327: workflow = getEnvironment().getWorkflow(workflowId);
328: assert routes == workflow.getRoutes().size() : "Created routes not reflected in CacheAdmin.getEnvironment().";
329: // delete some routes...
330: routeEngine.remove(workflow.getRoutes().get(0).getId());
331: workflow = getEnvironment().getWorkflow(workflowId);
332: assert routes - 1 == workflow.getRoutes().size() : "Deleted routes not reflected in CacheAdmin.getEnvironment().";
333: assert workflow.getRoutes().size() > 0;
334: routeEngine.remove(workflow.getRoutes().get(0).getId());
335: assert getEnvironment().getWorkflow(workflowId).getRoutes()
336: .size() == 0 : "Not all routes deleted.";
337: } finally {
338: if (workflowId != -1) {
339: workflowEngine.remove(workflowId);
340: }
341: if (stepDefinitionId != -1) {
342: stepDefinitionEngine.remove(stepDefinitionId);
343: }
344: if (aclId != -1) {
345: aclEngine.remove(aclId);
346: }
347: if (acl2Id != -1) {
348: aclEngine.remove(acl2Id);
349: }
350: }
351: }
352:
353: /**
354: * Tests the implicit creation of steps when adding a unique target
355: *
356: * @throws com.flexive.shared.exceptions.FxApplicationException
357: * if an error occurs
358: */
359: @Test
360: public void implicitStepCreation() throws FxApplicationException {
361: long workflowId = -1;
362: long aclId = -1;
363: long sd1 = -1;
364: long sd2 = -1;
365: try {
366: // create two independent steps
367: aclId = createAcl();
368: sd1 = stepDefinitionEngine.create(new StepDefinition(-1,
369: new FxString("base"), "descr", -1));
370: sd2 = stepDefinitionEngine.create(new StepDefinition(-2,
371: new FxString("derived"), "descr", -1));
372: // create a workflow which uses only the first step definition
373: workflowId = workflowEngine.create(new Workflow(-1, "test",
374: "descr", Arrays
375: .asList(new Step(-1, sd1, -1, aclId)),
376: new ArrayList<Route>()));
377: // introduce a unique target to sd2
378: StepDefinitionEdit edit = new StepDefinitionEdit(
379: getEnvironment().getStepDefinition(sd1));
380: edit.setUniqueTargetId(sd2);
381: stepDefinitionEngine.update(edit);
382: // check if the workflow contains a step for sd2
383: Workflow workflow = getEnvironment()
384: .getWorkflow(workflowId);
385: List<StepDefinition> usedStepDefinitions = FxSharedUtils
386: .getUsedStepDefinitions(workflow.getSteps(),
387: getEnvironment().getStepDefinitions());
388: assert usedStepDefinitions.contains(getEnvironment()
389: .getStepDefinition(sd1)) : "No step exists for step definition "
390: + sd1;
391: assert usedStepDefinitions.contains(getEnvironment()
392: .getStepDefinition(sd2)) : "No step created for step definition "
393: + sd2;
394: } finally {
395: if (workflowId != -1) {
396: workflowEngine.remove(workflowId);
397: }
398: if (sd1 != -1) {
399: stepDefinitionEngine.remove(sd1);
400: }
401: if (sd2 != -1) {
402: stepDefinitionEngine.remove(sd2);
403: }
404: if (aclId != -1) {
405: aclEngine.remove(aclId);
406: }
407: }
408: }
409:
410: /**
411: * Tests step definition updates
412: *
413: * @throws FxApplicationException if an error occured
414: */
415: @Test
416: public void updateStepDefinition() throws FxApplicationException {
417: long stepDefinitionId = -1;
418: try {
419: stepDefinitionId = createStepDefinition(null);
420: assert stepDefinitionId != -1 : "Failed to create step definition";
421: StepDefinition stepDefinition = getEnvironment()
422: .getStepDefinition(stepDefinitionId);
423: assert new FxString(STEPDEF_NAME).equals(stepDefinition
424: .getLabel()) : "Invalid name: "
425: + stepDefinition.getLabel();
426: assert STEPDEF_DESCRIPTION.equals(stepDefinition
427: .getDescription()) : "Invalid description: "
428: + stepDefinition.getDescription();
429: StepDefinitionEdit definitionEdit = new StepDefinitionEdit(
430: stepDefinition);
431: definitionEdit.setDescription(StringUtils
432: .reverse(stepDefinition.getDescription()));
433: FxString label = new FxString(STEPDEF_NAME);
434: label.setTranslation(label.getDefaultLanguage(),
435: StringUtils.reverse(label.getDefaultTranslation()));
436: definitionEdit.setLabel(label);
437: stepDefinitionEngine.update(definitionEdit);
438: stepDefinition = getEnvironment().getStepDefinition(
439: stepDefinitionId);
440: assert StringUtils.reverse(STEPDEF_DESCRIPTION).equals(
441: stepDefinition.getDescription()) : "Invalid description: "
442: + stepDefinition.getDescription();
443: assert label.equals(stepDefinition.getLabel()) : "Invalid label: "
444: + stepDefinition.getLabel();
445: } finally {
446: if (stepDefinitionId != -1) {
447: stepDefinitionEngine.remove(stepDefinitionId);
448: }
449: }
450: }
451:
452: @Test
453: public void stepDefinitionDefaultLanguage()
454: throws FxApplicationException {
455: long stepDefinitionId = -1;
456: try {
457: stepDefinitionId = createStepDefinition(null);
458: StepDefinition stepDefinition = getEnvironment()
459: .getStepDefinition(stepDefinitionId);
460: FxLanguage[] languages = EJBLookup.getLanguageEngine()
461: .loadAvailable();
462: for (FxLanguage language : languages) {
463: stepDefinition.getLabel().setTranslation(language,
464: "Translation " + language);
465: }
466: long defaultLanguage = languages[languages.length - 1]
467: .getId();
468: stepDefinition.getLabel().setDefaultLanguage(
469: defaultLanguage);
470: stepDefinitionEngine.update(stepDefinition);
471: assert getEnvironment().getStepDefinition(stepDefinitionId)
472: .getLabel().getDefaultLanguage() == defaultLanguage : "Default language not preserved correctly.";
473: } finally {
474: if (stepDefinitionId != -1) {
475: stepDefinitionEngine.remove(stepDefinitionId);
476: }
477: }
478: }
479:
480: @Test
481: public void stepDefinitionUniqueTarget()
482: throws FxApplicationException {
483: long stepDefinitionId = -1;
484: long targetStepDefinitionId = -1;
485: try {
486: stepDefinitionId = createStepDefinition("st1");
487: targetStepDefinitionId = createStepDefinition("st2");
488: StepDefinitionEdit stepDefinition = new StepDefinitionEdit(
489: getEnvironment()
490: .getStepDefinition(stepDefinitionId));
491: stepDefinition.setUniqueTargetId(targetStepDefinitionId);
492: stepDefinitionEngine.update(stepDefinition);
493: assert CacheAdmin.getEnvironment().getStepDefinition(
494: stepDefinitionId).getUniqueTargetId() == targetStepDefinitionId : "Target step definition ID not updated.";
495: } finally {
496: if (stepDefinitionId != -1) {
497: stepDefinitionEngine.remove(stepDefinitionId);
498: }
499: if (targetStepDefinitionId != -1) {
500: stepDefinitionEngine.remove(targetStepDefinitionId);
501: }
502: }
503: }
504:
505: @Test
506: public void loadAllSteps() throws FxApplicationException {
507: long workflowId = -1;
508: long stepDefinitionId = -1;
509: long stepId = -1;
510: try {
511: workflowId = createTestWorkflow();
512: stepDefinitionId = createStepDefinition(null);
513: stepId = stepEngine
514: .createStep(new Step(-1, stepDefinitionId,
515: workflowId, myWorkflowACL.getId()));
516: List<StepPermission> stepPermissions = stepEngine
517: .loadAllStepsForUser(FxContext.get().getTicket()
518: .getUserId());
519: assert stepPermissions.size() > 0 : "No steps/step permissions returned.";
520: // TODO add more checks
521: } finally {
522: if (stepId != -1) {
523: stepEngine.removeStep(stepId);
524: }
525: if (stepDefinitionId != -1) {
526: stepDefinitionEngine.remove(stepDefinitionId);
527: }
528: if (workflowId != -1) {
529: workflowEngine.remove(workflowId);
530: }
531: }
532: }
533:
534: /**
535: * Attempts to create a circular dependency by setting a stepdef's unique target
536: * on itself.
537: *
538: * @throws com.flexive.shared.exceptions.FxApplicationException
539: * if an error occured
540: */
541: @Test
542: public void stepDefinitionTargetCycle1()
543: throws FxApplicationException {
544: long id = -1;
545: try {
546: id = stepDefinitionEngine.create(new StepDefinition(-1,
547: new FxString("base"), "descr", -1));
548: assert getEnvironment().getStepDefinition(id)
549: .getUniqueTargetId() == -1;
550: // set unique target to itself
551: StepDefinitionEdit edit = new StepDefinitionEdit(
552: getEnvironment().getStepDefinition(id));
553: try {
554: // first try: sdedit should catch this
555: edit.setUniqueTargetId(id);
556: assert false : "It should not be possible to set the unique target ID to the ID of the "
557: + " step definition itself in StepDefinitionEdit";
558: } catch (FxRuntimeException e) {
559: // pass
560: }
561: try {
562: // second try: the stepdef constructor should catch this too
563: assert edit.getId() != -1;
564: new StepDefinition(edit.getId(), new FxString("test"),
565: "descr", edit.getId());
566: assert false : "The StepDefinition constructor should check if the unique target ID "
567: + " is equal to the step definition ID.";
568: } catch (FxRuntimeException e) {
569: // pass
570: }
571: } finally {
572: if (id != -1) {
573: stepDefinitionEngine.remove(id);
574: }
575: }
576: }
577:
578: /**
579: * Attempts to create a cycle between two workflow step definitions.
580: *
581: * @throws com.flexive.shared.exceptions.FxApplicationException
582: * if an error occured
583: */
584: @Test
585: public void stepDefinitionTargetCycle2()
586: throws FxApplicationException {
587: long sd1 = -1;
588: long sd2 = -1;
589: boolean createdCycle = false;
590: try {
591: sd1 = stepDefinitionEngine.create(new StepDefinition(-1,
592: new FxString("base"), "descr", -1));
593: sd2 = stepDefinitionEngine.create(new StepDefinition(-1,
594: new FxString("derived"), "descr", sd1));
595: // until now, the step definitions are valid and no cycle is created
596: assert getEnvironment().getStepDefinition(sd2)
597: .getUniqueTargetId() == sd1 : "Invalid unique target: "
598: + getEnvironment().getStepDefinition(sd2)
599: .getUniqueTargetId();
600: assert getEnvironment().getStepDefinition(sd1)
601: .getUniqueTargetId() == -1 : "Invalid unique target: "
602: + getEnvironment().getStepDefinition(sd1)
603: .getUniqueTargetId();
604: // create cycle by changing sd1's unique target to sd2
605: StepDefinitionEdit sdEdit = new StepDefinitionEdit(
606: getEnvironment().getStepDefinition(sd1));
607: sdEdit.setUniqueTargetId(sd2);
608: try {
609: stepDefinitionEngine.update(sdEdit);
610: createdCycle = true;
611: assert false : "Possible to create cycles in unique target definitions";
612: } catch (FxApplicationException e) {
613: // pass
614: }
615: } finally {
616: if (!createdCycle) {
617: // cleanup - unless we successfully created a cycle, in that case
618: // the stepdef table cannot be cleared up because of the circular dependency
619: if (sd2 != -1) {
620: stepDefinitionEngine.remove(sd2);
621: }
622: if (sd1 != -1) {
623: stepDefinitionEngine.remove(sd1);
624: }
625: }
626: }
627: }
628:
629: /**
630: * Attempts to create a longer cycle (with 10 nodes and the last one pointing
631: * to the first).
632: *
633: * @throws com.flexive.shared.exceptions.FxApplicationException
634: * if an error occured
635: */
636: @Test
637: public void stepDefinitionTargetCycle10()
638: throws FxApplicationException {
639: List<Long> ids = new ArrayList<Long>();
640: try {
641: for (int i = 0; i < 10; i++) {
642: // create a new step definition, with the unique target pointing to the last one (except for the first)
643: ids.add(stepDefinitionEngine.create(new StepDefinition(
644: -1, new FxString("test" + i), "descr",
645: i > 0 ? ids.get(i - 1) : -1)));
646:
647: }
648: // check if the unique targets have been created properly
649: long previousId = -1;
650: for (Long id : ids) {
651: StepDefinition sd = getEnvironment().getStepDefinition(
652: id);
653: assert sd.getId() != -1;
654: if (previousId != -1) {
655: assert sd.getUniqueTargetId() == previousId : "Unique target for step "
656: + sd.getId()
657: + " is "
658: + sd.getUniqueTargetId()
659: + ", expected: "
660: + previousId;
661: }
662: previousId = id;
663: }
664: // try to create cycle
665: StepDefinitionEdit sdEdit = new StepDefinitionEdit(
666: getEnvironment().getStepDefinition(ids.get(0)));
667: // point unique target to last element in list --> cycle created
668: sdEdit.setUniqueTargetId(ids.get(ids.size() - 1));
669: try {
670: stepDefinitionEngine.update(sdEdit);
671: assert false : "Cycle created, nodes = " + ids;
672: } catch (FxApplicationException e) {
673: // pass
674: }
675: } finally {
676: Collections.reverse(ids);
677: for (Long id : ids) {
678: stepDefinitionEngine.remove(id);
679: }
680: }
681: }
682:
683: /**
684: * Test the code we use in the workflow reference documentation
685: * @throws com.flexive.shared.exceptions.FxApplicationException on errors
686: */
687: @Test
688: public void workflowDocTest() throws FxApplicationException {
689: final List<StepDefinition> stepDefinitions = new ArrayList<StepDefinition>();
690: final List<Workflow> workflows = new ArrayList<Workflow>();
691: try {
692: // create step definition objects
693: final StepDefinitionEdit definition1 = new StepDefinition(
694: new FxString("step 1"), "first step", -1)
695: .asEditable();
696: final StepDefinitionEdit definition2 = new StepDefinition(
697: new FxString("step 2"), "second step", -1)
698: .asEditable();
699:
700: // store them in the database and store IDs
701: definition1.setId(EJBLookup
702: .getWorkflowStepDefinitionEngine().create(
703: definition1));
704: definition2.setId(EJBLookup
705: .getWorkflowStepDefinitionEngine().create(
706: definition2));
707:
708: stepDefinitions.addAll(Arrays.asList(definition1,
709: definition2));
710:
711: // create a workflow and auto-create steps using intermediate IDs
712: final Step step1 = new Step(-10, definition1.getId(),
713: ACL.Category.WORKFLOW.getDefaultId());
714: final Step step2 = new Step(-20, definition2.getId(),
715: ACL.Category.WORKFLOW.getDefaultId());
716:
717: // create a route between step1 and step2
718: final Route route = new Route(-1, UserGroup.GROUP_EVERYONE,
719: -10, -20);
720:
721: // create workflow object and store it in the database
722: final Workflow workflow = new Workflow(-1, "test wf",
723: "my test workflow", Arrays.asList(step1, step2),
724: Arrays.asList(route));
725: final long workflowId = EJBLookup.getWorkflowEngine()
726: .create(workflow);
727: final Workflow dbWorkflow = CacheAdmin.getEnvironment()
728: .getWorkflow(workflowId);
729: workflows.add(dbWorkflow);
730: assert dbWorkflow.getRoutes().size() == 1; // route available?
731: assert dbWorkflow.getSteps().size() == 2; // both steps available?
732:
733: // check from and to steps of our route
734: assert dbWorkflow.getRoutes().get(0).getFromStepId() == dbWorkflow
735: .getSteps().get(0).getId();
736: assert dbWorkflow.getRoutes().get(0).getToStepId() == dbWorkflow
737: .getSteps().get(1).getId();
738: } finally {
739: for (Workflow workflow : workflows) {
740: EJBLookup.getWorkflowEngine().remove(workflow.getId());
741: }
742: for (StepDefinition def : stepDefinitions) {
743: EJBLookup.getWorkflowStepDefinitionEngine().remove(
744: def.getId());
745: }
746: }
747:
748: }
749:
750: /**
751: * Creates a new step definition for testing.
752: *
753: * @return a new step definition for testing.
754: * @throws FxApplicationException
755: */
756: private long createStepDefinition(String name)
757: throws FxApplicationException {
758: if (name == null)
759: return stepDefinitionEngine
760: .create(new StepDefinition(-1, new FxString(
761: STEPDEF_NAME), STEPDEF_DESCRIPTION, -1));
762: else
763: return stepDefinitionEngine.create(new StepDefinition(-1,
764: new FxString(name), STEPDEF_DESCRIPTION, -1));
765: }
766:
767: /**
768: * Creates a new ACL for testing.
769: *
770: * @return an ACL for testing
771: * @throws FxApplicationException
772: */
773: private long createAcl() throws FxApplicationException {
774: return aclEngine.create(ACL_NAME + ctr++, new FxString(
775: ACL_LABEL), getUserTicket().getMandatorId(), "#000000",
776: "", ACL.Category.WORKFLOW);
777: }
778:
779: /**
780: * Creates a new workflow for testing.
781: *
782: * @return a new workflow for testing.
783: * @throws FxApplicationException
784: */
785: private long createTestWorkflow() throws FxApplicationException {
786: return workflowEngine.create(getTestWorkflow());
787: }
788:
789: private Workflow getTestWorkflow() {
790: return new Workflow(-1, WORKFLOW_NAME, WORKFLOW_DESCRIPTION,
791: new ArrayList<Step>(), new ArrayList<Route>());
792: }
793:
794: }
|