1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.INFO;
23 import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.SKIPPED;
24 import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.WARNING;
25
26 import java.io.ByteArrayInputStream;
27 import java.math.BigInteger;
28 import java.util.HashMap;
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.PropertyIds;
37 import org.apache.chemistry.opencmis.commons.data.ContentStream;
38 import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
39 import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
40 import org.apache.chemistry.opencmis.commons.enums.Action;
41 import org.apache.chemistry.opencmis.commons.enums.CapabilityContentStreamUpdates;
42 import org.apache.chemistry.opencmis.commons.enums.Updatability;
43 import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
44 import org.apache.chemistry.opencmis.commons.impl.IOUtils;
45 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
46 import org.apache.chemistry.opencmis.tck.impl.AbstractSessionTest;
47
48 public class ChangeTokenTest extends AbstractSessionTest {
49
50 @Override
51 public void init(Map<String, String> parameters) {
52 super.init(parameters);
53 setName("Change Token Test");
54 setDescription("Creates a document and a folder and updates them with an outdated change token.");
55 }
56
57 @Override
58 public void run(Session session) {
59
60 Folder testFolder = createTestFolder(session);
61
62 try {
63
64 runUpdateDocumentTest(session, testFolder);
65
66
67 runContentTest(session, testFolder);
68
69
70 runUpdateFolderTest(session, testFolder);
71
72
73 runAddChildFolderTest(session, testFolder);
74 } finally {
75
76 deleteTestFolder();
77 }
78 }
79
80 private void runUpdateDocumentTest(Session session, Folder testFolder) {
81 Document doc = createDocument(session, testFolder, "update1.txt", "Hello World!");
82
83 try {
84 if (doc.getChangeToken() == null) {
85 addResult(createResult(SKIPPED,
86 "Repository does not provide change tokens for documents. Test skipped!"));
87 return;
88 }
89
90 DocumentTypeDefinition type = (DocumentTypeDefinition) doc.getType();
91 PropertyDefinition<?> namePropDef = type.getPropertyDefinitions().get(PropertyIds.NAME);
92 if (namePropDef.getUpdatability() == Updatability.WHENCHECKEDOUT
93 || !doc.getAllowableActions().getAllowableActions().contains(Action.CAN_UPDATE_PROPERTIES)) {
94 addResult(createResult(SKIPPED, "Document name can't be changed. Test skipped!"));
95 return;
96 }
97
98
99 Map<String, Object> properties2 = new HashMap<String, Object>();
100 properties2.put(PropertyIds.NAME, "update2.txt");
101 ObjectId newId = doc.updateProperties(properties2, false);
102
103 if (!doc.getId().equals(newId.getId())) {
104
105
106 addResult(createResult(INFO,
107 "The repository created a new version. Change tokens are not relevant here."));
108 } else {
109 try {
110 Map<String, Object> properties3 = new HashMap<String, Object>();
111 properties3.put(PropertyIds.NAME, "update3.txt");
112 doc.updateProperties(properties3, false);
113
114 addResult(createResult(FAILURE, "Updating properties a second time with the same change token "
115 + "should result in an UpdateConflict exception!"));
116 } catch (CmisUpdateConflictException e) {
117
118 }
119 }
120 } finally {
121 deleteObject(doc);
122 }
123 }
124
125 private void runContentTest(Session session, Folder testFolder) {
126 if (session.getRepositoryInfo().getCapabilities().getContentStreamUpdatesCapability() != CapabilityContentStreamUpdates.ANYTIME) {
127 addResult(createResult(SKIPPED, "Repository doesn't allow to replace content. Test skipped!"));
128 return;
129 }
130
131 Document doc = createDocument(session, testFolder, "content1.txt", "Hello World!");
132
133 try {
134 if (doc.getChangeToken() == null) {
135 addResult(createResult(SKIPPED,
136 "Repository does not provide change tokens for documents. Test skipped!"));
137 return;
138 }
139
140 if (!doc.getAllowableActions().getAllowableActions().contains(Action.CAN_SET_CONTENT_STREAM)) {
141 addResult(createResult(SKIPPED, "Document content can't be changed. Test skipped!"));
142 return;
143 }
144
145 byte[] contentBytes = IOUtils.toUTF8Bytes("New content");
146 ContentStream contentStream = new ContentStreamImpl("content2.txt",
147 BigInteger.valueOf(contentBytes.length), "text/plain", new ByteArrayInputStream(contentBytes));
148
149 ObjectId newId = doc.setContentStream(contentStream, true, false);
150
151 if (newId == null) {
152
153
154 if (Boolean.TRUE.equals(((DocumentTypeDefinition) doc.getType()).isVersionable())) {
155 List<Document> versions = doc.getAllVersions();
156 if (versions == null || versions.size() < 1) {
157 addResult(createResult(FAILURE, "Repository returned an empty list of document versions!"));
158 } else {
159
160 newId = versions.get(0);
161 }
162 } else {
163
164
165 newId = doc;
166 }
167 }
168
169 if (newId != null) {
170 if (!doc.getId().equals(newId.getId())) {
171
172
173 addResult(createResult(INFO,
174 "The repository created a new version. Change tokens are not relevant here."));
175 } else {
176 try {
177 doc.setContentStream(contentStream, true, false);
178
179 addResult(createResult(FAILURE, "Updating content a second time with the same change token "
180 + "should result in an UpdateConflict exception!"));
181 } catch (CmisUpdateConflictException uce) {
182
183 }
184 }
185 }
186 } finally {
187 deleteObject(doc);
188 }
189 }
190
191 private void runUpdateFolderTest(Session session, Folder testFolder) {
192 Folder folder = createFolder(session, testFolder, "folder1");
193
194 try {
195 if (folder.getChangeToken() == null) {
196 addResult(createResult(SKIPPED, "Repository does not provide change tokens for folders. Test skipped!"));
197 return;
198 }
199
200 if (!folder.getAllowableActions().getAllowableActions().contains(Action.CAN_UPDATE_PROPERTIES)) {
201 addResult(createResult(SKIPPED, "Folder name can't be changed. Test skipped!"));
202 return;
203 }
204
205
206 Map<String, Object> properties2 = new HashMap<String, Object>();
207 properties2.put(PropertyIds.NAME, "folder2");
208 folder.updateProperties(properties2, false);
209
210 try {
211 Map<String, Object> properties3 = new HashMap<String, Object>();
212 properties3.put(PropertyIds.NAME, "folder3");
213 folder.updateProperties(properties3, false);
214
215 addResult(createResult(FAILURE, "Updating properties a second time with the same change token "
216 + "should result in an UpdateConflict exception!"));
217 } catch (CmisUpdateConflictException e) {
218
219 }
220
221 } finally {
222 deleteObject(folder);
223 }
224 }
225
226 private void runAddChildFolderTest(Session session, Folder testFolder) {
227 Folder folder = createFolder(session, testFolder, "folder1");
228
229 try {
230 if (folder.getChangeToken() == null) {
231 addResult(createResult(SKIPPED, "Repository does not provide change tokens for folders. Test skipped!"));
232 return;
233 }
234
235 if (!folder.getAllowableActions().getAllowableActions().contains(Action.CAN_UPDATE_PROPERTIES)) {
236 addResult(createResult(SKIPPED, "Folder name can't be changed. Test skipped!"));
237 return;
238 }
239
240 createDocument(session, folder, "doc1", "content");
241
242 try {
243 Map<String, Object> properties2 = new HashMap<String, Object>();
244 properties2.put(PropertyIds.NAME, "folder2");
245 folder.updateProperties(properties2, false);
246 } catch (CmisUpdateConflictException e) {
247 addResult(createResult(WARNING, "Adding a child to a folder changes the change token of the folder. "
248 + "CMIS clients might not expect that."));
249 }
250
251 } finally {
252 deleteObject(folder);
253 }
254 }
255 }