org.apache.slider.test.ContractTestUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.slider.test.ContractTestUtils.java

Source

/*
 * 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.slider.test;

import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.Assert;
import org.junit.internal.AssumptionViolatedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Properties;
import java.util.UUID;

/**
 * Utilities used across test cases to make assertions about filesystems
 * -assertions which fail with useful information.
 * This is lifted from Hadoop common Test; that JAR isn't published, so
 * we have to make do.
 */
public class ContractTestUtils extends Assert {

    private static final Logger LOG = LoggerFactory.getLogger(ContractTestUtils.class);

    public static final String IO_FILE_BUFFER_SIZE = "io.file.buffer.size";

    // For scale testing, we can repeatedly write small chunk data to generate
    // a large file.
    public static final String IO_CHUNK_BUFFER_SIZE = "io.chunk.buffer.size";
    public static final int DEFAULT_IO_CHUNK_BUFFER_SIZE = 128;
    public static final String IO_CHUNK_MODULUS_SIZE = "io.chunk.modulus.size";
    public static final int DEFAULT_IO_CHUNK_MODULUS_SIZE = 128;

    /**
     * Assert that a property in the property set matches the expected value
     * @param props property set
     * @param key property name
     * @param expected expected value. If null, the property must not be in the set
     */
    public static void assertPropertyEquals(Properties props, String key, String expected) {
        String val = props.getProperty(key);
        if (expected == null) {
            assertNull("Non null property " + key + " = " + val, val);
        } else {
            assertEquals("property " + key + " = " + val, expected, val);
        }
    }

    /**
     *
     * Write a file and read it in, validating the result. Optional flags control
     * whether file overwrite operations should be enabled, and whether the
     * file should be deleted afterwards.
     *
     * If there is a mismatch between what was written and what was expected,
     * a small range of bytes either side of the first error are logged to aid
     * diagnosing what problem occurred -whether it was a previous file
     * or a corrupting of the current file. This assumes that two
     * sequential runs to the same path use datasets with different character
     * moduli.
     *
     * @param fs filesystem
     * @param path path to write to
     * @param len length of data
     * @param overwrite should the create option allow overwrites?
     * @param delete should the file be deleted afterwards? -with a verification
     * that it worked. Deletion is not attempted if an assertion has failed
     * earlier -it is not in a <code>finally{}</code> block.
     * @throws IOException IO problems
     */
    public static void writeAndRead(FileSystem fs, Path path, byte[] src, int len, int blocksize, boolean overwrite,
            boolean delete) throws IOException {
        fs.mkdirs(path.getParent());

        writeDataset(fs, path, src, len, blocksize, overwrite);

        byte[] dest = readDataset(fs, path, len);

        compareByteArrays(src, dest, len);

        if (delete) {
            rejectRootOperation(path);
            boolean deleted = fs.delete(path, false);
            assertTrue("Deleted", deleted);
            assertPathDoesNotExist(fs, "Cleanup failed", path);
        }
    }

    /**
     * Write a file.
     * Optional flags control
     * whether file overwrite operations should be enabled
     * @param fs filesystem
     * @param path path to write to
     * @param len length of data
     * @param overwrite should the create option allow overwrites?
     * @throws IOException IO problems
     */
    public static void writeDataset(FileSystem fs, Path path, byte[] src, int len, int buffersize,
            boolean overwrite) throws IOException {
        assertTrue("Not enough data in source array to write " + len + " bytes", src.length >= len);
        FSDataOutputStream out = fs.create(path, overwrite, fs.getConf().getInt(IO_FILE_BUFFER_SIZE, 4096),
                (short) 1, buffersize);
        out.write(src, 0, len);
        out.close();
        assertFileHasLength(fs, path, len);
    }

    /**
     * Read the file and convert to a byte dataset.
     * This implements readfully internally, so that it will read
     * in the file without ever having to seek()
     * @param fs filesystem
     * @param path path to read from
     * @param len length of data to read
     * @return the bytes
     * @throws IOException IO problems
     */
    public static byte[] readDataset(FileSystem fs, Path path, int len) throws IOException {
        FSDataInputStream in = fs.open(path);
        byte[] dest = new byte[len];
        int offset = 0;
        int nread = 0;
        try {
            while (nread < len) {
                int nbytes = in.read(dest, offset + nread, len - nread);
                if (nbytes < 0) {
                    throw new EOFException("End of file reached before reading fully.");
                }
                nread += nbytes;
            }
        } finally {
            in.close();
        }
        return dest;
    }

    /**
     * Read a file, verify its length and contents match the expected array
     * @param fs filesystem
     * @param path path to file
     * @param original original dataset
     * @throws IOException IO Problems
     */
    public static void verifyFileContents(FileSystem fs, Path path, byte[] original) throws IOException {
        FileStatus stat = fs.getFileStatus(path);
        String statText = stat.toString();
        assertTrue("not a file " + statText, stat.isFile());
        assertEquals("wrong length " + statText, original.length, stat.getLen());
        byte[] bytes = readDataset(fs, path, original.length);
        compareByteArrays(original, bytes, original.length);
    }

    /**
     * Verify that the read at a specific offset in a stream
     * matches that expected
     * @param stm stream
     * @param fileContents original file contents
     * @param seekOff seek offset
     * @param toRead number of bytes to read
     * @throws IOException IO problems
     */
    public static void verifyRead(FSDataInputStream stm, byte[] fileContents, int seekOff, int toRead)
            throws IOException {
        byte[] out = new byte[toRead];
        stm.seek(seekOff);
        stm.readFully(out);
        byte[] expected = Arrays.copyOfRange(fileContents, seekOff, seekOff + toRead);
        compareByteArrays(expected, out, toRead);
    }

    /**
     * Assert that tthe array original[0..len] and received[] are equal.
     * A failure triggers the logging of the bytes near where the first
     * difference surfaces.
     * @param original source data
     * @param received actual
     * @param len length of bytes to compare
     */
    public static void compareByteArrays(byte[] original, byte[] received, int len) {
        assertEquals("Number of bytes read != number written", len, received.length);
        int errors = 0;
        int first_error_byte = -1;
        for (int i = 0; i < len; i++) {
            if (original[i] != received[i]) {
                if (errors == 0) {
                    first_error_byte = i;
                }
                errors++;
            }
        }

        if (errors > 0) {
            String message = String.format(" %d errors in file of length %d", errors, len);
            LOG.warn(message);
            // the range either side of the first error to print
            // this is a purely arbitrary number, to aid user debugging
            final int overlap = 10;
            for (int i = Math.max(0, first_error_byte - overlap); i < Math.min(first_error_byte + overlap,
                    len); i++) {
                byte actual = received[i];
                byte expected = original[i];
                String letter = toChar(actual);
                String line = String.format("[%04d] %2x %s\n", i, actual, letter);
                if (expected != actual) {
                    line = String.format("[%04d] %2x %s -expected %2x %s\n", i, actual, letter, expected,
                            toChar(expected));
                }
                LOG.warn(line);
            }
            fail(message);
        }
    }

    /**
     * Convert a byte to a character for printing. If the
     * byte value is < 32 -and hence unprintable- the byte is
     * returned as a two digit hex value
     * @param b byte
     * @return the printable character string
     */
    public static String toChar(byte b) {
        if (b >= 0x20) {
            return Character.toString((char) b);
        } else {
            return String.format("%02x", b);
        }
    }

    /**
     * Convert a buffer to a string, character by character
     * @param buffer input bytes
     * @return a string conversion
     */
    public static String toChar(byte[] buffer) {
        StringBuilder builder = new StringBuilder(buffer.length);
        for (byte b : buffer) {
            builder.append(toChar(b));
        }
        return builder.toString();
    }

    public static byte[] toAsciiByteArray(String s) {
        char[] chars = s.toCharArray();
        int len = chars.length;
        byte[] buffer = new byte[len];
        for (int i = 0; i < len; i++) {
            buffer[i] = (byte) (chars[i] & 0xff);
        }
        return buffer;
    }

    /**
     * Cleanup at the end of a test run
     * @param action action triggering the operation (for use in logging)
     * @param fileSystem filesystem to work with. May be null
     * @param cleanupPath path to delete as a string
     */
    public static void cleanup(String action, FileSystem fileSystem, String cleanupPath) {
        if (fileSystem == null) {
            return;
        }
        Path path = new Path(cleanupPath).makeQualified(fileSystem.getUri(), fileSystem.getWorkingDirectory());
        cleanup(action, fileSystem, path);
    }

    /**
     * Cleanup at the end of a test run
     * @param action action triggering the operation (for use in logging)
     * @param fileSystem filesystem to work with. May be null
     * @param path path to delete
     */
    public static void cleanup(String action, FileSystem fileSystem, Path path) {
        noteAction(action);
        try {
            rm(fileSystem, path, true, false);
        } catch (Exception e) {
            LOG.error("Error deleting in " + action + " - " + path + ": " + e, e);
        }
    }

    /**
     * Delete a directory. There's a safety check for operations against the
     * root directory -these are intercepted and rejected with an IOException
     * unless the allowRootDelete flag is true
     * @param fileSystem filesystem to work with. May be null
     * @param path path to delete
     * @param recursive flag to enable recursive delete
     * @param allowRootDelete can the root directory be deleted?
     * @throws IOException on any problem.
     */
    public static boolean rm(FileSystem fileSystem, Path path, boolean recursive, boolean allowRootDelete)
            throws IOException {
        if (fileSystem != null) {
            rejectRootOperation(path, allowRootDelete);
            if (fileSystem.exists(path)) {
                return fileSystem.delete(path, recursive);
            }
        }
        return false;

    }

    /**
     * Block any operation on the root path. This is a safety check
     * @param path path in the filesystem
     * @param allowRootOperation can the root directory be manipulated?
     * @throws IOException if the operation was rejected
     */
    public static void rejectRootOperation(Path path, boolean allowRootOperation) throws IOException {
        if (path.isRoot() && !allowRootOperation) {
            throw new IOException("Root directory operation rejected: " + path);
        }
    }

    /**
     * Block any operation on the root path. This is a safety check
     * @param path path in the filesystem
     * @throws IOException if the operation was rejected
     */
    public static void rejectRootOperation(Path path) throws IOException {
        rejectRootOperation(path, false);
    }

    public static void noteAction(String action) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("==============  " + action + " =============");
        }
    }

    /**
     * downgrade a failure to a message and a warning, then an
     * exception for the Junit test runner to mark as failed
     * @param message text message
     * @param failure what failed
     * @throws AssumptionViolatedException always
     */
    public static void downgrade(String message, Throwable failure) {
        LOG.warn("Downgrading test " + message, failure);
        AssumptionViolatedException ave = new AssumptionViolatedException(failure, null);
        throw ave;
    }

    /**
     * report an overridden test as unsupported
     * @param message message to use in the text
     * @throws AssumptionViolatedException always
     */
    public static void unsupported(String message) {
        skip(message);
    }

    /**
     * report a test has been skipped for some reason
     * @param message message to use in the text
     * @throws AssumptionViolatedException always
     */
    public static void skip(String message) {
        LOG.info("Skipping: {}", message);
        throw new AssumptionViolatedException(message);
    }

    /**
     * Fail with an exception that was received
     * @param text text to use in the exception
     * @param thrown a (possibly null) throwable to init the cause with
     * @throws AssertionError with the text and throwable -always
     */
    public static void fail(String text, Throwable thrown) {
        AssertionError e = new AssertionError(text);
        e.initCause(thrown);
        throw e;
    }

    /**
     * Make an assertion about the length of a file
     * @param fs filesystem
     * @param path path of the file
     * @param expected expected length
     * @throws IOException on File IO problems
     */
    public static void assertFileHasLength(FileSystem fs, Path path, int expected) throws IOException {
        FileStatus status = fs.getFileStatus(path);
        assertEquals("Wrong file length of file " + path + " status: " + status, expected, status.getLen());
    }

    /**
     * Assert that a path refers to a directory
     * @param fs filesystem
     * @param path path of the directory
     * @throws IOException on File IO problems
     */
    public static void assertIsDirectory(FileSystem fs, Path path) throws IOException {
        FileStatus fileStatus = fs.getFileStatus(path);
        assertIsDirectory(fileStatus);
    }

    /**
     * Assert that a path refers to a directory
     * @param fileStatus stats to check
     */
    public static void assertIsDirectory(FileStatus fileStatus) {
        assertTrue("Should be a directory -but isn't: " + fileStatus, fileStatus.isDirectory());
    }

    /**
     * Write the text to a file, returning the converted byte array
     * for use in validating the round trip
     * @param fs filesystem
     * @param path path of file
     * @param text text to write
     * @param overwrite should the operation overwrite any existing file?
     * @return the read bytes
     * @throws IOException on IO problems
     */
    public static byte[] writeTextFile(FileSystem fs, Path path, String text, boolean overwrite)
            throws IOException {
        byte[] bytes = new byte[0];
        if (text != null) {
            bytes = toAsciiByteArray(text);
        }
        createFile(fs, path, overwrite, bytes);
        return bytes;
    }

    /**
     * Create a file
     * @param fs filesystem
     * @param path       path to write
     * @param overwrite overwrite flag
     * @param data source dataset. Can be null
     * @throws IOException on any problem
     */
    public static void createFile(FileSystem fs, Path path, boolean overwrite, byte[] data) throws IOException {
        FSDataOutputStream stream = fs.create(path, overwrite);
        if (data != null && data.length > 0) {
            stream.write(data);
        }
        stream.close();
    }

    /**
     * Touch a file
     * @param fs filesystem
     * @param path path
     * @throws IOException IO problems
     */
    public static void touch(FileSystem fs, Path path) throws IOException {
        createFile(fs, path, true, null);
    }

    /**
     * Delete a file/dir and assert that delete() returned true
     * <i>and</i> that the path no longer exists. This variant rejects
     * all operations on root directories
     * @param fs filesystem
     * @param file path to delete
     * @param recursive flag to enable recursive delete
     * @throws IOException IO problems
     */
    public static void assertDeleted(FileSystem fs, Path file, boolean recursive) throws IOException {
        assertDeleted(fs, file, recursive, false);
    }

    /**
     * Delete a file/dir and assert that delete() returned true
     * <i>and</i> that the path no longer exists. This variant rejects
     * all operations on root directories
     * @param fs filesystem
     * @param file path to delete
     * @param recursive flag to enable recursive delete
     * @param allowRootOperations can the root dir be deleted?
     * @throws IOException IO problems
     */
    public static void assertDeleted(FileSystem fs, Path file, boolean recursive, boolean allowRootOperations)
            throws IOException {
        rejectRootOperation(file, allowRootOperations);
        assertPathExists(fs, "about to be deleted file", file);
        boolean deleted = fs.delete(file, recursive);
        String dir = ls(fs, file.getParent());
        assertTrue("Delete failed on " + file + ": " + dir, deleted);
        assertPathDoesNotExist(fs, "Deleted file", file);
    }

    /**
     * Read in "length" bytes, convert to an ascii string
     * @param fs filesystem
     * @param path path to read
     * @param length #of bytes to read.
     * @return the bytes read and converted to a string
     * @throws IOException IO problems
     */
    public static String readBytesToString(FileSystem fs, Path path, int length) throws IOException {
        FSDataInputStream in = fs.open(path);
        try {
            byte[] buf = new byte[length];
            in.readFully(0, buf);
            return toChar(buf);
        } finally {
            in.close();
        }
    }

    /**
     * Take an array of filestats and convert to a string (prefixed w/ a [01] counter
     * @param stats array of stats
     * @param separator separator after every entry
     * @return a stringified set
     */
    public static String fileStatsToString(FileStatus[] stats, String separator) {
        StringBuilder buf = new StringBuilder(stats.length * 128);
        for (int i = 0; i < stats.length; i++) {
            buf.append(String.format("[%02d] %s", i, stats[i])).append(separator);
        }
        return buf.toString();
    }

    /**
     * List a directory
     * @param fileSystem FS
     * @param path path
     * @return a directory listing or failure message
     * @throws IOException
     */
    public static String ls(FileSystem fileSystem, Path path) throws IOException {
        if (path == null) {
            //surfaces when someone calls getParent() on something at the top of the path
            return "/";
        }
        FileStatus[] stats;
        String pathtext = "ls " + path;
        try {
            stats = fileSystem.listStatus(path);
        } catch (FileNotFoundException e) {
            return pathtext + " -file not found";
        } catch (IOException e) {
            return pathtext + " -failed: " + e;
        }
        return dumpStats(pathtext, stats);
    }

    public static String dumpStats(String pathname, FileStatus[] stats) {
        return pathname + fileStatsToString(stats, "\n");
    }

    /**
    * Assert that a file exists and whose {@link FileStatus} entry
    * declares that this is a file and not a symlink or directory.
    * @param fileSystem filesystem to resolve path against
    * @param filename name of the file
    * @throws IOException IO problems during file operations
    */
    public static void assertIsFile(FileSystem fileSystem, Path filename) throws IOException {
        assertPathExists(fileSystem, "Expected file", filename);
        FileStatus status = fileSystem.getFileStatus(filename);
        assertIsFile(filename, status);
    }

    /**
     * Assert that a file exists and whose {@link FileStatus} entry
     * declares that this is a file and not a symlink or directory.
     * @param filename name of the file
     * @param status file status
     */
    public static void assertIsFile(Path filename, FileStatus status) {
        String fileInfo = filename + "  " + status;
        assertFalse("File claims to be a directory " + fileInfo, status.isDirectory());
        assertFalse("File claims to be a symlink " + fileInfo, status.isSymlink());
    }

    /**
     * Create a dataset for use in the tests; all data is in the range
     * base to (base+modulo-1) inclusive
     * @param len length of data
     * @param base base of the data
     * @param modulo the modulo
     * @return the newly generated dataset
     */
    public static byte[] dataset(int len, int base, int modulo) {
        byte[] dataset = new byte[len];
        for (int i = 0; i < len; i++) {
            dataset[i] = (byte) (base + (i % modulo));
        }
        return dataset;
    }

    /**
     * Assert that a path exists -but make no assertions as to the
     * type of that entry
     *
     * @param fileSystem filesystem to examine
     * @param message message to include in the assertion failure message
     * @param path path in the filesystem
     * @throws FileNotFoundException raised if the path is missing
     * @throws IOException IO problems
     */
    public static void assertPathExists(FileSystem fileSystem, String message, Path path) throws IOException {
        if (!fileSystem.exists(path)) {
            //failure, report it
            String listing = ls(fileSystem, path.getParent());
            throw new FileNotFoundException(
                    message + ": not found " + path + " in \"" + path.getParent() + "\" :\n" + listing);
        }
    }

    /**
     * Assert that a path does not exist
     *
     * @param fileSystem filesystem to examine
     * @param message message to include in the assertion failure message
     * @param path path in the filesystem
     * @throws IOException IO problems
     */
    public static void assertPathDoesNotExist(FileSystem fileSystem, String message, Path path) throws IOException {
        try {
            FileStatus status = fileSystem.getFileStatus(path);
            fail(message + ": unexpectedly found " + path + " as  " + status);
        } catch (FileNotFoundException expected) {
            //this is expected

        }
    }

    /**
     * Assert that a FileSystem.listStatus on a dir finds the subdir/child entry
     * @param fs filesystem
     * @param dir directory to scan
     * @param subdir full path to look for
     * @throws IOException IO probles
     */
    public static void assertListStatusFinds(FileSystem fs, Path dir, Path subdir) throws IOException {
        FileStatus[] stats = fs.listStatus(dir);
        boolean found = false;
        StringBuilder builder = new StringBuilder();
        for (FileStatus stat : stats) {
            builder.append(stat.toString()).append('\n');
            if (stat.getPath().equals(subdir)) {
                found = true;
            }
        }
        assertTrue("Path " + subdir + " not found in directory " + dir + ":" + builder, found);
    }

    /**
     * Test for the host being an OSX machine
     * @return true if the JVM thinks that is running on OSX
     */
    public static boolean isOSX() {
        return System.getProperty("os.name").contains("OS X");
    }

    /**
     * compare content of file operations using a double byte array
     * @param concat concatenated files
     * @param bytes bytes
     */
    public static void validateFileContent(byte[] concat, byte[][] bytes) {
        int idx = 0;
        boolean mismatch = false;

        for (byte[] bb : bytes) {
            for (byte b : bb) {
                if (b != concat[idx++]) {
                    mismatch = true;
                    break;
                }
            }
            if (mismatch)
                break;
        }
        assertFalse("File content of file is not as expected at offset " + idx, mismatch);
    }

    /**
     * Receives test data from the given input file and checks the size of the
     * data as well as the pattern inside the received data.
     *
     * @param fs FileSystem
     * @param path Input file to be checked
     * @param expectedSize the expected size of the data to be read from the
     *        input file in bytes
     * @param bufferLen Pattern length
     * @param modulus   Pattern modulus
     * @throws IOException
     *         thrown if an error occurs while reading the data
     */
    public static void verifyReceivedData(FileSystem fs, Path path, final long expectedSize, final int bufferLen,
            final int modulus) throws IOException {
        final byte[] testBuffer = new byte[bufferLen];

        long totalBytesRead = 0;
        int nextExpectedNumber = 0;
        final InputStream inputStream = fs.open(path);
        try {
            while (true) {
                final int bytesRead = inputStream.read(testBuffer);
                if (bytesRead < 0) {
                    break;
                }

                totalBytesRead += bytesRead;

                for (int i = 0; i < bytesRead; ++i) {
                    if (testBuffer[i] != nextExpectedNumber) {
                        throw new IOException(
                                "Read number " + testBuffer[i] + " but expected " + nextExpectedNumber);
                    }

                    ++nextExpectedNumber;

                    if (nextExpectedNumber == modulus) {
                        nextExpectedNumber = 0;
                    }
                }
            }

            if (totalBytesRead != expectedSize) {
                throw new IOException(
                        "Expected to read " + expectedSize + " bytes but only received " + totalBytesRead);
            }
        } finally {
            inputStream.close();
        }
    }

    /**
     * Generates test data of the given size according to some specific pattern
     * and writes it to the provided output file.
     *
     * @param fs FileSystem
     * @param path Test file to be generated
     * @param size The size of the test data to be generated in bytes
     * @param bufferLen Pattern length
     * @param modulus   Pattern modulus
     * @throws IOException
     *         thrown if an error occurs while writing the data
     */
    public static long generateTestFile(FileSystem fs, Path path, final long size, final int bufferLen,
            final int modulus) throws IOException {
        final byte[] testBuffer = new byte[bufferLen];
        for (int i = 0; i < testBuffer.length; ++i) {
            testBuffer[i] = (byte) (i % modulus);
        }

        final OutputStream outputStream = fs.create(path, false);
        long bytesWritten = 0;
        try {
            while (bytesWritten < size) {
                final long diff = size - bytesWritten;
                if (diff < testBuffer.length) {
                    outputStream.write(testBuffer, 0, (int) diff);
                    bytesWritten += diff;
                } else {
                    outputStream.write(testBuffer);
                    bytesWritten += testBuffer.length;
                }
            }

            return bytesWritten;
        } finally {
            outputStream.close();
        }
    }

    /**
     * Creates and reads a file with the given size. The test file is generated
     * according to a specific pattern so it can be easily verified even if it's
     * a multi-GB one.
     * During the read phase the incoming data stream is also checked against
     * this pattern.
     *
     * @param fs FileSystem
     * @param parent Test file parent dir path
     * @throws IOException
     *    thrown if an I/O error occurs while writing or reading the test file
     */
    public static void createAndVerifyFile(FileSystem fs, Path parent, final long fileSize) throws IOException {
        int testBufferSize = fs.getConf().getInt(IO_CHUNK_BUFFER_SIZE, DEFAULT_IO_CHUNK_BUFFER_SIZE);
        int modulus = fs.getConf().getInt(IO_CHUNK_MODULUS_SIZE, DEFAULT_IO_CHUNK_MODULUS_SIZE);

        final String objectName = UUID.randomUUID().toString();
        final Path objectPath = new Path(parent, objectName);

        // Write test file in a specific pattern
        assertEquals(fileSize, generateTestFile(fs, objectPath, fileSize, testBufferSize, modulus));
        assertPathExists(fs, "not created successful", objectPath);

        // Now read the same file back and verify its content
        try {
            verifyReceivedData(fs, objectPath, fileSize, testBufferSize, modulus);
        } finally {
            // Delete test file
            fs.delete(objectPath, false);
        }
    }
}