DiskFileItemTest.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
*
* https://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.commons.fileupload2.core;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
import org.apache.commons.fileupload2.core.DeferrableOutputStream.State;
import org.apache.commons.fileupload2.core.FileItemFactory.AbstractFileItemBuilder;
import org.junit.jupiter.api.Test;
/**
* Tests for {@link DiskFileItem}.
*/
class DiskFileItemTest {
@SuppressWarnings("deprecation")
protected void assertState(final DiskFileItem dfi, final State state, final boolean inMemory, final Path parentDir, String testString) throws IOException {
final DeferrableOutputStream dos = (DeferrableOutputStream) dfi.getOutputStream();
assertEquals(state, dos.getState());
assertEquals(inMemory, dfi.isInMemory());
assertEquals(inMemory, dos.isInMemory());
if (parentDir == null) {
assertNull(dos.getPath());
} else {
assertNotNull(dos.getPath());
assertEquals(parentDir, dos.getPath().getParent());
}
if (testString != null) {
assertEquals(testString.length(), dfi.getSize());
assertEquals(testString.length(), dos.getSize());
assertEquals(testString, dfi.getString());
assertArrayEquals(testString.getBytes(), dfi.get());
} else {
assertNull(dfi.get());
assertNull(dfi.getString());
}
}
@Test
void testBuilderHeaders() {
final var builder = DiskFileItem.builder();
assertNotNull(builder.getFileItemHeaders());
final var fileItem = builder.get();
assertNotNull(fileItem.getHeaders(), "Missing default headers (empty)");
assertFalse(fileItem.getHeaders().getHeaderNames().hasNext());
assertNotNull(fileItem.getHeaders());
final var fileItemHeaders = AbstractFileItemBuilder.newFileItemHeaders();
assertNotNull(fileItemHeaders);
fileItem.setHeaders(fileItemHeaders);
assertSame(fileItemHeaders, fileItem.getHeaders());
}
/**
* Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-295">FILEUPLOAD-29</a>:
* A {@link #DiskFileItem} with threshold 0 must always create a file, as soon as data comes in.
*/
@Test
void testStateModelWithPositiveThreshold() {
final IntConsumer tester = (numBytes) -> {
try {
final Path testDir = Paths.get("target/unit-tests/" + DiskFileItemTest.class.getSimpleName());
Files.createDirectories(testDir);
final Path tempTestDir = Files.createTempDirectory(testDir, "testDir");
final DiskFileItemFactory dfif = DiskFileItemFactory.builder()
.setThreshold(numBytes)
.setPath(tempTestDir)
.setCharset(StandardCharsets.UTF_8)
.get();
assertEquals(numBytes, dfif.getThreshold());
final DiskFileItem dfi = dfif.fileItemBuilder()
.get();
// Make sure, that the threshold has not been tampered with.
assertEquals(numBytes, dfi.getThreshold());
// We haven't written any data. So, the output file is null.
assertState(dfi, State.initialized, true, null, null);
// Write some data.
final StringBuilder sb = new StringBuilder();
try (OutputStream os = dfi.getOutputStream()) {
for (int i = 0; i < numBytes-1; i++) {
os.write('.');
sb.append('.');
assertState(dfi, State.opened, true, null, null);
}
/*
* Write another byte. This should hit the threshold,
* thus trigger persisting the in memory data.
*/
os.write(',');
sb.append(',');
assertState(dfi, State.persisted, false, tempTestDir, null);
}
// The output stream is closed now, so the state has changed again.
assertState(dfi, State.closed, false, tempTestDir, sb.toString());
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
};
tester.accept(5);
tester.accept(8193); // Typical buffer size +1
}
/**
* Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-295">FILEUPLOAD-29</a>:
* A {@link #DiskFileItem} with threshold -1 must always create a (possibly empty) file.
*/
@Test
void testStateModelWithThresholdMinusOne() {
final Consumer<String> tester = (ts) -> {
try {
final Path testDir = Paths.get("target/unit-tests/" + DiskFileItemTest.class.getSimpleName());
Files.createDirectories(testDir);
final Path tempTestDir = Files.createTempDirectory(testDir, "testDir");
final DiskFileItemFactory dfif = DiskFileItemFactory.builder()
.setBufferSize(-1)
.setPath(tempTestDir)
.setCharset(StandardCharsets.UTF_8)
.get();
// Make sure, that the threshold has not been tampered with.
assertEquals(-1, dfif.getThreshold());
final DiskFileItem dfi = dfif.fileItemBuilder()
.get();
// Make sure, that the threshold has not been tampered with.
assertEquals(-1, dfi.getThreshold());
// We haven't written any data. Yet, the output file already exists (threshold=-1)
assertState(dfi, State.persisted, false, tempTestDir, null);
try (OutputStream out = dfi.getOutputStream()) {
out.write(ts.getBytes());
}
// After writing some data, the output file does still exist, except that the size has changed.
assertState(dfi, State.closed, false, tempTestDir, ts);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
};
tester.accept("abcdef");
tester.accept("aAbBcCdDeEfF012345");
}
/**
* Test for <a href="https://issues.apache.org/jira/browse/FILEUPLOAD-295">FILEUPLOAD-29</a>:
* A {@link #DiskFileItem} with threshold 0 must always create a file, as soon as data comes in.
*/
@Test
void testStateModelWithThresholdZero() {
final IntConsumer tester = (numBytes) -> {
try {
final Path testDir = Paths.get("target/unit-tests/" + DiskFileItemTest.class.getSimpleName());
Files.createDirectories(testDir);
final Path tempTestDir = Files.createTempDirectory(testDir, "testDir");
final DiskFileItemFactory dfif = DiskFileItemFactory.builder()
.setBufferSize(0)
.setPath(tempTestDir)
.setCharset(StandardCharsets.UTF_8)
.get();
assertEquals(0, dfif.getThreshold());
final DiskFileItem dfi = dfif.fileItemBuilder()
.get();
// Make sure, that the threshold has not been tampered with.
assertEquals(0, dfi.getThreshold());
// We haven't written any data. So, the output file is null.
assertState(dfi, State.initialized, true, null, null);
// Write some data.
final StringBuilder sb = new StringBuilder();
try (OutputStream os = dfi.getOutputStream()) {
for (int i = 0; i < numBytes; i++) {
os.write('.');
sb.append('.');
assertState(dfi, State.persisted, false, tempTestDir, null);
}
os.write(',');
sb.append(',');
}
// The output stream is closed now, so the state has changed again.
assertState(dfi, State.closed, false, tempTestDir, sb.toString());
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
};
tester.accept(5);
tester.accept(8193); // Typical buffer size +1
}
}