ImageParsersNoTempFileTest.java
/*
* 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.tika.parser.image;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.tika.TikaTest;
import org.apache.tika.io.CacheMemoryBudget;
import org.apache.tika.io.TemporaryResources;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.HttpHeaders;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TIFF;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
/**
* Embedded images usually arrive already in memory; the image parsers must not spool them to
* disk just to read metadata. The file-system tags are the visible consequence: they describe
* whatever file was read, so in-memory input must not carry them and real files must.
*/
public class ImageParsersNoTempFileTest extends TikaTest {
private static final String FILE_NAME_KEY = ImageMetadataExtractor.UNKNOWN_IMG_NS + "File Name";
private static final String FILE_SIZE_KEY = ImageMetadataExtractor.UNKNOWN_IMG_NS + "File Size";
private static final String FILE_MODIFIED_KEY =
ImageMetadataExtractor.UNKNOWN_IMG_NS + "File Modified Date";
@TempDir
Path tempDir;
private static final String JPEG = "/test-documents/testJPEG_EXIF.jpg";
private static final String TIFF_RES = "/test-documents/testTIFF.tif";
private static final String WEBP = "/test-documents/testWebp_Alpha_Lossless.webp";
private static final String WEBP_WIDTH = ImageMetadataExtractor.UNKNOWN_IMG_NS + "Image Width";
private static ParseContext context() {
ParseContext context = new ParseContext();
context.set(CacheMemoryBudget.class, new CacheMemoryBudget(64L * 1024 * 1024));
return context;
}
private byte[] bytes(String resource) throws Exception {
try (InputStream is = getResourceAsStream(resource)) {
return is.readAllBytes();
}
}
@Test
public void testJpegInMemory() throws Exception {
assertNotSpooled(new JpegParser(), JPEG, TIFF.IMAGE_WIDTH.getName());
}
@Test
public void testTiffInMemory() throws Exception {
assertNotSpooled(new TiffParser(), TIFF_RES, TIFF.IMAGE_WIDTH.getName());
}
@Test
public void testWebPInMemory() throws Exception {
assertNotSpooled(new WebPParser(), WEBP, WEBP_WIDTH);
}
@Test
public void testJpegFromFile() throws Exception {
assertKeepsFileTags(new JpegParser(), JPEG, TIFF.IMAGE_WIDTH.getName(), "jpg");
}
@Test
public void testTiffFromFile() throws Exception {
assertKeepsFileTags(new TiffParser(), TIFF_RES, TIFF.IMAGE_WIDTH.getName(), "tif");
}
@Test
public void testWebPFromFile() throws Exception {
assertKeepsFileTags(new WebPParser(), WEBP, WEBP_WIDTH, "webp");
}
private void assertNotSpooled(Parser parser, String resource, String widthKey)
throws Exception {
byte[] bytes = bytes(resource);
Metadata metadata = new Metadata();
if (resource.endsWith(".png")) {
metadata.set(HttpHeaders.CONTENT_TYPE, "image/png");
}
try (TemporaryResources tmp = new TemporaryResources()) {
tmp.setTemporaryFileDirectory(tempDir);
// a stream-backed, non-file TikaInputStream whose only spill target is tempDir
TikaInputStream tis = TikaInputStream.get(new ByteArrayInputStream(bytes), tmp, metadata);
parser.parse(tis, new DefaultHandler(), metadata, context());
// temp files live until tmp closes, so any spool would be visible right here
try (Stream<Path> files = Files.list(tempDir)) {
assertEquals(0, files.filter(Files::isRegularFile).count(),
"parser spooled an in-memory image to disk");
}
}
assertNotNull(metadata.get(widthKey), "metadata was extracted");
assertNull(metadata.get(FILE_NAME_KEY), "in-memory input must not carry file tags");
assertNull(metadata.get(FILE_SIZE_KEY), "in-memory input must not carry file tags");
assertNull(metadata.get(FILE_MODIFIED_KEY), "in-memory input must not carry file tags");
}
private void assertKeepsFileTags(Parser parser, String resource, String widthKey, String ext)
throws Exception {
byte[] bytes = bytes(resource);
Path image = tempDir.resolve("image." + ext);
Files.write(image, bytes);
Metadata metadata = new Metadata();
try (TikaInputStream tis = TikaInputStream.get(image, metadata)) {
parser.parse(tis, new DefaultHandler(), metadata, context());
}
assertNotNull(metadata.get(widthKey), "metadata was extracted");
assertEquals(image.getFileName().toString(), metadata.get(FILE_NAME_KEY),
"a real file keeps metadata-extractor's file-system tags");
assertNotNull(metadata.get(FILE_SIZE_KEY), "a real file keeps its size tag");
}
}