001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.search.test;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.search.Hits;
019    import com.liferay.portal.kernel.search.SearchContext;
020    import com.liferay.portal.kernel.test.IdempotentRetryAssert;
021    import com.liferay.portal.kernel.test.util.SearchContextTestUtil;
022    import com.liferay.portal.kernel.test.util.ServiceContextTestUtil;
023    import com.liferay.portal.kernel.util.CharPool;
024    import com.liferay.portal.kernel.util.ListUtil;
025    import com.liferay.portal.kernel.util.LocaleUtil;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.kernel.util.StringUtil;
028    import com.liferay.portal.model.BaseModel;
029    import com.liferay.portal.model.Group;
030    import com.liferay.portal.service.ServiceContext;
031    import com.liferay.portlet.asset.AssetRendererFactoryRegistryUtil;
032    import com.liferay.portlet.asset.model.AssetEntry;
033    import com.liferay.portlet.asset.model.AssetRenderer;
034    import com.liferay.portlet.asset.model.AssetRendererFactory;
035    import com.liferay.portlet.asset.model.DDMFormValuesReader;
036    import com.liferay.portlet.asset.service.persistence.AssetEntryQuery;
037    import com.liferay.portlet.asset.service.persistence.test.AssetEntryQueryTestUtil;
038    import com.liferay.portlet.asset.util.AssetUtil;
039    import com.liferay.portlet.dynamicdatamapping.model.DDMForm;
040    import com.liferay.portlet.dynamicdatamapping.model.DDMFormField;
041    import com.liferay.portlet.dynamicdatamapping.model.DDMFormFieldOptions;
042    import com.liferay.portlet.dynamicdatamapping.model.DDMFormFieldType;
043    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
044    import com.liferay.portlet.dynamicdatamapping.model.DDMTemplate;
045    import com.liferay.portlet.dynamicdatamapping.model.Value;
046    import com.liferay.portlet.dynamicdatamapping.render.ValueAccessor;
047    import com.liferay.portlet.dynamicdatamapping.storage.DDMFormFieldValue;
048    import com.liferay.portlet.dynamicdatamapping.storage.DDMFormValues;
049    import com.liferay.portlet.dynamicdatamapping.storage.FieldConstants;
050    import com.liferay.portlet.dynamicdatamapping.util.DDMIndexerUtil;
051    import com.liferay.portlet.dynamicdatamapping.util.test.DDMStructureTestUtil;
052    import com.liferay.portlet.dynamicdatamapping.util.test.DDMTemplateTestUtil;
053    
054    import java.util.List;
055    import java.util.Locale;
056    import java.util.Map;
057    import java.util.concurrent.Callable;
058    import java.util.concurrent.TimeUnit;
059    
060    import org.apache.commons.lang.ArrayUtils;
061    
062    import org.junit.Assert;
063    
064    /**
065     * @author Preston Crary
066     * @author Andr?? de Oliveira
067     */
068    public abstract class TestOrderHelper {
069    
070            public void testOrderByDDMBooleanField() throws Exception {
071                    testOrderByDDMField(
072                            new String[] {"false", "true", "false", "true"},
073                            new String[] {"false", "false", "true", "true"},
074                            FieldConstants.BOOLEAN, DDMFormFieldType.CHECKBOX);
075            }
076    
077            public void testOrderByDDMBooleanFieldRepeatable() throws Exception {
078                    testOrderByDDMFieldRepeatable(
079                            new String[] {
080                                    "true|true", "false|false", "true|true", "false|false"
081                            },
082                            new String[] {
083                                    "false|false", "false|false", "true|true", "true|true"
084                            },
085                            FieldConstants.BOOLEAN, DDMFormFieldType.CHECKBOX);
086            }
087    
088            public void testOrderByDDMIntegerField() throws Exception {
089                    testOrderByDDMField(
090                            new String[] {"1", "10", "3", "2"},
091                            new String[] {"1", "2", "3", "10"}, FieldConstants.INTEGER,
092                            DDMFormFieldType.INTEGER);
093            }
094    
095            public void testOrderByDDMIntegerFieldRepeatable() throws Exception {
096                    testOrderByDDMFieldRepeatable(
097                            new String[] {"50", "707|25", "1|99|42"},
098                            new String[] {"1|99|42", "707|25", "50"}, FieldConstants.INTEGER,
099                            DDMFormFieldType.INTEGER);
100            }
101    
102            public void testOrderByDDMNumberField() throws Exception {
103                    testOrderByDDMField(
104                            new String[] {"3", "3.14", "12.34", "2.72", "1.41", "23.45", "20"},
105                            new String[] {"1.41", "2.72", "3", "3.14", "12.34", "20", "23.45"},
106                            FieldConstants.NUMBER, DDMFormFieldType.NUMBER);
107            }
108    
109            public void testOrderByDDMNumberFieldRepeatable() throws Exception {
110                    testOrderByDDMFieldRepeatable(
111                            new String[] {"20|12.34", "16.0", "3.14"},
112                            new String[] {"3.14", "20|12.34", "16.0"}, FieldConstants.NUMBER,
113                            DDMFormFieldType.NUMBER);
114            }
115    
116            public void testOrderByDDMRadioField() throws Exception {
117                    testOrderByDDMRadioField("text");
118            }
119    
120            public void testOrderByDDMRadioFieldKeyword() throws Exception {
121                    testOrderByDDMRadioField("keyword");
122            }
123    
124            public void testOrderByDDMTextField() throws Exception {
125                    testOrderByDDMTextField("text");
126            }
127    
128            public void testOrderByDDMTextFieldKeyword() throws Exception {
129                    testOrderByDDMTextField("keyword");
130            }
131    
132            public void testOrderByDDMTextFieldRepeatable() throws Exception {
133                    testOrderByDDMFieldRepeatable(
134                            new String[] {"B", "X|Y", "D|A|C|Z"},
135                            new String[] {"D|A|C|Z", "B", "X|Y"}, "string",
136                            DDMFormFieldType.TEXT);
137            }
138    
139            protected static String[] toJsonArrays(String ... strings) {
140                    String[] jsonArrays = new String[strings.length];
141    
142                    for (int i = 0; i < strings.length; i++) {
143                            jsonArrays[i] = "[\"" + strings[i] + "\"]";
144                    }
145    
146                    return jsonArrays;
147            }
148    
149            protected TestOrderHelper(Group group) throws Exception {
150                    _group = group;
151    
152                    _serviceContext = ServiceContextTestUtil.getServiceContext(
153                            group.getGroupId());
154            }
155    
156            protected DDMStructure addDDMStructure() throws Exception {
157                    DDMForm ddmForm = DDMStructureTestUtil.getSampleDDMForm(
158                            "name", _dataType, _indexType, _repeatable, _type,
159                            new Locale[] {LocaleUtil.US}, LocaleUtil.US);
160    
161                    setDDMFormFieldOptions(ddmForm);
162    
163                    return DDMStructureTestUtil.addStructure(
164                            _serviceContext.getScopeGroupId(),
165                            getSearchableAssetEntryStructureClassName(), ddmForm);
166            }
167    
168            protected DDMTemplate addDDMTemplate(DDMStructure ddmStructure)
169                    throws Exception {
170    
171                    return DDMTemplateTestUtil.addTemplate(
172                            _serviceContext.getScopeGroupId(), ddmStructure.getStructureId());
173            }
174    
175            protected void addSearchableAssetEntries(
176                            DDMStructure ddmStructure, DDMTemplate ddmTemplate)
177                    throws Exception {
178    
179                    BaseModel<?> parentBaseModel = getSearchableAssetEntryParentBaseModel(
180                            _group, _serviceContext);
181    
182                    for (String value : _unsortedValues) {
183                            if (!_repeatable) {
184                                    addSearchableAssetEntry(
185                                            value, parentBaseModel, ddmStructure, ddmTemplate,
186                                            _serviceContext);
187                            }
188                            else {
189                                    addSearchableAssetEntryRepeatable(
190                                            StringUtil.split(value, CharPool.PIPE), parentBaseModel,
191                                            ddmStructure, ddmTemplate, _serviceContext);
192                            }
193                    }
194            }
195    
196            protected abstract BaseModel<?> addSearchableAssetEntry(
197                            String fieldValue, BaseModel<?> parentBaseModel,
198                            DDMStructure ddmStructure, DDMTemplate ddmTemplate,
199                            ServiceContext serviceContext)
200                    throws Exception;
201    
202            protected abstract BaseModel<?> addSearchableAssetEntryRepeatable(
203                            String[] fieldValues, BaseModel<?> parentBaseModel,
204                            DDMStructure ddmStructure, DDMTemplate ddmTemplate,
205                            ServiceContext serviceContext)
206                    throws Exception;
207    
208            protected void assertSearch(AssetEntryQuery assetEntryQuery)
209                    throws Exception {
210    
211                    Hits hits = search(assetEntryQuery);
212    
213                    List<AssetEntry> assetEntries = AssetUtil.getAssetEntries(hits);
214    
215                    Assert.assertEquals(
216                            ArrayUtils.toString(_sortedValues),
217                            ArrayUtils.toString(getValues(assetEntries)));
218            }
219    
220            protected AssetEntryQuery createAssetEntryQuery(DDMStructure ddmStructure)
221                    throws Exception {
222    
223                    AssetEntryQuery assetEntryQuery =
224                            AssetEntryQueryTestUtil.createAssetEntryQuery(
225                                    _group.getGroupId(),
226                                    new String[] {getSearchableAssetEntryClassName()});
227    
228                    String orderByCol1 = DDMIndexerUtil.encodeName(
229                            ddmStructure.getStructureId(), "name");
230    
231                    assetEntryQuery.setOrderByCol1(orderByCol1);
232                    assetEntryQuery.setOrderByType1("asc");
233    
234                    return assetEntryQuery;
235            }
236    
237            protected AssetRendererFactory getAssetRendererFactory() {
238                    return AssetRendererFactoryRegistryUtil.
239                            getAssetRendererFactoryByClassName(
240                                    getSearchableAssetEntryClassName());
241            }
242    
243            protected abstract String getSearchableAssetEntryClassName();
244    
245            protected abstract BaseModel<?> getSearchableAssetEntryParentBaseModel(
246                    Group group, ServiceContext serviceContext) throws Exception;
247    
248            protected abstract String getSearchableAssetEntryStructureClassName();
249    
250            protected String getValue(AssetRenderer assetRenderer) throws Exception {
251                    DDMFormValuesReader ddmFormValuesReader =
252                            assetRenderer.getDDMFormValuesReader();
253    
254                    DDMFormValues ddmFormValues = ddmFormValuesReader.getDDMFormValues();
255    
256                    Map<String, List<DDMFormFieldValue>> ddmFormFieldValuesMap =
257                            ddmFormValues.getDDMFormFieldValuesMap();
258    
259                    return ListUtil.toString(
260                            ddmFormFieldValuesMap.get("name"),
261                            new ValueAccessor(LocaleUtil.getDefault()) {
262    
263                                    @Override
264                                    public String get(DDMFormFieldValue ddmFormFieldValue) {
265                                            Value value = ddmFormFieldValue.getValue();
266    
267                                            return value.getString(locale);
268                                    }
269    
270                            },
271                            StringPool.PIPE);
272            }
273    
274            protected String[] getValues(List<AssetEntry> assetEntries)
275                    throws Exception {
276    
277                    AssetRendererFactory assetRendererFactory = getAssetRendererFactory();
278    
279                    String[] values = new String[assetEntries.size()];
280    
281                    for (int i = 0; i < assetEntries.size(); i++) {
282                            AssetEntry assetEntry = assetEntries.get(i);
283    
284                            AssetRenderer assetRenderer = assetRendererFactory.getAssetRenderer(
285                                    assetEntry.getClassPK());
286    
287                            values[i] = getValue(assetRenderer);
288                    }
289    
290                    return values;
291            }
292    
293            protected Hits search(AssetEntryQuery assetEntryQuery) throws Exception {
294                    SearchContext searchContext = SearchContextTestUtil.getSearchContext();
295    
296                    searchContext.setGroupIds(assetEntryQuery.getGroupIds());
297    
298                    return AssetUtil.search(
299                            searchContext, assetEntryQuery, QueryUtil.ALL_POS,
300                            QueryUtil.ALL_POS);
301            }
302    
303            protected void setDDMFormFieldOptions(DDMForm ddmForm) {
304                    if (!_type.equals(DDMFormFieldType.RADIO)) {
305                            return;
306                    }
307    
308                    List<DDMFormField> ddmFormFields = ddmForm.getDDMFormFields();
309    
310                    DDMFormField ddmFormField = ddmFormFields.get(0);
311    
312                    DDMFormFieldOptions ddmFormFieldOptions = new DDMFormFieldOptions();
313    
314                    for (String option : _unsortedValues) {
315                            ddmFormFieldOptions.addOptionLabel(option, LocaleUtil.US, option);
316                    }
317    
318                    ddmFormField.setDDMFormFieldOptions(ddmFormFieldOptions);
319            }
320    
321            protected void testOrderByDDMField() throws Exception {
322                    DDMStructure ddmStructure = addDDMStructure();
323    
324                    DDMTemplate ddmTemplate = addDDMTemplate(ddmStructure);
325    
326                    addSearchableAssetEntries(ddmStructure, ddmTemplate);
327    
328                    final AssetEntryQuery assetEntryQuery = createAssetEntryQuery(
329                            ddmStructure);
330    
331                    IdempotentRetryAssert.retryAssert(
332                            3, TimeUnit.SECONDS,
333                            new Callable<Void>() {
334    
335                                    @Override
336                                    public Void call() throws Exception {
337                                            assertSearch(assetEntryQuery);
338    
339                                            return null;
340                                    }
341    
342                            });
343            }
344    
345            protected void testOrderByDDMField(
346                            String[] unsortedValues, String[] sortedValues, String dataType,
347                            String type)
348                    throws Exception {
349    
350                    testOrderByDDMField(
351                            unsortedValues, sortedValues, dataType, "text", type);
352            }
353    
354            protected void testOrderByDDMField(
355                            String[] unsortedValues, String[] sortedValues, String dataType,
356                            String indexType, String type)
357                    throws Exception {
358    
359                    _unsortedValues = unsortedValues;
360                    _sortedValues = sortedValues;
361                    _dataType = dataType;
362                    _indexType = indexType;
363                    _type = type;
364                    _repeatable = false;
365    
366                    testOrderByDDMField();
367            }
368    
369            protected void testOrderByDDMFieldRepeatable(
370                            String[] unsortedValues, String[] sortedValues, String dataType,
371                            String type)
372                    throws Exception {
373    
374                    _unsortedValues = unsortedValues;
375                    _sortedValues = sortedValues;
376                    _dataType = dataType;
377                    _indexType = "text";
378                    _type = type;
379                    _repeatable = true;
380    
381                    testOrderByDDMField();
382            }
383    
384            protected void testOrderByDDMRadioField(String indexType) throws Exception {
385                    testOrderByDDMField(
386                            toJsonArrays("a", "D", "c", "B"), toJsonArrays("a", "B", "c", "D"),
387                            FieldConstants.STRING, indexType, DDMFormFieldType.RADIO);
388            }
389    
390            protected void testOrderByDDMTextField(String indexType) throws Exception {
391                    testOrderByDDMField(
392                            new String[] {"a", "D", "c", "B"},
393                            new String[] {"a", "B", "c", "D"}, FieldConstants.STRING, indexType,
394                            DDMFormFieldType.TEXT);
395            }
396    
397            private String _dataType;
398            private final Group _group;
399            private String _indexType;
400            private boolean _repeatable;
401            private final ServiceContext _serviceContext;
402            private String[] _sortedValues;
403            private String _type;
404            private String[] _unsortedValues;
405    
406    }