| /* |
| * 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); |
| } |
| } |
| } |