/* * 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.hadoop.fs.swift; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.swift.exceptions.SwiftOperationFailedException; import org.apache.hadoop.fs.swift.snative.SwiftNativeFileSystem; import org.apache.hadoop.fs.swift.snative.SwiftNativeFileSystemStore; import org.apache.hadoop.fs.swift.util.DurationStats; import org.apache.hadoop.fs.swift.util.SwiftTestUtils; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Assume; import org.junit.Before; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import static org.apache.hadoop.fs.swift.util.SwiftTestUtils.assertPathExists; import static org.apache.hadoop.fs.swift.util.SwiftTestUtils.cleanupInTeardown; import static org.apache.hadoop.fs.swift.util.SwiftTestUtils.getServiceURI; import static org.apache.hadoop.fs.swift.util.SwiftTestUtils.noteAction; /** * This is the base class for most of the Swift tests */ public class SwiftFileSystemBaseTest extends Assert implements SwiftTestConstants { protected static final Log LOG = LogFactory.getLog(SwiftFileSystemBaseTest.class); protected SwiftNativeFileSystem fs; protected static SwiftNativeFileSystem lastFs; protected byte[] data = SwiftTestUtils.dataset(getBlockSize() * 2, 0, 255); private Configuration conf; @Before public void setUp() throws Exception { noteAction("setup"); final URI uri = getFilesystemURI(); conf = createConfiguration(); fs = createSwiftFS(); try { fs.initialize(uri, conf); } catch (IOException e) { //FS init failed, set it to null so that teardown doesn't //attempt to use it fs = null; throw e; } //remember the last FS lastFs = fs; noteAction("setup complete"); } /** * Configuration generator. May be overridden to inject * some custom options * @return a configuration with which to create FS instances */ protected Configuration createConfiguration() { return new Configuration(); } @After public void tearDown() throws Exception { cleanupInTeardown(fs, "/test"); } @AfterClass public static void classTearDown() throws Exception { if (lastFs != null) { List<DurationStats> statistics = lastFs.getOperationStatistics(); for (DurationStats stat : statistics) { LOG.info(stat.toString()); } } } /** * Get the configuration used to set up the FS * @return the configuration */ public Configuration getConf() { return conf; } /** * Describe the test, combining some logging with details * for people reading the code * * @param description test description */ protected void describe(String description) { noteAction(description); } protected URI getFilesystemURI() throws URISyntaxException, IOException { return getServiceURI(createConfiguration()); } protected SwiftNativeFileSystem createSwiftFS() throws IOException { SwiftNativeFileSystem swiftNativeFileSystem = new SwiftNativeFileSystem(); return swiftNativeFileSystem; } protected int getBlockSize() { return 1024; } /** * Is rename supported? * @return true */ protected boolean renameSupported() { return true; } /** * assume in a test that rename is supported; * skip it if not */ protected void assumeRenameSupported() { Assume.assumeTrue(renameSupported()); } /** * Take an unqualified path, and qualify it w.r.t the * current filesystem * @param pathString source path * @return a qualified path instance */ protected Path path(String pathString) { return new Path(pathString).makeQualified(fs); } /** * Get the filesystem * @return the current FS */ public SwiftNativeFileSystem getFs() { return fs; } /** * Create a file using the standard {@link #data} bytes. * * @param path path to write * @throws IOException on any problem */ protected void createFile(Path path) throws IOException { createFile(path, data); } /** * Create a file with the given data. * * @param path path to write * @param sourceData source dataset * @throws IOException on any problem */ protected void createFile(Path path, byte[] sourceData) throws IOException { FSDataOutputStream out = fs.create(path); out.write(sourceData, 0, sourceData.length); out.close(); } /** * Create and then close a file * @param path path to create * @throws IOException on a failure */ protected void createEmptyFile(Path path) throws IOException { FSDataOutputStream out = fs.create(path); out.close(); } /** * Get the inner store -useful for lower level operations * * @return the store */ protected SwiftNativeFileSystemStore getStore() { return fs.getStore(); } /** * Rename a path * @param src source * @param dst dest * @param renameMustSucceed flag to say "this rename must exist" * @param srcExists add assert that the source exists afterwards * @param dstExists add assert the dest exists afterwards * @throws IOException IO trouble */ protected void rename(Path src, Path dst, boolean renameMustSucceed, boolean srcExists, boolean dstExists) throws IOException { if (renameMustSucceed) { renameToSuccess(src, dst, srcExists, dstExists); } else { renameToFailure(src, dst); } } /** * Get a string describing the outcome of a rename, by listing the dest * path and its parent along with some covering text * @param src source patj * @param dst dest path * @return a string for logs and exceptions * @throws IOException IO problems */ private String getRenameOutcome(Path src, Path dst) throws IOException { String lsDst = ls(dst); Path parent = dst.getParent(); String lsParent = parent != null ? ls(parent) : ""; return " result of " + src + " => " + dst + " - " + lsDst + " \n" + lsParent; } /** * Rename, expecting an exception to be thrown * * @param src source * @param dst dest * @throws IOException a failure other than an * expected SwiftRenameException or FileNotFoundException */ protected void renameToFailure(Path src, Path dst) throws IOException { try { getStore().rename(src, dst); fail("Expected failure renaming " + src + " to " + dst + "- but got success"); } catch (SwiftOperationFailedException e) { LOG.debug("Rename failed (expected):" + e); } catch (FileNotFoundException e) { LOG.debug("Rename failed (expected):" + e); } } /** * Rename to success * * @param src source * @param dst dest * @param srcExists add assert that the source exists afterwards * @param dstExists add assert the dest exists afterwards * @throws SwiftOperationFailedException operation failure * @throws IOException IO problems */ protected void renameToSuccess(Path src, Path dst, boolean srcExists, boolean dstExists) throws SwiftOperationFailedException, IOException { getStore().rename(src, dst); String outcome = getRenameOutcome(src, dst); assertEquals("Source " + src + "exists: " + outcome, srcExists, fs.exists(src)); assertEquals("Destination " + dstExists + " exists" + outcome, dstExists, fs.exists(dst)); } /** * List a path in the test FS * @param path path to list * @return the contents of the path/dir * @throws IOException IO problems */ protected String ls(Path path) throws IOException { return SwiftTestUtils.ls(fs, path); } /** * assert that a path exists * @param message message to use in an assertion * @param path path to probe * @throws IOException IO problems */ public void assertExists(String message, Path path) throws IOException { assertPathExists(fs, message, path); } /** * assert that a path does not * @param message message to use in an assertion * @param path path to probe * @throws IOException IO problems */ public void assertPathDoesNotExist(String message, Path path) throws IOException { SwiftTestUtils.assertPathDoesNotExist(fs, message, path); } /** * 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 * @throws IOException IO problems during file operations */ protected void assertIsFile(Path filename) throws IOException { SwiftTestUtils.assertIsFile(fs, filename); } /** * Assert that a file exists and whose {@link FileStatus} entry * declares that this is a file and not a symlink or directory. * * @throws IOException IO problems during file operations */ protected void mkdirs(Path path) throws IOException { assertTrue("Failed to mkdir" + path, fs.mkdirs(path)); } /** * Assert that a delete succeeded * @param path path to delete * @param recursive recursive flag * @throws IOException IO problems */ protected void assertDeleted(Path path, boolean recursive) throws IOException { SwiftTestUtils.assertDeleted(fs, path, recursive); } /** * Assert that a value is not equal to the expected value * @param message message if the two values are equal * @param expected expected value * @param actual actual value */ protected void assertNotEqual(String message, int expected, int actual) { assertTrue(message, actual != expected); } /** * Get the number of partitions written from the Swift Native FS APIs * @param out output stream * @return the number of partitioned files written by the stream */ protected int getPartitionsWritten(FSDataOutputStream out) { return SwiftNativeFileSystem.getPartitionsWritten(out); } /** * Assert that the no. of partitions written matches expectations * @param action operation (for use in the assertions) * @param out output stream * @param expected expected no. of partitions */ protected void assertPartitionsWritten(String action, FSDataOutputStream out, long expected) { OutputStream nativeStream = out.getWrappedStream(); int written = getPartitionsWritten(out); if(written !=expected) { Assert.fail(action + ": " + TestSwiftFileSystemPartitionedUploads.WRONG_PARTITION_COUNT + " + expected: " + expected + " actual: " + written + " -- " + nativeStream); } } /** * Assert that the result value == -1; which implies * that a read was successful * @param text text to include in a message (usually the operation) * @param result read result to validate */ protected void assertMinusOne(String text, int result) { assertEquals(text + " wrong read result " + result, -1, result); } }