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.CacheAdmin;
036: import com.flexive.shared.EJBLookup;
037: import com.flexive.shared.tree.FxTreeNode;
038: import com.flexive.shared.tree.FxTreeMode;
039: import com.flexive.shared.tree.FxTreeNodeEdit;
040: import com.flexive.shared.workflow.Step;
041: import com.flexive.shared.workflow.StepDefinition;
042: import com.flexive.shared.content.FxPK;
043: import com.flexive.shared.content.FxContent;
044: import com.flexive.shared.exceptions.FxApplicationException;
045: import com.flexive.shared.search.*;
046: import com.flexive.shared.search.query.PropertyValueComparator;
047: import com.flexive.shared.search.query.QueryOperatorNode;
048: import com.flexive.shared.search.query.SqlQueryBuilder;
049: import com.flexive.shared.search.query.VersionFilter;
050: import com.flexive.shared.security.Account;
051: import com.flexive.shared.security.ACL;
052: import com.flexive.shared.security.Mandator;
053: import com.flexive.shared.security.LifeCycleInfo;
054: import com.flexive.shared.structure.FxType;
055: import com.flexive.shared.structure.FxDataType;
056: import com.flexive.shared.structure.FxPropertyAssignment;
057: import com.flexive.shared.value.*;
058: import static com.flexive.tests.embedded.FxTestUtils.login;
059: import static com.flexive.tests.embedded.FxTestUtils.logout;
060: import static org.testng.Assert.assertEquals;
061: import org.testng.annotations.AfterClass;
062: import org.testng.annotations.BeforeClass;
063: import org.testng.annotations.Test;
064: import org.testng.annotations.DataProvider;
065: import org.apache.commons.lang.StringUtils;
066: import org.apache.commons.lang.RandomStringUtils;
067: import org.apache.commons.collections.CollectionUtils;
068:
069: import java.util.*;
070:
071: /**
072: * FxSQL search query engine tests.
073: * <p/>
074: * Test data is created in init1201_testcontent.gy !
075: *
076: * @author Daniel Lichtenberger (daniel.lichtenberger@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
077: * @version $Rev: 256 $
078: */
079: @Test(groups={"ejb","search"})
080: public class SearchEngineTest {
081: private static final String TEST_SUFFIX = "SearchProp";
082: private static final String TEST_TYPE = "SearchTest";
083: private static final Map<String, FxDataType> TEST_PROPS = new HashMap<String, FxDataType>();
084:
085: static {
086: TEST_PROPS.put("string", FxDataType.String1024);
087: TEST_PROPS.put("text", FxDataType.Text);
088: TEST_PROPS.put("html", FxDataType.HTML);
089: TEST_PROPS.put("number", FxDataType.Number);
090: TEST_PROPS.put("largeNumber", FxDataType.LargeNumber);
091: TEST_PROPS.put("float", FxDataType.Float);
092: TEST_PROPS.put("double", FxDataType.Double);
093: TEST_PROPS.put("date", FxDataType.Date);
094: TEST_PROPS.put("dateTime", FxDataType.DateTime);
095: TEST_PROPS.put("boolean", FxDataType.Boolean);
096: TEST_PROPS.put("binary", FxDataType.Binary);
097: TEST_PROPS.put("reference", FxDataType.Reference);
098: TEST_PROPS.put("selectOne", FxDataType.SelectOne);
099: TEST_PROPS.put("selectMany", FxDataType.SelectMany);
100: TEST_PROPS.put("dateRange", FxDataType.DateRange);
101: TEST_PROPS.put("dateTimeRange", FxDataType.DateTimeRange);
102: }
103:
104: private int testInstanceCount; // number of instances for the SearchTest type
105: private final List<Long> generatedNodeIds = new ArrayList<Long>();
106:
107: @BeforeClass
108: public void setup() throws Exception {
109: login(TestUsers.SUPERVISOR);
110: final List<FxPK> testPks = new SqlQueryBuilder().select("@pk")
111: .type(TEST_TYPE).getResult().collectColumn(1);
112: testInstanceCount = testPks.size();
113: assert testInstanceCount > 0 : "No instances of test type "
114: + TEST_TYPE + " found.";
115: // link test instances in tree
116: for (FxPK pk : testPks) {
117: generatedNodeIds.add(EJBLookup.getTreeEngine()
118: .save(
119: FxTreeNodeEdit.createNew("test" + pk)
120: .setReference(pk).setName(
121: RandomStringUtils
122: .random(1024))));
123: }
124: }
125:
126: @AfterClass
127: public void shutdown() throws Exception {
128: for (long nodeId : generatedNodeIds) {
129: EJBLookup.getTreeEngine().remove(
130: FxTreeNodeEdit.createNew("").setReference(
131: new FxPK(nodeId)).setMode(FxTreeMode.Edit),
132: false, true);
133: }
134: logout();
135: }
136:
137: @Test
138: public void simpleSelectTest() throws FxApplicationException {
139: final FxResultSet result = new SqlQueryBuilder().select(
140: "caption", "comment").enterSub(
141: QueryOperatorNode.Operator.AND).condition("caption",
142: PropertyValueComparator.LIKE, "test caption%")
143: .condition("comment", PropertyValueComparator.LIKE,
144: "folder comment%").closeSub().getResult();
145: assert result.getRowCount() == 25 : "Expected to fetch 25 rows, got: "
146: + result.getRowCount();
147: assert result.getColumnIndex("co.caption") == 1 : "Unexpected column index for co.caption: "
148: + result.getColumnIndex("co.caption");
149: assert result.getColumnIndex("co.comment") == 2 : "Unexpected column index for co.comment: "
150: + result.getColumnIndex("co.comment");
151: for (int i = 1; i <= result.getRowCount(); i++) {
152: assert result.getString(i, 1).startsWith("test caption") : "Unexpected column value: "
153: + result.getString(i, 1);
154: assert result.getString(i, 2).startsWith("folder comment") : "Unexpected column value: "
155: + result.getString(i, 2);
156: }
157: }
158:
159: @Test
160: public void simpleNestedQueryTest() throws FxApplicationException {
161: final FxResultSet result = new SqlQueryBuilder().select(
162: "caption").andSub().condition("caption",
163: PropertyValueComparator.LIKE, "test caption%").orSub()
164: .condition("comment", PropertyValueComparator.LIKE,
165: "folder comment 1").condition("comment",
166: PropertyValueComparator.LIKE,
167: "folder comment 2").closeSub().getResult();
168: assert result.getRowCount() == 2 : "Expected to fetch 2 rows, got: "
169: + result.getRowCount();
170: for (int i = 1; i <= 2; i++) {
171: assert result.getString(i, 1).matches("test caption [12]") : "Unexpected column value: "
172: + result.getString(i, 1);
173: }
174: }
175:
176: /**
177: * Check if the SQL search for empty string properties works.
178: *
179: * @throws FxApplicationException if the search failed
180: */
181: @Test
182: public void stringEmptyQuery() throws FxApplicationException {
183: new SqlQueryBuilder().condition("caption",
184: PropertyValueComparator.EMPTY, null).getResult();
185: new SqlQueryBuilder().condition("caption",
186: PropertyValueComparator.NOT_EMPTY, null).getResult();
187: new SqlQueryBuilder().condition("caption",
188: PropertyValueComparator.EMPTY, null).orSub().condition(
189: "caption", PropertyValueComparator.EMPTY, null)
190: .condition("caption",
191: PropertyValueComparator.NOT_EMPTY, null)
192: .closeSub().getResult();
193: }
194:
195: @Test
196: public void selectUserTest() throws FxApplicationException {
197: for (FxResultRow row : new SqlQueryBuilder().select(
198: "created_by", "created_by.username").getResult()
199: .getResultRows()) {
200: final Account account = EJBLookup.getAccountEngine().load(
201: ((FxLargeNumber) row.getFxValue(1))
202: .getDefaultTranslation());
203: assertEquals(row.getFxValue(2).getDefaultTranslation(),
204: account.getName());
205: }
206: }
207:
208: @Test
209: public void filterByTypeTest() throws FxApplicationException {
210: final FxResultSet result = new SqlQueryBuilder().select(
211: "typedef").filterType("FOLDER").getResult();
212: assert result.getRowCount() > 0;
213: final FxType folderType = CacheAdmin.getEnvironment().getType(
214: "FOLDER");
215: for (FxResultRow row : result.getResultRows()) {
216: assert folderType.getId() == ((FxLargeNumber) row
217: .getValue(1)).getBestTranslation() : "Unexpected result type: "
218: + row.getValue(1)
219: + ", expected: "
220: + folderType.getId();
221: }
222: }
223:
224: @Test
225: public void briefcaseQueryTest() throws FxApplicationException {
226: // create briefcase
227: final String selectFolders = new SqlQueryBuilder().filterType(
228: "FOLDER").getQuery();
229: final FxSQLSearchParams params = new FxSQLSearchParams()
230: .saveResultInBriefcase("test briefcase", "description",
231: (Long) null);
232: final FxResultSet result = EJBLookup.getSearchEngine().search(
233: selectFolders, 0, Integer.MAX_VALUE, params);
234: long bcId = result.getCreatedBriefcaseId();
235: try {
236: assert result.getRowCount() > 0;
237: assert result.getCreatedBriefcaseId() != -1 : "Briefcase should have been created, but no ID returned.";
238:
239: // select briefcase
240: final FxResultSet briefcase = new SqlQueryBuilder()
241: .filterBriefcase(result.getCreatedBriefcaseId())
242: .getResult();
243: assert briefcase.getRowCount() > 0 : "Empty briefcase returned, but getResult returned "
244: + result.getRowCount() + " rows.";
245: } finally {
246: EJBLookup.getBriefcaseEngine().remove(bcId);
247: }
248: }
249:
250: @Test
251: public void typeConditionTest() throws FxApplicationException {
252: final FxResultSet result = new SqlQueryBuilder().select(
253: "typedef").type("CONTACTDATA").getResult();
254: final FxType cdType = CacheAdmin.getEnvironment().getType(
255: "CONTACTDATA");
256: assert result.getRowCount() > 0;
257: for (FxResultRow row : result.getResultRows()) {
258: assert ((FxLargeNumber) row.getFxValue(1))
259: .getDefaultTranslation() == cdType.getId() : "Unexpected type in result, expected "
260: + cdType.getId() + ", was: " + row.getFxValue(1);
261: }
262: }
263:
264: /**
265: * Generic tests on the SearchTest type.
266: *
267: * @param name the base property name
268: * @param dataType the datatype of the property
269: * @throws com.flexive.shared.exceptions.FxApplicationException
270: * on search engine errors
271: */
272: @Test(dataProvider="testProperties")
273: public void genericSelectTest(String name, FxDataType dataType)
274: throws FxApplicationException {
275: // also select virtual properties to make sure they don't mess up the result
276: final FxResultSet result = new SqlQueryBuilder().select(
277: getTestPropertyName(name)).type(TEST_TYPE).getResult();
278: assert result.getRowCount() == testInstanceCount : "Expected all test instances to be returned, got "
279: + result.getRowCount()
280: + " instead of "
281: + testInstanceCount;
282: final int idx = 1;
283: for (FxResultRow row : result.getResultRows()) {
284: assert dataType.getValueClass().isAssignableFrom(
285: row.getFxValue(idx).getClass()) : "Invalid class returned for datatype "
286: + dataType
287: + ": "
288: + row.getFxValue(idx).getClass()
289: + " instead of " + dataType.getValueClass();
290: assert row.getFxValue(idx).getXPathName() != null : "XPath was null";
291: assert row.getFxValue(idx).getXPathName().equalsIgnoreCase(
292: getTestPropertyName(name)) : "Invalid property name: "
293: + row.getFxValue(idx).getXPathName()
294: + ", expected: " + getTestPropertyName(name);
295: }
296: }
297:
298: @Test
299: public void selectVirtualPropertiesTest()
300: throws FxApplicationException {
301: final FxResultSet result = new SqlQueryBuilder().select("@pk",
302: "@path", "@node_position",
303: getTestPropertyName("string")).type(TEST_TYPE)
304: .getResult();
305: final int idx = 4;
306: for (FxResultRow row : result.getResultRows()) {
307: assert getTestPropertyName("string").equalsIgnoreCase(
308: row.getFxValue(idx).getXPathName()) : "Invalid property name from XPath: "
309: + row.getFxValue(idx).getXPathName()
310: + ", expected: " + getTestPropertyName("string");
311: }
312: }
313:
314: @Test(dataProvider="testProperties")
315: public void orderByTest(String name, FxDataType dataType)
316: throws FxApplicationException {
317: final FxResultSet result = new SqlQueryBuilder().select("@pk",
318: getTestPropertyName(name)).type(TEST_TYPE).orderBy(2,
319: SortDirection.ASCENDING).getResult();
320: assert result.getRowCount() > 0;
321: assertAscendingOrder(result, 2);
322: }
323:
324: @Test
325: public void orderByResultPreferencesTest()
326: throws FxApplicationException {
327: setResultPreferences(SortDirection.ASCENDING);
328: final FxResultSet result = new SqlQueryBuilder().select("@pk",
329: getTestPropertyName("string")).filterType(TEST_TYPE)
330: .getResult();
331: assertAscendingOrder(result, 2);
332:
333: setResultPreferences(SortDirection.DESCENDING);
334: final FxResultSet descendingResult = new SqlQueryBuilder()
335: .select("@pk", getTestPropertyName("string"))
336: .filterType(TEST_TYPE).getResult();
337: assertDescendingOrder(descendingResult, 2);
338: }
339:
340: private void setResultPreferences(SortDirection sortDirection)
341: throws FxApplicationException {
342: final ResultPreferencesEdit prefs = new ResultPreferencesEdit(
343: new ArrayList<ResultColumnInfo>(0), Arrays
344: .asList(new ResultOrderByInfo(Table.CONTENT,
345: getTestPropertyName("string"), "",
346: sortDirection)), 25, 100);
347: EJBLookup.getResultPreferencesEngine().save(prefs,
348: CacheAdmin.getEnvironment().getType(TEST_TYPE).getId(),
349: ResultViewType.LIST, AdminResultLocations.DEFAULT);
350: }
351:
352: /**
353: * Tests all available value comparators for the given datatype. Note that no semantic
354: * tests are performed, each comparator is executed with a random value.
355: *
356: * @param name the base property name
357: * @param dataType the datatype of the property
358: * @throws com.flexive.shared.exceptions.FxApplicationException
359: * on search engine errors
360: */
361: @Test(dataProvider="testProperties")
362: public void genericConditionTest(String name, FxDataType dataType)
363: throws FxApplicationException {
364: final FxPropertyAssignment assignment = getTestPropertyAssignment(name);
365: final Random random = new Random(0);
366:
367: // need to get some folder IDs for the reference property
368: final List<FxPK> folderPks = new SqlQueryBuilder()
369: .select("@pk").type("folder").getResult()
370: .collectColumn(1);
371:
372: for (PropertyValueComparator comparator : PropertyValueComparator
373: .getAvailable(dataType)) {
374: for (String prefix : new String[] { TEST_TYPE + "/",
375: TEST_TYPE + "/groupTop/",
376: TEST_TYPE + "/groupTop/groupNested/" }) {
377: final String assignmentName = prefix
378: + getTestPropertyName(name);
379: try {
380: // submit a query with the given property/comparator combination
381: final FxValue value;
382: switch (dataType) {
383: case Reference:
384: value = new FxReference(new ReferencedContent(
385: folderPks.get(random.nextInt(folderPks
386: .size()))));
387: break;
388: case DateRange:
389: // a query is always performed against a particular date, but not a date range
390: value = new FxDate(new Date());
391: break;
392: case DateTimeRange:
393: value = new FxDateTime(new Date());
394: break;
395: default:
396: value = dataType.getRandomValue(random,
397: assignment);
398: }
399: new SqlQueryBuilder().condition(assignmentName,
400: comparator, value).getResult();
401: // no exception thrown, consider it a success
402: } catch (Exception e) {
403: assert false : "Failed to submit for property "
404: + dataType + " with comparator "
405: + comparator + ":\n" + e.getMessage()
406: + ", thrown at:\n"
407: + StringUtils.join(e.getStackTrace(), '\n');
408: }
409: }
410: }
411: }
412:
413: /**
414: * Tests relative comparators like < and == for all datatypes that support them.
415: *
416: * @param name the base property name
417: * @param dataType the datatype of the property
418: * @throws com.flexive.shared.exceptions.FxApplicationException
419: * on search engine errors
420: */
421: @Test(dataProvider="testProperties")
422: public void genericRelativeComparatorsTest(String name,
423: FxDataType dataType) throws FxApplicationException {
424: final String propertyName = getTestPropertyName(name);
425:
426: for (PropertyValueComparator comparator : PropertyValueComparator
427: .getAvailable(dataType)) {
428: if (!(comparator.equals(PropertyValueComparator.EQ)
429: || comparator.equals(PropertyValueComparator.GE)
430: || comparator.equals(PropertyValueComparator.GT)
431: || comparator.equals(PropertyValueComparator.LE) || comparator
432: .equals(PropertyValueComparator.LT))) {
433: continue;
434: }
435: final FxValue value = getTestValue(name, comparator);
436: final SqlQueryBuilder builder = new SqlQueryBuilder()
437: .select("@pk", propertyName).condition(
438: propertyName, comparator, value);
439: final FxResultSet result = builder.getResult();
440: assert result.getRowCount() > 0 : "Cannot test on empty result sets, query=\n"
441: + builder.getQuery();
442: for (FxResultRow row : result.getResultRows()) {
443: final FxValue rowValue = row.getFxValue(2);
444: switch (comparator) {
445: case EQ:
446: assert rowValue.compareTo(value) == 0 : "Result value "
447: + rowValue
448: + " is not equal to "
449: + value
450: + " (compareTo = "
451: + rowValue.compareTo(value) + ")";
452: assert rowValue.getBestTranslation().equals(
453: value.getBestTranslation()) : "Result value "
454: + rowValue + " is not equal to " + value;
455: break;
456: case LT:
457: assert rowValue.compareTo(value) < 0 : "Result value "
458: + rowValue + " is not less than " + value;
459: break;
460: case LE:
461: assert rowValue.compareTo(value) <= 0 : "Result value "
462: + rowValue
463: + " is not less or equal to "
464: + value;
465: break;
466: case GT:
467: assert rowValue.compareTo(value) > 0 : "Result value "
468: + rowValue
469: + " is not greater than "
470: + value;
471: break;
472: case GE:
473: assert rowValue.compareTo(value) >= 0 : "Result value "
474: + rowValue
475: + " is not greater or equal to "
476: + value;
477: break;
478: default:
479: assert false : "Invalid comparator: " + comparator;
480: }
481: }
482: }
483: }
484:
485: /**
486: * Finds a FxValue of the test instances that matches some of the result rows
487: * for the given comparator, but not all or none.
488: *
489: * @param name the test property name
490: * @param comparator the comparator
491: * @return a value that matches some rows
492: * @throws FxApplicationException on search engine errors
493: */
494: private FxValue getTestValue(String name,
495: PropertyValueComparator comparator)
496: throws FxApplicationException {
497: final FxResultSet result = new SqlQueryBuilder().select(
498: getTestPropertyName(name)).type(TEST_TYPE).getResult();
499: final List<FxValue> values = result.collectColumn(1);
500: assert values.size() == testInstanceCount : "Expected "
501: + testInstanceCount + " rows, got: " + values.size();
502: for (FxValue value : values) {
503: if (value == null || value.isEmpty()) {
504: continue;
505: }
506: int match = 0; // number of matched values for the given comparator
507: int count = 0; // number of values checked so far
508: for (FxValue value2 : values) {
509: if (value2 == null || value2.isEmpty()) {
510: continue;
511: }
512: count++;
513: switch (comparator) {
514: case EQ:
515: if (value.getBestTranslation().equals(
516: value2.getBestTranslation())) {
517: match++;
518: }
519: break;
520: case LT:
521: if (value2.compareTo(value) < 0) {
522: match++;
523: }
524: break;
525: case LE:
526: if (value2.compareTo(value) <= 0) {
527: match++;
528: }
529: break;
530: case GT:
531: if (value2.compareTo(value) > 0) {
532: match++;
533: }
534: break;
535: case GE:
536: if (value2.compareTo(value) >= 0) {
537: match++;
538: }
539: break;
540: default:
541: assert false : "Cannot check relative ordering for comparator "
542: + comparator;
543: }
544: if (match > 0 && count > match) {
545: // this value is matched by _some_ other row values, so it's suitable as test input
546: if (value instanceof FxDateRange) {
547: // daterange checks are performed against an actual date, not another range
548: return new FxDate(((FxDateRange) value)
549: .getBestTranslation().getLower());
550: } else if (value instanceof FxDateTimeRange) {
551: // see above
552: return new FxDateTime(((FxDateTimeRange) value)
553: .getBestTranslation().getLower());
554: }
555: return value;
556: }
557: }
558: }
559: throw new IllegalArgumentException(
560: "Failed to find a suitable test value for property "
561: + getTestPropertyName(name)
562: + " and comparator " + comparator);
563: }
564:
565: @Test
566: public void aclSelectorTest() throws FxApplicationException {
567: final FxResultSet result = new SqlQueryBuilder().select("@pk",
568: "acl", "acl.label", "acl.name", "acl.mandator",
569: "acl.description", "acl.cat_type", "acl.color",
570: "acl.created_by", "acl.created_at", "acl.modified_by",
571: "acl.modified_at").getResult();
572: assert result.getRowCount() > 0;
573: for (FxResultRow row : result.getResultRows()) {
574: final ACL acl = CacheAdmin.getEnvironment().getACL(
575: row.getLong("acl"));
576: final FxContent content = EJBLookup.getContentEngine()
577: .load(row.getPk(1));
578: assert content.getAclId() == acl.getId() : "Invalid ACL for instance "
579: + row.getPk(1)
580: + ": "
581: + acl.getId()
582: + ", content engine returned " + content.getAclId();
583:
584: // check label
585: assert acl.getLabel().getBestTranslation().equals(
586: row.getFxValue("acl.label").getBestTranslation()) : "Invalid ACL label '"
587: + row.getValue(3)
588: + "', expected: '"
589: + acl.getLabel() + "'";
590:
591: // check fields selected directly from the ACL table
592: assertEquals(row.getString("acl.name"), (Object) acl
593: .getName(), "Invalid value for field: name");
594: assertEquals(row.getLong("acl.mandator"), (Object) acl
595: .getMandatorId(),
596: "Invalid value for field: mandator");
597: assertEquals(row.getString("acl.description"), (Object) acl
598: .getDescription(),
599: "Invalid value for field: description");
600: assertEquals(row.getInt("acl.cat_type"), (Object) acl
601: .getCategory().getId(),
602: "Invalid value for field: category");
603: assertEquals(row.getString("acl.color"), (Object) acl
604: .getColor(), "Invalid value for field: color");
605: checkLifecycleInfo(row, "acl", acl.getLifeCycleInfo());
606: }
607: }
608:
609: @Test
610: public void stepSelectorTest() throws FxApplicationException {
611: final FxResultSet result = new SqlQueryBuilder().select("@pk",
612: "step", "step.label", "step.id", "step.stepdef",
613: "step.workflow", "step.acl").getResult();
614: assert result.getRowCount() > 0;
615: for (FxResultRow row : result.getResultRows()) {
616: final Step step = CacheAdmin.getEnvironment().getStep(
617: row.getLong("step"));
618: final StepDefinition definition = CacheAdmin
619: .getEnvironment().getStepDefinition(
620: step.getStepDefinitionId());
621: assert definition.getLabel().getBestTranslation().equals(
622: row.getFxValue("step.label").getBestTranslation()) : "Invalid step label '"
623: + row.getValue(3)
624: + "', expected: '"
625: + definition.getLabel() + "'";
626: final FxContent content = EJBLookup.getContentEngine()
627: .load(row.getPk(1));
628: assert content.getStepId() == step.getId() : "Invalid step for instance "
629: + row.getPk(1)
630: + ": "
631: + step.getId()
632: + ", content engine returned "
633: + content.getStepId();
634:
635: // check fields selected from the ACL table
636: assertEquals(row.getLong("step.id"), step.getId(),
637: "Invalid value for field: id");
638: assertEquals(row.getLong("step.stepdef"), step
639: .getStepDefinitionId(),
640: "Invalid value for field: stepdef");
641: assertEquals(row.getLong("step.workflow"), step
642: .getWorkflowId(),
643: "Invalid value for field: workflow");
644: assertEquals(row.getLong("step.acl"), step.getAclId(),
645: "Invalid value for field: acl");
646: }
647: }
648:
649: @Test
650: public void mandatorSelectorTest() throws FxApplicationException {
651: final FxResultSet result = new SqlQueryBuilder().select("@pk",
652: "mandator", "mandator.id", "mandator.metadata",
653: "mandator.is_active", "mandator.created_by",
654: "mandator.created_at", "mandator.modified_by",
655: "mandator.modified_at").getResult();
656: assert result.getRowCount() > 0;
657: for (FxResultRow row : result.getResultRows()) {
658: final Mandator mandator = CacheAdmin.getEnvironment()
659: .getMandator(row.getLong("mandator"));
660: final FxContent content = EJBLookup.getContentEngine()
661: .load(row.getPk(1));
662:
663: assertEquals(mandator.getId(), content.getMandatorId(),
664: "Search returned different mandator than content engine");
665: assertEquals(row.getLong("mandator.id"), mandator.getId(),
666: "Invalid value for field: id");
667: assertEquals(
668: row.getValue("mandator.metadata") != null ? row
669: .getLong("mandator.metadata") : -1,
670: mandator.getMetadataId(),
671: "Invalid value for field: metadata");
672: assertEquals(row.getLong("mandator.is_active"), mandator
673: .isActive() ? 1 : 0,
674: "Invalid value for field: is_active");
675: checkLifecycleInfo(row, "mandator", mandator
676: .getLifeCycleInfo());
677: }
678: }
679:
680: @Test
681: public void accountSelectorTest() throws FxApplicationException {
682: for (String name : new String[] { "created_by", "modified_by" }) {
683: final FxResultSet result = new SqlQueryBuilder().select(
684: "@pk", name, name + ".mandator",
685: name + ".username", name + ".password",
686: name + ".email", name + ".contact_id",
687: name + ".valid_from", name + ".valid_to",
688: name + ".description", name + ".created_by",
689: name + ".created_at", name + ".modified_by",
690: name + ".modified_at", name + ".is_active",
691: name + ".is_validated", name + ".lang",
692: name + ".login_name", name + ".allow_multilogin",
693: name + ".default_node").maxRows(10).getResult();
694: assert result.getRowCount() == 10 : "Expected 10 result rows";
695: for (FxResultRow row : result.getResultRows()) {
696: final Account account = EJBLookup.getAccountEngine()
697: .load(row.getLong(name));
698: assertEquals(row.getString(name + ".username"), account
699: .getName(), "Invalid value for field: username");
700: assertEquals(row.getString(name + ".login_name"),
701: account.getLoginName(),
702: "Invalid value for field: login_name");
703: assertEquals(row.getString(name + ".email"), account
704: .getEmail(), "Invalid value for field: email");
705: assertEquals(row.getLong(name + ".contact_id"), account
706: .getContactDataId(),
707: "Invalid value for field: contact_id");
708: assertEquals(row.getLong(name + ".is_active"), account
709: .isActive() ? 1 : 0,
710: "Invalid value for field: is_active");
711: assertEquals(row.getLong(name + ".is_validated"),
712: account.isValidated() ? 1 : 0,
713: "Invalid value for field: is_validated");
714: assertEquals(row.getLong(name + ".allow_multilogin"),
715: account.isAllowMultiLogin() ? 1 : 0,
716: "Invalid value for field: allow_multilogin");
717: assertEquals(row.getLong(name + ".lang"), account
718: .getLanguage().getId(),
719: "Invalid value for field: lang");
720: // default_node is not supported yet
721: //assertEquals(row.getLong(name + ".default_node"), account.getDefaultNode(), "Invalid value for field: default_node");
722: checkLifecycleInfo(row, name, account
723: .getLifeCycleInfo());
724: }
725: }
726: }
727:
728: private void checkLifecycleInfo(FxResultRow row, String baseName,
729: LifeCycleInfo lifeCycleInfo) {
730: assertEquals(row.getLong(baseName + ".created_by"),
731: lifeCycleInfo.getCreatorId(),
732: "Invalid value for field: created_by");
733: assertEquals(row.getDate(baseName + ".created_at").getTime(),
734: lifeCycleInfo.getCreationTime(),
735: "Invalid value for field: id");
736: assertEquals(row.getLong(baseName + ".modified_by"),
737: lifeCycleInfo.getModificatorId(),
738: "Invalid value for field: modified_by");
739: assertEquals(row.getDate(baseName + ".modified_at").getTime(),
740: lifeCycleInfo.getModificationTime(),
741: "Invalid value for field: modified_at");
742: }
743:
744: @Test
745: public void treeSelectorTest() throws FxApplicationException {
746: final FxResultSet result = new SqlQueryBuilder().select("@pk",
747: "@path").isChild(FxTreeNode.ROOT_NODE).getResult();
748: assert result.getRowCount() > 0;
749: for (FxResultRow row : result.getResultRows()) {
750: final List<FxPaths.Path> paths = row.getPaths(2);
751: assert paths.size() > 0 : "Returned no path information for content "
752: + row.getPk(1);
753: for (FxPaths.Path path : paths) {
754: assert path.getItems().size() > 0 : "Empty path returned";
755: final FxPaths.Item leaf = path.getItems().get(
756: path.getItems().size() - 1);
757: assert leaf.getReferenceId() == row.getPk(1).getId() : "Expected reference ID "
758: + row.getPk(1)
759: + ", got: "
760: + leaf.getReferenceId()
761: + " (nodeId="
762: + leaf.getNodeId() + ")";
763:
764: final String treePath = StringUtils.join(EJBLookup
765: .getTreeEngine().getLabels(FxTreeMode.Edit,
766: leaf.getNodeId()), '/');
767: assert treePath.equals(path.getCaption()) : "Unexpected tree path '"
768: + path.getCaption()
769: + "', expected: '"
770: + treePath + "'";
771:
772: }
773: }
774: // test selection via node path
775: final FxResultSet pathResult = new SqlQueryBuilder().select(
776: "@pk", "@path").isChild("/").getResult();
777: assert pathResult.getRowCount() == result.getRowCount() : "Path select returned "
778: + pathResult.getRowCount()
779: + " rows, select by ID returned "
780: + result.getRowCount() + " rows.";
781: // query a leaf node
782: new SqlQueryBuilder().select("@pk").isChild(
783: EJBLookup.getTreeEngine().getPathById(FxTreeMode.Edit,
784: pathResult.getResultRow(0).getPk(1).getId()));
785: }
786:
787: @Test
788: public void fulltextSearchTest() throws FxApplicationException {
789: final FxResultSet result = new SqlQueryBuilder().select("@pk",
790: getTestPropertyName("string")).type(TEST_TYPE).maxRows(
791: 1).getResult();
792: assert result.getRowCount() == 1 : "Expected only one result, got: "
793: + result.getRowCount();
794:
795: // perform a fulltext query against the first word
796: final FxPK pk = result.getResultRow(0).getPk(1);
797: final String[] words = StringUtils.split(((FxString) result
798: .getResultRow(0).getFxValue(2)).getBestTranslation(),
799: ' ');
800: assert words.length > 0;
801: assert words[0].length() > 0 : "Null length word: " + words[0];
802: final FxResultSet ftresult = new SqlQueryBuilder()
803: .select("@pk").fulltext(words[0]).getResult();
804: assert ftresult.getRowCount() > 0 : "Expected at least one result for fulltext query '"
805: + words[0] + "'";
806: assert ftresult.collectColumn(1).contains(pk) : "Didn't find pk "
807: + pk + " in result, got: " + ftresult.collectColumn(1);
808: }
809:
810: @Test
811: public void versionFilterTest() throws FxApplicationException {
812: final List<FxPK> allVersions = getPksForVersion(VersionFilter.ALL);
813: final List<FxPK> liveVersions = getPksForVersion(VersionFilter.LIVE);
814: final List<FxPK> maxVersions = getPksForVersion(VersionFilter.MAX);
815: assert allVersions.size() > 0 : "All versions result must not be empty";
816: assert liveVersions.size() > 0 : "Live versions result must not be empty";
817: assert maxVersions.size() > 0 : "Max versions result must not be empty";
818: assert allVersions.size() > liveVersions.size() : "Expected more than only live versions";
819: assert allVersions.size() > maxVersions.size() : "Expected more than only max versions";
820: assert !CollectionUtils.isEqualCollection(liveVersions,
821: maxVersions) : "Expected different results for max and live version filter";
822: for (FxPK pk : liveVersions) {
823: final FxContent content = EJBLookup.getContentEngine()
824: .load(pk);
825: assert content.isLiveVersion() : "Expected live version for "
826: + pk;
827: }
828: for (FxPK pk : maxVersions) {
829: final FxContent content = EJBLookup.getContentEngine()
830: .load(pk);
831: assert content.isMaxVersion() : "Expected max version for "
832: + pk;
833: assert content.getVersion() == 1
834: || !content.isLiveVersion();
835: }
836: }
837:
838: @Test
839: public void lastContentChangeTest() throws FxApplicationException {
840: final long lastContentChange = EJBLookup.getSearchEngine()
841: .getLastContentChange(false);
842: assert lastContentChange > 0;
843: final FxContent content = EJBLookup.getContentEngine()
844: .initialize(TEST_TYPE);
845: content.setValue("/" + getTestPropertyName("string"),
846: new FxString(false, "lastContentChangeTest"));
847: FxPK pk = null;
848: try {
849: assert EJBLookup.getSearchEngine().getLastContentChange(
850: false) == lastContentChange : "Didn't touch contents, but lastContentChange timestamp was increased";
851: pk = EJBLookup.getContentEngine().save(content);
852: assert EJBLookup.getSearchEngine().getLastContentChange(
853: false) > lastContentChange : "Saved content, but lastContentChange timestamp was not increased: "
854: + EJBLookup.getSearchEngine().getLastContentChange(
855: false);
856: } finally {
857: if (pk != null) {
858: EJBLookup.getContentEngine().remove(pk);
859: }
860: }
861: }
862:
863: @Test
864: public void lastContentChangeTreeTest()
865: throws FxApplicationException {
866: final long lastContentChange = EJBLookup.getSearchEngine()
867: .getLastContentChange(false);
868: assert lastContentChange > 0;
869: final long nodeId = EJBLookup.getTreeEngine().save(
870: FxTreeNodeEdit.createNew("bla"));
871: try {
872: final long editContentChange = EJBLookup.getSearchEngine()
873: .getLastContentChange(false);
874: assert editContentChange > lastContentChange : "Saved content, but lastContentChange timestamp was not increased: "
875: + editContentChange;
876: EJBLookup.getTreeEngine().activate(FxTreeMode.Edit, nodeId,
877: false);
878: assert EJBLookup.getSearchEngine().getLastContentChange(
879: true) > editContentChange : "Activated content, but live mode lastContentChange timestamp was not increased: "
880: + EJBLookup.getSearchEngine().getLastContentChange(
881: true);
882: assert EJBLookup.getSearchEngine().getLastContentChange(
883: false) == editContentChange : "Edit tree didn't change, but lastContentChange timestamp was updated";
884: } finally {
885: try {
886: EJBLookup.getTreeEngine().remove(
887: EJBLookup.getTreeEngine().getNode(
888: FxTreeMode.Edit, nodeId), true, false);
889: } catch (FxApplicationException e) {
890: // pass
891: }
892: try {
893: EJBLookup.getTreeEngine().remove(
894: EJBLookup.getTreeEngine().getNode(
895: FxTreeMode.Live, nodeId), true, false);
896: } catch (FxApplicationException e) {
897: // pass
898: }
899: }
900: }
901:
902: private List<FxPK> getPksForVersion(VersionFilter versionFilter)
903: throws FxApplicationException {
904: return new SqlQueryBuilder().select("@pk").type(TEST_TYPE)
905: .filterVersion(versionFilter).getResult()
906: .collectColumn(1);
907: }
908:
909: @DataProvider(name="testProperties")
910: public Object[][] getTestProperties() {
911: final Object[][] result = new Object[TEST_PROPS.size()][];
912: int ctr = 0;
913: for (Map.Entry<String, FxDataType> entry : TEST_PROPS
914: .entrySet()) {
915: result[ctr++] = new Object[] { entry.getKey(),
916: entry.getValue() };
917: }
918: return result;
919: }
920:
921: private String getTestPropertyName(String baseName) {
922: return baseName + TEST_SUFFIX;
923: }
924:
925: private FxPropertyAssignment getTestPropertyAssignment(
926: String baseName) {
927: return (FxPropertyAssignment) CacheAdmin
928: .getEnvironment()
929: .getAssignment(
930: TEST_TYPE + "/" + getTestPropertyName(baseName));
931: }
932:
933: private void assertAscendingOrder(FxResultSet result, int column) {
934: assertOrder(result, column, true);
935: }
936:
937: private void assertDescendingOrder(FxResultSet result, int column) {
938: assertOrder(result, column, false);
939: }
940:
941: private void assertOrder(FxResultSet result, int column,
942: boolean ascending) {
943: FxValue oldValue = null;
944: for (FxResultRow row : result.getResultRows()) {
945: // check order
946: assert oldValue == null
947: || (ascending ? row.getFxValue(column).compareTo(
948: oldValue) >= 0 : row.getFxValue(column)
949: .compareTo(oldValue) <= 0) : row
950: .getFxValue(column)
951: + " is not "
952: + (ascending ? "greater" : "less")
953: + " than " + oldValue;
954: oldValue = row.getFxValue(column);
955: }
956: }
957:
958: }
|