HADOOP-11012. hadoop fs -text of zero-length file causes EOFException. Contributed by Eric Payne

(cherry picked from commit 01e8f056d9)
This commit is contained in:
Jason Lowe 2014-09-02 18:25:03 +00:00
parent a96696bdc3
commit 0a582c77ef
3 changed files with 72 additions and 20 deletions

View File

@ -397,6 +397,9 @@ Release 2.6.0 - UNRELEASED
HADOOP-11036. Add build directory to .gitignore (Tsuyoshi OZAWA via aw) HADOOP-11036. Add build directory to .gitignore (Tsuyoshi OZAWA via aw)
HADOOP-11012. hadoop fs -text of zero-length file causes EOFException
(Eric Payne via jlowe)
Release 2.5.1 - UNRELEASED Release 2.5.1 - UNRELEASED
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.fs.shell; package org.apache.hadoop.fs.shell;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -126,8 +127,17 @@ class Display extends FsCommand {
protected InputStream getInputStream(PathData item) throws IOException { protected InputStream getInputStream(PathData item) throws IOException {
FSDataInputStream i = (FSDataInputStream)super.getInputStream(item); FSDataInputStream i = (FSDataInputStream)super.getInputStream(item);
// Handle 0 and 1-byte files
short leadBytes;
try {
leadBytes = i.readShort();
} catch (EOFException e) {
i.seek(0);
return i;
}
// Check type of stream first // Check type of stream first
switch(i.readShort()) { switch(leadBytes) {
case 0x1f8b: { // RFC 1952 case 0x1f8b: { // RFC 1952
// Must be gzip // Must be gzip
i.seek(0); i.seek(0);

View File

@ -42,29 +42,14 @@ public class TestTextCommand {
System.getProperty("test.build.data", "build/test/data/") + "/testText"; System.getProperty("test.build.data", "build/test/data/") + "/testText";
private static final String AVRO_FILENAME = private static final String AVRO_FILENAME =
new Path(TEST_ROOT_DIR, "weather.avro").toUri().getPath(); new Path(TEST_ROOT_DIR, "weather.avro").toUri().getPath();
private static final String TEXT_FILENAME =
new Path(TEST_ROOT_DIR, "testtextfile.txt").toUri().getPath();
/** /**
* Tests whether binary Avro data files are displayed correctly. * Tests whether binary Avro data files are displayed correctly.
*/ */
@Test (timeout = 30000) @Test (timeout = 30000)
public void testDisplayForAvroFiles() throws Exception { public void testDisplayForAvroFiles() throws Exception {
// Create a small Avro data file on the local file system.
createAvroFile(generateWeatherAvroBinaryData());
// Prepare and call the Text command's protected getInputStream method
// using reflection.
Configuration conf = new Configuration();
URI localPath = new URI(AVRO_FILENAME);
PathData pathData = new PathData(localPath, conf);
Display.Text text = new Display.Text();
text.setConf(conf);
Method method = text.getClass().getDeclaredMethod(
"getInputStream", PathData.class);
method.setAccessible(true);
InputStream stream = (InputStream) method.invoke(text, pathData);
String output = inputStreamToString(stream);
// Check the output.
String expectedOutput = String expectedOutput =
"{\"station\":\"011990-99999\",\"time\":-619524000000,\"temp\":0}" + "{\"station\":\"011990-99999\",\"time\":-619524000000,\"temp\":0}" +
System.getProperty("line.separator") + System.getProperty("line.separator") +
@ -77,18 +62,72 @@ public class TestTextCommand {
"{\"station\":\"012650-99999\",\"time\":-655509600000,\"temp\":78}" + "{\"station\":\"012650-99999\",\"time\":-655509600000,\"temp\":78}" +
System.getProperty("line.separator"); System.getProperty("line.separator");
String output = readUsingTextCommand(AVRO_FILENAME,
generateWeatherAvroBinaryData());
assertEquals(expectedOutput, output); assertEquals(expectedOutput, output);
} }
/**
* Tests that a zero-length file is displayed correctly.
*/
@Test (timeout = 30000)
public void testEmptyTextFil() throws Exception {
byte[] emptyContents = { };
String output = readUsingTextCommand(TEXT_FILENAME, emptyContents);
assertTrue("".equals(output));
}
/**
* Tests that a one-byte file is displayed correctly.
*/
@Test (timeout = 30000)
public void testOneByteTextFil() throws Exception {
byte[] oneByteContents = { 'x' };
String output = readUsingTextCommand(TEXT_FILENAME, oneByteContents);
assertTrue(new String(oneByteContents).equals(output));
}
/**
* Tests that a one-byte file is displayed correctly.
*/
@Test (timeout = 30000)
public void testTwoByteTextFil() throws Exception {
byte[] twoByteContents = { 'x', 'y' };
String output = readUsingTextCommand(TEXT_FILENAME, twoByteContents);
assertTrue(new String(twoByteContents).equals(output));
}
// Create a file on the local file system and read it using
// the Display.Text class.
private String readUsingTextCommand(String fileName, byte[] fileContents)
throws Exception {
createFile(fileName, fileContents);
// Prepare and call the Text command's protected getInputStream method
// using reflection.
Configuration conf = new Configuration();
URI localPath = new URI(fileName);
PathData pathData = new PathData(localPath, conf);
Display.Text text = new Display.Text() {
@Override
public InputStream getInputStream(PathData item) throws IOException {
return super.getInputStream(item);
}
};
text.setConf(conf);
InputStream stream = (InputStream) text.getInputStream(pathData);
return inputStreamToString(stream);
}
private String inputStreamToString(InputStream stream) throws IOException { private String inputStreamToString(InputStream stream) throws IOException {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
IOUtils.copy(stream, writer); IOUtils.copy(stream, writer);
return writer.toString(); return writer.toString();
} }
private void createAvroFile(byte[] contents) throws IOException { private void createFile(String fileName, byte[] contents) throws IOException {
(new File(TEST_ROOT_DIR)).mkdir(); (new File(TEST_ROOT_DIR)).mkdir();
File file = new File(AVRO_FILENAME); File file = new File(fileName);
file.createNewFile(); file.createNewFile();
FileOutputStream stream = new FileOutputStream(file); FileOutputStream stream = new FileOutputStream(file);
stream.write(contents); stream.write(contents);