View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.tck.impl;
20  
21  import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNotEmpty;
22  import static org.apache.chemistry.opencmis.commons.impl.CollectionsHelper.isNullOrEmpty;
23  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.FAILURE;
24  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.INFO;
25  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.OK;
26  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.SKIPPED;
27  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.UNEXPECTED_EXCEPTION;
28  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.WARNING;
29  
30  import java.io.BufferedInputStream;
31  import java.io.ByteArrayInputStream;
32  import java.io.IOException;
33  import java.io.InputStream;
34  import java.io.InputStreamReader;
35  import java.io.Reader;
36  import java.math.BigInteger;
37  import java.security.MessageDigest;
38  import java.security.NoSuchAlgorithmException;
39  import java.util.ArrayList;
40  import java.util.Arrays;
41  import java.util.Collections;
42  import java.util.GregorianCalendar;
43  import java.util.HashMap;
44  import java.util.HashSet;
45  import java.util.List;
46  import java.util.Map;
47  import java.util.Set;
48  
49  import org.apache.chemistry.opencmis.client.SessionParameterMap;
50  import org.apache.chemistry.opencmis.client.api.CmisObject;
51  import org.apache.chemistry.opencmis.client.api.Document;
52  import org.apache.chemistry.opencmis.client.api.FileableCmisObject;
53  import org.apache.chemistry.opencmis.client.api.Folder;
54  import org.apache.chemistry.opencmis.client.api.Item;
55  import org.apache.chemistry.opencmis.client.api.ItemIterable;
56  import org.apache.chemistry.opencmis.client.api.ObjectId;
57  import org.apache.chemistry.opencmis.client.api.ObjectType;
58  import org.apache.chemistry.opencmis.client.api.OperationContext;
59  import org.apache.chemistry.opencmis.client.api.Policy;
60  import org.apache.chemistry.opencmis.client.api.Property;
61  import org.apache.chemistry.opencmis.client.api.Relationship;
62  import org.apache.chemistry.opencmis.client.api.Rendition;
63  import org.apache.chemistry.opencmis.client.api.Session;
64  import org.apache.chemistry.opencmis.client.api.SessionFactory;
65  import org.apache.chemistry.opencmis.client.api.Tree;
66  import org.apache.chemistry.opencmis.client.bindings.impl.ClientVersion;
67  import org.apache.chemistry.opencmis.client.runtime.OperationContextImpl;
68  import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl;
69  import org.apache.chemistry.opencmis.commons.PropertyIds;
70  import org.apache.chemistry.opencmis.commons.SessionParameter;
71  import org.apache.chemistry.opencmis.commons.data.Ace;
72  import org.apache.chemistry.opencmis.commons.data.Acl;
73  import org.apache.chemistry.opencmis.commons.data.AllowableActions;
74  import org.apache.chemistry.opencmis.commons.data.ContentStream;
75  import org.apache.chemistry.opencmis.commons.data.ContentStreamHash;
76  import org.apache.chemistry.opencmis.commons.data.NewTypeSettableAttributes;
77  import org.apache.chemistry.opencmis.commons.data.ObjectData;
78  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
79  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
80  import org.apache.chemistry.opencmis.commons.data.RepositoryCapabilities;
81  import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
82  import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
83  import org.apache.chemistry.opencmis.commons.definitions.PropertyDecimalDefinition;
84  import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
85  import org.apache.chemistry.opencmis.commons.definitions.PropertyIntegerDefinition;
86  import org.apache.chemistry.opencmis.commons.definitions.PropertyStringDefinition;
87  import org.apache.chemistry.opencmis.commons.definitions.RelationshipTypeDefinition;
88  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
89  import org.apache.chemistry.opencmis.commons.enums.Action;
90  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
91  import org.apache.chemistry.opencmis.commons.enums.BindingType;
92  import org.apache.chemistry.opencmis.commons.enums.CapabilityOrderBy;
93  import org.apache.chemistry.opencmis.commons.enums.Cardinality;
94  import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
95  import org.apache.chemistry.opencmis.commons.enums.ContentStreamAllowed;
96  import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
97  import org.apache.chemistry.opencmis.commons.enums.PropertyType;
98  import org.apache.chemistry.opencmis.commons.enums.Updatability;
99  import org.apache.chemistry.opencmis.commons.enums.VersioningState;
100 import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
101 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
102 import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
103 import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
104 import org.apache.chemistry.opencmis.commons.impl.IOUtils;
105 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamHashImpl;
106 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
107 import org.apache.chemistry.opencmis.tck.CmisTestResult;
108 import org.apache.chemistry.opencmis.tck.CmisTestResultStatus;
109 
110 /**
111  * Base class for tests that require an OpenCMIS session.
112  */
113 public abstract class AbstractSessionTest extends AbstractCmisTest {
114 
115     public static final OperationContext SELECT_ALL_NO_CACHE_OC = new OperationContextImpl();
116     public static final OperationContext SELECT_ALL_NO_CACHE_OC_ORDER_BY_NAME;
117     static {
118         SELECT_ALL_NO_CACHE_OC.setFilterString("*");
119         SELECT_ALL_NO_CACHE_OC.setCacheEnabled(false);
120         SELECT_ALL_NO_CACHE_OC.setIncludeAllowableActions(true);
121         SELECT_ALL_NO_CACHE_OC.setIncludeAcls(true);
122         SELECT_ALL_NO_CACHE_OC.setIncludePathSegments(true);
123         SELECT_ALL_NO_CACHE_OC.setIncludePolicies(true);
124         SELECT_ALL_NO_CACHE_OC.setIncludeRelationships(IncludeRelationships.BOTH);
125         SELECT_ALL_NO_CACHE_OC.setRenditionFilterString("*");
126         SELECT_ALL_NO_CACHE_OC.setOrderBy(null);
127 
128         SELECT_ALL_NO_CACHE_OC_ORDER_BY_NAME = new OperationContextImpl(SELECT_ALL_NO_CACHE_OC);
129         SELECT_ALL_NO_CACHE_OC_ORDER_BY_NAME.setOrderBy("cmis:name");
130     }
131 
132     public static final String TCK_USER_AGENT = "OpenCMIS-TCK/"
133             + (ClientVersion.OPENCMIS_VERSION == null ? "?" : ClientVersion.OPENCMIS_VERSION) + " "
134             + ClientVersion.OPENCMIS_USER_AGENT;
135 
136     private final SessionFactory factory = SessionFactoryImpl.newInstance();
137     private Folder testFolder;
138 
139     private Boolean supportsRelationships;
140     private Boolean supportsPolicies;
141     private Boolean supportsItems;
142     private Boolean supportsSecondaries;
143 
144     public BindingType getBinding() {
145         if (getParameters() == null) {
146             return null;
147         }
148 
149         try {
150             return BindingType.fromValue(getParameters().get(SessionParameter.BINDING_TYPE));
151         } catch (Exception e) {
152             return null;
153         }
154     }
155 
156     @Override
157     public String getName() {
158         return super.getName() + " (" + getBinding() + ")";
159     }
160 
161     @Override
162     public void run() throws Exception {
163         Session session;
164 
165         SessionParameterMap parameters = new SessionParameterMap(getParameters());
166         if (!parameters.containsKey(SessionParameter.USER_AGENT)) {
167             parameters.setUserAgent(TCK_USER_AGENT);
168         }
169 
170         String repId = parameters.get(SessionParameter.REPOSITORY_ID);
171         if (repId != null && repId.length() > 0) {
172             session = factory.createSession(parameters);
173         } else {
174             session = factory.getRepositories(parameters).get(0).createSession();
175         }
176 
177         // switch off the cache
178         session.getDefaultContext().setCacheEnabled(false);
179 
180         try {
181             run(session);
182         } catch (Exception e) {
183             if (!(e instanceof FatalTestException)) {
184                 addResult(createResult(UNEXPECTED_EXCEPTION, "Exception: " + e, e, true));
185             }
186         } catch (Error err) {
187             addResult(createResult(UNEXPECTED_EXCEPTION, "Error: " + err, err, true));
188         } finally {
189             testFolder = null;
190         }
191     }
192 
193     public abstract void run(Session session) throws Exception;
194 
195     protected RepositoryInfo getRepositoryInfo(Session session) {
196         RepositoryInfo ri = session.getRepositoryInfo();
197 
198         CmisTestResult failure = createResult(FAILURE, "Repository info is null!", true);
199         addResult(assertNotNull(ri, null, failure));
200 
201         return ri;
202     }
203 
204     protected String getFolderTestTypeId() {
205         String objectTypeId = getParameters().get(TestParameters.DEFAULT_FOLDER_TYPE);
206         if (objectTypeId == null) {
207             objectTypeId = TestParameters.DEFAULT_FOLDER_TYPE_VALUE;
208         }
209 
210         return objectTypeId;
211     }
212 
213     protected String getDocumentTestTypeId() {
214         String objectTypeId = getParameters().get(TestParameters.DEFAULT_DOCUMENT_TYPE);
215         if (objectTypeId == null) {
216             objectTypeId = TestParameters.DEFAULT_DOCUMENT_TYPE_VALUE;
217         }
218 
219         return objectTypeId;
220     }
221 
222     protected String getRelationshipTestTypeId() {
223         String objectTypeId = getParameters().get(TestParameters.DEFAULT_RELATIONSHIP_TYPE);
224         if (objectTypeId == null) {
225             objectTypeId = TestParameters.DEFAULT_RELATIONSHIP_TYPE_VALUE;
226         }
227 
228         return objectTypeId;
229     }
230 
231     protected String getPolicyTestTypeId() {
232         String objectTypeId = getParameters().get(TestParameters.DEFAULT_POLICY_TYPE);
233         if (objectTypeId == null) {
234             objectTypeId = TestParameters.DEFAULT_POLICY_TYPE_VALUE;
235         }
236 
237         return objectTypeId;
238     }
239 
240     protected String getItemTestTypeId() {
241         String objectTypeId = getParameters().get(TestParameters.DEFAULT_ITEM_TYPE);
242         if (objectTypeId == null) {
243             objectTypeId = TestParameters.DEFAULT_ITEM_TYPE_VALUE;
244         }
245 
246         return objectTypeId;
247     }
248 
249     protected String getSecondaryTestTypeId() {
250         String objectTypeId = getParameters().get(TestParameters.DEFAULT_SECONDARY_TYPE);
251         if (objectTypeId == null) {
252             objectTypeId = TestParameters.DEFAULT_SECONDARY_TYPE_VALUE;
253         }
254 
255         return objectTypeId;
256     }
257 
258     // --- helpers ---
259 
260     protected String[] getAllProperties(CmisObject object) {
261         String[] propertiesk = new String[object.getType().getPropertyDefinitions().size()];
262 
263         int i = 0;
264         for (String propId : object.getType().getPropertyDefinitions().keySet()) {
265             propertiesk[i++] = propId;
266         }
267 
268         return propertiesk;
269     }
270 
271     protected String getStringFromContentStream(ContentStream contentStream) throws IOException {
272         if (contentStream == null || contentStream.getStream() == null) {
273             return null;
274         }
275 
276         StringBuilder sb = new StringBuilder(4096);
277         Reader reader = new InputStreamReader(contentStream.getStream(), IOUtils.UTF8);
278 
279         try {
280             final char[] buffer = new char[64 * 1024];
281             int b;
282             while (true) {
283                 b = reader.read(buffer, 0, buffer.length);
284                 if (b > 0) {
285                     if (sb.length() + b > 10 * 1024 * 1024) {
286                         throw new IOException("File too large!");
287                     }
288 
289                     sb.append(buffer, 0, b);
290                 } else if (b == -1) {
291                     break;
292                 }
293             }
294         } finally {
295             IOUtils.closeQuietly(reader);
296         }
297 
298         return sb.toString();
299     }
300 
301     // --- handy create and delete methods ---
302 
303     /**
304      * Creates a folder.
305      */
306     protected Folder createFolder(Session session, Folder parent, String name) {
307         return createFolder(session, parent, name, getFolderTestTypeId());
308     }
309 
310     /**
311      * Creates a folder.
312      */
313     protected Folder createFolder(Session session, Folder parent, String name, String objectTypeId) {
314         if (parent == null) {
315             throw new IllegalArgumentException("Parent is not set!");
316         }
317         if (name == null) {
318             throw new IllegalArgumentException("Name is not set!");
319         }
320         if (objectTypeId == null) {
321             throw new IllegalArgumentException("Object Type ID is not set!");
322         }
323 
324         // check type
325         ObjectType type;
326         try {
327             type = session.getTypeDefinition(objectTypeId);
328         } catch (CmisObjectNotFoundException e) {
329             addResult(createResult(UNEXPECTED_EXCEPTION,
330                     "Folder type '" + objectTypeId + "' is not available: " + e.getMessage(), e, true));
331             return null;
332         }
333 
334         if (Boolean.FALSE.equals(type.isCreatable())) {
335             addResult(createResult(SKIPPED, "Folder type '" + objectTypeId + "' is not creatable!", true));
336             return null;
337         }
338 
339         // create
340         Map<String, Object> properties = new HashMap<String, Object>();
341         properties.put(PropertyIds.NAME, name);
342         properties.put(PropertyIds.OBJECT_TYPE_ID, objectTypeId);
343 
344         Folder result = null;
345         try {
346             // create the folder
347             result = parent.createFolder(properties, null, null, null, SELECT_ALL_NO_CACHE_OC);
348         } catch (CmisBaseException e) {
349             addResult(createResult(UNEXPECTED_EXCEPTION, "Folder could not be created! Exception: " + e.getMessage(), e,
350                     true));
351             return null;
352         }
353 
354         try {
355             CmisTestResult f;
356 
357             // check folder name
358             f = createResult(FAILURE, "Folder name does not match!", false);
359             addResult(assertEquals(name, result.getName(), null, f));
360 
361             // check the new folder
362             String[] propertiesToCheck = new String[result.getType().getPropertyDefinitions().size()];
363 
364             int i = 0;
365             for (String propId : result.getType().getPropertyDefinitions().keySet()) {
366                 propertiesToCheck[i++] = propId;
367             }
368 
369             addResult(checkObject(session, result, propertiesToCheck, "New folder object spec compliance"));
370 
371             // check object parents
372             List<Folder> objectParents = result.getParents();
373 
374             f = createResult(FAILURE, "Newly created folder has no or more than one parent! ID: " + result.getId(),
375                     true);
376             addResult(assertEquals(1, objectParents.size(), null, f));
377 
378             f = createResult(FAILURE,
379                     "First object parent of the newly created folder does not match parent! ID: " + result.getId(),
380                     true);
381             assertShallowEquals(parent, objectParents.get(0), null, f);
382 
383             // check folder parent
384             Folder folderParent = result.getFolderParent();
385             f = createResult(FAILURE, "Newly created folder has no folder parent! ID: " + result.getId(), true);
386             addResult(assertNotNull(folderParent, null, f));
387 
388             f = createResult(FAILURE,
389                     "Folder parent of the newly created folder does not match parent! ID: " + result.getId(), true);
390             assertShallowEquals(parent, folderParent, null, f);
391 
392             // check children of parent
393             boolean found = false;
394             for (CmisObject child : parent.getChildren(SELECT_ALL_NO_CACHE_OC)) {
395                 if (child == null) {
396                     addResult(createResult(FAILURE, "Parent folder contains a null child!", true));
397                 } else {
398                     if (result.getId().equals(child.getId())) {
399                         found = true;
400 
401                         f = createResult(FAILURE, "Folder and parent child don't match! ID: " + result.getId(), true);
402                         assertShallowEquals(result, child, null, f);
403                         break;
404                     }
405                 }
406             }
407 
408             if (!found) {
409                 addResult(createResult(FAILURE, "Folder is not a child of the parent folder! ID: " + result.getId(),
410                         true));
411             }
412         } catch (CmisBaseException e) {
413             addResult(createResult(UNEXPECTED_EXCEPTION,
414                     "Newly created folder is invalid! Exception: " + e.getMessage(), e, true));
415         }
416 
417         return result;
418     }
419 
420     /**
421      * Counts the children in a folder.
422      */
423     protected int countFolderChildren(Folder folder) {
424         int count = 0;
425 
426         for (@SuppressWarnings("unused")
427         CmisObject object : folder.getChildren()) {
428             count++;
429         }
430 
431         return count;
432     }
433 
434     /**
435      * Creates a document.
436      */
437     protected Document createDocument(Session session, Folder parent, String name, String content) {
438         return createDocument(session, parent, name, getDocumentTestTypeId(), null, content);
439     }
440 
441     /**
442      * Creates a document.
443      */
444     protected Document createDocument(Session session, Folder parent, String name, String objectTypeId,
445             String[] secondaryTypeIds, String content) {
446         if (parent == null) {
447             throw new IllegalArgumentException("Parent is not set!");
448         }
449         if (name == null) {
450             throw new IllegalArgumentException("Name is not set!");
451         }
452         if (objectTypeId == null) {
453             throw new IllegalArgumentException("Object Type ID is not set!");
454         }
455 
456         if (content == null) {
457             content = "";
458         }
459 
460         // check type
461         ObjectType type;
462         try {
463             type = session.getTypeDefinition(objectTypeId);
464         } catch (CmisObjectNotFoundException e) {
465             addResult(createResult(UNEXPECTED_EXCEPTION,
466                     "Document type '" + objectTypeId + "' is not available: " + e.getMessage(), e, true));
467             return null;
468         }
469 
470         if (Boolean.FALSE.equals(type.isCreatable())) {
471             addResult(createResult(SKIPPED, "Document type '" + objectTypeId + "' is not creatable!", true));
472             return null;
473         }
474 
475         // create
476         Map<String, Object> properties = new HashMap<String, Object>();
477         properties.put(PropertyIds.NAME, name);
478         properties.put(PropertyIds.OBJECT_TYPE_ID, objectTypeId);
479 
480         if (secondaryTypeIds != null) {
481             properties.put(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, Arrays.asList(secondaryTypeIds));
482         }
483 
484         type = session.getTypeDefinition(objectTypeId);
485         if (!(type instanceof DocumentTypeDefinition)) {
486             addResult(createResult(FAILURE, "Type is not a document type! Type: " + objectTypeId, true));
487             return null;
488         }
489 
490         DocumentTypeDefinition docType = (DocumentTypeDefinition) type;
491         VersioningState versioningState = (Boolean.TRUE.equals(docType.isVersionable()) ? VersioningState.MAJOR
492                 : VersioningState.NONE);
493 
494         byte[] contentBytes = null;
495         Document result = null;
496         try {
497             contentBytes = IOUtils.toUTF8Bytes(content);
498             ContentStream contentStream = new ContentStreamImpl(name, BigInteger.valueOf(contentBytes.length),
499                     "text/plain", new ByteArrayInputStream(contentBytes));
500 
501             // create the document
502             result = parent.createDocument(properties, contentStream, versioningState, null, null, null,
503                     SELECT_ALL_NO_CACHE_OC);
504 
505             contentStream.getStream().close();
506         } catch (Exception e) {
507             addResult(createResult(UNEXPECTED_EXCEPTION, "Document could not be created! Exception: " + e.getMessage(),
508                     e, true));
509             return null;
510         }
511 
512         try {
513             CmisTestResult f;
514 
515             // check document name
516             f = createResult(FAILURE, "Document name does not match!");
517             addResult(assertEquals(name, result.getName(), null, f));
518 
519             // check content length
520             f = createResult(WARNING, "Content length does not match!");
521             addResult(assertEquals((long) contentBytes.length, result.getContentStreamLength(), null, f));
522 
523             // check hash property
524             List<ContentStreamHash> hashes = result.getContentStreamHashes();
525             if (docType.getPropertyDefinitions() != null
526                     && docType.getPropertyDefinitions().containsKey(PropertyIds.CONTENT_STREAM_HASH)) {
527                 f = createResult(WARNING,
528                         "Document type provides the cmis:contentStreamHash property, but there is no value for the test document.");
529                 addResult(assertNotNull(hashes, null, f));
530             }
531 
532             // check the new document
533             addResult(checkObject(session, result, getAllProperties(result), "New document object spec compliance"));
534 
535             // check content
536             try {
537                 ContentStream contentStream = result.getContentStream();
538 
539                 f = createResult(WARNING, "Document filename and the filename of the content stream do not match!");
540                 addResult(assertEquals(name, contentStream.getFileName(), null, f));
541 
542                 f = createResult(WARNING,
543                         "cmis:contentStreamFileName and the filename of the content stream do not match!");
544                 addResult(assertEquals(result.getContentStreamFileName(), contentStream.getFileName(), null, f));
545 
546                 String fetchedContent = getStringFromContentStream(result.getContentStream());
547                 if (!content.equals(fetchedContent)) {
548                     addResult(createResult(FAILURE,
549                             "Content of newly created document doesn't match the orign content!"));
550                 }
551 
552                 // check hashes
553                 if (hashes != null) {
554                     for (ContentStreamHash hash : hashes) {
555                         if (hash.getAlgorithm() == null) {
556                             addResult(createResult(FAILURE,
557                                     "This content stream hash is invalid: " + hash.getPropertyValue()));
558                         } else {
559                             InputStream stream = null;
560                             try {
561                                 stream = new ByteArrayInputStream(IOUtils.toUTF8Bytes(content));
562                                 List<ContentStreamHash> testHash = ContentStreamHashImpl
563                                         .createContentStreamHashes(stream, hash.getAlgorithm());
564 
565                                 f = createResult(CmisTestResultStatus.FAILURE,
566                                         "This content stream hash is wrong: " + hash.getPropertyValue());
567                                 addResult(assertEquals(testHash.get(0).getHash(), hash.getHash(), null, f));
568                             } catch (NoSuchAlgorithmException e) {
569                                 // we don't know this algorithm - that's ok
570                             } finally {
571                                 IOUtils.closeQuietly(stream);
572                             }
573                         }
574                     }
575                 }
576             } catch (IOException e) {
577                 addResult(createResult(UNEXPECTED_EXCEPTION,
578                         "Content of newly created document couldn't be read! Exception: " + e.getMessage(), e, true));
579             }
580         } catch (CmisBaseException e) {
581             addResult(createResult(UNEXPECTED_EXCEPTION,
582                     "Newly created document is invalid! Exception: " + e.getMessage(), e, true));
583         }
584 
585         // check parents
586         List<Folder> parents = result.getParents(SELECT_ALL_NO_CACHE_OC);
587         boolean found = false;
588         for (Folder folder : parents) {
589             if (parent.getId().equals(folder.getId())) {
590                 found = true;
591                 break;
592             }
593         }
594 
595         if (!found) {
596             addResult(createResult(FAILURE,
597                     "The folder the document has been created in is not in the list of the document parents!"));
598         }
599 
600         return result;
601     }
602 
603     /**
604      * Creates a relationship.
605      */
606     protected Relationship createRelationship(Session session, String name, ObjectId source, ObjectId target) {
607         String objectTypeId = getRelationshipTestTypeId();
608         return createRelationship(session, name, source, target, objectTypeId);
609     }
610 
611     /**
612      * Creates a relationship.
613      */
614     protected Relationship createRelationship(Session session, String name, ObjectId source, ObjectId target,
615             String objectTypeId) {
616         if (name == null) {
617             throw new IllegalArgumentException("Name is not set!");
618         }
619         if (objectTypeId == null) {
620             throw new IllegalArgumentException("Object Type ID is not set!");
621         }
622 
623         // check type
624         ObjectType type;
625         try {
626             type = session.getTypeDefinition(objectTypeId);
627         } catch (CmisObjectNotFoundException e) {
628             addResult(createResult(UNEXPECTED_EXCEPTION,
629                     "Relationship type '" + objectTypeId + "' is not available: " + e.getMessage(), e, true));
630             return null;
631         }
632 
633         if (Boolean.FALSE.equals(type.isCreatable())) {
634             addResult(createResult(SKIPPED, "Relationship type '" + objectTypeId + "' is not creatable!", true));
635             return null;
636         }
637 
638         // create
639         Map<String, Object> properties = new HashMap<String, Object>();
640         properties.put(PropertyIds.NAME, name);
641         properties.put(PropertyIds.OBJECT_TYPE_ID, objectTypeId);
642         properties.put(PropertyIds.SOURCE_ID, source.getId());
643         properties.put(PropertyIds.TARGET_ID, target.getId());
644 
645         ObjectId relId;
646         Relationship result = null;
647 
648         try {
649             relId = session.createRelationship(properties);
650             result = (Relationship) session.getObject(relId, SELECT_ALL_NO_CACHE_OC);
651         } catch (Exception e) {
652             addResult(createResult(UNEXPECTED_EXCEPTION,
653                     "Relationship could not be created! Exception: " + e.getMessage(), e, true));
654         }
655 
656         if (result != null) {
657             try {
658                 // check the new relationship
659                 addResult(
660                         checkObject(session, result, getAllProperties(result), "New document object spec compliance"));
661             } catch (CmisBaseException e) {
662                 addResult(createResult(UNEXPECTED_EXCEPTION,
663                         "Newly created document is invalid! Exception: " + e.getMessage(), e, true));
664             }
665         }
666 
667         return result;
668     }
669 
670     /**
671      * Creates a policy.
672      */
673     protected Policy createPolicy(Session session, Folder parent, String name, String policyText) {
674         return createPolicy(session, parent, name, policyText, getPolicyTestTypeId());
675     }
676 
677     /**
678      * Creates a policy.
679      */
680     protected Policy createPolicy(Session session, Folder parent, String name, String policyText, String objectTypeId) {
681         if (parent == null) {
682             throw new IllegalArgumentException("Parent is not set!");
683         }
684         if (name == null) {
685             throw new IllegalArgumentException("Name is not set!");
686         }
687         if (objectTypeId == null) {
688             throw new IllegalArgumentException("Object Type ID is not set!");
689         }
690 
691         // check type
692         ObjectType type;
693         try {
694             type = session.getTypeDefinition(objectTypeId);
695         } catch (CmisObjectNotFoundException e) {
696             addResult(createResult(UNEXPECTED_EXCEPTION,
697                     "Policy type '" + objectTypeId + "' is not available: " + e.getMessage(), e, true));
698             return null;
699         }
700 
701         if (Boolean.FALSE.equals(type.isCreatable())) {
702             addResult(createResult(SKIPPED, "Policy type '" + objectTypeId + "' is not creatable!", true));
703             return null;
704         }
705 
706         boolean isFilable = Boolean.TRUE.equals(type.isFileable());
707 
708         addResult(
709                 createResult(INFO, "Policy type '" + objectTypeId + "' is " + (isFilable ? "" : "not ") + "filable."));
710 
711         // create
712         Map<String, Object> properties = new HashMap<String, Object>();
713         properties.put(PropertyIds.NAME, name);
714         properties.put(PropertyIds.OBJECT_TYPE_ID, objectTypeId);
715         if (policyText != null) {
716             properties.put(PropertyIds.POLICY_TEXT, policyText);
717         }
718 
719         Policy result = null;
720         try {
721             // create the item
722             if (isFilable) {
723                 result = parent.createPolicy(properties, null, null, null, SELECT_ALL_NO_CACHE_OC);
724             } else {
725                 ObjectId policyId = session.createPolicy(properties, null, null, null, null);
726                 result = (Policy) session.getObject(policyId, SELECT_ALL_NO_CACHE_OC);
727             }
728         } catch (CmisBaseException e) {
729             addResult(createResult(UNEXPECTED_EXCEPTION, "Policy could not be created! Exception: " + e.getMessage(), e,
730                     true));
731             return null;
732         }
733 
734         CmisTestResult f;
735         try {
736             // check item name
737             f = createResult(FAILURE, "Policy name does not match!", false);
738             addResult(assertEquals(name, result.getName(), null, f));
739 
740             addResult(checkObject(session, result, getAllProperties(result), "New policy object spec compliance"));
741         } catch (CmisBaseException e) {
742             addResult(createResult(UNEXPECTED_EXCEPTION,
743                     "Newly created policy is invalid! Exception: " + e.getMessage(), e, true));
744         }
745 
746         // check parents
747         List<Folder> parents = result.getParents(SELECT_ALL_NO_CACHE_OC);
748 
749         if (isFilable) {
750             boolean found = false;
751             for (Folder folder : parents) {
752                 if (parent.getId().equals(folder.getId())) {
753                     found = true;
754                     break;
755                 }
756             }
757 
758             if (!found) {
759                 addResult(createResult(FAILURE,
760                         "The folder the item has been created in is not in the list of the item parents!"));
761             }
762         } else {
763             f = createResult(FAILURE, "Policy is not filable but has a parent!", false);
764             addResult(assertIsTrue(parents.isEmpty(), null, f));
765         }
766 
767         return result;
768     }
769 
770     /**
771      * Creates a item.
772      */
773     protected Item createItem(Session session, Folder parent, String name) {
774         return createItem(session, parent, name, getItemTestTypeId());
775     }
776 
777     /**
778      * Creates a item.
779      */
780     protected Item createItem(Session session, Folder parent, String name, String objectTypeId) {
781         if (parent == null) {
782             throw new IllegalArgumentException("Parent is not set!");
783         }
784         if (name == null) {
785             throw new IllegalArgumentException("Name is not set!");
786         }
787         if (objectTypeId == null) {
788             throw new IllegalArgumentException("Object Type ID is not set!");
789         }
790 
791         // check type
792         ObjectType type;
793         try {
794             type = session.getTypeDefinition(objectTypeId);
795         } catch (CmisObjectNotFoundException e) {
796             addResult(createResult(UNEXPECTED_EXCEPTION,
797                     "Item type '" + objectTypeId + "' is not available: " + e.getMessage(), e, true));
798             return null;
799         }
800 
801         if (Boolean.FALSE.equals(type.isCreatable())) {
802             addResult(createResult(SKIPPED, "Item type '" + objectTypeId + "' is not creatable!", true));
803             return null;
804         }
805 
806         // create
807         Map<String, Object> properties = new HashMap<String, Object>();
808         properties.put(PropertyIds.NAME, name);
809         properties.put(PropertyIds.OBJECT_TYPE_ID, objectTypeId);
810 
811         Item result = null;
812         try {
813             // create the item
814             result = parent.createItem(properties, null, null, null, SELECT_ALL_NO_CACHE_OC);
815         } catch (CmisBaseException e) {
816             addResult(createResult(UNEXPECTED_EXCEPTION, "Item could not be created! Exception: " + e.getMessage(), e,
817                     true));
818             return null;
819         }
820 
821         try {
822             CmisTestResult f;
823 
824             // check item name
825             f = createResult(FAILURE, "Item name does not match!", false);
826             addResult(assertEquals(name, result.getName(), null, f));
827 
828             addResult(checkObject(session, result, getAllProperties(result), "New item object spec compliance"));
829         } catch (CmisBaseException e) {
830             addResult(createResult(UNEXPECTED_EXCEPTION, "Newly created item is invalid! Exception: " + e.getMessage(),
831                     e, true));
832         }
833 
834         // check parents
835         List<Folder> parents = result.getParents(SELECT_ALL_NO_CACHE_OC);
836         boolean found = false;
837         for (Folder folder : parents) {
838             if (parent.getId().equals(folder.getId())) {
839                 found = true;
840                 break;
841             }
842         }
843 
844         if (!found) {
845             addResult(createResult(FAILURE,
846                     "The folder the item has been created in is not in the list of the item parents!"));
847         }
848 
849         return result;
850     }
851 
852     /**
853      * Deletes an object and checks if it is deleted.
854      */
855     protected void deleteObject(CmisObject object) {
856         if (object != null) {
857             if (object instanceof Folder) {
858                 try {
859                     ((Folder) object).deleteTree(true, null, true);
860                 } catch (CmisBaseException e) {
861                     addResult(createResult(UNEXPECTED_EXCEPTION,
862                             "Folder could not be deleted! Exception: " + e.getMessage(), e, true));
863                 }
864             } else {
865                 try {
866                     object.delete(true);
867                 } catch (CmisBaseException e) {
868                     addResult(createResult(UNEXPECTED_EXCEPTION,
869                             "Object could not be deleted! Exception: " + e.getMessage(), e, true));
870                 }
871             }
872 
873             CmisTestResult f = createResult(FAILURE,
874                     "Object should not exist anymore but it is still there! ID: " + object.getId(), true);
875             addResult(assertIsFalse(exists(object), null, f));
876         }
877     }
878 
879     /**
880      * Tests if an object exists by refreshing it.
881      */
882     protected boolean exists(CmisObject object) {
883         try {
884             object.refresh();
885             return true;
886         } catch (CmisObjectNotFoundException e) {
887             return false;
888         }
889     }
890 
891     // --- type helpers ---
892 
893     /**
894      * Creates a new type.
895      */
896     protected ObjectType createType(Session session, TypeDefinition typeDef) {
897 
898         NewTypeSettableAttributes settableAttributes = session.getRepositoryInfo().getCapabilities()
899                 .getNewTypeSettableAttributes();
900         if (settableAttributes == null) {
901             addResult(createResult(WARNING, "Repository Info does not indicate, which type attributes can be set!"));
902         } else {
903             // TODO: add more tests
904         }
905 
906         ObjectType newType = null;
907         try {
908             newType = session.createType(typeDef);
909             addResult(createInfoResult("Created type '" + typeDef.getId()
910                     + "'. Repository assigned the following type ID: " + newType.getId()));
911         } catch (CmisBaseException e) {
912             addResult(createResult(FAILURE, "Creating type '" + typeDef.getId() + "' failed: " + e.getMessage(), e,
913                     false));
914             return null;
915         }
916 
917         addResult(checkTypeDefinition(session, newType, "Newly created type spec compliance."));
918 
919         if (newType.getTypeMutability() == null) {
920             addResult(createResult(FAILURE,
921                     "Newly created type does not provide type mutability data! ID: " + newType.getId()));
922         }
923 
924         return newType;
925     }
926 
927     /**
928      * Deletes a type.
929      */
930     protected void deleteType(Session session, String typeId) {
931         ObjectType type = session.getTypeDefinition(typeId);
932 
933         if (type == null) {
934             addResult(createResult(FAILURE, "Type does not exist and therefore cannot be deleted! ID: " + typeId));
935             return;
936         }
937 
938         // check if type can be deleted
939         if (type.getTypeMutability() == null) {
940             addResult(createResult(FAILURE, "Type does not provide type mutability data! ID: " + typeId));
941         } else {
942             if (!Boolean.TRUE.equals(type.getTypeMutability().canDelete())) {
943                 addResult(createResult(WARNING,
944                         "Type indicates that it cannot be deleted. Trying it anyway. ID: " + typeId));
945             }
946         }
947 
948         // delete it
949         try {
950             session.deleteType(typeId);
951         } catch (CmisBaseException e) {
952             addResult(createResult(FAILURE, "Deleting type '" + typeId + "' failed: " + e.getMessage(), e, false));
953             return;
954         }
955 
956         // check if the type still exists
957         try {
958             session.getTypeDefinition(typeId);
959             addResult(
960                     createResult(FAILURE, "Type should not exist anymore but it is still there! ID: " + typeId, true));
961         } catch (CmisObjectNotFoundException e) {
962             // expected result
963         }
964     }
965 
966     // --- test folder methods ---
967 
968     /**
969      * Creates a test folder.
970      */
971     protected Folder createTestFolder(Session session) {
972 
973         String testFolderParentPath = getParameters().get(TestParameters.DEFAULT_TEST_FOLDER_PARENT);
974         if (testFolderParentPath == null) {
975             testFolderParentPath = TestParameters.DEFAULT_TEST_FOLDER_PARENT_VALUE;
976         }
977 
978         String name = "cmistck" + System.currentTimeMillis() + session.getRepositoryInfo().hashCode();
979 
980         Folder parent = null;
981         try {
982             CmisObject parentObject = session.getObjectByPath(testFolderParentPath, SELECT_ALL_NO_CACHE_OC);
983             if (!(parentObject instanceof Folder)) {
984                 addResult(createResult(FAILURE,
985                         "Parent folder of the test folder is actually not a folder! Path: " + testFolderParentPath,
986                         true));
987             }
988 
989             parent = (Folder) parentObject;
990         } catch (CmisBaseException e) {
991             addResult(createResult(UNEXPECTED_EXCEPTION,
992                     "Test folder could not be created! Exception: " + e.getMessage(), e, true));
993         }
994 
995         if (parent != null) {
996             testFolder = createFolder(session, parent, name);
997         }
998 
999         return testFolder;
1000     }
1001 
1002     /**
1003      * Get the test folder.
1004      */
1005     protected Folder getTestFolder() {
1006         return testFolder;
1007     }
1008 
1009     /**
1010      * Delete the test folder.
1011      */
1012     protected void deleteTestFolder() {
1013         deleteObject(testFolder);
1014     }
1015 
1016     // --- reusable checks ----
1017 
1018     protected boolean isGetDescendantsSupported(Session session) {
1019         RepositoryCapabilities cap = session.getRepositoryInfo().getCapabilities();
1020 
1021         if (cap == null) {
1022             return false;
1023         }
1024 
1025         if (cap.isGetDescendantsSupported() == null) {
1026             return false;
1027         }
1028 
1029         return cap.isGetDescendantsSupported().booleanValue();
1030     }
1031 
1032     protected boolean isGetFolderTreeSupported(Session session) {
1033         RepositoryCapabilities cap = session.getRepositoryInfo().getCapabilities();
1034 
1035         if (cap == null) {
1036             return false;
1037         }
1038 
1039         if (cap.isGetFolderTreeSupported() == null) {
1040             return false;
1041         }
1042 
1043         return cap.isGetFolderTreeSupported().booleanValue();
1044     }
1045 
1046     protected boolean isOrderByNameSupported(Session session) {
1047         if (session.getRepositoryInfo().getCapabilities().getOrderByCapability() == CapabilityOrderBy.NONE) {
1048             return false;
1049         }
1050 
1051         return true;
1052     }
1053 
1054     protected boolean hasRelationships(Session session) {
1055         if (supportsRelationships == null) {
1056             supportsRelationships = Boolean.FALSE;
1057             for (ObjectType type : session.getTypeChildren(null, false)) {
1058                 if (BaseTypeId.CMIS_RELATIONSHIP.value().equals(type.getId())) {
1059                     supportsRelationships = Boolean.TRUE;
1060                     break;
1061                 }
1062             }
1063         }
1064 
1065         return supportsRelationships.booleanValue();
1066     }
1067 
1068     protected boolean hasPolicies(Session session) {
1069         if (supportsPolicies == null) {
1070             supportsPolicies = Boolean.FALSE;
1071             for (ObjectType type : session.getTypeChildren(null, false)) {
1072                 if (BaseTypeId.CMIS_POLICY.value().equals(type.getId())) {
1073                     supportsPolicies = Boolean.TRUE;
1074                     break;
1075                 }
1076             }
1077         }
1078 
1079         return supportsPolicies.booleanValue();
1080     }
1081 
1082     protected boolean hasItems(Session session) {
1083         if (supportsItems == null) {
1084             supportsItems = Boolean.FALSE;
1085             for (ObjectType type : session.getTypeChildren(null, false)) {
1086                 if (BaseTypeId.CMIS_ITEM.value().equals(type.getId())) {
1087                     supportsItems = Boolean.TRUE;
1088                     break;
1089                 }
1090             }
1091         }
1092 
1093         return supportsItems.booleanValue();
1094     }
1095 
1096     protected boolean hasSecondaries(Session session) {
1097         if (supportsSecondaries == null) {
1098             supportsSecondaries = Boolean.FALSE;
1099             for (ObjectType type : session.getTypeChildren(null, false)) {
1100                 if (BaseTypeId.CMIS_SECONDARY.value().equals(type.getId())) {
1101                     supportsSecondaries = Boolean.TRUE;
1102                     break;
1103                 }
1104             }
1105         }
1106 
1107         return supportsSecondaries.booleanValue();
1108     }
1109 
1110     protected CmisTestResult checkObject(Session session, CmisObject object, String[] properties, String message) {
1111         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
1112 
1113         CmisTestResult f;
1114 
1115         f = createResult(FAILURE, "Object is null!", true);
1116         addResult(results, assertNotNull(object, null, f));
1117 
1118         if (object != null) {
1119             f = createResult(FAILURE, "Object ID is not set!");
1120             addResult(results, assertStringNotEmpty(object.getId(), null, f));
1121 
1122             GregorianCalendar creationDate = null;
1123             GregorianCalendar lastModificationDate = null;
1124 
1125             // properties
1126             for (String propId : properties) {
1127                 Property<?> prop = object.getProperty(propId);
1128 
1129                 // values of non-spec properties are not checked here
1130                 PropertyCheckEnum propertyCheck = PropertyCheckEnum.NO_VALUE_CHECK;
1131 
1132                 // known properties that are strings and must be set
1133                 if (PropertyIds.OBJECT_ID.equals(propId) || PropertyIds.BASE_TYPE_ID.equals(propId)
1134                         || PropertyIds.OBJECT_TYPE_ID.equals(propId) || PropertyIds.PATH.equals(propId)
1135                         || PropertyIds.SOURCE_ID.equals(propId) || PropertyIds.TARGET_ID.equals(propId)) {
1136                     propertyCheck = PropertyCheckEnum.STRING_MUST_NOT_BE_EMPTY;
1137                 }
1138 
1139                 if (!(object instanceof Relationship)) {
1140                     if (PropertyIds.CREATED_BY.equals(propId) || PropertyIds.LAST_MODIFIED_BY.equals(propId)) {
1141                         propertyCheck = PropertyCheckEnum.STRING_MUST_NOT_BE_EMPTY;
1142                     }
1143                 }
1144 
1145                 // known properties that are strings and should be set
1146                 if (PropertyIds.NAME.equals(propId) || PropertyIds.POLICY_TEXT.equals(propId)) {
1147                     propertyCheck = PropertyCheckEnum.STRING_SHOULD_NOT_BE_EMPTY;
1148                 }
1149 
1150                 // known properties that are not strings and must be set
1151                 if (PropertyIds.IS_IMMUTABLE.equals(propId)) {
1152                     propertyCheck = PropertyCheckEnum.MUST_BE_SET;
1153                 }
1154 
1155                 if (!(object instanceof Relationship)) {
1156                     if (PropertyIds.CREATION_DATE.equals(propId) || PropertyIds.LAST_MODIFICATION_DATE.equals(propId)) {
1157                         propertyCheck = PropertyCheckEnum.MUST_BE_SET;
1158                     }
1159                 }
1160 
1161                 // special case: parent
1162                 if (PropertyIds.PARENT_ID.equals(propId)) {
1163                     if (object instanceof Folder) {
1164                         if (((Folder) object).isRootFolder()) {
1165                             propertyCheck = PropertyCheckEnum.MUST_NOT_BE_SET;
1166                         } else {
1167                             propertyCheck = PropertyCheckEnum.STRING_MUST_NOT_BE_EMPTY;
1168                         }
1169                     } else {
1170                         addResult(results, createResult(FAILURE,
1171                                 "Property " + PropertyIds.PARENT_ID + " is only defined for folders!"));
1172                     }
1173                 }
1174 
1175                 // special case: path
1176                 if (PropertyIds.PATH.equals(propId) && prop.getFirstValue() != null) {
1177                     Object path = prop.getFirstValue();
1178                     if (path instanceof String) {
1179                         f = createResult(FAILURE, "Path does not start with '/': " + path);
1180                         addResult(results, assertIsTrue(
1181                                 ((String) path).length() > 0 && ((String) path).charAt(0) == '/', null, f));
1182                     } else {
1183                         addResult(results, createResult(FAILURE, "Property " + PropertyIds.PATH + " is not a string!"));
1184                     }
1185                 }
1186 
1187                 // check property
1188                 addResult(results, checkProperty(prop, "Property " + propId, propertyCheck));
1189 
1190                 // catch creationDate and lastModificationDate
1191                 if (PropertyIds.CREATION_DATE.equals(propId)) {
1192                     if (prop != null) {
1193                         creationDate = (GregorianCalendar) prop.getFirstValue();
1194                     }
1195                 } else if (PropertyIds.LAST_MODIFICATION_DATE.equals(propId)) {
1196                     if (prop != null) {
1197                         lastModificationDate = (GregorianCalendar) prop.getFirstValue();
1198                     }
1199                 }
1200             }
1201 
1202             // check creationDate <= lastModificationDate
1203             if (creationDate != null && lastModificationDate != null) {
1204                 f = createResult(FAILURE, "Last modification date precedes creation date!");
1205                 addResult(results, assertIsTrue(
1206                         creationDate.getTimeInMillis() <= lastModificationDate.getTimeInMillis(), null, f));
1207 
1208                 f = createResult(WARNING, "Creation date and last modification date have different timezones.");
1209                 addResult(assertIsTrue(creationDate.getTimeZone().hasSameRules(lastModificationDate.getTimeZone()),
1210                         null, f));
1211             }
1212 
1213             // allowable actions
1214             if ((object.getAllowableActions() == null)
1215                     || (object.getAllowableActions().getAllowableActions() == null)) {
1216                 addResult(results, createResult(FAILURE, "Object has no allowable actions!"));
1217             } else {
1218                 Set<Action> actions = object.getAllowableActions().getAllowableActions();
1219 
1220                 f = createResult(FAILURE, "Object has no CAN_GET_PROPERTIES allowable action!");
1221                 addResult(results, assertAllowableAction(object, Action.CAN_GET_PROPERTIES, null, f));
1222                 addResult(results, assertIsTrue(object.hasAllowableAction(Action.CAN_GET_PROPERTIES), null, f));
1223 
1224                 if (object instanceof Document) {
1225                     if (actions.contains(Action.CAN_CHECK_OUT) && actions.contains(Action.CAN_CHECK_IN)) {
1226                         addResult(results, createResult(FAILURE,
1227                                 "Document object has CAN_CHECK_OUT and CAN_CHECK_IN allowable actions!"));
1228                     }
1229 
1230                     if (actions.contains(Action.CAN_CHECK_OUT) && actions.contains(Action.CAN_CANCEL_CHECK_OUT)) {
1231                         addResult(results, createResult(FAILURE,
1232                                 "Document object has CAN_CHECK_OUT and CAN_CANCEL_CHECK_OUT allowable actions!"));
1233                     }
1234 
1235                     Document doc = (Document) object;
1236                     DocumentTypeDefinition docType = (DocumentTypeDefinition) doc.getType();
1237                     if (doc.isVersionSeriesCheckedOut() != null) {
1238                         if (doc.isVersionSeriesCheckedOut()) {
1239                             f = createResult(WARNING,
1240                                     "Document is checked out and has CAN_CHECK_OUT allowable action!");
1241                             addResult(results, assertNotAllowableAction(object, Action.CAN_CHECK_OUT, null, f));
1242 
1243                             if (doc.getVersionSeriesCheckedOutId() == null) {
1244                                 addResult(results, createResult(WARNING,
1245                                         "Document is checked out and but the property cmis:versionSeriesCheckedOutId is not set!"));
1246                             } else {
1247                                 if (doc.getVersionSeriesCheckedOutId().equals(object.getId())) {
1248                                     // object is PWC
1249                                     f = createResult(FAILURE, "PWC doesn't have CAN_CHECK_IN allowable action!");
1250                                     addResult(results, assertAllowableAction(object, Action.CAN_CHECK_IN, null, f));
1251 
1252                                     f = createResult(FAILURE,
1253                                             "PWC doesn't have CAN_CANCEL_CHECK_OUT allowable action!");
1254                                     addResult(results,
1255                                             assertAllowableAction(object, Action.CAN_CANCEL_CHECK_OUT, null, f));
1256                                 } else {
1257                                     // object is not PWC
1258                                     f = createResult(WARNING, "Non-PWC has CAN_CHECK_IN allowable action!");
1259                                     addResult(results, assertNotAllowableAction(object, Action.CAN_CHECK_IN, null, f));
1260 
1261                                     f = createResult(WARNING, "Non-PWC has CAN_CANCEL_CHECK_OUT allowable action!");
1262                                     addResult(results,
1263                                             assertNotAllowableAction(object, Action.CAN_CANCEL_CHECK_OUT, null, f));
1264                                 }
1265                             }
1266                         } else {
1267                             f = createResult(FAILURE,
1268                                     "Document is not checked out and has CAN_CHECK_IN allowable action!");
1269                             addResult(results, assertNotAllowableAction(object, Action.CAN_CHECK_IN, null, f));
1270 
1271                             f = createResult(FAILURE,
1272                                     "Document is not checked out and has CAN_CANCEL_CHECK_OUT allowable action!");
1273                             addResult(results, assertNotAllowableAction(object, Action.CAN_CANCEL_CHECK_OUT, null, f));
1274 
1275                             // versionable check
1276                             if (docType.isVersionable()) {
1277                                 if (Boolean.TRUE.equals(doc.isLatestVersion())) {
1278                                     f = createResult(WARNING,
1279                                             "Document is versionable and not checked but has no CAN_CHECK_OUT allowable action!");
1280                                     addResult(results, assertAllowableAction(object, Action.CAN_CHECK_OUT, null, f));
1281                                 }
1282                             } else {
1283                                 f = createResult(FAILURE,
1284                                         "Document is not versionable but has CAN_CHECK_OUT allowable action!");
1285                                 addResult(results, assertNotAllowableAction(object, Action.CAN_CHECK_OUT, null, f));
1286                             }
1287                         }
1288                     } else {
1289                         addResult(results,
1290                                 createResult(WARNING, "Property cmis:isVersionSeriesCheckedOut is not set!"));
1291                     }
1292 
1293                     // immutable check
1294                     if (Boolean.TRUE.equals(doc.isImmutable())) {
1295                         f = createResult(FAILURE,
1296                                 "Document is immutable and has CAN_UPDATE_PROPERTIES allowable action!");
1297                         addResult(results, assertNotAllowableAction(object, Action.CAN_UPDATE_PROPERTIES, null, f));
1298 
1299                         f = createResult(FAILURE, "Document is immutable and has CAN_DELETE_OBJECT allowable action!");
1300                         addResult(results, assertNotAllowableAction(object, Action.CAN_DELETE_OBJECT, null, f));
1301                     }
1302                 } else {
1303                     f = createResult(FAILURE, "Non-Document object has CAN_CHECK_IN allowable action!");
1304                     addResult(results, assertNotAllowableAction(object, Action.CAN_CHECK_IN, null, f));
1305 
1306                     f = createResult(FAILURE, "Non-Document object has CAN_CHECK_OUT allowable action!");
1307                     addResult(results, assertNotAllowableAction(object, Action.CAN_CHECK_OUT, null, f));
1308 
1309                     f = createResult(FAILURE, "Non-Document object has CAN_CANCEL_CHECK_OUT allowable action!");
1310                     addResult(results, assertNotAllowableAction(object, Action.CAN_CANCEL_CHECK_OUT, null, f));
1311 
1312                     f = createResult(FAILURE, "Non-Document object has CAN_GET_CONTENT_STREAM allowable action!");
1313                     addResult(results, assertNotAllowableAction(object, Action.CAN_GET_CONTENT_STREAM, null, f));
1314 
1315                     f = createResult(FAILURE, "Non-Document object has CAN_DELETE_CONTENT_STREAM allowable action!");
1316                     addResult(results, assertNotAllowableAction(object, Action.CAN_DELETE_CONTENT_STREAM, null, f));
1317 
1318                     f = createResult(FAILURE, "Non-Document object has CAN_GET_ALL_VERSIONS allowable action!");
1319                     addResult(results, assertNotAllowableAction(object, Action.CAN_GET_ALL_VERSIONS, null, f));
1320                 }
1321 
1322                 if (object instanceof Folder) {
1323                     Folder folder = (Folder) object;
1324                     if (folder.isRootFolder()) {
1325                         f = createResult(FAILURE, "Root folder has CAN_DELETE_OBJECT allowable action!");
1326                         addResult(results, assertNotAllowableAction(object, Action.CAN_DELETE_OBJECT, null, f));
1327 
1328                         f = createResult(FAILURE, "Root folder has CAN_GET_FOLDER_PARENT allowable action!");
1329                         addResult(results, assertNotAllowableAction(object, Action.CAN_GET_FOLDER_PARENT, null, f));
1330 
1331                         f = createResult(FAILURE, "Root folder has CAN_MOVE_OBJECT allowable action!");
1332                         addResult(results, assertNotAllowableAction(object, Action.CAN_MOVE_OBJECT, null, f));
1333                     }
1334                 } else {
1335                     f = createResult(FAILURE, "Non-Folder object has CAN_GET_DESCENDANTS allowable action!");
1336                     addResult(results, assertNotAllowableAction(object, Action.CAN_GET_DESCENDANTS, null, f));
1337 
1338                     f = createResult(FAILURE, "Non-Folder object has CAN_GET_FOLDER_PARENT allowable action!");
1339                     addResult(results, assertNotAllowableAction(object, Action.CAN_GET_FOLDER_PARENT, null, f));
1340 
1341                     f = createResult(FAILURE, "Non-Folder object has CAN_GET_CHILDREN allowable action!");
1342                     addResult(results, assertNotAllowableAction(object, Action.CAN_GET_CHILDREN, null, f));
1343 
1344                     f = createResult(FAILURE, "Non-Folder object has CAN_DELETE_TREE allowable action!");
1345                     addResult(results, assertNotAllowableAction(object, Action.CAN_DELETE_TREE, null, f));
1346 
1347                     f = createResult(FAILURE, "Non-Folder object has CAN_GET_FOLDER_PARENT allowable action!");
1348                     addResult(results, assertNotAllowableAction(object, Action.CAN_GET_FOLDER_PARENT, null, f));
1349 
1350                     f = createResult(FAILURE, "Non-Folder object has CAN_CREATE_DOCUMENT allowable action!");
1351                     addResult(results, assertNotAllowableAction(object, Action.CAN_CREATE_DOCUMENT, null, f));
1352 
1353                     f = createResult(FAILURE, "Non-Folder object has CAN_CREATE_FOLDER allowable action!");
1354                     addResult(results, assertNotAllowableAction(object, Action.CAN_CREATE_FOLDER, null, f));
1355                 }
1356 
1357                 if (!(object instanceof FileableCmisObject) || (object instanceof Folder)) {
1358                     f = createResult(FAILURE,
1359                             "Non-Filable object or folder has CAN_ADD_OBJECT_TO_FOLDER allowable action!");
1360                     addResult(results, assertNotAllowableAction(object, Action.CAN_ADD_OBJECT_TO_FOLDER, null, f));
1361 
1362                     f = createResult(FAILURE,
1363                             "Non-Filable object or folder has CAN_REMOVE_OBJECT_FROM_FOLDER allowable action!");
1364                     addResult(results, assertNotAllowableAction(object, Action.CAN_REMOVE_OBJECT_FROM_FOLDER, null, f));
1365                 }
1366 
1367                 if (!(object instanceof FileableCmisObject)) {
1368                     f = createResult(FAILURE, "Non-Fileable object has CAN_MOVE_OBJECT allowable action!");
1369                     addResult(results, assertNotAllowableAction(object, Action.CAN_MOVE_OBJECT, null, f));
1370                 }
1371 
1372                 // get allowable actions again
1373                 AllowableActions allowableActions = session.getBinding().getObjectService()
1374                         .getAllowableActions(session.getRepositoryInfo().getId(), object.getId(), null);
1375 
1376                 if (allowableActions.getAllowableActions() == null) {
1377                     addResult(results,
1378                             createResult(FAILURE, "getAllowableActions() didn't returned allowable actions!"));
1379                 } else {
1380                     f = createResult(FAILURE,
1381                             "Object allowable actions don't match the allowable actions returned by getAllowableActions()!");
1382                     addResult(results, assertEqualSet(object.getAllowableActions().getAllowableActions(),
1383                             allowableActions.getAllowableActions(), null, f));
1384                 }
1385             }
1386 
1387             // check ACL
1388             if (object.getAcl() != null && object.getAcl().getAces() != null) {
1389                 addResult(results, checkACL(session, object.getAcl(), true, "ACL"));
1390             }
1391 
1392             // check policies
1393             if (hasPolicies(session)) {
1394                 try {
1395                     List<ObjectData> appliedPolicies = session.getBinding().getPolicyService()
1396                             .getAppliedPolicies(session.getRepositoryInfo().getId(), object.getId(), "*", null);
1397 
1398                     if (appliedPolicies == null) {
1399                         appliedPolicies = Collections.emptyList();
1400                     }
1401 
1402                     List<Policy> objectPolicies = object.getPolicies();
1403                     if (objectPolicies == null) {
1404                         objectPolicies = Collections.emptyList();
1405                     }
1406 
1407                     f = createResult(FAILURE,
1408                             "The number of policies returned by getAppliedPolicies() and the number of object policies don't match!");
1409                     addResult(results, assertEquals(appliedPolicies.size(), objectPolicies.size(), null, f));
1410                 } catch (CmisNotSupportedException e) {
1411                     addResult(results,
1412                             createResult(WARNING, "getAppliedPolicies() not supported for object: " + object.getId()));
1413                 }
1414             }
1415 
1416             // check relationships
1417             checkRelationships(session, results, object);
1418 
1419             // check document content
1420             checkDocumentContent(session, results, object);
1421 
1422             // check renditions
1423             if (object.getRenditions() != null) {
1424                 addResult(results, checkRenditions(session, object, "Rendition check"));
1425             }
1426 
1427             // check allowed child object type ids
1428             if (object instanceof Folder) {
1429                 List<String> otids = object.getPropertyValue(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS);
1430                 if (otids != null) {
1431                     for (String otid : otids) {
1432                         try {
1433                             session.getTypeDefinition(otid);
1434                         } catch (CmisBaseException e) {
1435                             addResult(results,
1436                                     createResult(FAILURE,
1437                                             "The cmis:allowedChildObjectTypeIds property contains the type ID '" + otid
1438                                                     + "' but the type doesn't exists. Folder ID: " + object.getId()));
1439                         }
1440                     }
1441                 }
1442             }
1443 
1444             // check path
1445             if (object instanceof FileableCmisObject) {
1446                 List<String> paths = ((FileableCmisObject) object).getPaths();
1447                 if (object instanceof Folder) {
1448                     f = createResult(FAILURE, "Folder does not have excatly one path! This is an OpenCMIS bug!");
1449                     addResult(results, assertEquals(1, paths.size(), null, f));
1450                 } else {
1451                     if (Boolean.FALSE.equals(session.getRepositoryInfo().getCapabilities().isMultifilingSupported())) {
1452                         f = createResult(FAILURE,
1453                                 "Repository does not support multi-filing, but the object has more than one parent!");
1454                         addResult(results, assertIsTrue(paths.size() < 2, null, f));
1455                     }
1456                 }
1457             }
1458         }
1459 
1460         CmisTestResultImpl result = createResult(getWorst(results), message);
1461         result.getChildren().addAll(results);
1462 
1463         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
1464     }
1465 
1466     protected CmisTestResult checkACL(Session session, Acl acl, boolean checkExact, String message) {
1467         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
1468 
1469         CmisTestResult f;
1470 
1471         f = createResult(FAILURE, "ACL is null!");
1472         addResult(results, assertNotNull(acl, null, f));
1473 
1474         if (acl != null) {
1475 
1476             f = createResult(FAILURE, "List of ACEs is null!");
1477             addResult(results, assertNotNull(acl.getAces(), null, f));
1478 
1479             if (acl.getAces() != null) {
1480                 for (Ace ace : acl.getAces()) {
1481                     f = createResult(FAILURE, "ACE with empty principal ID!");
1482                     addResult(results, assertStringNotEmpty(ace.getPrincipalId(), null, f));
1483 
1484                     f = createResult(FAILURE, "ACE with empty permission list!");
1485                     addResult(results, assertListNotEmpty(ace.getPermissions(), null, f));
1486 
1487                     if (ace.getPermissions() != null) {
1488                         for (String permission : ace.getPermissions()) {
1489                             f = createResult(FAILURE, "ACE with empty permission entry!");
1490                             addResult(results, assertStringNotEmpty(permission, null, f));
1491                         }
1492                     }
1493                 }
1494             }
1495 
1496             CmisTestResultStatus status = checkExact ? WARNING : INFO;
1497             f = createResult(status, "ACL is provided but the isExact flag is not set!");
1498             addResult(results, assertNotNull(acl.isExact(), null, f));
1499         }
1500 
1501         CmisTestResultImpl result = createResult(getWorst(results), message);
1502         result.getChildren().addAll(results);
1503 
1504         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
1505     }
1506 
1507     private void checkRelationships(Session session, List<CmisTestResult> results, CmisObject object) {
1508         if (object instanceof Relationship) {
1509             if (isNotEmpty(object.getRelationships())) {
1510                 addResult(results, createResult(FAILURE, "A relationship has relationships!"));
1511                 return;
1512             }
1513         }
1514 
1515         if (object.getRelationships() != null) {
1516             for (Relationship relationship : object.getRelationships()) {
1517                 if (relationship == null) {
1518                     addResult(results, createResult(FAILURE, "A relationship in the relationship list is null!"));
1519                     continue;
1520                 }
1521 
1522                 CmisObject fullRelationshipObject = session.getObject(relationship, SELECT_ALL_NO_CACHE_OC);
1523                 addResult(results,
1524                         checkObject(session, fullRelationshipObject, getAllProperties(fullRelationshipObject),
1525                                 "Relationship check: " + fullRelationshipObject.getId()));
1526             }
1527         }
1528     }
1529 
1530     private void checkDocumentContent(Session session, List<CmisTestResult> results, CmisObject object) {
1531         if (!(object instanceof Document)) {
1532             // only documents have content
1533             return;
1534         }
1535 
1536         CmisTestResult f;
1537 
1538         Document doc = (Document) object;
1539         DocumentTypeDefinition type = (DocumentTypeDefinition) doc.getType();
1540 
1541         // check ContentStreamAllowed flag
1542         boolean hasContentProperties = (doc.getContentStreamFileName() != null) || (doc.getContentStreamId() != null)
1543                 || (doc.getContentStreamLength() > -1) || (doc.getContentStreamMimeType() != null);
1544 
1545         if (hasContentProperties) {
1546             if (type.getContentStreamAllowed() == ContentStreamAllowed.NOTALLOWED) {
1547                 addResult(results, createResult(FAILURE,
1548                         "Content properties have values but the document type doesn't allow content!"));
1549             }
1550         } else {
1551             if (type.getContentStreamAllowed() == ContentStreamAllowed.REQUIRED) {
1552                 addResult(results,
1553                         createResult(FAILURE, "Content properties are not set but the document type demands content!"));
1554             }
1555         }
1556 
1557         // get the content stream
1558         ContentStream contentStream = doc.getContentStream();
1559 
1560         if (contentStream == null) {
1561             if (hasContentProperties && doc.getContentStreamLength() > 0) {
1562                 addResult(results,
1563                         createResult(FAILURE, "Content properties have values but the document has no content!"));
1564             }
1565 
1566             if (type.getContentStreamAllowed() == ContentStreamAllowed.REQUIRED) {
1567                 addResult(results,
1568                         createResult(FAILURE, "The document type demands content but the document has no content!"));
1569             }
1570 
1571             return;
1572         }
1573 
1574         if (type.getContentStreamAllowed() == ContentStreamAllowed.NOTALLOWED) {
1575             addResult(results, createResult(FAILURE, "Document type doesn't allow content but document has content!"));
1576         }
1577 
1578         // file name check
1579         f = createResult(FAILURE, "Content file names don't match!");
1580         addResult(results, assertEquals(doc.getContentStreamFileName(), contentStream.getFileName(), null, f));
1581 
1582         if (doc.getContentStreamLength() > -1 && contentStream.getLength() > -1) {
1583             f = createResult(FAILURE, "Content lengths don't match!");
1584             addResult(results, assertEquals(doc.getContentStreamLength(), contentStream.getLength(), null, f));
1585         }
1586 
1587         // MIME type check
1588         String docMimeType = doc.getContentStreamMimeType();
1589         if (docMimeType != null) {
1590             int x = docMimeType.indexOf(';');
1591             if (x > -1) {
1592                 docMimeType = docMimeType.substring(0, x);
1593             }
1594             docMimeType = docMimeType.trim();
1595         }
1596 
1597         String contentMimeType = contentStream.getMimeType();
1598         if (contentMimeType != null) {
1599             int x = contentMimeType.indexOf(';');
1600             if (x > -1) {
1601                 contentMimeType = contentMimeType.substring(0, x);
1602             }
1603             contentMimeType = contentMimeType.trim();
1604         }
1605 
1606         f = createResult(FAILURE, "Content MIME types don't match!");
1607         addResult(results, assertEquals(docMimeType, contentMimeType, null, f));
1608 
1609         if (contentStream.getMimeType() != null) {
1610             if (contentMimeType.equals(docMimeType)) {
1611                 f = createResult(WARNING, "Content MIME types don't match!");
1612                 addResult(results, assertEquals(doc.getContentStreamMimeType(), contentStream.getMimeType(), null, f));
1613             }
1614 
1615             f = createResult(FAILURE, "Content MIME types is invalid: " + contentStream.getMimeType());
1616             addResult(results, assertIsTrue(
1617                     contentStream.getMimeType().length() > 2 && contentStream.getMimeType().indexOf('/') > 0, null, f));
1618         }
1619 
1620         // check stream
1621         InputStream stream = contentStream.getStream();
1622         if (stream == null) {
1623             addResult(results, createResult(FAILURE, "Document has no content stream!"));
1624             return;
1625         }
1626 
1627         // collect hashes
1628         List<ContentStreamHash> hashes = doc.getContentStreamHashes();
1629         List<MessageDigest> messageDigests = null;
1630         List<String> algorithms = null;
1631 
1632         if (hashes != null) {
1633             algorithms = new ArrayList<String>(hashes.size());
1634             messageDigests = new ArrayList<MessageDigest>(hashes.size());
1635 
1636             for (ContentStreamHash hash : hashes) {
1637                 if (hash.getAlgorithm() == null) {
1638                     addResult(results,
1639                             createResult(FAILURE, "Invalid content stream hash: " + hash.getPropertyValue()));
1640                 } else {
1641                     try {
1642                         messageDigests.add(MessageDigest.getInstance(hash.getAlgorithm()));
1643                         algorithms.add(hash.getAlgorithm());
1644                     } catch (NoSuchAlgorithmException e) {
1645                         // we don't know this algorithm - that's ok
1646                     }
1647                 }
1648             }
1649         }
1650 
1651         try {
1652             long bytes = 0;
1653             byte[] buffer = new byte[64 * 1024];
1654             int b = stream.read(buffer);
1655             while (b > -1) {
1656                 bytes += b;
1657 
1658                 if (messageDigests != null) {
1659                     for (MessageDigest md : messageDigests) {
1660                         md.update(buffer, 0, b);
1661                     }
1662                 }
1663 
1664                 b = stream.read(buffer);
1665             }
1666             stream.close();
1667 
1668             // check content length
1669             if (doc.getContentStreamLength() > -1) {
1670                 f = createResult(FAILURE,
1671                         "Content stream length property value doesn't match the actual content length!");
1672                 addResult(results, assertEquals(doc.getContentStreamLength(), bytes, null, f));
1673             }
1674 
1675             if (contentStream.getLength() > -1) {
1676                 f = createResult(FAILURE, "Content length value doesn't match the actual content length!");
1677                 addResult(results, assertEquals(contentStream.getLength(), bytes, null, f));
1678             }
1679 
1680             // check hashes
1681             if (messageDigests != null) {
1682                 int n = messageDigests.size();
1683                 for (int i = 0; i < n; i++) {
1684                     ContentStreamHash testHash = new ContentStreamHashImpl(algorithms.get(i),
1685                             messageDigests.get(i).digest());
1686 
1687                     for (ContentStreamHash repHash : hashes) {
1688                         if (testHash.getAlgorithm().equals(repHash.getAlgorithm())) {
1689                             f = createResult(CmisTestResultStatus.FAILURE,
1690                                     "This content stream hash is wrong: " + repHash.getPropertyValue());
1691                             addResult(assertEquals(testHash.getHash(), repHash.getHash(), null, f));
1692                             break;
1693                         }
1694                     }
1695                 }
1696             }
1697 
1698         } catch (Exception e) {
1699             addResult(results, createResult(FAILURE, "Reading content failed: " + e, e, false));
1700         } finally {
1701             IOUtils.closeQuietly(stream);
1702         }
1703     }
1704 
1705     protected CmisTestResult checkRenditions(Session session, CmisObject object, String message) {
1706         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
1707 
1708         CmisTestResult f;
1709 
1710         if (object.getRenditions() != null) {
1711 
1712             for (Rendition rend : object.getRenditions()) {
1713                 f = createResult(FAILURE, "A rendition in the list of renditions is null!");
1714                 addResult(results, assertNotNull(rend, null, f));
1715 
1716                 if (rend != null) {
1717                     f = createResult(FAILURE, "A rendition has an empty stream ID!");
1718                     addResult(results, assertStringNotEmpty(rend.getStreamId(), null, f));
1719 
1720                     f = createResult(FAILURE, "A rendition has an empty kind! Stream ID: " + rend.getStreamId());
1721                     addResult(results, assertStringNotEmpty(rend.getKind(), null, f));
1722 
1723                     f = createResult(FAILURE, "A rendition has an empty MIME type! Stream ID: " + rend.getStreamId());
1724                     addResult(results, assertStringNotEmpty(rend.getMimeType(), null, f));
1725 
1726                     if ("cmis:thumbnail".equals(rend.getKind())) {
1727                         f = createResult(WARNING,
1728                                 "A rendition is of kind 'cmis:thumbnail' but the height is not set or has an invalid value! Stream ID: "
1729                                         + rend.getStreamId());
1730                         addResult(results, assertIsTrue(rend.getHeight() > 0, null, f));
1731 
1732                         f = createResult(WARNING,
1733                                 "A rendition is of kind 'cmis:thumbnail' but the width is not set or has an invalid value! Stream ID: "
1734                                         + rend.getStreamId());
1735                         addResult(results, assertIsTrue(rend.getWidth() > 0, null, f));
1736                     }
1737 
1738                     // check the content
1739                     ContentStream contentStream = rend.getContentStream();
1740                     f = createResult(FAILURE, "A rendition has no content stream! Stream ID: " + rend.getStreamId());
1741                     addResult(results, assertNotNull(contentStream, null, f));
1742 
1743                     if (contentStream != null) {
1744                         InputStream stream = contentStream.getStream();
1745 
1746                         f = createResult(FAILURE, "A rendition has no stream! Stream ID: " + rend.getStreamId());
1747                         addResult(results, assertNotNull(stream, null, f));
1748 
1749                         if (stream != null) {
1750                             try {
1751                                 long bytes = 0;
1752                                 byte[] buffer = new byte[64 * 1024];
1753                                 int b = stream.read(buffer);
1754                                 while (b > -1) {
1755                                     bytes += b;
1756                                     b = stream.read(buffer);
1757                                 }
1758                                 stream.close();
1759 
1760                                 // check content length
1761                                 if (rend.getLength() > -1) {
1762                                     f = createResult(FAILURE,
1763                                             "Rendition content stream length value doesn't match the actual content length!");
1764                                     addResult(results, assertEquals(rend.getLength(), bytes, null, f));
1765                                 }
1766                             } catch (Exception e) {
1767                                 addResult(results, createResult(FAILURE, "Reading content failed: " + e, e, false));
1768                             } finally {
1769                                 IOUtils.closeQuietly(stream);
1770                             }
1771                         }
1772                     }
1773                 }
1774             }
1775         }
1776 
1777         CmisTestResultImpl result = createResult(getWorst(results), message);
1778         result.getChildren().addAll(results);
1779 
1780         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
1781     }
1782 
1783     protected CmisTestResult checkVersionHistory(Session session, CmisObject object, String[] properties,
1784             String message) {
1785         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
1786 
1787         CmisTestResult f;
1788 
1789         if (object.getBaseTypeId() != BaseTypeId.CMIS_DOCUMENT) {
1790             // skip non-document objects
1791             return null;
1792         }
1793 
1794         if (!Boolean.TRUE.equals(((DocumentTypeDefinition) object.getType()).isVersionable())) {
1795             // skip non-versionable types
1796             return null;
1797         }
1798 
1799         Document doc = (Document) object;
1800 
1801         // check version series ID
1802         String versionSeriesId = doc.getVersionSeriesId();
1803 
1804         f = createResult(FAILURE, "Versionable document has no version series ID property!");
1805         addResult(results, assertStringNotEmpty(versionSeriesId, null, f));
1806         if (versionSeriesId == null) {
1807             CmisTestResultImpl result = createResult(getWorst(results), message);
1808             result.getChildren().addAll(results);
1809             return result;
1810         }
1811 
1812         // get version history
1813         List<Document> versions = doc.getAllVersions(SELECT_ALL_NO_CACHE_OC);
1814 
1815         f = createResult(FAILURE, "Version history is null!");
1816         addResult(results, assertNotNull(versions, null, f));
1817         if (versions == null) {
1818             CmisTestResultImpl result = createResult(getWorst(results), message);
1819             result.getChildren().addAll(results);
1820             return result;
1821         }
1822 
1823         f = createResult(FAILURE, "Version history must have at least one version!");
1824         addResult(results, assertListNotEmpty(versions, null, f));
1825 
1826         if (!versions.isEmpty()) {
1827             // get latest version
1828             Document lastestVersion = doc.getObjectOfLatestVersion(false, SELECT_ALL_NO_CACHE_OC);
1829             addResult(results, checkObject(session, lastestVersion, properties,
1830                     "Latest version check: " + lastestVersion.getId()));
1831 
1832             f = createResult(FAILURE, "Latest version is not flagged as latest version! ID: " + lastestVersion.getId());
1833             addResult(results, assertIsTrue(lastestVersion.isLatestVersion(), null, f));
1834 
1835             // get latest major version
1836             Document lastestMajorVersion = null;
1837             try {
1838                 lastestMajorVersion = doc.getObjectOfLatestVersion(true, SELECT_ALL_NO_CACHE_OC);
1839 
1840                 f = createResult(FAILURE, "getObjectOfLatestVersion returned an invalid object!");
1841                 addResult(results, assertNotNull(lastestMajorVersion, null, f));
1842             } catch (CmisObjectNotFoundException e) {
1843                 // no latest major version
1844             }
1845             if (lastestMajorVersion != null) {
1846                 addResult(results, checkObject(session, lastestMajorVersion, properties,
1847                         "Latest major version check: " + lastestMajorVersion.getId()));
1848 
1849                 f = createResult(FAILURE, "Latest major version is not flagged as latest major version! ID: "
1850                         + lastestMajorVersion.getId());
1851                 addResult(results, assertIsTrue(lastestMajorVersion.isLatestMajorVersion(), null, f));
1852             }
1853 
1854             // iterate through the version history and test each version
1855             // document
1856             long creatationDate = Long.MAX_VALUE;
1857             int latestVersion = 0;
1858             int latestMajorVersion = 0;
1859             long latestModificationDate = Long.MAX_VALUE;
1860             int latestModifictaionIndex = Integer.MIN_VALUE;
1861             Set<String> versionLabels = new HashSet<String>();
1862             boolean found = false;
1863             boolean foundLastestVersion = false;
1864             boolean foundLastestMajorVersion = false;
1865             for (int i = 0; i < versions.size(); i++) {
1866                 Document version = versions.get(i);
1867 
1868                 f = createResult(FAILURE, "Version " + i + " is null!");
1869                 addResult(results, assertNotNull(version, null, f));
1870                 if (version == null) {
1871                     continue;
1872                 }
1873 
1874                 addResult(results, checkObject(session, version, properties, "Version check: " + version.getId()));
1875 
1876                 // check first entry
1877                 if (i == 0) {
1878                     if (version.isVersionSeriesCheckedOut()) {
1879                         f = createResult(WARNING,
1880                                 "Version series is checked-out and the PWC is not the latest version! ID: "
1881                                         + version.getId()
1882                                         + " (Note: The words of the CMIS specification define that the PWC is the latest version."
1883                                         + " But that is not the intention of the spec and will be changed in CMIS 1.1."
1884                                         + " Thus this a warning, not an error.)");
1885                         addResult(results, assertIsTrue(version.isLatestVersion(), null, f));
1886                     } else {
1887                         f = createResult(FAILURE,
1888                                 "Version series is not checked-out and first version history entry is not the latest version! ID: "
1889                                         + version.getId());
1890                         addResult(results, assertIsTrue(version.isLatestVersion(), null, f));
1891                     }
1892                 }
1893 
1894                 // check version ID
1895                 f = createResult(FAILURE, "Version series id does not match! ID: " + version.getId());
1896                 addResult(results, assertEquals(versionSeriesId, version.getVersionSeriesId(), null, f));
1897 
1898                 // check creation date
1899                 if (creatationDate == version.getCreationDate().getTimeInMillis()) {
1900                     addResult(results, createResult(WARNING, "Two or more versions have the same creation date!"));
1901                 } else {
1902                     f = createResult(FAILURE, "Version history order incorrect! Must be sorted bei creation date!");
1903                     addResult(results,
1904                             assertIsTrue(version.getCreationDate().getTimeInMillis() <= creatationDate, null, f));
1905                 }
1906 
1907                 // count latest versions and latest major versions
1908                 if (version.isLatestVersion()) {
1909                     latestVersion++;
1910                 }
1911 
1912                 if (version.isLatestMajorVersion()) {
1913                     latestMajorVersion++;
1914                 }
1915 
1916                 // find latest modification date
1917                 if (latestModificationDate == version.getLastModificationDate().getTimeInMillis()) {
1918                     addResult(results,
1919                             createResult(WARNING, "Two or more versions have the same last modification date!"));
1920                 } else if (latestModificationDate < version.getLastModificationDate().getTimeInMillis()) {
1921                     latestModificationDate = version.getLastModificationDate().getTimeInMillis();
1922                     latestModifictaionIndex = i;
1923                 }
1924 
1925                 // check for version label duplicates
1926                 String versionLabel = version.getVersionLabel();
1927                 f = createResult(WARNING, "More than one version have this version label: " + versionLabel);
1928                 addResult(results, assertIsFalse(versionLabels.contains(versionLabel), null, f));
1929 
1930                 versionLabels.add(versionLabel);
1931 
1932                 // check PWC
1933                 if (version.getId().equals(version.getVersionSeriesCheckedOutId())) {
1934                     f = createResult(FAILURE,
1935                             "PWC must not be flagged as latest major version! ID: " + version.getId());
1936                     addResult(results, assertIsFalse(version.isLatestMajorVersion(), null, f));
1937                 }
1938 
1939                 // check checked out
1940                 if (Boolean.TRUE.equals(doc.isVersionSeriesCheckedOut())) {
1941                     f = createResult(WARNING,
1942                             "Version series is marked as checked out but cmis:versionSeriesCheckedOutId is not set! ID: "
1943                                     + version.getId());
1944                     addResult(results, assertStringNotEmpty(doc.getVersionSeriesCheckedOutId(), null, f));
1945 
1946                     f = createResult(WARNING,
1947                             "Version series is marked as checked out but cmis:versionSeriesCheckedOutBy is not set! ID: "
1948                                     + version.getId());
1949                     addResult(results, assertStringNotEmpty(doc.getVersionSeriesCheckedOutBy(), null, f));
1950                 } else if (Boolean.FALSE.equals(doc.isVersionSeriesCheckedOut())) {
1951                     f = createResult(FAILURE,
1952                             "Version series is not marked as checked out but cmis:versionSeriesCheckedOutId is set! ID: "
1953                                     + version.getId());
1954                     addResult(results, assertNull(doc.getVersionSeriesCheckedOutId(), null, f));
1955 
1956                     f = createResult(FAILURE,
1957                             "Version series is not marked as checked out but cmis:versionSeriesCheckedOutIdBy is set! ID: "
1958                                     + version.getId());
1959                     addResult(results, assertNull(doc.getVersionSeriesCheckedOutBy(), null, f));
1960                 }
1961 
1962                 // found origin object?
1963                 if (version.getId().equals(object.getId())) {
1964                     found = true;
1965                 }
1966 
1967                 // found latest version?
1968                 if (version.getId().equals(lastestVersion.getId())) {
1969                     foundLastestVersion = true;
1970                 }
1971 
1972                 // found latest major version?
1973                 if (lastestMajorVersion != null && version.getId().equals(lastestMajorVersion.getId())) {
1974                     foundLastestMajorVersion = true;
1975                 }
1976             }
1977 
1978             // check latest versions
1979             f = createResult(FAILURE,
1980                     "Version series ID has " + latestVersion + " latest versions! There must be only one!");
1981             addResult(results, assertEquals(1, latestVersion, null, f));
1982 
1983             if (!foundLastestVersion) {
1984                 addResult(results, createResult(FAILURE, "Latest version not found in version history!"));
1985             }
1986 
1987             // check latest major versions
1988             if (lastestMajorVersion == null) {
1989                 f = createResult(FAILURE, "Version series ID has " + latestMajorVersion
1990                         + " latest major version(s) but getObjectOfLatestVersion() didn't return a major version!");
1991                 addResult(results, assertEquals(0, latestMajorVersion, null, f));
1992             } else {
1993                 f = createResult(FAILURE, "Version series ID has " + latestMajorVersion
1994                         + " latest major versions but there should be exactly one!");
1995                 addResult(results, assertEquals(1, latestMajorVersion, null, f));
1996 
1997                 if (!foundLastestMajorVersion) {
1998                     addResult(results, createResult(FAILURE, "Latest major version not found in version history!"));
1999                 }
2000             }
2001 
2002             // check latest version
2003             if (latestModifictaionIndex >= 0) {
2004                 f = createResult(FAILURE,
2005                         "Version with the latest modification date is not flagged as latest version! ID: "
2006                                 + versions.get(latestModifictaionIndex));
2007                 addResult(results, assertIsTrue(versions.get(latestModifictaionIndex).isLatestVersion(), null, f));
2008             }
2009 
2010             // check if the origin object was found
2011             if (!found) {
2012                 addResult(results, createResult(FAILURE, "Document not found in its version history!"));
2013             }
2014         }
2015 
2016         CmisTestResultImpl result = createResult(getWorst(results), message);
2017         result.getChildren().addAll(results);
2018 
2019         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
2020     }
2021 
2022     protected CmisTestResult assertAllowableAction(CmisObject object, Action action, CmisTestResult success,
2023             CmisTestResult failure) {
2024         AllowableActions allowableActions = object.getAllowableActions();
2025         if (allowableActions != null && allowableActions.getAllowableActions() != null) {
2026             if (allowableActions.getAllowableActions().contains(action)) {
2027                 return success;
2028             }
2029         }
2030 
2031         return failure;
2032     }
2033 
2034     protected CmisTestResult assertNotAllowableAction(CmisObject object, Action action, CmisTestResult success,
2035             CmisTestResult failure) {
2036         AllowableActions allowableActions = object.getAllowableActions();
2037         if (allowableActions != null && allowableActions.getAllowableActions() != null) {
2038             if (!allowableActions.getAllowableActions().contains(action)) {
2039                 return success;
2040             }
2041         }
2042 
2043         return failure;
2044     }
2045 
2046     protected CmisTestResult checkProperty(Property<?> property, String message, PropertyCheckEnum propertyCheck) {
2047         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
2048 
2049         CmisTestResult f;
2050 
2051         f = createResult(FAILURE, "Property is not included in response!");
2052         addResult(results, assertNotNull(property, null, f));
2053 
2054         if (property != null) {
2055             f = createResult(FAILURE, "Property ID is not set or empty!");
2056             addResult(results, assertStringNotEmpty(property.getId(), null, f));
2057 
2058             f = createResult(WARNING, "Display name is not set!");
2059             addResult(results, assertNotNull(property.getDisplayName(), null, f));
2060 
2061             f = createResult(WARNING, "Query name is not set!");
2062             addResult(results, assertNotNull(property.getQueryName(), null, f));
2063 
2064             f = createResult(WARNING, "Local name is not set!");
2065             addResult(results, assertNotNull(property.getLocalName(), null, f));
2066 
2067             if ((propertyCheck == PropertyCheckEnum.MUST_BE_SET)
2068                     || (propertyCheck == PropertyCheckEnum.STRING_MUST_NOT_BE_EMPTY)) {
2069                 f = createResult(FAILURE, "Property has no value!");
2070                 addResult(results, assertListNotEmpty(property.getValues(), null, f));
2071             } else if (propertyCheck == PropertyCheckEnum.STRING_SHOULD_NOT_BE_EMPTY) {
2072                 f = createResult(WARNING, "Property has no value!");
2073                 addResult(results, assertListNotEmpty(property.getValues(), null, f));
2074             } else if (propertyCheck == PropertyCheckEnum.MUST_NOT_BE_SET) {
2075                 f = createResult(FAILURE, "Property has a value!");
2076                 addResult(results, assertIsTrue(property.getValues().isEmpty(), null, f));
2077             }
2078 
2079             boolean isString = ((property.getDefinition().getPropertyType() == PropertyType.STRING)
2080                     || (property.getDefinition().getPropertyType() == PropertyType.ID)
2081                     || (property.getDefinition().getPropertyType() == PropertyType.URI)
2082                     || (property.getDefinition().getPropertyType() == PropertyType.HTML));
2083             for (Object value : property.getValues()) {
2084                 if (value == null) {
2085                     addResult(results, createResult(FAILURE, "Property values contain a null value!"));
2086                     break;
2087                 } else if (isString) {
2088                     if (propertyCheck == PropertyCheckEnum.STRING_MUST_NOT_BE_EMPTY) {
2089                         f = createResult(FAILURE, "Property values contain an empty string!");
2090                         addResult(results, assertStringNotEmpty(value.toString(), null, f));
2091                     } else if (propertyCheck == PropertyCheckEnum.STRING_SHOULD_NOT_BE_EMPTY) {
2092                         f = createResult(WARNING, "Property values contain an empty string!");
2093                         addResult(results, assertStringNotEmpty(value.toString(), null, f));
2094                     }
2095                 }
2096             }
2097 
2098             if (property.getDefinition().getCardinality() == Cardinality.SINGLE) {
2099                 f = createResult(FAILURE, "Property cardinality is SINGLE but property has more than one value!");
2100                 addResult(results, assertIsTrue(property.getValues().size() <= 1, null, f));
2101             }
2102 
2103             if (property.getDefinition().isRequired() == null) {
2104                 addResult(results, createResult(FAILURE, "Property definition doesn't contain the required flag!"));
2105             } else {
2106                 if (property.getDefinition().isRequired().booleanValue()) {
2107                     f = createResult(FAILURE, "Property is required but has no value!");
2108                     addResult(results, assertListNotEmpty(property.getValues(), null, f));
2109                 }
2110             }
2111         }
2112 
2113         CmisTestResultImpl result = createResult(getWorst(results), message);
2114         result.getChildren().addAll(results);
2115 
2116         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
2117     }
2118 
2119     protected CmisTestResult checkChildren(Session session, Folder folder, String message) {
2120         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
2121 
2122         CmisTestResult f;
2123 
2124         if (folder == null) {
2125             return createResult(FAILURE, "Folder is null!");
2126         }
2127 
2128         // getChildren
2129 
2130         boolean supportsOrderByName = isOrderByNameSupported(session);
2131         OperationContext orderContext = (supportsOrderByName ? SELECT_ALL_NO_CACHE_OC_ORDER_BY_NAME
2132                 : SELECT_ALL_NO_CACHE_OC);
2133 
2134         long childrenCount = 0;
2135         long childrenFolderCount = 0;
2136         ItemIterable<CmisObject> children = folder.getChildren(orderContext);
2137 
2138         int orderByNameIssues = 0;
2139         String lastName = null;
2140 
2141         for (CmisObject child : children) {
2142             childrenCount++;
2143             if (child instanceof Folder) {
2144                 childrenFolderCount++;
2145             }
2146 
2147             checkChild(session, results, folder, child);
2148 
2149             if (lastName != null && child.getName() != null) {
2150                 if (child.getName().compareToIgnoreCase(lastName) < 0) {
2151                     orderByNameIssues++;
2152                 }
2153             }
2154 
2155             lastName = child.getName();
2156         }
2157 
2158         if (children.getTotalNumItems() >= 0) {
2159             f = createResult(WARNING, "Number of children doesn't match the reported total number of items!");
2160             addResult(results, assertEquals(childrenCount, children.getTotalNumItems(), null, f));
2161         } else {
2162             addResult(results, createResult(WARNING, "getChildren did not report the total number of items!"));
2163         }
2164 
2165         if (supportsOrderByName) {
2166             f = createResult(WARNING,
2167                     "Children should be ordered by cmis:name, but they are not! (It might be a collation mismtach.)");
2168             addResult(results, assertEquals(0, orderByNameIssues, null, f));
2169         } else {
2170             addResult(results, createResult(INFO, "Repository doesn't support Order By for getChildren()."));
2171         }
2172 
2173         // test path segments
2174 
2175         ObjectInFolderList pathSegementChildren = session.getBinding().getNavigationService().getChildren(
2176                 session.getRepositoryInfo().getId(), folder.getId(), "cmis:objectId,cmis:name", null, null, null, null,
2177                 Boolean.TRUE, BigInteger.valueOf(10), BigInteger.ZERO, null);
2178 
2179         if (pathSegementChildren != null && pathSegementChildren.getObjects() != null) {
2180             for (ObjectInFolderData objectInFolder : pathSegementChildren.getObjects()) {
2181                 String pathSegement = objectInFolder.getPathSegment();
2182                 String objectId = (String) objectInFolder.getObject().getProperties().getProperties()
2183                         .get(PropertyIds.OBJECT_ID).getFirstValue();
2184 
2185                 if (pathSegement == null) {
2186                     addResult(results, createResult(FAILURE, "getChildren omitted path segement! ID: " + objectId));
2187                 } else {
2188                     CmisObject pathSegementChild = session.getObjectByPath(folder.getPath(), pathSegement);
2189 
2190                     f = createResult(FAILURE,
2191                             "Combining the path of the parent folder and the path segement of a child returns a different object! ID: "
2192                                     + objectId);
2193                     addResult(results, assertEquals(objectId, pathSegementChild.getId(), null, f));
2194                 }
2195             }
2196         }
2197 
2198         // getDescendants
2199 
2200         if (isGetDescendantsSupported(session)) {
2201             long descendantsCount = 0;
2202             List<Tree<FileableCmisObject>> descendants = folder.getDescendants(1, SELECT_ALL_NO_CACHE_OC);
2203 
2204             for (Tree<FileableCmisObject> child : descendants) {
2205                 descendantsCount++;
2206 
2207                 if (child == null) {
2208                     addResult(results, createResult(FAILURE, "Folder descendants contain a null tree!"));
2209                 } else {
2210                     checkChild(session, results, folder, child.getItem());
2211                 }
2212             }
2213 
2214             f = createResult(FAILURE,
2215                     "Number of descendants doesn't match the number of children returned by getChildren!");
2216             addResult(results, assertEquals(childrenCount, descendantsCount, null, f));
2217         } else {
2218             addResult(results, createResult(SKIPPED, "getDescendants is not supported."));
2219         }
2220 
2221         // getFolderTree
2222 
2223         if (isGetFolderTreeSupported(session)) {
2224             long folderTreeCount = 0;
2225             List<Tree<FileableCmisObject>> folderTree = folder.getFolderTree(1, SELECT_ALL_NO_CACHE_OC);
2226 
2227             for (Tree<FileableCmisObject> child : folderTree) {
2228                 folderTreeCount++;
2229 
2230                 if (child == null) {
2231                     addResult(results, createResult(FAILURE, "Folder tree contains a null tree!"));
2232                 } else {
2233                     checkChild(session, results, folder, child.getItem());
2234                 }
2235             }
2236 
2237             f = createResult(FAILURE, "Number of folders doesn't match the number of folders returned by getChildren!");
2238             addResult(results, assertEquals(childrenFolderCount, folderTreeCount, null, f));
2239         } else {
2240             addResult(results, createResult(SKIPPED, "getFolderTree is not supported."));
2241         }
2242 
2243         // --- wrap up ---
2244 
2245         CmisTestResultImpl result = createResult(getWorst(results), message);
2246         result.getChildren().addAll(results);
2247 
2248         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
2249     }
2250 
2251     private void checkChild(Session session, List<CmisTestResult> results, Folder folder, CmisObject child) {
2252         CmisTestResult f;
2253 
2254         if (child == null) {
2255             addResult(results, createResult(FAILURE, "Folder contains a null child!"));
2256         } else {
2257             String[] propertiesToCheck = new String[child.getType().getPropertyDefinitions().size()];
2258 
2259             int i = 0;
2260             for (String propId : child.getType().getPropertyDefinitions().keySet()) {
2261                 propertiesToCheck[i++] = propId;
2262             }
2263 
2264             addResult(results, checkObject(session, child, propertiesToCheck, "Child check: " + child.getId()));
2265             addResult(results, checkVersionHistory(session, child, propertiesToCheck,
2266                     "Child version history check: " + child.getId()));
2267 
2268             f = createResult(FAILURE,
2269                     "Child is not fileable! ID: " + child.getId() + " / Type: " + child.getType().getId());
2270             addResult(results, assertIsTrue(child instanceof FileableCmisObject, null, f));
2271 
2272             if (child instanceof FileableCmisObject) {
2273                 FileableCmisObject fileableChild = (FileableCmisObject) child;
2274 
2275                 Set<Action> actions = fileableChild.getAllowableActions().getAllowableActions();
2276                 boolean hasObjectParentsAction = actions.contains(Action.CAN_GET_OBJECT_PARENTS);
2277                 boolean hasFolderParentAction = actions.contains(Action.CAN_GET_FOLDER_PARENT);
2278 
2279                 if (hasObjectParentsAction || hasFolderParentAction) {
2280                     List<Folder> parents = fileableChild.getParents();
2281 
2282                     f = createResult(FAILURE, "Child has no parents! ID: " + child.getId());
2283                     addResult(results, assertListNotEmpty(parents, null, f));
2284 
2285                     if (child instanceof Folder) {
2286                         f = createResult(FAILURE,
2287                                 "Child is a folder and has more than one parent! ID: " + child.getId());
2288                         addResult(results, assertIsFalse(parents.size() > 1, null, f));
2289 
2290                         Folder folderParent = ((Folder) child).getFolderParent();
2291                         if (folderParent == null) {
2292                             addResult(results,
2293                                     createResult(FAILURE,
2294                                             "getFolderParent() returns null for a non-root folder object! ID: "
2295                                                     + child.getId()));
2296                         } else {
2297                             f = createResult(FAILURE,
2298                                     "getFolderParent() returns wrong parent object! ID: " + child.getId());
2299                             addResult(results, assertEquals(folder.getId(), folderParent.getId(), null, f));
2300 
2301                             if (parents.size() > 0 && parents.get(0) != null) {
2302                                 f = createResult(FAILURE,
2303                                         "getFolderParent() and getParents() return different parents for a folder object! ID: "
2304                                                 + child.getId());
2305                                 addResult(results, assertEquals(parents.get(0).getId(), folderParent.getId(), null, f));
2306                             }
2307                         }
2308                     }
2309 
2310                     boolean foundParent = false;
2311                     for (Folder parent : parents) {
2312                         if (parent == null) {
2313                             f = createResult(FAILURE, "One of childs parents is null! ID: " + child.getId());
2314                             addResult(results, assertListNotEmpty(parents, null, f));
2315                         } else if (folder.getId().equals(parent.getId())) {
2316                             foundParent = true;
2317                             break;
2318                         }
2319                     }
2320 
2321                     if (!foundParent) {
2322                         addResult(results, createResult(FAILURE,
2323                                 "Parent folder is not in parents of the child! ID: " + child.getId()));
2324                     }
2325                 }
2326 
2327                 // get object by ID and compare
2328                 CmisObject objectById = session.getObject(child.getId(), SELECT_ALL_NO_CACHE_OC);
2329 
2330                 f = createResult(FAILURE, "Child and object fetched by ID don't match! ID: " + child.getId());
2331                 addResult(results, assertEquals(child, objectById, null, f, false, false));
2332 
2333                 // get object by path and compare
2334                 List<String> paths = ((FileableCmisObject) child).getPaths();
2335 
2336                 if (isNullOrEmpty(paths)) {
2337                     addResult(results, createResult(FAILURE, "Child has no path! " + child.getId()));
2338                 } else {
2339                     for (String path : paths) {
2340                         CmisObject objectByPath = session.getObjectByPath(path, SELECT_ALL_NO_CACHE_OC);
2341 
2342                         f = createResult(FAILURE, "Child and object fetched by path don't match! ID: " + child.getId()
2343                                 + " / Path: " + path);
2344                         addResult(results, assertEquals(child, objectByPath, null, f, false, false));
2345 
2346                         f = createResult(FAILURE, "Object fetched by id and object fetched by path don't match! ID: "
2347                                 + child.getId() + " / Path: " + path);
2348                         addResult(results, assertEquals(objectById, objectByPath, null, f, true, true));
2349                     }
2350                 }
2351             }
2352 
2353             if (child instanceof Folder) {
2354                 f = createResult(WARNING, "Child has no CAN_GET_FOLDER_PARENT allowable action! ID: " + child.getId());
2355                 addResult(results, assertAllowableAction(child, Action.CAN_GET_FOLDER_PARENT, null, f));
2356             } else {
2357                 f = createResult(WARNING, "Child has no CAN_GET_OBJECT_PARENTS allowable action! ID: " + child.getId());
2358                 addResult(results, assertAllowableAction(child, Action.CAN_GET_OBJECT_PARENTS, null, f));
2359             }
2360         }
2361     }
2362 
2363     protected CmisTestResult assertShallowEquals(CmisObject expected, CmisObject actual, CmisTestResult success,
2364             CmisTestResult failure) {
2365 
2366         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
2367 
2368         CmisTestResult f;
2369 
2370         if ((expected == null) && (actual == null)) {
2371             return success;
2372         }
2373 
2374         if (expected == null) {
2375             f = createResult(FAILURE, "Expected object is null, but actual object is not!");
2376             addResultChild(failure, f);
2377 
2378             return failure;
2379         }
2380 
2381         if (actual == null) {
2382             f = createResult(FAILURE, "Actual object is null, but expected object is not!");
2383             addResultChild(failure, f);
2384 
2385             return failure;
2386         }
2387 
2388         f = createResult(FAILURE, "Ids don't match!");
2389         addResult(results, assertEquals(expected.getId(), actual.getId(), null, f));
2390 
2391         f = createResult(FAILURE, "Base types don't match!");
2392         addResult(results, assertEquals(expected.getBaseTypeId(), actual.getBaseTypeId(), null, f));
2393 
2394         f = createResult(FAILURE, "Types don't match!");
2395         addResult(results, assertEquals(expected.getType().getId(), actual.getType().getId(), null, f));
2396 
2397         if (getWorst(results).getLevel() <= OK.getLevel()) {
2398             for (CmisTestResult result : results) {
2399                 addResultChild(success, result);
2400             }
2401 
2402             return success;
2403         } else {
2404             for (CmisTestResult result : results) {
2405                 addResultChild(failure, result);
2406             }
2407 
2408             return failure;
2409         }
2410     }
2411 
2412     // --- type checks ---
2413 
2414     protected CmisTestResult checkQueryName(String queryName, boolean isRequired, String message) {
2415         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
2416 
2417         CmisTestResult f;
2418 
2419         if (queryName == null || queryName.length() == 0) {
2420             addResult(results, createResult(isRequired ? FAILURE : WARNING, "Query name is not set!"));
2421         } else {
2422             f = createResult(FAILURE, "Query name contains invalid character: ' '");
2423             addResult(results, assertIsTrue(queryName.indexOf(' ') < 0, null, f));
2424 
2425             f = createResult(FAILURE, "Query name contains invalid character: ','");
2426             addResult(results, assertIsTrue(queryName.indexOf(',') < 0, null, f));
2427 
2428             f = createResult(FAILURE, "Query name contains invalid character: '\"'");
2429             addResult(results, assertIsTrue(queryName.indexOf('"') < 0, null, f));
2430 
2431             f = createResult(FAILURE, "Query name contains invalid character: '''");
2432             addResult(results, assertIsTrue(queryName.indexOf('\'') < 0, null, f));
2433 
2434             f = createResult(FAILURE, "Query name contains invalid character: '\\'");
2435             addResult(results, assertIsTrue(queryName.indexOf('\\') < 0, null, f));
2436 
2437             f = createResult(FAILURE, "Query name contains invalid character: '.'");
2438             addResult(results, assertIsTrue(queryName.indexOf('.') < 0, null, f));
2439 
2440             f = createResult(FAILURE, "Query name contains invalid character: '('");
2441             addResult(results, assertIsTrue(queryName.indexOf('(') < 0, null, f));
2442 
2443             f = createResult(FAILURE, "Query name contains invalid character: ')'");
2444             addResult(results, assertIsTrue(queryName.indexOf(')') < 0, null, f));
2445 
2446             f = createResult(FAILURE, "Query name contains invalid character: '\\t'");
2447             addResult(results, assertIsTrue(queryName.indexOf('\t') < 0, null, f));
2448 
2449             f = createResult(FAILURE, "Query name contains invalid character: '\\n'");
2450             addResult(results, assertIsTrue(queryName.indexOf('\n') < 0, null, f));
2451 
2452             f = createResult(FAILURE, "Query name contains invalid character: '\\r'");
2453             addResult(results, assertIsTrue(queryName.indexOf('\r') < 0, null, f));
2454         }
2455 
2456         CmisTestResultImpl result = createResult(getWorst(results), message);
2457         result.getChildren().addAll(results);
2458 
2459         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
2460     }
2461 
2462     protected CmisTestResult checkTypeDefinition(Session session, TypeDefinition type, String message) {
2463         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
2464 
2465         CmisTestResult f;
2466 
2467         f = createResult(FAILURE, "Type is null!");
2468         addResult(results, assertNotNull(type, null, f));
2469 
2470         if (type != null) {
2471             f = createResult(FAILURE, "Type ID is not set!");
2472             addResult(results, assertStringNotEmpty(type.getId(), null, f));
2473 
2474             f = createResult(FAILURE, "Base type ID is not set!");
2475             addResult(results, assertNotNull(type.getBaseTypeId(), null, f));
2476 
2477             f = createResult(FAILURE, "Local name is not set!");
2478             addResult(results, assertStringNotEmpty(type.getLocalName(), null, f));
2479 
2480             // f = createResult(FAILURE, "Local namespace is not set!");
2481             // addResult(results, assertStringNotEmpty(type.(), null, f));
2482 
2483             boolean isQueryNameRequired = Boolean.TRUE.equals(type.isQueryable());
2484             addResult(results, checkQueryName(type.getQueryName(), isQueryNameRequired,
2485                     "Type Query Name: " + type.getQueryName()));
2486 
2487             if ((type.getId() != null) && (type.getBaseTypeId() != null)) {
2488                 if (type.getBaseTypeId().value().equals(type.getId())) {
2489                     f = createResult(FAILURE, "Base type has parent type!");
2490                     addResult(results, assertStringNullOrEmpty(type.getParentTypeId(), null, f));
2491 
2492                     f = createResult(FAILURE, "Query name of base type is wrong!");
2493                     addResult(results, assertEquals(type.getId(), type.getQueryName(), null, f));
2494                 } else {
2495                     f = createResult(FAILURE, "Parent type is not set!");
2496                     addResult(results, assertStringNotEmpty(type.getParentTypeId(), null, f));
2497                 }
2498             }
2499 
2500             f = createResult(FAILURE, "Creatable flag is not set!");
2501             addResult(results, assertNotNull(type.isCreatable(), null, f));
2502 
2503             f = createResult(FAILURE, "Fileable flag is not set!");
2504             addResult(results, assertNotNull(type.isFileable(), null, f));
2505 
2506             f = createResult(FAILURE, "Controllable ACL flag is not set!");
2507             addResult(results, assertNotNull(type.isControllableAcl(), null, f));
2508 
2509             f = createResult(FAILURE, "Controllable Policy flag is not set!");
2510             addResult(results, assertNotNull(type.isControllablePolicy(), null, f));
2511 
2512             f = createResult(FAILURE, "Fulltext indexed flag is not set!");
2513             addResult(results, assertNotNull(type.isFulltextIndexed(), null, f));
2514 
2515             f = createResult(FAILURE, "Included in super type flag is not set!");
2516             addResult(results, assertNotNull(type.isIncludedInSupertypeQuery(), null, f));
2517 
2518             f = createResult(FAILURE, "Queryable flag is not set!");
2519             addResult(results, assertNotNull(type.isQueryable(), null, f));
2520 
2521             f = createResult(WARNING, "Type display name is not set!");
2522             addResult(results, assertStringNotEmpty(type.getDisplayName(), null, f));
2523 
2524             f = createResult(WARNING, "Type description is not set!");
2525             addResult(results, assertStringNotEmpty(type.getDescription(), null, f));
2526 
2527             if (BaseTypeId.CMIS_DOCUMENT.equals(type.getBaseTypeId())) {
2528                 DocumentTypeDefinition docType = (DocumentTypeDefinition) type;
2529 
2530                 f = createResult(FAILURE, "Versionable flag is not set!");
2531                 addResult(results, assertNotNull(docType.isVersionable(), null, f));
2532 
2533                 f = createResult(FAILURE, "Content stream allowed flag is not set!");
2534                 addResult(results, assertNotNull(docType.getContentStreamAllowed(), null, f));
2535             } else if (BaseTypeId.CMIS_FOLDER.equals(type.getBaseTypeId())) {
2536                 if (type.isFileable() != null) {
2537                     f = createResult(FAILURE, "Folder types must be fileable!");
2538                     addResult(results, assertIsTrue(type.isFileable(), null, f));
2539                 }
2540             } else if (BaseTypeId.CMIS_RELATIONSHIP.equals(type.getBaseTypeId())) {
2541                 RelationshipTypeDefinition relType = (RelationshipTypeDefinition) type;
2542 
2543                 f = createResult(FAILURE, "Allowed Source Type IDs are not set!");
2544                 addResult(results, assertNotNull(relType.getAllowedSourceTypeIds(), null, f));
2545 
2546                 if (relType.getAllowedSourceTypeIds() != null) {
2547                     for (String typeId : relType.getAllowedSourceTypeIds()) {
2548                         try {
2549                             session.getTypeDefinition(typeId);
2550                         } catch (CmisInvalidArgumentException e) {
2551                             addResult(results, createResult(WARNING,
2552                                     "Allowed Source Type IDs contain a type ID that doesn't exist: " + typeId));
2553                         } catch (CmisObjectNotFoundException e) {
2554                             addResult(results, createResult(WARNING,
2555                                     "Allowed Source Type IDs contain a type ID that doesn't exist: " + typeId));
2556                         }
2557                     }
2558                 }
2559 
2560                 f = createResult(FAILURE, "Allowed Target Type IDs are not set!");
2561                 addResult(results, assertNotNull(relType.getAllowedTargetTypeIds(), null, f));
2562 
2563                 if (relType.getAllowedTargetTypeIds() != null) {
2564                     for (String typeId : relType.getAllowedTargetTypeIds()) {
2565                         try {
2566                             session.getTypeDefinition(typeId);
2567                         } catch (CmisInvalidArgumentException e) {
2568                             addResult(results, createResult(WARNING,
2569                                     "Allowed Target Type IDs contain a type ID that doesn't exist: " + typeId));
2570                         } catch (CmisObjectNotFoundException e) {
2571                             addResult(results, createResult(WARNING,
2572                                     "Allowed Target Type IDs contain a type ID that doesn't exist: " + typeId));
2573                         }
2574                     }
2575                 }
2576 
2577                 if (type.isFileable() != null) {
2578                     f = createResult(FAILURE, "Relationship types must not be fileable!");
2579                     addResult(results, assertIsFalse(type.isFileable(), null, f));
2580                 }
2581             } else if (BaseTypeId.CMIS_POLICY.equals(type.getBaseTypeId())) {
2582                 // nothing to do
2583             } else if (BaseTypeId.CMIS_SECONDARY.equals(type.getBaseTypeId())) {
2584                 if (type.isCreatable() != null) {
2585                     f = createResult(FAILURE, "Secondary types must not be creatable!");
2586                     addResult(results, assertIsFalse(type.isCreatable(), null, f));
2587                 }
2588 
2589                 if (type.isFileable() != null) {
2590                     f = createResult(FAILURE, "Secondary types must not be fileable!");
2591                     addResult(results, assertIsFalse(type.isFileable(), null, f));
2592                 }
2593 
2594                 if (type.isControllableAcl() != null) {
2595                     f = createResult(FAILURE, "The controllable ACL flag must be false for secondary types!");
2596                     addResult(results, assertIsFalse(type.isControllableAcl(), null, f));
2597                 }
2598 
2599                 if (type.isControllablePolicy() != null) {
2600                     f = createResult(FAILURE, "The controllable policy flag must be false for secondary types!");
2601                     addResult(results, assertIsFalse(type.isControllablePolicy(), null, f));
2602                 }
2603             }
2604 
2605             // check properties
2606             if (!BaseTypeId.CMIS_SECONDARY.equals(type.getBaseTypeId())) {
2607 
2608                 f = createResult(FAILURE, "Type has no property definitions!");
2609                 addResult(results, assertNotNull(type.getPropertyDefinitions(), null, f));
2610 
2611                 if (type.getPropertyDefinitions() != null) {
2612                     for (PropertyDefinition<?> propDef : type.getPropertyDefinitions().values()) {
2613                         if (propDef == null) {
2614                             addResult(results, createResult(FAILURE, "A property definition is null!"));
2615                         } else if (propDef.getId() == null) {
2616                             addResult(results, createResult(FAILURE, "A property definition ID is null!"));
2617                         } else {
2618                             addResult(results,
2619                                     checkPropertyDefinition(propDef, "Property definition: " + propDef.getId()));
2620                         }
2621                     }
2622                 }
2623 
2624                 CmisPropertyDefintion cpd;
2625 
2626                 // cmis:name
2627                 cpd = new CmisPropertyDefintion(PropertyIds.NAME, null, PropertyType.STRING, Cardinality.SINGLE, null,
2628                         null, null);
2629                 addResult(results, cpd.check(type));
2630 
2631                 // cmis:objectId
2632                 cpd = new CmisPropertyDefintion(PropertyIds.OBJECT_ID, false, PropertyType.ID, Cardinality.SINGLE,
2633                         Updatability.READONLY, null, null);
2634                 addResult(results, cpd.check(type));
2635 
2636                 // cmis:baseTypeId
2637                 cpd = new CmisPropertyDefintion(PropertyIds.BASE_TYPE_ID, false, PropertyType.ID, Cardinality.SINGLE,
2638                         Updatability.READONLY, null, null);
2639                 addResult(results, cpd.check(type));
2640 
2641                 // cmis:objectTypeId
2642                 cpd = new CmisPropertyDefintion(PropertyIds.OBJECT_TYPE_ID, true, PropertyType.ID, Cardinality.SINGLE,
2643                         Updatability.ONCREATE, null, null);
2644                 addResult(results, cpd.check(type));
2645 
2646                 // cmis:createdBy
2647                 cpd = new CmisPropertyDefintion(PropertyIds.CREATED_BY, false, PropertyType.STRING, Cardinality.SINGLE,
2648                         Updatability.READONLY, true, true);
2649                 addResult(results, cpd.check(type));
2650 
2651                 // cmis:creationDate
2652                 cpd = new CmisPropertyDefintion(PropertyIds.CREATION_DATE, false, PropertyType.DATETIME,
2653                         Cardinality.SINGLE, Updatability.READONLY, true, true);
2654                 addResult(results, cpd.check(type));
2655 
2656                 // cmis:lastModifiedBy
2657                 cpd = new CmisPropertyDefintion(PropertyIds.LAST_MODIFIED_BY, false, PropertyType.STRING,
2658                         Cardinality.SINGLE, Updatability.READONLY, true, true);
2659                 addResult(results, cpd.check(type));
2660 
2661                 // cmis:lastModificationDate
2662                 cpd = new CmisPropertyDefintion(PropertyIds.LAST_MODIFICATION_DATE, false, PropertyType.DATETIME,
2663                         Cardinality.SINGLE, Updatability.READONLY, true, true);
2664                 addResult(results, cpd.check(type));
2665 
2666                 // cmis:changeToken
2667                 cpd = new CmisPropertyDefintion(PropertyIds.CHANGE_TOKEN, false, PropertyType.STRING,
2668                         Cardinality.SINGLE, Updatability.READONLY, null, null);
2669                 addResult(results, cpd.check(type));
2670 
2671                 // CMIS 1.1 properties
2672                 if (session.getRepositoryInfo().getCmisVersion() == CmisVersion.CMIS_1_1) {
2673                     // cmis:description
2674                     cpd = new CmisPropertyDefintion(PropertyIds.DESCRIPTION, null, PropertyType.STRING,
2675                             Cardinality.SINGLE, null, null, null);
2676                     addResult(results, cpd.check(type));
2677 
2678                     // cmis:secondaryObjectTypeIds
2679                     cpd = new CmisPropertyDefintion(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, false, PropertyType.ID,
2680                             Cardinality.MULTI, null, null, false);
2681                     addResult(results, cpd.check(type));
2682 
2683                     if (BaseTypeId.CMIS_DOCUMENT.equals(type.getBaseTypeId())) {
2684                         // cmis:isPrivateWorkingCopy
2685                         cpd = new CmisPropertyDefintion(PropertyIds.IS_PRIVATE_WORKING_COPY, null, PropertyType.BOOLEAN,
2686                                 Cardinality.SINGLE, Updatability.READONLY, null, null);
2687                         addResult(results, cpd.check(type));
2688                     }
2689                 }
2690 
2691                 if (BaseTypeId.CMIS_DOCUMENT.equals(type.getBaseTypeId())) {
2692                     // cmis:isImmutable
2693                     cpd = new CmisPropertyDefintion(PropertyIds.IS_IMMUTABLE, false, PropertyType.BOOLEAN,
2694                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2695                     addResult(results, cpd.check(type));
2696 
2697                     // cmis:isLatestVersion
2698                     cpd = new CmisPropertyDefintion(PropertyIds.IS_LATEST_VERSION, false, PropertyType.BOOLEAN,
2699                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2700                     addResult(results, cpd.check(type));
2701 
2702                     // cmis:isMajorVersion
2703                     cpd = new CmisPropertyDefintion(PropertyIds.IS_MAJOR_VERSION, false, PropertyType.BOOLEAN,
2704                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2705                     addResult(results, cpd.check(type));
2706 
2707                     // cmis:isLatestMajorVersion
2708                     cpd = new CmisPropertyDefintion(PropertyIds.IS_LATEST_MAJOR_VERSION, false, PropertyType.BOOLEAN,
2709                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2710                     addResult(results, cpd.check(type));
2711 
2712                     // cmis:versionLabel
2713                     cpd = new CmisPropertyDefintion(PropertyIds.VERSION_LABEL, false, PropertyType.STRING,
2714                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2715                     addResult(results, cpd.check(type));
2716 
2717                     // cmis:versionSeriesId
2718                     cpd = new CmisPropertyDefintion(PropertyIds.VERSION_SERIES_ID, false, PropertyType.ID,
2719                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2720                     addResult(results, cpd.check(type));
2721 
2722                     // cmis:isVersionSeriesCheckedOut
2723                     cpd = new CmisPropertyDefintion(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT, false,
2724                             PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, null, null);
2725                     addResult(results, cpd.check(type));
2726 
2727                     // cmis:versionSeriesCheckedOutBy
2728                     cpd = new CmisPropertyDefintion(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY, false,
2729                             PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, null, null);
2730                     addResult(results, cpd.check(type));
2731 
2732                     // cmis:versionSeriesCheckedOutId
2733                     cpd = new CmisPropertyDefintion(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID, false, PropertyType.ID,
2734                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2735                     addResult(results, cpd.check(type));
2736 
2737                     // cmis:checkinComment
2738                     cpd = new CmisPropertyDefintion(PropertyIds.CHECKIN_COMMENT, false, PropertyType.STRING,
2739                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2740                     addResult(results, cpd.check(type));
2741 
2742                     // cmis:contentStreamLength
2743                     cpd = new CmisPropertyDefintion(PropertyIds.CONTENT_STREAM_LENGTH, false, PropertyType.INTEGER,
2744                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2745                     addResult(results, cpd.check(type));
2746 
2747                     // cmis:contentStreamMimeType
2748                     cpd = new CmisPropertyDefintion(PropertyIds.CONTENT_STREAM_MIME_TYPE, false, PropertyType.STRING,
2749                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2750                     addResult(results, cpd.check(type));
2751 
2752                     // cmis:contentStreamFileName
2753                     cpd = new CmisPropertyDefintion(PropertyIds.CONTENT_STREAM_FILE_NAME, false, PropertyType.STRING,
2754                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2755                     addResult(results, cpd.check(type));
2756 
2757                     // cmis:contentStreamId
2758                     cpd = new CmisPropertyDefintion(PropertyIds.CONTENT_STREAM_ID, false, PropertyType.ID,
2759                             Cardinality.SINGLE, Updatability.READONLY, null, null);
2760                     addResult(results, cpd.check(type));
2761                 } else if (BaseTypeId.CMIS_FOLDER.equals(type.getBaseTypeId())) {
2762                     // cmis:parentId
2763                     cpd = new CmisPropertyDefintion(PropertyIds.PARENT_ID, false, PropertyType.ID, Cardinality.SINGLE,
2764                             Updatability.READONLY, null, null);
2765                     addResult(results, cpd.check(type));
2766 
2767                     // cmis:path
2768                     cpd = new CmisPropertyDefintion(PropertyIds.PATH, false, PropertyType.STRING, Cardinality.SINGLE,
2769                             Updatability.READONLY, null, null);
2770                     addResult(results, cpd.check(type));
2771 
2772                     // cmis:allowedChildObjectTypeIds
2773                     cpd = new CmisPropertyDefintion(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS, false, PropertyType.ID,
2774                             Cardinality.MULTI, Updatability.READONLY, null, false);
2775                     addResult(results, cpd.check(type));
2776                 } else if (BaseTypeId.CMIS_RELATIONSHIP.equals(type.getBaseTypeId())) {
2777                     // cmis:sourceId
2778                     cpd = new CmisPropertyDefintion(PropertyIds.SOURCE_ID, true, PropertyType.ID, Cardinality.SINGLE,
2779                             null, null, null);
2780                     addResult(results, cpd.check(type));
2781 
2782                     // cmis:targetId
2783                     cpd = new CmisPropertyDefintion(PropertyIds.TARGET_ID, true, PropertyType.ID, Cardinality.SINGLE,
2784                             null, null, null);
2785                     addResult(results, cpd.check(type));
2786                 } else if (BaseTypeId.CMIS_POLICY.equals(type.getBaseTypeId())) {
2787                     // cmis:policyText
2788                     cpd = new CmisPropertyDefintion(PropertyIds.POLICY_TEXT, null, PropertyType.STRING,
2789                             Cardinality.SINGLE, null, null, null);
2790                     addResult(results, cpd.check(type));
2791                 }
2792             }
2793         }
2794 
2795         CmisTestResultImpl result = createResult(getWorst(results), message);
2796         result.getChildren().addAll(results);
2797 
2798         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
2799     }
2800 
2801     protected CmisTestResult checkPropertyDefinition(PropertyDefinition<?> propDef, String message) {
2802         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
2803 
2804         CmisTestResult f;
2805 
2806         f = createResult(FAILURE, "Property definition is null!");
2807         addResult(results, assertNotNull(propDef, null, f));
2808 
2809         if (propDef != null) {
2810             f = createResult(FAILURE, "Property ID is not set!");
2811             addResult(results, assertStringNotEmpty(propDef.getId(), null, f));
2812 
2813             f = createResult(WARNING, "Local name is not set!");
2814             addResult(results, assertStringNotEmpty(propDef.getLocalName(), null, f));
2815 
2816             // f = createResult(WARNING, "Local namespace is not set!");
2817             // addResult(results,
2818             // assertStringNotEmpty(propDef.getLocalNamespace(), null, f));
2819 
2820             f = createResult(FAILURE, "Query name is not set!");
2821             addResult(results, assertStringNotEmpty(propDef.getQueryName(), null, f));
2822 
2823             f = createResult(WARNING, "Display name is not set!");
2824             addResult(results, assertStringNotEmpty(propDef.getDisplayName(), null, f));
2825 
2826             f = createResult(WARNING, "Description is not set!");
2827             addResult(results, assertStringNotEmpty(propDef.getDescription(), null, f));
2828 
2829             f = createResult(FAILURE, "Property type is not set!");
2830             addResult(results, assertNotNull(propDef.getPropertyType(), null, f));
2831 
2832             f = createResult(FAILURE, "Cardinality is not set!");
2833             addResult(results, assertNotNull(propDef.getCardinality(), null, f));
2834 
2835             f = createResult(FAILURE, "Updatability is not set!");
2836             addResult(results, assertNotNull(propDef.getUpdatability(), null, f));
2837 
2838             f = createResult(FAILURE, "Inherited flag is not set!");
2839             addResult(results, assertNotNull(propDef.isInherited(), null, f));
2840 
2841             f = createResult(FAILURE, "Required flag is not set!");
2842             addResult(results, assertNotNull(propDef.isRequired(), null, f));
2843 
2844             f = createResult(FAILURE, "Queryable flag is not set!");
2845             addResult(results, assertNotNull(propDef.isQueryable(), null, f));
2846 
2847             f = createResult(FAILURE, "Orderable flag is not set!");
2848             addResult(results, assertNotNull(propDef.isOrderable(), null, f));
2849         }
2850 
2851         CmisTestResultImpl result = createResult(getWorst(results), message);
2852         result.getChildren().addAll(results);
2853 
2854         return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
2855     }
2856 
2857     protected CmisTestResult assertEquals(TypeDefinition expected, TypeDefinition actual, CmisTestResult success,
2858             CmisTestResult failure) {
2859 
2860         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
2861 
2862         CmisTestResult f;
2863 
2864         if ((expected == null) && (actual == null)) {
2865             return success;
2866         }
2867 
2868         if (expected == null) {
2869             f = createResult(FAILURE, "Expected type defintion is null, but actual type defintion is not!");
2870             addResultChild(failure, f);
2871 
2872             return failure;
2873         }
2874 
2875         if (actual == null) {
2876             f = createResult(FAILURE, "Actual type defintion is null, but expected type defintion is not!");
2877             addResultChild(failure, f);
2878 
2879             return failure;
2880         }
2881 
2882         f = createResult(FAILURE, "Type IDs don't match!");
2883         addResult(results, assertEquals(expected.getId(), actual.getId(), null, f));
2884 
2885         f = createResult(FAILURE, "Base type IDs don't match!");
2886         addResult(results, assertEquals(expected.getBaseTypeId(), actual.getBaseTypeId(), null, f));
2887 
2888         f = createResult(FAILURE, "Parent type IDs don't match!");
2889         addResult(results, assertEquals(expected.getParentTypeId(), actual.getParentTypeId(), null, f));
2890 
2891         f = createResult(FAILURE, "Query names don't match!");
2892         addResult(results, assertEquals(expected.getQueryName(), actual.getQueryName(), null, f));
2893 
2894         f = createResult(FAILURE, "Local names don't match!");
2895         addResult(results, assertEquals(expected.getLocalName(), actual.getLocalName(), null, f));
2896 
2897         f = createResult(FAILURE, "Local namespaces don't match!");
2898         addResult(results, assertEquals(expected.getLocalNamespace(), actual.getLocalNamespace(), null, f));
2899 
2900         f = createResult(FAILURE, "Display names don't match!");
2901         addResult(results, assertEquals(expected.getDisplayName(), actual.getDisplayName(), null, f));
2902 
2903         f = createResult(FAILURE, "Descriptions don't match!");
2904         addResult(results, assertEquals(expected.getDescription(), actual.getDescription(), null, f));
2905 
2906         f = createResult(FAILURE, "Controllable ACl flags don't match!");
2907         addResult(results, assertEquals(expected.isControllableAcl(), actual.isControllableAcl(), null, f));
2908 
2909         f = createResult(FAILURE, "Controllable Policy flags don't match!");
2910         addResult(results, assertEquals(expected.isControllablePolicy(), actual.isControllablePolicy(), null, f));
2911 
2912         f = createResult(FAILURE, "Creatable flags don't match!");
2913         addResult(results, assertEquals(expected.isCreatable(), actual.isCreatable(), null, f));
2914 
2915         f = createResult(FAILURE, "Fileable flags don't match!");
2916         addResult(results, assertEquals(expected.isFileable(), actual.isFileable(), null, f));
2917 
2918         f = createResult(FAILURE, "Fulltext indexed flags don't match!");
2919         addResult(results, assertEquals(expected.isFulltextIndexed(), actual.isFulltextIndexed(), null, f));
2920 
2921         f = createResult(FAILURE, "Queryable flags don't match!");
2922         addResult(results, assertEquals(expected.isQueryable(), actual.isQueryable(), null, f));
2923 
2924         f = createResult(FAILURE, "Included in supertype query flags don't match!");
2925         addResult(results,
2926                 assertEquals(expected.isIncludedInSupertypeQuery(), actual.isIncludedInSupertypeQuery(), null, f));
2927 
2928         if (expected.getTypeMutability() != null && actual.getTypeMutability() != null) {
2929             f = createResult(FAILURE, "Type Mutability: Create flags don't match!");
2930             addResult(results, assertEquals(expected.getTypeMutability().canCreate(),
2931                     actual.getTypeMutability().canCreate(), null, f));
2932 
2933             f = createResult(FAILURE, "Type Mutability: update flags don't match!");
2934             addResult(results, assertEquals(expected.getTypeMutability().canUpdate(),
2935                     actual.getTypeMutability().canUpdate(), null, f));
2936 
2937             f = createResult(FAILURE, "Type Mutability: delete flags don't match!");
2938             addResult(results, assertEquals(expected.getTypeMutability().canDelete(),
2939                     actual.getTypeMutability().canDelete(), null, f));
2940         } else {
2941             f = createResult(FAILURE, "Type Mutability infos don't match!");
2942             addResult(results, assertEquals(expected.getTypeMutability(), actual.getTypeMutability(), null, f));
2943         }
2944 
2945         if ((expected.getPropertyDefinitions() != null) && (actual.getPropertyDefinitions() != null)) {
2946             Map<String, PropertyDefinition<?>> epd = expected.getPropertyDefinitions();
2947             Map<String, PropertyDefinition<?>> apd = actual.getPropertyDefinitions();
2948 
2949             f = createResult(FAILURE, "Different number of property defintions!");
2950             addResult(results, assertEquals(epd.size(), apd.size(), null, f));
2951 
2952             for (PropertyDefinition<?> pd : epd.values()) {
2953                 f = createResult(FAILURE, "Property definition mismatch: " + pd.getId());
2954                 addResult(results, assertEquals(pd, apd.get(pd.getId()), null, f));
2955             }
2956         }
2957 
2958         if (getWorst(results).getLevel() <= OK.getLevel()) {
2959             for (CmisTestResult result : results) {
2960                 addResultChild(success, result);
2961             }
2962 
2963             return success;
2964         } else {
2965             for (CmisTestResult result : results) {
2966                 addResultChild(failure, result);
2967             }
2968 
2969             return failure;
2970         }
2971     }
2972 
2973     protected CmisTestResult assertEquals(PropertyDefinition<?> expected, PropertyDefinition<?> actual,
2974             CmisTestResult success, CmisTestResult failure) {
2975 
2976         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
2977 
2978         CmisTestResult f;
2979 
2980         if ((expected == null) && (actual == null)) {
2981             return success;
2982         }
2983 
2984         if (expected == null) {
2985             f = createResult(FAILURE, "Expected property defintion is null, but actual property defintion is not!");
2986             addResultChild(failure, f);
2987 
2988             return failure;
2989         }
2990 
2991         if (actual == null) {
2992             f = createResult(FAILURE, "Actual property defintion is null, but expected property defintion is not!");
2993             addResultChild(failure, f);
2994 
2995             return failure;
2996         }
2997 
2998         f = createResult(FAILURE, "Property IDs don't match!");
2999         addResult(results, assertEquals(expected.getId(), actual.getId(), null, f));
3000 
3001         f = createResult(FAILURE, "Local names don't match!");
3002         addResult(results, assertEquals(expected.getLocalName(), actual.getLocalName(), null, f));
3003 
3004         f = createResult(FAILURE, "Local namespaces don't match!");
3005         addResult(results, assertEquals(expected.getLocalNamespace(), actual.getLocalNamespace(), null, f));
3006 
3007         f = createResult(FAILURE, "Display names don't match!");
3008         addResult(results, assertEquals(expected.getDisplayName(), actual.getDisplayName(), null, f));
3009 
3010         f = createResult(FAILURE, "Query names don't match!");
3011         addResult(results, assertEquals(expected.getQueryName(), actual.getQueryName(), null, f));
3012 
3013         f = createResult(FAILURE, "Property types don't match!");
3014         addResult(results, assertEquals(expected.getPropertyType(), actual.getPropertyType(), null, f));
3015 
3016         f = createResult(FAILURE, "Cardinalities don't match!");
3017         addResult(results, assertEquals(expected.getCardinality(), actual.getCardinality(), null, f));
3018 
3019         f = createResult(FAILURE, "Descriptions don't match!");
3020         addResult(results, assertEquals(expected.getDescription(), actual.getDescription(), null, f));
3021 
3022         f = createResult(FAILURE, "Updatability flags don't match!");
3023         addResult(results, assertEquals(expected.getUpdatability(), actual.getUpdatability(), null, f));
3024 
3025         f = createResult(FAILURE, "Default values don't match!");
3026         addResult(results, assertEqualLists(expected.getDefaultValue(), actual.getDefaultValue(), null, f));
3027 
3028         f = createResult(FAILURE, "Inherited flags don't match!");
3029         addResult(results, assertEquals(expected.isInherited(), actual.isInherited(), null, f));
3030 
3031         f = createResult(FAILURE, "Required flags don't match!");
3032         addResult(results, assertEquals(expected.isRequired(), actual.isRequired(), null, f));
3033 
3034         f = createResult(FAILURE, "Queryable flags don't match!");
3035         addResult(results, assertEquals(expected.isQueryable(), actual.isQueryable(), null, f));
3036 
3037         f = createResult(FAILURE, "Orderable flags don't match!");
3038         addResult(results, assertEquals(expected.isOrderable(), actual.isOrderable(), null, f));
3039 
3040         f = createResult(FAILURE, "Open choice flags don't match!");
3041         addResult(results, assertEquals(expected.isOpenChoice(), actual.isOpenChoice(), null, f));
3042 
3043         if (getWorst(results).getLevel() <= OK.getLevel()) {
3044             for (CmisTestResult result : results) {
3045                 addResultChild(success, result);
3046             }
3047 
3048             return success;
3049         } else {
3050             for (CmisTestResult result : results) {
3051                 addResultChild(failure, result);
3052             }
3053 
3054             return failure;
3055         }
3056     }
3057 
3058     protected CmisTestResult assertEquals(CmisObject expected, CmisObject actual, CmisTestResult success,
3059             CmisTestResult failure, boolean checkAcls, boolean checkPolicies) {
3060 
3061         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3062 
3063         CmisTestResult f;
3064 
3065         if ((expected == null) && (actual == null)) {
3066             return success;
3067         }
3068 
3069         if (expected == null) {
3070             f = createResult(FAILURE, "Expected object is null, but actual object is not!");
3071             addResultChild(failure, f);
3072 
3073             return failure;
3074         }
3075 
3076         if (actual == null) {
3077             f = createResult(FAILURE, "Actual object is null, but expected object is not!");
3078             addResultChild(failure, f);
3079 
3080             return failure;
3081         }
3082 
3083         if (expected.getProperties().size() != actual.getProperties().size()) {
3084             f = createResult(FAILURE, "Number of properties don't match");
3085             addResult(results, assertEquals(expected.getProperties().size(), actual.getProperties().size(), null, f));
3086         } else {
3087             for (Property<?> expectedProperty : expected.getProperties()) {
3088                 Property<?> actualProperty = actual.getProperty(expectedProperty.getId());
3089 
3090                 f = createResult(FAILURE, "Properties don't match! Property: " + expectedProperty.getId());
3091                 addResult(results, assertEquals(expectedProperty, actualProperty, null, f));
3092             }
3093         }
3094 
3095         f = createResult(FAILURE, "Allowable actions don't match!");
3096         addResult(results, assertEquals(expected.getAllowableActions(), actual.getAllowableActions(), null, f));
3097 
3098         if (checkAcls) {
3099             f = createResult(FAILURE, "ACLs don't match!");
3100             addResult(results, assertEquals(expected.getAcl(), actual.getAcl(), null, f));
3101         }
3102 
3103         if (checkPolicies) {
3104             f = createResult(FAILURE, "Policies don't match!");
3105             addResult(results, assertEqualObjectList(expected.getPolicies(), actual.getPolicies(), null, f));
3106         }
3107 
3108         f = createResult(FAILURE, "Relationships don't match!");
3109         addResult(results, assertEqualObjectList(expected.getRelationships(), actual.getRelationships(), null, f));
3110 
3111         f = createResult(FAILURE, "Renditions don't match!");
3112         addResult(results, assertEqualRenditionLists(expected.getRenditions(), actual.getRenditions(), null, f));
3113 
3114         if (getWorst(results).getLevel() <= OK.getLevel()) {
3115             for (CmisTestResult result : results) {
3116                 addResultChild(success, result);
3117             }
3118 
3119             return success;
3120         } else {
3121             for (CmisTestResult result : results) {
3122                 addResultChild(failure, result);
3123             }
3124 
3125             return failure;
3126         }
3127     }
3128 
3129     protected CmisTestResult assertEqualObjectList(List<? extends CmisObject> expected,
3130             List<? extends CmisObject> actual, CmisTestResult success, CmisTestResult failure) {
3131 
3132         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3133 
3134         CmisTestResult f;
3135 
3136         if ((expected == null) && (actual == null)) {
3137             return success;
3138         }
3139 
3140         if (expected == null) {
3141             f = createResult(FAILURE, "Expected list of CMIS objects is null, but actual list of CMIS objects is not!");
3142             addResultChild(failure, f);
3143 
3144             return failure;
3145         }
3146 
3147         if (actual == null) {
3148             f = createResult(FAILURE, "Actual list of CMIS objects is null, but expected list of CMIS objects is not!");
3149             addResultChild(failure, f);
3150 
3151             return failure;
3152         }
3153 
3154         if (expected.size() != actual.size()) {
3155             addResult(results, createResult(CmisTestResultStatus.INFO,
3156                     "Object list sizes don't match! expected: " + expected.size() + " / actual: " + actual.size()));
3157         } else {
3158             for (int i = 0; i < expected.size(); i++) {
3159                 f = createResult(FAILURE, "Objects at position " + i + "  dont't match!");
3160                 addResult(results, assertEquals(expected.get(i), actual.get(i), null, f, true, false));
3161             }
3162         }
3163 
3164         if (getWorst(results).getLevel() <= OK.getLevel()) {
3165             for (CmisTestResult result : results) {
3166                 addResultChild(success, result);
3167             }
3168 
3169             return success;
3170         } else {
3171             for (CmisTestResult result : results) {
3172                 addResultChild(failure, result);
3173             }
3174 
3175             return failure;
3176         }
3177     }
3178 
3179     protected CmisTestResult assertEquals(Property<?> expected, Property<?> actual, CmisTestResult success,
3180             CmisTestResult failure) {
3181 
3182         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3183 
3184         CmisTestResult f;
3185 
3186         if ((expected == null) && (actual == null)) {
3187             return success;
3188         }
3189 
3190         if (expected == null) {
3191             f = createResult(FAILURE, "Expected property is null, but actual property is not!");
3192             addResultChild(failure, f);
3193 
3194             return failure;
3195         }
3196 
3197         if (actual == null) {
3198             f = createResult(FAILURE, "Actual property is null, but expected property is not!");
3199             addResultChild(failure, f);
3200 
3201             return failure;
3202         }
3203 
3204         f = createResult(FAILURE, "Property definitions don't match!");
3205         addResult(results, assertEquals(expected.getDefinition(), actual.getDefinition(), null, f));
3206 
3207         f = createResult(FAILURE, "Property values don't match!");
3208         addResult(results, assertEqualLists(expected.getValues(), actual.getValues(), null, f));
3209 
3210         if (getWorst(results).getLevel() <= OK.getLevel()) {
3211             for (CmisTestResult result : results) {
3212                 addResultChild(success, result);
3213             }
3214 
3215             return success;
3216         } else {
3217             for (CmisTestResult result : results) {
3218                 addResultChild(failure, result);
3219             }
3220 
3221             return failure;
3222         }
3223     }
3224 
3225     protected CmisTestResult assertEquals(AllowableActions expected, AllowableActions actual, CmisTestResult success,
3226             CmisTestResult failure) {
3227 
3228         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3229 
3230         CmisTestResult f;
3231 
3232         if ((expected == null) && (actual == null)) {
3233             return success;
3234         }
3235 
3236         if (expected == null) {
3237             f = createResult(FAILURE, "Expected allowable actions are null, but actual allowable actions are not!");
3238             addResultChild(failure, f);
3239 
3240             return failure;
3241         }
3242 
3243         if (actual == null) {
3244             f = createResult(FAILURE, "Actual allowable actions are null, but expected allowable actions are not!");
3245             addResultChild(failure, f);
3246 
3247             return failure;
3248         }
3249 
3250         f = createResult(FAILURE, "Allowable action sets don't match!");
3251         addResult(results, assertEqualSet(expected.getAllowableActions(), actual.getAllowableActions(), null, f));
3252 
3253         if (getWorst(results).getLevel() <= OK.getLevel()) {
3254             for (CmisTestResult result : results) {
3255                 addResultChild(success, result);
3256             }
3257 
3258             return success;
3259         } else {
3260             for (CmisTestResult result : results) {
3261                 addResultChild(failure, result);
3262             }
3263 
3264             return failure;
3265         }
3266     }
3267 
3268     protected CmisTestResult assertEquals(Acl expected, Acl actual, CmisTestResult success, CmisTestResult failure) {
3269 
3270         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3271 
3272         CmisTestResult f;
3273 
3274         if ((expected == null) && (actual == null)) {
3275             return success;
3276         }
3277 
3278         if (expected == null) {
3279             f = createResult(FAILURE, "Expected ACL is null, but actual ACL is not!");
3280             addResultChild(failure, f);
3281 
3282             return failure;
3283         }
3284 
3285         if (actual == null) {
3286             f = createResult(FAILURE, "Actual ACL is null, but expected ACL is not!");
3287             addResultChild(failure, f);
3288 
3289             return failure;
3290         }
3291 
3292         f = createResult(FAILURE, "ACEs don't match!");
3293         addResult(results, assertEqualAceLists(expected.getAces(), actual.getAces(), null, f));
3294 
3295         f = createResult(FAILURE, "Exact flags dont't match!");
3296         addResult(results, assertEquals(expected.isExact(), actual.isExact(), null, f));
3297 
3298         if (getWorst(results).getLevel() <= OK.getLevel()) {
3299             for (CmisTestResult result : results) {
3300                 addResultChild(success, result);
3301             }
3302 
3303             return success;
3304         } else {
3305             for (CmisTestResult result : results) {
3306                 addResultChild(failure, result);
3307             }
3308 
3309             return failure;
3310         }
3311     }
3312 
3313     protected CmisTestResult assertEqualAceLists(List<Ace> expected, List<Ace> actual, CmisTestResult success,
3314             CmisTestResult failure) {
3315 
3316         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3317 
3318         CmisTestResult f;
3319 
3320         if (expected == null && actual == null) {
3321             return success;
3322         }
3323 
3324         if (expected == null) {
3325             return addResultChild(failure, createResult(CmisTestResultStatus.INFO, "Expected ACE list is null!"));
3326         }
3327 
3328         if (actual == null) {
3329             return addResultChild(failure, createResult(CmisTestResultStatus.INFO, "Actual ACE list is null!"));
3330         }
3331 
3332         if (expected.size() != actual.size()) {
3333             addResult(results, createResult(CmisTestResultStatus.INFO,
3334                     "ACE list sizes don't match! expected: " + expected.size() + " / actual: " + actual.size()));
3335         } else {
3336             for (int i = 0; i < expected.size(); i++) {
3337                 f = createResult(FAILURE, "ACEs at position " + i + "  dont't match!");
3338                 addResult(results, assertEquals(expected.get(i), actual.get(i), null, f));
3339             }
3340         }
3341 
3342         if (getWorst(results).getLevel() <= OK.getLevel()) {
3343             for (CmisTestResult result : results) {
3344                 addResultChild(success, result);
3345             }
3346 
3347             return success;
3348         } else {
3349             for (CmisTestResult result : results) {
3350                 addResultChild(failure, result);
3351             }
3352 
3353             return failure;
3354         }
3355     }
3356 
3357     protected CmisTestResult assertEquals(Ace expected, Ace actual, CmisTestResult success, CmisTestResult failure) {
3358 
3359         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3360 
3361         CmisTestResult f;
3362 
3363         if ((expected == null) && (actual == null)) {
3364             return success;
3365         }
3366 
3367         if (expected == null) {
3368             f = createResult(FAILURE, "Expected ACE is null, but actual ACE is not!");
3369             addResultChild(failure, f);
3370 
3371             return failure;
3372         }
3373 
3374         if (actual == null) {
3375             f = createResult(FAILURE, "Actual ACE is null, but expected ACE is not!");
3376             addResultChild(failure, f);
3377 
3378             return failure;
3379         }
3380 
3381         f = createResult(FAILURE, "Principal IDs dont't match!");
3382         addResult(results, assertEquals(expected.getPrincipalId(), actual.getPrincipalId(), null, f));
3383 
3384         f = createResult(FAILURE, "Permissions dont't match!");
3385         addResult(results, assertEqualLists(expected.getPermissions(), actual.getPermissions(), null, f));
3386 
3387         if (getWorst(results).getLevel() <= OK.getLevel()) {
3388             for (CmisTestResult result : results) {
3389                 addResultChild(success, result);
3390             }
3391 
3392             return success;
3393         } else {
3394             for (CmisTestResult result : results) {
3395                 addResultChild(failure, result);
3396             }
3397 
3398             return failure;
3399         }
3400     }
3401 
3402     protected CmisTestResult assertEqualRenditionLists(List<Rendition> expected, List<Rendition> actual,
3403             CmisTestResult success, CmisTestResult failure) {
3404 
3405         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3406 
3407         CmisTestResult f;
3408 
3409         if (expected == null && actual == null) {
3410             return success;
3411         }
3412 
3413         if (expected == null) {
3414             return addResultChild(failure, createResult(CmisTestResultStatus.INFO, "Expected rendition list is null!"));
3415         }
3416 
3417         if (actual == null) {
3418             return addResultChild(failure, createResult(CmisTestResultStatus.INFO, "Actual rendition list is null!"));
3419         }
3420 
3421         if (expected.size() != actual.size()) {
3422             addResult(results, createResult(CmisTestResultStatus.INFO,
3423                     "Rendition list sizes don't match! expected: " + expected.size() + " / actual: " + actual.size()));
3424         } else {
3425             for (int i = 0; i < expected.size(); i++) {
3426                 f = createResult(FAILURE, "Renditions at position " + i + "  dont't match!");
3427                 addResult(results, assertEquals(expected.get(i), actual.get(i), null, f));
3428             }
3429         }
3430 
3431         if (getWorst(results).getLevel() <= OK.getLevel()) {
3432             for (CmisTestResult result : results) {
3433                 addResultChild(success, result);
3434             }
3435 
3436             return success;
3437         } else {
3438             for (CmisTestResult result : results) {
3439                 addResultChild(failure, result);
3440             }
3441 
3442             return failure;
3443         }
3444     }
3445 
3446     protected CmisTestResult assertEquals(Rendition expected, Rendition actual, CmisTestResult success,
3447             CmisTestResult failure) {
3448 
3449         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3450 
3451         CmisTestResult f;
3452 
3453         if ((expected == null) && (actual == null)) {
3454             return success;
3455         }
3456 
3457         if (expected == null) {
3458             f = createResult(FAILURE, "Expected rendition is null, but actual rendition is not!");
3459             addResultChild(failure, f);
3460 
3461             return failure;
3462         }
3463 
3464         if (actual == null) {
3465             f = createResult(FAILURE, "Actual rendition is null, but expected rendition is not!");
3466             addResultChild(failure, f);
3467 
3468             return failure;
3469         }
3470 
3471         f = createResult(FAILURE, "Stream IDs dont't match!");
3472         addResult(results, assertEquals(expected.getStreamId(), actual.getStreamId(), null, f));
3473 
3474         f = createResult(FAILURE, "Kinds dont't match!");
3475         addResult(results, assertEquals(expected.getKind(), actual.getKind(), null, f));
3476 
3477         f = createResult(FAILURE, "MIME types dont't match!");
3478         addResult(results, assertEquals(expected.getMimeType(), actual.getMimeType(), null, f));
3479 
3480         f = createResult(FAILURE, "Titles dont't match!");
3481         addResult(results, assertEquals(expected.getTitle(), actual.getTitle(), null, f));
3482 
3483         f = createResult(FAILURE, "Lengths dont't match!");
3484         addResult(results, assertEquals(expected.getLength(), actual.getLength(), null, f));
3485 
3486         f = createResult(FAILURE, "Heights dont't match!");
3487         addResult(results, assertEquals(expected.getBigHeight(), actual.getBigHeight(), null, f));
3488 
3489         f = createResult(FAILURE, "Widths dont't match!");
3490         addResult(results, assertEquals(expected.getBigWidth(), actual.getBigWidth(), null, f));
3491 
3492         f = createResult(FAILURE, "Rendition document IDs dont't match!");
3493         addResult(results, assertEquals(expected.getRenditionDocumentId(), actual.getRenditionDocumentId(), null, f));
3494 
3495         if (getWorst(results).getLevel() <= OK.getLevel()) {
3496             for (CmisTestResult result : results) {
3497                 addResultChild(success, result);
3498             }
3499 
3500             return success;
3501         } else {
3502             for (CmisTestResult result : results) {
3503                 addResultChild(failure, result);
3504             }
3505 
3506             return failure;
3507         }
3508     }
3509 
3510     protected CmisTestResult assertEquals(ContentStream expected, ContentStream actual, CmisTestResult success,
3511             CmisTestResult failure) {
3512 
3513         List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3514 
3515         CmisTestResult f;
3516 
3517         if ((expected == null) && (actual == null)) {
3518             return success;
3519         }
3520 
3521         if (expected == null) {
3522             f = createResult(FAILURE, "Expected stream is null, but actual stream is not!");
3523             addResultChild(failure, f);
3524 
3525             IOUtils.closeQuietly(actual);
3526 
3527             return failure;
3528         }
3529 
3530         if (actual == null) {
3531             f = createResult(FAILURE, "Actual object is null, but expected object is not!");
3532             addResultChild(failure, f);
3533 
3534             IOUtils.closeQuietly(expected);
3535 
3536             return failure;
3537         }
3538 
3539         f = createResult(WARNING, "Filenames don't match!");
3540         addResult(results, assertEquals(expected.getFileName(), actual.getFileName(), null, f));
3541 
3542         f = createResult(FAILURE, "MIME types don't match!");
3543         addResult(results, assertEquals(expected.getMimeType(), actual.getMimeType(), null, f));
3544 
3545         f = createResult(WARNING, "Lengths don't match!");
3546         addResult(results, assertEquals(expected.getBigLength(), actual.getBigLength(), null, f));
3547 
3548         boolean match = true;
3549 
3550         BufferedInputStream as = new BufferedInputStream(actual.getStream(), 64 * 1024);
3551         BufferedInputStream es = new BufferedInputStream(expected.getStream(), 64 * 1024);
3552 
3553         try {
3554             int ab = 0;
3555             int eb = 0;
3556 
3557             while (true) {
3558                 if (ab > -1) {
3559                     ab = as.read();
3560                 }
3561 
3562                 if (eb > -1) {
3563                     eb = es.read();
3564                 }
3565 
3566                 if (ab == -1 && eb == -1) {
3567                     break;
3568                 }
3569 
3570                 if (ab != eb) {
3571                     match = false;
3572                 }
3573             }
3574         } catch (Exception e) {
3575             f = createResult(UNEXPECTED_EXCEPTION, e.getMessage(), e, false);
3576             addResultChild(failure, f);
3577         }
3578 
3579         if (!match) {
3580             f = createResult(FAILURE, "Content streams don't match!");
3581             addResultChild(failure, f);
3582         }
3583 
3584         IOUtils.closeQuietly(as);
3585         IOUtils.closeQuietly(es);
3586 
3587         if (getWorst(results).getLevel() <= OK.getLevel()) {
3588             for (CmisTestResult result : results) {
3589                 addResultChild(success, result);
3590             }
3591 
3592             return success;
3593         } else {
3594             for (CmisTestResult result : results) {
3595                 addResultChild(failure, result);
3596             }
3597 
3598             return failure;
3599         }
3600     }
3601 
3602     // --- helpers ---
3603 
3604     protected void addResult(List<CmisTestResult> results, CmisTestResult result) {
3605         if (result != null) {
3606             if (result instanceof CmisTestResultImpl) {
3607                 ((CmisTestResultImpl) result).setStackTrace(getStackTrace());
3608             }
3609 
3610             results.add(result);
3611             if (result.isFatal()) {
3612                 throw new FatalTestException(result.getMessage());
3613             }
3614         }
3615     }
3616 
3617     protected CmisTestResultStatus getWorst(List<CmisTestResult> results) {
3618         if (isNullOrEmpty(results)) {
3619             return CmisTestResultStatus.OK;
3620         }
3621 
3622         int max = 0;
3623 
3624         for (CmisTestResult result : results) {
3625             if (max < result.getStatus().getLevel()) {
3626                 max = result.getStatus().getLevel();
3627             }
3628         }
3629 
3630         return CmisTestResultStatus.fromLevel(max);
3631     }
3632 
3633     // --- helper classes ---
3634 
3635     public class CmisPropertyDefintion {
3636         private final String id;
3637         private final Boolean required;
3638         private final PropertyType propertyType;
3639         private final Cardinality cardinality;
3640         private final Updatability updatability;
3641         private final Boolean queryable;
3642         private final Boolean orderable;
3643 
3644         public CmisPropertyDefintion(String id, Boolean required, PropertyType propertyType, Cardinality cardinality,
3645                 Updatability updatability, Boolean queryable, Boolean orderable) {
3646             this.id = id;
3647             this.required = required;
3648             this.propertyType = propertyType;
3649             this.cardinality = cardinality;
3650             this.updatability = updatability;
3651             this.queryable = queryable;
3652             this.orderable = (cardinality == Cardinality.MULTI ? Boolean.FALSE : orderable);
3653         }
3654 
3655         public CmisTestResult check(TypeDefinition type) {
3656             List<CmisTestResult> results = new ArrayList<CmisTestResult>();
3657 
3658             CmisTestResult f;
3659 
3660             Map<String, PropertyDefinition<?>> propDefs = type.getPropertyDefinitions();
3661             if (propDefs == null) {
3662                 addResult(results, createResult(FAILURE, "Property definitions are missing!"));
3663             } else {
3664                 PropertyDefinition<?> propDef = propDefs.get(id);
3665                 if (propDef == null) {
3666                     addResult(results, createResult(FAILURE, "Property definition is missing!"));
3667                 } else {
3668                     if ((required != null) && !required.equals(propDef.isRequired())) {
3669                         f = createResult(FAILURE,
3670                                 "Required flag: expected: " + required + " / actual: " + propDef.isRequired());
3671                         addResult(results, f);
3672                     }
3673 
3674                     if (!propertyType.equals(propDef.getPropertyType())) {
3675                         f = createResult(FAILURE,
3676                                 "Property type: expected: " + propertyType + " / actual: " + propDef.getPropertyType());
3677                         addResult(results, f);
3678                     }
3679 
3680                     if (!cardinality.equals(propDef.getCardinality())) {
3681                         f = createResult(FAILURE,
3682                                 "Cardinality: expected: " + cardinality + " / actual: " + propDef.getCardinality());
3683                         addResult(results, f);
3684                     }
3685 
3686                     if ((updatability != null) && !updatability.equals(propDef.getUpdatability())) {
3687                         f = createResult(FAILURE,
3688                                 "Updatability: expected: " + updatability + " / actual: " + propDef.getUpdatability());
3689                         addResult(results, f);
3690                     }
3691 
3692                     if ((queryable != null) && !queryable.equals(propDef.isQueryable())) {
3693                         f = createResult(FAILURE,
3694                                 "Queryable: expected: " + queryable + " / actual: " + propDef.isQueryable());
3695                         addResult(results, f);
3696                     }
3697 
3698                     boolean isPropertyQueryNameRequired = Boolean.TRUE.equals(queryable);
3699                     checkQueryName(propDef.getQueryName(), isPropertyQueryNameRequired,
3700                             "Property Query Name: " + propDef.getQueryName());
3701 
3702                     if ((orderable != null) && !orderable.equals(propDef.isOrderable())) {
3703                         f = createResult(FAILURE,
3704                                 "Orderable: expected: " + orderable + " / actual: " + propDef.isOrderable());
3705                         addResult(results, f);
3706                     }
3707 
3708                     if (type.getBaseTypeId() != null) {
3709                         Boolean inherited = !type.getBaseTypeId().value().equals(type.getId());
3710                         if (!inherited.equals(propDef.isInherited())) {
3711                             f = createResult(FAILURE,
3712                                     "Inhertited: expected: " + inherited + " / actual: " + propDef.isInherited());
3713                             addResult(results, f);
3714                         }
3715                     }
3716 
3717                     // data type specific tests
3718                     if (propDef instanceof PropertyStringDefinition) {
3719                         PropertyStringDefinition stringPropDef = (PropertyStringDefinition) propDef;
3720 
3721                         if (stringPropDef.getMaxLength() != null) {
3722                             if (stringPropDef.getMaxLength().signum() == 0) {
3723                                 f = createResult(WARNING, "Max length is 0!");
3724                                 addResult(results, f);
3725                             } else if (stringPropDef.getMaxLength().signum() == -1) {
3726                                 f = createResult(FAILURE, "Max length is negative!");
3727                                 addResult(results, f);
3728                             }
3729                         }
3730                     } else if (propDef instanceof PropertyIntegerDefinition) {
3731                         PropertyIntegerDefinition intPropDef = (PropertyIntegerDefinition) propDef;
3732 
3733                         if (intPropDef.getMinValue() != null && intPropDef.getMaxValue() != null) {
3734                             if (intPropDef.getMinValue().compareTo(intPropDef.getMaxValue()) == 0) {
3735                                 f = createResult(WARNING, "Min and max values are equal!");
3736                                 addResult(results, f);
3737                             } else if (intPropDef.getMinValue().compareTo(intPropDef.getMaxValue()) == 1) {
3738                                 f = createResult(FAILURE, "Min value is greater than max value!");
3739                                 addResult(results, f);
3740                             }
3741                         }
3742                     } else if (propDef instanceof PropertyDecimalDefinition) {
3743                         PropertyDecimalDefinition decPropDef = (PropertyDecimalDefinition) propDef;
3744 
3745                         if (decPropDef.getMinValue() != null && decPropDef.getMaxValue() != null) {
3746                             if (decPropDef.getMinValue().compareTo(decPropDef.getMaxValue()) == 0) {
3747                                 f = createResult(WARNING, "Min and max values are equal!");
3748                                 addResult(results, f);
3749                             } else if (decPropDef.getMinValue().compareTo(decPropDef.getMaxValue()) == 1) {
3750                                 f = createResult(FAILURE, "Min value is greater than max value!");
3751                                 addResult(results, f);
3752                             }
3753                         }
3754                     }
3755                 }
3756             }
3757 
3758             CmisTestResultImpl result = createResult(getWorst(results), "Property definition: " + id);
3759             result.getChildren().addAll(results);
3760 
3761             return result.getStatus().getLevel() <= OK.getLevel() ? null : result;
3762         }
3763     }
3764 }