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.tests.crud;
20  
21  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.FAILURE;
22  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.SKIPPED;
23  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.UNEXPECTED_EXCEPTION;
24  import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.WARNING;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.IOException;
28  import java.io.OutputStream;
29  import java.util.List;
30  import java.util.Map;
31  
32  import org.apache.chemistry.opencmis.client.api.Document;
33  import org.apache.chemistry.opencmis.client.api.Folder;
34  import org.apache.chemistry.opencmis.client.api.ObjectId;
35  import org.apache.chemistry.opencmis.client.api.Session;
36  import org.apache.chemistry.opencmis.commons.data.ContentStream;
37  import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
38  import org.apache.chemistry.opencmis.commons.enums.Action;
39  import org.apache.chemistry.opencmis.commons.enums.BindingType;
40  import org.apache.chemistry.opencmis.commons.enums.CapabilityContentStreamUpdates;
41  import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
42  import org.apache.chemistry.opencmis.commons.enums.ContentStreamAllowed;
43  import org.apache.chemistry.opencmis.commons.exceptions.CmisNotSupportedException;
44  import org.apache.chemistry.opencmis.commons.impl.IOUtils;
45  import org.apache.chemistry.opencmis.tck.CmisTestResult;
46  import org.apache.chemistry.opencmis.tck.impl.AbstractSessionTest;
47  
48  /**
49   * Content test.
50   */
51  public class SetAndDeleteContentTest extends AbstractSessionTest {
52  
53      private static final String CONTENT1 = "one";
54      private static final String CONTENT2 = "two";
55      private static final String CONTENT3 = "three";
56  
57      @Override
58      public void init(Map<String, String> parameters) {
59          super.init(parameters);
60          setName("Set, Append, and Delete Content Test");
61          setDescription("Creates a new document and tries to set, append, and delete its content.");
62      }
63  
64      @Override
65      public void run(Session session) {
66          CmisTestResult f;
67  
68          if (getContentStreamUpdatesCapbility(session) == CapabilityContentStreamUpdates.NONE) {
69              addResult(createResult(SKIPPED, "Stream updates are not supported. Test skipped!"));
70              return;
71          }
72  
73          try {
74              // create folder and document
75              Folder testFolder = createTestFolder(session);
76              Document doc = createDocument(session, testFolder, "contenttest.txt", CONTENT1);
77              Document workDoc = doc;
78              DocumentTypeDefinition docType = (DocumentTypeDefinition) doc.getType();
79  
80              // test if check out is required and possible
81              boolean checkedout = false;
82              if (!doc.getAllowableActions().getAllowableActions().contains(Action.CAN_SET_CONTENT_STREAM)) {
83                  if (!docType.isVersionable()) {
84                      addResult(createResult(SKIPPED,
85                              "The test document does not accept a new content stream. Test skipped!"));
86                      doc.delete(true);
87                      return;
88                  } else {
89                      workDoc = (Document) session.getObject(doc.checkOut(), SELECT_ALL_NO_CACHE_OC);
90                      checkedout = true;
91  
92                      if (!workDoc.getAllowableActions().getAllowableActions().contains(Action.CAN_SET_CONTENT_STREAM)) {
93                          addResult(createResult(SKIPPED,
94                                  "The test PWC does not accept a new content stream. Test skipped!"));
95                          workDoc.cancelCheckOut();
96                          doc.delete(true);
97                          return;
98                      }
99                  }
100             }
101 
102             // test if the content stream can be deleted
103             if (docType.getContentStreamAllowed() == ContentStreamAllowed.REQUIRED) {
104                 addResult(createResult(SKIPPED,
105                         "A content stream is required for this document type. deleteContentStream() test skipped!"));
106             } else {
107                 // delete content stream
108                 try {
109                     ObjectId newObjectId = workDoc.deleteContentStream(true);
110 
111                     // deleteContentStream may have created a new version
112                     Document contentDoc = getNewVersion(session, workDoc, checkedout, newObjectId,
113                             "deleteContentStream()");
114 
115                     f = createResult(FAILURE, "Document still has content after deleteContentStream() has been called!");
116                     addResult(assertNull(contentDoc.getContentStream(), null, f));
117 
118                     f = createResult(
119                             FAILURE,
120                             "Document still has a MIME type after deleteContentStream() has been called: "
121                                     + contentDoc.getContentStreamMimeType());
122                     addResult(assertNull(contentDoc.getContentStreamMimeType(), null, f));
123 
124                     f = createResult(FAILURE,
125                             "Document still has a content length after deleteContentStream() has been called: "
126                                     + contentDoc.getContentStreamLength());
127                     addResult(assertEquals(-1L, contentDoc.getContentStreamLength(), null, f));
128 
129                     f = createResult(
130                             FAILURE,
131                             "Document still has a file name after deleteContentStream() has been called: "
132                                     + contentDoc.getContentStreamFileName());
133                     addResult(assertNull(contentDoc.getContentStreamFileName(), null, f));
134 
135                     workDoc = contentDoc;
136                 } catch (CmisNotSupportedException e) {
137                     addResult(createResult(WARNING, "deleteContentStream() is not supported!"));
138                 }
139             }
140 
141             // set a new content stream
142             byte[] contentBytes = IOUtils.toUTF8Bytes(CONTENT2);
143 
144             try {
145                 ContentStream contentStream = session.getObjectFactory().createContentStream(workDoc.getName(),
146                         contentBytes.length, "text/plain", new ByteArrayInputStream(contentBytes));
147 
148                 ObjectId newObjectId = workDoc.setContentStream(contentStream, true, true);
149 
150                 IOUtils.closeQuietly(contentStream);
151 
152                 // setContentStream may have created a new version
153                 Document contentDoc = getNewVersion(session, workDoc, checkedout, newObjectId, "setContentStream()");
154 
155                 // test new content
156                 try {
157                     String content = getStringFromContentStream(contentDoc.getContentStream());
158                     f = createResult(FAILURE, "Document content doesn't match the content set by setContentStream()!");
159                     addResult(assertEquals(CONTENT2, content, null, f));
160                 } catch (IOException e) {
161                     addResult(createResult(UNEXPECTED_EXCEPTION,
162                             "Document content couldn't be read! Exception: " + e.getMessage(), e, true));
163                 }
164 
165                 workDoc = contentDoc;
166             } catch (CmisNotSupportedException e) {
167                 addResult(createResult(WARNING, "setContentStream() is not supported!"));
168             }
169 
170             // test appendContentStream
171             if (session.getRepositoryInfo().getCmisVersion() != CmisVersion.CMIS_1_0) {
172                 contentBytes = IOUtils.toUTF8Bytes(CONTENT3);
173 
174                 try {
175                     ContentStream contentStream = session.getObjectFactory().createContentStream(workDoc.getName(),
176                             contentBytes.length, "text/plain", new ByteArrayInputStream(contentBytes));
177 
178                     ObjectId newObjectId = workDoc.appendContentStream(contentStream, true);
179 
180                     // appendContentStream may have created a new version
181                     Document contentDoc = getNewVersion(session, workDoc, checkedout, newObjectId,
182                             "appendContentStream()");
183 
184                     // test new content
185                     try {
186                         String content = getStringFromContentStream(contentDoc.getContentStream());
187                         f = createResult(FAILURE,
188                                 "Document content doesn't match the content set by setContentStream() followed by appendContentStream()!");
189                         addResult(assertEquals(CONTENT2 + CONTENT3, content, null, f));
190                     } catch (IOException e) {
191                         addResult(createResult(UNEXPECTED_EXCEPTION, "Document content couldn't be read! Exception: "
192                                 + e.getMessage(), e, true));
193                     }
194 
195                     // test append stream
196                     testAppendStream(session, testFolder, 16 * 1024);
197                     testAppendStream(session, testFolder, 8);
198                     testAppendStream(session, testFolder, 0);
199                 } catch (CmisNotSupportedException e) {
200                     addResult(createResult(WARNING, "appendContentStream() is not supported!"));
201                 }
202             }
203 
204             // cancel a possible check out
205             if (checkedout) {
206                 workDoc.cancelCheckOut();
207             }
208 
209             // remove the document
210             deleteObject(doc);
211         } finally {
212             deleteTestFolder();
213         }
214     }
215 
216     private void testAppendStream(Session session, Folder testFolder, int bufferSize) {
217         CmisTestResult f;
218 
219         // create an empty document
220         Document doc = createDocument(session, testFolder, "appendstreamtest.txt", "");
221         Document workDoc = doc;
222 
223         boolean checkedout = false;
224         DocumentTypeDefinition docType = (DocumentTypeDefinition) doc.getType();
225 
226         if (Boolean.TRUE.equals(docType.isVersionable())) {
227             workDoc = (Document) session.getObject(doc.checkOut(), SELECT_ALL_NO_CACHE_OC);
228             checkedout = true;
229         }
230 
231         try {
232             // create an overwrite OutputStream
233             OutputStream out1 = workDoc.createOverwriteOutputStream("appendstreamtest", "text/plain", bufferSize);
234 
235             out1.write(IOUtils.toUTF8Bytes("line 1\n"));
236             out1.write(IOUtils.toUTF8Bytes("line 2\n"));
237             out1.flush();
238 
239             out1.write(IOUtils.toUTF8Bytes("line 3\n"));
240             out1.close();
241 
242             // check document content
243             workDoc.refresh();
244             String content1 = getStringFromContentStream(workDoc.getContentStream());
245 
246             f = createResult(FAILURE, "Overwrite OutputStream: wrong content!");
247             addResult(assertEquals("line 1\nline 2\nline 3\n", content1, null, f));
248 
249             // create an append OutputStream
250             OutputStream out2 = workDoc.createAppendOutputStream(bufferSize);
251 
252             out2.write(IOUtils.toUTF8Bytes("line 4\n"));
253             out2.write(IOUtils.toUTF8Bytes("line 5\n"));
254             out2.flush();
255 
256             out2.write(IOUtils.toUTF8Bytes("line 6\n"));
257             out2.close();
258 
259             // check document content
260             workDoc.refresh();
261             String content2 = getStringFromContentStream(workDoc.getContentStream());
262 
263             f = createResult(FAILURE, "Overwrite OutputStream: wrong content!");
264             addResult(assertEquals("line 1\nline 2\nline 3\nline 4\nline 5\nline 6\n", content2, null, f));
265 
266         } catch (IOException e) {
267             addResult(createResult(UNEXPECTED_EXCEPTION, "Appending content via an OutputStream failed! Exception: "
268                     + e.getMessage(), e, false));
269         } finally {
270             // cancel a possible check out
271             if (checkedout) {
272                 workDoc.cancelCheckOut();
273             }
274 
275             // remove the document
276             deleteObject(doc);
277         }
278     }
279 
280     private CapabilityContentStreamUpdates getContentStreamUpdatesCapbility(Session session) {
281         if (session.getRepositoryInfo().getCapabilities() == null) {
282             return null;
283         }
284 
285         return session.getRepositoryInfo().getCapabilities().getContentStreamUpdatesCapability();
286     }
287 
288     private Document getNewVersion(Session session, Document orgDoc, boolean checkedout, ObjectId newObjectId,
289             String operation) {
290         Document result = orgDoc;
291 
292         if (newObjectId != null) {
293             // -> Non AtomPub binding
294             if (!orgDoc.getId().equals(newObjectId.getId())) {
295                 if (checkedout) {
296                     addResult(createResult(FAILURE, operation + " created a new version from a PWC!"));
297                 } else {
298                     result = (Document) session.getObject(newObjectId, SELECT_ALL_NO_CACHE_OC);
299                     addResult(checkObject(session, result, getAllProperties(result), "Version created by " + operation
300                             + "  compliance"));
301                 }
302             }
303         } else {
304             if (getBinding() != BindingType.ATOMPUB) {
305                 addResult(createResult(FAILURE, operation + " did not return an object id!"));
306             }
307 
308             // -> AtomPub binding or incompliant other binding
309             if (checkedout) {
310                 // we cannot check if the repository does the right thing,
311                 // but if there is a problem the versioning tests should
312                 // catch it
313             } else if (Boolean.TRUE.equals(((DocumentTypeDefinition) orgDoc.getType()).isVersionable())) {
314                 List<Document> versions = orgDoc.getAllVersions();
315                 if (versions == null || versions.isEmpty()) {
316                     addResult(createResult(FAILURE, operation
317                             + " created a new version but the version history is empty!"));
318                 } else if (!orgDoc.getId().equals(versions.get(0).getId())) {
319                     result = (Document) session.getObject(versions.get(0), SELECT_ALL_NO_CACHE_OC);
320                     addResult(checkObject(session, result, getAllProperties(result), "Version created by " + operation
321                             + " compliance"));
322                 }
323             }
324         }
325 
326         return result;
327     }
328 }