package org.apache.hadoop.hdfs;
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Random;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.logging.impl.Log4JLogger;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.log4j.Level;
/**
* Unittest for HftpFileSystem.
*
*/
public class TestHftpFileSystem extends TestCase {
private static final Random RAN = new Random();
private static final Path TEST_FILE = new Path("/testfile+1");
private static Configuration config = null;
private static MiniDFSCluster cluster = null;
private static FileSystem hdfs = null;
private static HftpFileSystem hftpFs = null;
/**
* Setup hadoop mini-cluster for test.
*/
private static void oneTimeSetUp() throws IOException {
((Log4JLogger)HftpFileSystem.LOG).getLogger().setLevel(Level.ALL);
final long seed = RAN.nextLong();
System.out.println("seed=" + seed);
RAN.setSeed(seed);
config = new Configuration();
config.set("slave.host.name", "localhost");
cluster = new MiniDFSCluster(config, 2, true, null);
hdfs = cluster.getFileSystem();
final String hftpuri = "hftp://" + config.get("dfs.http.address");
System.out.println("hftpuri=" + hftpuri);
hftpFs = (HftpFileSystem) new Path(hftpuri).getFileSystem(config);
}
/**
* Shutdown the hadoop mini-cluster.
*/
private static void oneTimeTearDown() throws IOException {
hdfs.close();
hftpFs.close();
cluster.shutdown();
}
public TestHftpFileSystem(String name) {
super(name);
}
/**
* For one time setup / teardown.
*/
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTestSuite(TestHftpFileSystem.class);
return new TestSetup(suite) {
@Override
protected void setUp() throws IOException {
oneTimeSetUp();
}
@Override
protected void tearDown() throws IOException {
oneTimeTearDown();
}
};
}
/**
* Tests isUnderConstruction() functionality.
*/
public void testIsUnderConstruction() throws Exception {
// Open output file stream.
FSDataOutputStream out = hdfs.create(TEST_FILE, true);
out.writeBytes("test");
// Test file under construction.
FSDataInputStream in1 = hftpFs.open(TEST_FILE);
assertTrue(in1.isUnderConstruction());
in1.close();
// Close output file stream.
out.close();
// Test file not under construction.
FSDataInputStream in2 = hftpFs.open(TEST_FILE);
assertFalse(in2.isUnderConstruction());
in2.close();
}
/**
* Tests getPos() functionality.
*/
public void testGetPos() throws Exception {
// Write a test file.
FSDataOutputStream out = hdfs.create(TEST_FILE, true);
out.writeBytes("0123456789");
out.close();
FSDataInputStream in = hftpFs.open(TEST_FILE);
// Test read().
for (int i = 0; i < 5; ++i) {
assertEquals(i, in.getPos());
in.read();
}
// Test read(b, off, len).
assertEquals(5, in.getPos());
byte[] buffer = new byte[10];
assertEquals(2, in.read(buffer, 0, 2));
assertEquals(7, in.getPos());
// Test read(b).
int bytesRead = in.read(buffer);
assertEquals(7 + bytesRead, in.getPos());
// Test EOF.
for (int i = 0; i < 100; ++i) {
in.read();
}
assertEquals(10, in.getPos());
in.close();
}
/**
* Tests seek().
*/
public void testSeek() throws Exception {
// Write a test file.
FSDataOutputStream out = hdfs.create(TEST_FILE, true);
out.writeBytes("0123456789");
out.close();
FSDataInputStream in = hftpFs.open(TEST_FILE);
in.seek(7);
assertEquals('7', in.read());
}
public void testPrematureEOS() throws IOException, URISyntaxException {
try {
readHftpFile(true, true);
fail("did not get expected EOFException");
} catch (Exception e) {
assertTrue(
String.format("got [%s] instead of expected EOFException", e),
e instanceof EOFException
);
}
}
public void testMissingContentLengthWhenStrict()
throws IOException, URISyntaxException {
try {
readHftpFile(true, false);
fail("did not get expected IOException");
} catch (Exception e) {
assertTrue(
String.format("got [%s] instead of expected IOException", e),
e instanceof IOException &&
e.getMessage().toLowerCase().contains("missing")
);
}
}
public void testPrematureEOSCompatible1() throws IOException, URISyntaxException {
try {
readHftpFile(false, false);
} catch (Exception e) {
fail(String.format("unexpected exception [%s]", e));
}
}
public void testPrematureEOSCompatible2() throws IOException, URISyntaxException {
try {
readHftpFile(false, true);
fail("did not get expected EOFException");
} catch (Exception e) {
assertTrue(
String.format("got [%s] instead of expected EOFException", e),
e instanceof EOFException
);
}
}
public void readHftpFile(
boolean strictContentLength, boolean sendContentLength
)
throws IOException, URISyntaxException {
int bufSize = 128 * 1024;
byte[] buf = DFSTestUtil.generateSequentialBytes(0, bufSize);
final ByteArrayInputStream inputStream = new ByteArrayInputStream(buf);
final long contentLength = bufSize + 1;
Configuration conf = new Configuration();
conf.setBoolean(HftpFileSystem.STRICT_CONTENT_LENGTH, strictContentLength);
HftpFileSystem fileSystem =
new MockHftpFileSystem(
sendContentLength ? contentLength : null, inputStream, conf
);
FSDataInputStream dataInputStream = fileSystem.open(new Path("dont-care"));
byte[] readBuf = new byte[1024];
while (dataInputStream.read(readBuf) > -1) {
//nothing
}
dataInputStream.close();
}
private static class MockHftpFileSystem extends HftpFileSystem {
private final Long contentLength;
private final ByteArrayInputStream inputStream;
MockHftpFileSystem(Long contentLength, ByteArrayInputStream inputStream)
throws IOException, URISyntaxException {
this(contentLength, inputStream, new Configuration());
}
MockHftpFileSystem(
Long contentLength, ByteArrayInputStream inputStream, Configuration conf
) throws IOException, URISyntaxException {
this.contentLength = contentLength;
this.inputStream = inputStream;
this.initialize(new URI("hftp://localhost:1234"), conf);
}
@Override
protected HttpURLConnection openConnection(String path, String query)
throws IOException {
return new HttpURLConnection(null){
@Override
public String getHeaderField(String name) {
if (HftpFileSystem.CONTENT_LENGTH_FIELD.equals(name) &&
contentLength != null) {
return String.valueOf(contentLength);
} else {
return super.getHeaderField(name);
}
}
@Override
public InputStream getInputStream() throws IOException {
return inputStream;
}
@Override
public void disconnect() {
}
@Override
public boolean usingProxy() {
return false;
}
@Override
public void connect() throws IOException {
}
};
}
}
}