PackageMultiEntryTest.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.pkg;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream;
import org.apache.commons.compress.archivers.cpio.CpioArchiveEntry;
import org.apache.commons.compress.archivers.cpio.CpioArchiveOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.apache.tika.metadata.HttpHeaders;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
/**
* Every entry of a multi-entry archive must be parsed. The per-entry TikaInputStream wraps the
* archive's own stream; closing it must not close the archive (cpio's stream refuses further
* reads once closed, zip's silently returns no more entries).
*/
public class PackageMultiEntryTest extends AbstractPkgTest {
@TempDir
Path tmp;
private static final String[] NAMES = {"a.txt", "b.txt", "c.txt"};
private static byte[] body(String name) {
return ("entry " + name + " body\n").repeat(64).getBytes(StandardCharsets.UTF_8);
}
private static byte[] cpio() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (CpioArchiveOutputStream out = new CpioArchiveOutputStream(bos)) {
for (String n : NAMES) {
byte[] b = body(n);
CpioArchiveEntry e = new CpioArchiveEntry(n);
e.setSize(b.length);
put(out, e, b);
}
}
return bos.toByteArray();
}
private static byte[] ar() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ArArchiveOutputStream out = new ArArchiveOutputStream(bos)) {
for (String n : NAMES) {
byte[] b = body(n);
put(out, new ArArchiveEntry(n, b.length), b);
}
}
return bos.toByteArray();
}
private static byte[] tar() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (TarArchiveOutputStream out = new TarArchiveOutputStream(bos)) {
for (String n : NAMES) {
byte[] b = body(n);
TarArchiveEntry e = new TarArchiveEntry(n);
e.setSize(b.length);
put(out, e, b);
}
}
return bos.toByteArray();
}
private static byte[] zip() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ZipArchiveOutputStream out = new ZipArchiveOutputStream(bos)) {
for (String n : NAMES) {
put(out, new ZipArchiveEntry(n), body(n));
}
}
return bos.toByteArray();
}
private static <E extends org.apache.commons.compress.archivers.ArchiveEntry> void put(
ArchiveOutputStream<E> out, E entry, byte[] b) throws IOException {
out.putArchiveEntry(entry);
out.write(b);
out.closeArchiveEntry();
}
/** The module's test classpath has no text parser, so entries are checked by name and
* declared size rather than by content. */
private void assertAllEntries(String ext, byte[] archive) throws Exception {
Path p = tmp.resolve("multi." + ext);
Files.write(p, archive);
List<Metadata> list = getRecursiveMetadata(p, false);
assertEquals(NAMES.length + 1, list.size(), ext + ": container + one per entry");
assertNull(list.get(0).get(TikaCoreProperties.EMBEDDED_EXCEPTION), ext);
for (int i = 0; i < NAMES.length; i++) {
Metadata m = list.get(i + 1);
assertEquals(NAMES[i], m.get(TikaCoreProperties.RESOURCE_NAME_KEY), ext);
assertEquals(Integer.toString(body(NAMES[i]).length), m.get(HttpHeaders.CONTENT_LENGTH),
ext + ": declared size of " + NAMES[i]);
}
}
@Test
public void testCpio() throws Exception {
assertAllEntries("cpio", cpio());
}
@Test
public void testAr() throws Exception {
assertAllEntries("ar", ar());
}
@Test
public void testTar() throws Exception {
assertAllEntries("tar", tar());
}
@Test
public void testZip() throws Exception {
assertAllEntries("zip", zip());
}
}