/*
* (C) Copyright 2006-2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed 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.
*
* Contributors:
* bstefanescu
*/
package org.nuxeo.ecm.automation.core.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.ecm.automation.AutomationService;
import org.nuxeo.ecm.automation.OperationChain;
import org.nuxeo.ecm.automation.OperationContext;
import org.nuxeo.ecm.automation.OperationException;
import org.nuxeo.ecm.automation.core.operations.FetchContextDocument;
import org.nuxeo.ecm.automation.core.operations.RestoreDocumentInput;
import org.nuxeo.ecm.automation.core.operations.SetInputAsVar;
import org.nuxeo.ecm.automation.core.operations.blob.AttachBlob;
import org.nuxeo.ecm.automation.core.operations.blob.BlobToFile;
import org.nuxeo.ecm.automation.core.operations.blob.ConcatenatePDFs;
import org.nuxeo.ecm.automation.core.operations.blob.CreateBlob;
import org.nuxeo.ecm.automation.core.operations.blob.GetAllDocumentBlobs;
import org.nuxeo.ecm.automation.core.operations.blob.GetDocumentBlob;
import org.nuxeo.ecm.automation.core.operations.blob.GetDocumentBlobs;
import org.nuxeo.ecm.automation.core.operations.blob.SetBlobFileName;
import org.nuxeo.ecm.automation.core.operations.document.CreateDocument;
import org.nuxeo.ecm.automation.core.operations.document.FetchDocument;
import org.nuxeo.ecm.automation.core.operations.document.RemoveDocumentBlob;
import org.nuxeo.ecm.automation.core.operations.document.SetDocumentBlob;
import org.nuxeo.ecm.automation.core.scripting.Scripting;
import org.nuxeo.ecm.automation.core.util.BlobList;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.Blobs;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.PathRef;
import org.nuxeo.ecm.core.event.EventService;
import org.nuxeo.ecm.core.test.CoreFeature;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.test.runner.Deploy;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.LocalDeploy;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*/
@RunWith(FeaturesRunner.class)
@Features(CoreFeature.class)
@Deploy("org.nuxeo.ecm.automation.core")
@LocalDeploy("org.nuxeo.ecm.automation.core:test-operations.xml")
// @RepositoryConfig(cleanup=Granularity.METHOD)
public class BlobOperationsTest {
protected DocumentModel src;
protected DocumentModel dst;
@Inject
AutomationService service;
@Inject
CoreSession session;
@Before
public void initRepo() throws Exception {
session.removeChildren(session.getRootDocument().getRef());
session.save();
src = session.createDocumentModel("/", "src", "Workspace");
src.setPropertyValue("dc:title", "Source");
src = session.createDocument(src);
session.save();
src = session.getDocument(src.getRef());
dst = session.createDocumentModel("/", "dst", "Workspace");
dst.setPropertyValue("dc:title", "Destination");
dst = session.createDocument(dst);
session.save();
dst = session.getDocument(dst.getRef());
}
@After
public void clearRepo() throws Exception {
Framework.getLocalService(EventService.class).waitForAsyncCompletion();
}
// ------ Tests comes here --------
@Test
public void testSetAndGetAndRemoveBlob() throws Exception {
OperationContext ctx = new OperationContext(session);
ctx.setInput(src);
OperationChain chain = new OperationChain("testChain");
chain.add(FetchContextDocument.ID);
chain.add(CreateDocument.ID).set("type", "File").set("name", "file").set("properties", "dc:title=MyDoc");
chain.add(SetDocumentBlob.ID).set("file", Blobs.createBlob("blob content"));
chain.add(GetDocumentBlob.ID);
// chain.add(Operations.BLOB_POST).set("url", Framework.createTempFile("",
// suffix));
Blob out = (Blob) service.run(ctx, chain);
assertEquals("blob content", out.getString());
// chain 2 is removing the blob created earlier
chain = new OperationChain("testRemoveChain");
chain.add(FetchDocument.ID).set("value", new PathRef("/src/file"));
chain.add(RemoveDocumentBlob.ID);
chain.add(GetDocumentBlob.ID);
out = (Blob) service.run(ctx, chain);
assertNotNull(out);
}
@Test
public void testCreateAndAttachBlob() throws Exception {
OperationContext ctx = new OperationContext(session);
ctx.setInput(src);
File file = Framework.createTempFile("nx-test-blob-", ".tmp");
try {
CreateBlob.skipProtocolCheck = true;
FileUtils.writeStringToFile(file, "blob content");
OperationChain chain = new OperationChain("testChain");
chain.add(FetchContextDocument.ID);
chain.add(CreateDocument.ID).set("type", "File").set("name", "file").set("properties", "dc:title=MyDoc");
chain.add(SetInputAsVar.ID).set("name", "doc");
chain.add(CreateBlob.ID).set("file", file.toURI().toURL());
chain.add(AttachBlob.ID).set("document", Scripting.newExpression("doc"));
chain.add(RestoreDocumentInput.ID).set("name", "doc");
chain.add(GetDocumentBlob.ID);
Blob out = (Blob) service.run(ctx, chain);
assertEquals("blob content", out.getString());
} finally {
CreateBlob.skipProtocolCheck = false;
file.delete();
}
}
@Test
public void testSetAndGetAndRemoveBlobs() throws Exception {
OperationContext ctx = new OperationContext(session);
ctx.setInput(src);
BlobList blobs = new BlobList();
blobs.add(Blobs.createBlob("blob1"));
blobs.add(Blobs.createBlob("blob2"));
// chain 1 is creating a list of 2 blobs.
OperationChain chain = new OperationChain("testChain");
chain.add(FetchContextDocument.ID);
chain.add(CreateDocument.ID).set("type", "File").set("name", "file").set("properties", "dc:title=MyDoc");
chain.add(SetDocumentBlob.ID).set("xpath", "files:files").set("file", Blobs.createBlob("blob1"));
chain.add(SetDocumentBlob.ID).set("xpath", "files:files").set("file", Blobs.createBlob("blob2"));
chain.add(GetDocumentBlobs.ID);
BlobList out = (BlobList) service.run(ctx, chain);
assertEquals(2, out.size());
assertEquals("blob1", out.get(0).getString());
assertEquals("blob2", out.get(1).getString());
// chain 2 is removing the blobs we constructed earlier.
chain = new OperationChain("testRemoveChain");
chain.add(FetchDocument.ID).set("value", new PathRef("/src/file"));
chain.add(RemoveDocumentBlob.ID).set("xpath", "files:files");
chain.add(GetDocumentBlobs.ID);
out = (BlobList) service.run(ctx, chain);
assertEquals(0, out.size());
}
@Test
public void testRemoveBlobFromList() throws Exception {
OperationContext ctx = new OperationContext(session);
ctx.setInput(src);
BlobList blobs = new BlobList();
blobs.add(Blobs.createBlob("blob1"));
blobs.add(Blobs.createBlob("blob2"));
// chain 1 is creating a list of 2 blobs.
OperationChain chain = new OperationChain("testChain");
chain.add(FetchContextDocument.ID);
chain.add(CreateDocument.ID).set("type", "File").set("name", "file").set("properties", "dc:title=MyDoc");
chain.add(SetDocumentBlob.ID).set("xpath", "files:files").set("file", Blobs.createBlob("blob1"));
chain.add(SetDocumentBlob.ID).set("xpath", "files:files").set("file", Blobs.createBlob("blob2"));
chain.add(SetDocumentBlob.ID).set("xpath", "files:files").set("file", Blobs.createBlob("blob3"));
chain.add(GetDocumentBlobs.ID);
BlobList out = (BlobList) service.run(ctx, chain);
assertEquals(3, out.size());
assertEquals("blob1", out.get(0).getString());
assertEquals("blob2", out.get(1).getString());
assertEquals("blob3", out.get(2).getString());
// chain 2 is removing blob2.
chain = new OperationChain("testRemoveChain");
chain.add(FetchDocument.ID).set("value", new PathRef("/src/file"));
chain.add(RemoveDocumentBlob.ID).set("xpath", "files:files/file[1]");
chain.add(GetDocumentBlobs.ID);
out = (BlobList) service.run(ctx, chain);
assertEquals(2, out.size());
assertEquals("blob1", out.get(0).getString());
assertEquals("blob3", out.get(1).getString());
}
@Test
public void testExportBlobToFile() throws Exception {
File dir = File.createTempFile("automation-test-", ".tmp",
org.apache.commons.io.FileUtils.getTempDirectory().getParentFile().getParentFile());
dir.delete();
dir.mkdirs();
OperationContext ctx = new OperationContext(session);
Blob blob = Blobs.createBlob("test");
blob.setFilename("myblob");
ctx.setInput(blob);
OperationChain chain = new OperationChain("testChain");
chain.add(BlobToFile.ID).set("directory", dir.getAbsolutePath()).set("prefix", "test-");
Blob out = (Blob) service.run(ctx, chain);
assertSame(blob, out);
File file = new File(dir, "test-" + blob.getFilename());
assertEquals(blob.getString(), FileUtils.readFileToString(file));
file.delete();
// test again but without prefix
chain = new OperationChain("testChain");
chain.add(BlobToFile.ID).set("directory", dir.getAbsolutePath());
out = (Blob) service.run(ctx, chain);
assertSame(blob, out);
file = new File(dir, blob.getFilename());
assertEquals(blob.getString(), FileUtils.readFileToString(file));
file.delete();
dir.delete();
}
@Test
public void testFilenameModification() throws Exception {
// create a file
Blob blob = Blobs.createBlob("the blob content");
blob.setFilename("initial_name.txt");
DocumentModel file = session.createDocumentModel(src.getPathAsString(), "blobWithName", "File");
file.setPropertyValue("dc:title", "The File");
file.setPropertyValue("file:content", (Serializable) blob);
file = session.createDocument(file);
session.save();
file = session.getDocument(file.getRef());
blob = (Blob) file.getPropertyValue("file:content");
assertEquals("the blob content", blob.getString());
assertEquals("initial_name.txt", blob.getFilename());
// execute the set blob name operation
OperationContext ctx = new OperationContext(session);
ctx.setInput(file);
OperationChain chain = new OperationChain("testChain");
chain.add(FetchContextDocument.ID);
chain.add(SetBlobFileName.ID).set("name", "modified_name.txt");
service.run(ctx, chain);
file = session.getDocument(file.getRef());
blob = (Blob) file.getPropertyValue("file:content");
assertEquals("the blob content", blob.getString());
assertEquals("modified_name.txt", blob.getFilename());
}
@SuppressWarnings("unchecked")
@Test
public void testGetAllDocumentBlobsOperation() throws Exception {
// Create a file
Blob mainFile = Blobs.createBlob("the blob content");
// Create files list
Map<String, Serializable> file = new HashMap<>();
ArrayList<Map<String, Serializable>> files = new ArrayList<>();
// Attach one file to the list
File tmpFile = Framework.createTempFile("test", ".txt");
FileUtils.writeStringToFile(tmpFile, "Content");
Blob blob = Blobs.createBlob(tmpFile);
blob.setFilename("initial_name.txt");
Framework.trackFile(tmpFile, blob);
file.put("file", (Serializable) blob);
files.add(file);
// Create document
DocumentModel docFile = session.createDocumentModel(src.getPathAsString(), "blobWithName", "File");
// Attach files to document
docFile.setPropertyValue("dc:title", "The File");
docFile.setPropertyValue("file:content", (Serializable) mainFile);
docFile.setPropertyValue("files:files", files);
docFile = session.createDocument(docFile);
session.save();
// execute operation chain containing GetAllDocumentBlobs one
OperationContext ctx = new OperationContext(session);
ctx.setInput(docFile);
OperationChain chain = new OperationChain("testBlobsChain");
chain.add(FetchContextDocument.ID);
chain.add(GetAllDocumentBlobs.ID);
files = (ArrayList<Map<String, Serializable>>) service.run(ctx, chain);
assertEquals(files.size(), 2);
}
@Test
public void testPDFMerge() throws Exception {
// Fetch two files
File pdfMerge1 = org.nuxeo.common.utils.FileUtils.getResourceFileFromContext("pdfMerge1.pdf");
File pdfMerge2 = org.nuxeo.common.utils.FileUtils.getResourceFileFromContext("pdfMerge2.pdf");
Blob pdf1 = Blobs.createBlob(pdfMerge1);
Blob pdf2 = Blobs.createBlob(pdfMerge2);
pdf1.setMimeType("application/pdf");
pdf2.setMimeType("application/pdf");
// Add them to list
BlobList blobs = new BlobList();
blobs.add(pdf1);
blobs.add(pdf2);
// Execute pdf merge operation
OperationContext ctx = new OperationContext(session);
ctx.setInput(blobs);
// Inject a blob into context
ctx.put("blobToAppend", pdf1);
Map<String, Object> params = new HashMap<>();
params.put("filename", "pdfresult");
// Put as parameter the context variable to get the context blob
params.put("blob_to_append", "blobToAppend");
Blob blob = (Blob) service.run(ctx, ConcatenatePDFs.ID, params);
assertNotNull(blob);
assertEquals("pdfresult", blob.getFilename());
// Test failures
// Test check on mimetype failure
blobs.clear();
pdf1.setMimeType("application/html");
blobs.add(pdf1);
blobs.add(pdf2);
params.clear();
params.put("filename", "pdfresult");
ctx = new OperationContext(session);
ctx.setInput(blobs);
try {
service.run(ctx, ConcatenatePDFs.ID, params);
// Should fails before
fail();
} catch (OperationException e) {
assertEquals("Blob pdfMerge1.pdf is not a PDF.", e.getMessage());
}
// Test check on context blob failure
pdf1.setMimeType("application/pdf");
blobs.clear();
blobs.add(pdf1);
blobs.add(pdf2);
params.clear();
params.put("filename", "pdfresult");
params.put("blob_to_append", "blobToAppend");
ctx = new OperationContext(session);
ctx.setInput(blobs);
// Inject a file into context for failing
ctx.put("blobToAppend", pdfMerge1);
try {
service.run(ctx, ConcatenatePDFs.ID, params);
// Should fails before
fail();
} catch (OperationException e) {
assertNotNull("The blob to append from variable context: 'blobToAppend' is not a blob.",
e.getMessage());
}
}
// TODO add post and file2pdf tests
}