blob: ab544df660a42b3c6eac067be578ddafc5bf2a64 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.chemistry.opencmis.tck.tests.crud;
import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.FAILURE;
import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.INFO;
import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.SKIPPED;
import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.WARNING;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.ObjectId;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
import org.apache.chemistry.opencmis.commons.enums.Action;
import org.apache.chemistry.opencmis.commons.enums.CapabilityContentStreamUpdates;
import org.apache.chemistry.opencmis.commons.enums.Updatability;
import org.apache.chemistry.opencmis.commons.exceptions.CmisUpdateConflictException;
import org.apache.chemistry.opencmis.commons.impl.IOUtils;
import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
import org.apache.chemistry.opencmis.tck.impl.AbstractSessionTest;
public class ChangeTokenTest extends AbstractSessionTest {
@Override
public void init(Map<String, String> parameters) {
super.init(parameters);
setName("Change Token Test");
setDescription("Creates a document and a folder and updates them with an outdated change token.");
}
@Override
public void run(Session session) {
// create a test folder
Folder testFolder = createTestFolder(session);
try {
// update document properties test
runUpdateDocumentTest(session, testFolder);
// content update test
runContentTest(session, testFolder);
// update folder properties test
runUpdateFolderTest(session, testFolder);
// add child and update folder properties test
runAddChildFolderTest(session, testFolder);
} finally {
// delete the test folder
deleteTestFolder();
}
}
private void runUpdateDocumentTest(Session session, Folder testFolder) {
Document doc = createDocument(session, testFolder, "update1.txt", "Hello World!");
try {
if (doc.getChangeToken() == null) {
addResult(createResult(SKIPPED,
"Repository does not provide change tokens for documents. Test skipped!"));
return;
}
DocumentTypeDefinition type = (DocumentTypeDefinition) doc.getType();
PropertyDefinition<?> namePropDef = type.getPropertyDefinitions().get(PropertyIds.NAME);
if (namePropDef.getUpdatability() == Updatability.WHENCHECKEDOUT
|| !doc.getAllowableActions().getAllowableActions().contains(Action.CAN_UPDATE_PROPERTIES)) {
addResult(createResult(SKIPPED, "Document name can't be changed. Test skipped!"));
return;
}
// the first update should succeed
Map<String, Object> properties2 = new HashMap<String, Object>();
properties2.put(PropertyIds.NAME, "update2.txt");
ObjectId newId = doc.updateProperties(properties2, false);
if (!doc.getId().equals(newId.getId())) {
// the repository created a new version
// -> a change token test does not make sense
addResult(createResult(INFO,
"The repository created a new version. Change tokens are not relevant here."));
} else {
try {
Map<String, Object> properties3 = new HashMap<String, Object>();
properties3.put(PropertyIds.NAME, "update3.txt");
doc.updateProperties(properties3, false);
addResult(createResult(FAILURE, "Updating properties a second time with the same change token "
+ "should result in an UpdateConflict exception!"));
} catch (CmisUpdateConflictException e) {
// expected exception
}
}
} finally {
deleteObject(doc);
}
}
private void runContentTest(Session session, Folder testFolder) {
if (session.getRepositoryInfo().getCapabilities().getContentStreamUpdatesCapability() != CapabilityContentStreamUpdates.ANYTIME) {
addResult(createResult(SKIPPED, "Repository doesn't allow to replace content. Test skipped!"));
return;
}
Document doc = createDocument(session, testFolder, "content1.txt", "Hello World!");
try {
if (doc.getChangeToken() == null) {
addResult(createResult(SKIPPED,
"Repository does not provide change tokens for documents. Test skipped!"));
return;
}
if (!doc.getAllowableActions().getAllowableActions().contains(Action.CAN_SET_CONTENT_STREAM)) {
addResult(createResult(SKIPPED, "Document content can't be changed. Test skipped!"));
return;
}
byte[] contentBytes = IOUtils.toUTF8Bytes("New content");
ContentStream contentStream = new ContentStreamImpl("content2.txt",
BigInteger.valueOf(contentBytes.length), "text/plain", new ByteArrayInputStream(contentBytes));
ObjectId newId = doc.setContentStream(contentStream, true, false);
if (newId == null) {
// the AtomPub binding does not return an id here
// -> get the latest id from the version series
if (Boolean.TRUE.equals(((DocumentTypeDefinition) doc.getType()).isVersionable())) {
List<Document> versions = doc.getAllVersions();
if (versions == null || versions.size() < 1) {
addResult(createResult(FAILURE, "Repository returned an empty list of document versions!"));
} else {
// the latest document is at the top of the list
newId = versions.get(0);
}
} else {
// the document type is not versionable
// -> the repository couldn't create a new version
newId = doc;
}
}
if (newId != null) {
if (!doc.getId().equals(newId.getId())) {
// the repository created a new version
// -> a change token test does not make sense
addResult(createResult(INFO,
"The repository created a new version. Change tokens are not relevant here."));
} else {
try {
doc.setContentStream(contentStream, true, false);
addResult(createResult(FAILURE, "Updating content a second time with the same change token "
+ "should result in an UpdateConflict exception!"));
} catch (CmisUpdateConflictException uce) {
// expected exception
}
}
}
} finally {
deleteObject(doc);
}
}
private void runUpdateFolderTest(Session session, Folder testFolder) {
Folder folder = createFolder(session, testFolder, "folder1");
try {
if (folder.getChangeToken() == null) {
addResult(createResult(SKIPPED, "Repository does not provide change tokens for folders. Test skipped!"));
return;
}
if (!folder.getAllowableActions().getAllowableActions().contains(Action.CAN_UPDATE_PROPERTIES)) {
addResult(createResult(SKIPPED, "Folder name can't be changed. Test skipped!"));
return;
}
// the first update should succeed
Map<String, Object> properties2 = new HashMap<String, Object>();
properties2.put(PropertyIds.NAME, "folder2");
folder.updateProperties(properties2, false);
try {
Map<String, Object> properties3 = new HashMap<String, Object>();
properties3.put(PropertyIds.NAME, "folder3");
folder.updateProperties(properties3, false);
addResult(createResult(FAILURE, "Updating properties a second time with the same change token "
+ "should result in an UpdateConflict exception!"));
} catch (CmisUpdateConflictException e) {
// expected exception
}
} finally {
deleteObject(folder);
}
}
private void runAddChildFolderTest(Session session, Folder testFolder) {
Folder folder = createFolder(session, testFolder, "folder1");
try {
if (folder.getChangeToken() == null) {
addResult(createResult(SKIPPED, "Repository does not provide change tokens for folders. Test skipped!"));
return;
}
if (!folder.getAllowableActions().getAllowableActions().contains(Action.CAN_UPDATE_PROPERTIES)) {
addResult(createResult(SKIPPED, "Folder name can't be changed. Test skipped!"));
return;
}
createDocument(session, folder, "doc1", "content");
try {
Map<String, Object> properties2 = new HashMap<String, Object>();
properties2.put(PropertyIds.NAME, "folder2");
folder.updateProperties(properties2, false);
} catch (CmisUpdateConflictException e) {
addResult(createResult(WARNING, "Adding a child to a folder changes the change token of the folder. "
+ "CMIS clients might not expect that."));
}
} finally {
deleteObject(folder);
}
}
}