Browse Source
chore(deps): bump org.apache.hadoop:hadoop-common from 3.2.4 to 3.4.0 in /other/java/hdfs3 (#7512)
chore(deps): bump org.apache.hadoop:hadoop-common from 3.2.4 to 3.4.0 in /other/java/hdfs3 (#7512)
* chore(deps): bump org.apache.hadoop:hadoop-common in /other/java/hdfs3 Bumps org.apache.hadoop:hadoop-common from 3.2.4 to 3.4.0. --- updated-dependencies: - dependency-name: org.apache.hadoop:hadoop-common dependency-version: 3.4.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> * add java client unit tests * Update dependency-reduced-pom.xml * add java integration tests * fix * fix buffer --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: chrislu <chris.lu@gmail.com>pull/7514/head
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 2585 additions and 10 deletions
-
170.github/workflows/java_integration_tests.yml
-
64.github/workflows/java_unit_tests.yml
-
323other/java/client/src/test/java/seaweedfs/client/FilerClientIntegrationTest.java
-
417other/java/client/src/test/java/seaweedfs/client/SeaweedStreamIntegrationTest.java
-
190other/java/hdfs2/README.md
-
19other/java/hdfs2/pom.xml
-
90other/java/hdfs2/src/test/java/seaweed/hdfs/SeaweedFileSystemConfigTest.java
-
379other/java/hdfs2/src/test/java/seaweed/hdfs/SeaweedFileSystemTest.java
-
190other/java/hdfs3/README.md
-
263other/java/hdfs3/dependency-reduced-pom.xml
-
21other/java/hdfs3/pom.xml
-
90other/java/hdfs3/src/test/java/seaweed/hdfs/SeaweedFileSystemConfigTest.java
-
379other/java/hdfs3/src/test/java/seaweed/hdfs/SeaweedFileSystemTest.java
@ -0,0 +1,170 @@ |
|||||
|
name: Java Client Integration Tests |
||||
|
|
||||
|
on: |
||||
|
push: |
||||
|
branches: [ master ] |
||||
|
paths: |
||||
|
- 'other/java/**' |
||||
|
- 'weed/**' |
||||
|
- '.github/workflows/java_integration_tests.yml' |
||||
|
pull_request: |
||||
|
branches: [ master ] |
||||
|
paths: |
||||
|
- 'other/java/**' |
||||
|
- 'weed/**' |
||||
|
- '.github/workflows/java_integration_tests.yml' |
||||
|
|
||||
|
jobs: |
||||
|
test: |
||||
|
name: Java Integration Tests |
||||
|
runs-on: ubuntu-latest |
||||
|
|
||||
|
strategy: |
||||
|
matrix: |
||||
|
java: ['11', '17'] |
||||
|
|
||||
|
steps: |
||||
|
- name: Checkout code |
||||
|
uses: actions/checkout@v4 |
||||
|
|
||||
|
- name: Set up Go |
||||
|
uses: actions/setup-go@v6 |
||||
|
with: |
||||
|
go-version-file: 'go.mod' |
||||
|
id: go |
||||
|
|
||||
|
- name: Set up Java |
||||
|
uses: actions/setup-java@v4 |
||||
|
with: |
||||
|
java-version: ${{ matrix.java }} |
||||
|
distribution: 'temurin' |
||||
|
cache: 'maven' |
||||
|
|
||||
|
- name: Build SeaweedFS |
||||
|
run: | |
||||
|
cd weed |
||||
|
go install -buildvcs=false |
||||
|
weed version |
||||
|
|
||||
|
- name: Start SeaweedFS Server |
||||
|
run: | |
||||
|
# Create clean data directory |
||||
|
export WEED_DATA_DIR="/tmp/seaweedfs-java-tests-$(date +%s)" |
||||
|
mkdir -p "$WEED_DATA_DIR" |
||||
|
|
||||
|
# Start SeaweedFS with optimized settings for CI |
||||
|
weed server -dir="$WEED_DATA_DIR" \ |
||||
|
-master.raftHashicorp \ |
||||
|
-master.electionTimeout=1s \ |
||||
|
-master.volumeSizeLimitMB=100 \ |
||||
|
-volume.max=100 \ |
||||
|
-volume.preStopSeconds=1 \ |
||||
|
-master.peers=none \ |
||||
|
-filer -filer.maxMB=64 \ |
||||
|
-master.port=9333 \ |
||||
|
-volume.port=8080 \ |
||||
|
-filer.port=8888 \ |
||||
|
-metricsPort=9324 > seaweedfs.log 2>&1 & |
||||
|
|
||||
|
SERVER_PID=$! |
||||
|
echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV |
||||
|
echo "WEED_DATA_DIR=$WEED_DATA_DIR" >> $GITHUB_ENV |
||||
|
echo "SeaweedFS server started with PID: $SERVER_PID" |
||||
|
|
||||
|
- name: Wait for SeaweedFS Components |
||||
|
run: | |
||||
|
echo "Waiting for SeaweedFS components to start..." |
||||
|
|
||||
|
# Wait for master |
||||
|
for i in {1..30}; do |
||||
|
if curl -s http://localhost:9333/cluster/status > /dev/null 2>&1; then |
||||
|
echo "✓ Master server is ready" |
||||
|
break |
||||
|
fi |
||||
|
echo "Waiting for master server... ($i/30)" |
||||
|
sleep 2 |
||||
|
done |
||||
|
|
||||
|
# Wait for volume |
||||
|
for i in {1..30}; do |
||||
|
if curl -s http://localhost:8080/status > /dev/null 2>&1; then |
||||
|
echo "✓ Volume server is ready" |
||||
|
break |
||||
|
fi |
||||
|
echo "Waiting for volume server... ($i/30)" |
||||
|
sleep 2 |
||||
|
done |
||||
|
|
||||
|
# Wait for filer |
||||
|
for i in {1..30}; do |
||||
|
if curl -s http://localhost:8888/ > /dev/null 2>&1; then |
||||
|
echo "✓ Filer is ready" |
||||
|
break |
||||
|
fi |
||||
|
echo "Waiting for filer... ($i/30)" |
||||
|
sleep 2 |
||||
|
done |
||||
|
|
||||
|
echo "✓ All SeaweedFS components are ready!" |
||||
|
|
||||
|
# Display cluster status |
||||
|
echo "Cluster status:" |
||||
|
curl -s http://localhost:9333/cluster/status | head -20 |
||||
|
|
||||
|
- name: Build and Install SeaweedFS Client |
||||
|
working-directory: other/java/client |
||||
|
run: | |
||||
|
mvn clean install -DskipTests -Dmaven.javadoc.skip=true -Dgpg.skip=true |
||||
|
|
||||
|
- name: Run Client Unit Tests |
||||
|
working-directory: other/java/client |
||||
|
run: | |
||||
|
mvn test -Dtest=SeaweedReadTest,SeaweedCipherTest |
||||
|
|
||||
|
- name: Run Client Integration Tests |
||||
|
working-directory: other/java/client |
||||
|
env: |
||||
|
SEAWEEDFS_TEST_ENABLED: true |
||||
|
run: | |
||||
|
mvn test -Dtest=*IntegrationTest |
||||
|
|
||||
|
- name: Run HDFS2 Configuration Tests |
||||
|
working-directory: other/java/hdfs2 |
||||
|
run: | |
||||
|
mvn test -Dtest=SeaweedFileSystemConfigTest -Dmaven.javadoc.skip=true -Dgpg.skip=true |
||||
|
|
||||
|
- name: Run HDFS3 Configuration Tests |
||||
|
working-directory: other/java/hdfs3 |
||||
|
run: | |
||||
|
mvn test -Dtest=SeaweedFileSystemConfigTest -Dmaven.javadoc.skip=true -Dgpg.skip=true |
||||
|
|
||||
|
- name: Display logs on failure |
||||
|
if: failure() |
||||
|
run: | |
||||
|
echo "=== SeaweedFS Server Log ===" |
||||
|
tail -100 seaweedfs.log || echo "No server log" |
||||
|
echo "" |
||||
|
echo "=== Cluster Status ===" |
||||
|
curl -s http://localhost:9333/cluster/status || echo "Cannot reach cluster" |
||||
|
echo "" |
||||
|
echo "=== Process Status ===" |
||||
|
ps aux | grep weed || echo "No weed processes" |
||||
|
|
||||
|
- name: Cleanup |
||||
|
if: always() |
||||
|
run: | |
||||
|
# Stop server using stored PID |
||||
|
if [ -n "$SERVER_PID" ]; then |
||||
|
echo "Stopping SeaweedFS server (PID: $SERVER_PID)" |
||||
|
kill -9 $SERVER_PID 2>/dev/null || true |
||||
|
fi |
||||
|
|
||||
|
# Fallback: kill any remaining weed processes |
||||
|
pkill -f "weed server" || true |
||||
|
|
||||
|
# Clean up data directory |
||||
|
if [ -n "$WEED_DATA_DIR" ]; then |
||||
|
echo "Cleaning up data directory: $WEED_DATA_DIR" |
||||
|
rm -rf "$WEED_DATA_DIR" || true |
||||
|
fi |
||||
|
|
||||
@ -0,0 +1,64 @@ |
|||||
|
name: Java Client Unit Tests |
||||
|
|
||||
|
on: |
||||
|
push: |
||||
|
branches: [ master ] |
||||
|
paths: |
||||
|
- 'other/java/**' |
||||
|
- '.github/workflows/java_unit_tests.yml' |
||||
|
pull_request: |
||||
|
branches: [ master ] |
||||
|
paths: |
||||
|
- 'other/java/**' |
||||
|
- '.github/workflows/java_unit_tests.yml' |
||||
|
|
||||
|
jobs: |
||||
|
test: |
||||
|
name: Java Unit Tests |
||||
|
runs-on: ubuntu-latest |
||||
|
|
||||
|
strategy: |
||||
|
matrix: |
||||
|
java: ['8', '11', '17', '21'] |
||||
|
|
||||
|
steps: |
||||
|
- name: Checkout code |
||||
|
uses: actions/checkout@v4 |
||||
|
|
||||
|
- name: Set up Java |
||||
|
uses: actions/setup-java@v4 |
||||
|
with: |
||||
|
java-version: ${{ matrix.java }} |
||||
|
distribution: 'temurin' |
||||
|
cache: 'maven' |
||||
|
|
||||
|
- name: Build and Install SeaweedFS Client |
||||
|
working-directory: other/java/client |
||||
|
run: | |
||||
|
mvn clean install -DskipTests -Dmaven.javadoc.skip=true -Dgpg.skip=true |
||||
|
|
||||
|
- name: Run Client Unit Tests |
||||
|
working-directory: other/java/client |
||||
|
run: | |
||||
|
mvn test -Dtest=SeaweedReadTest,SeaweedCipherTest |
||||
|
|
||||
|
- name: Run HDFS2 Configuration Tests |
||||
|
working-directory: other/java/hdfs2 |
||||
|
run: | |
||||
|
mvn test -Dtest=SeaweedFileSystemConfigTest -Dmaven.javadoc.skip=true -Dgpg.skip=true |
||||
|
|
||||
|
- name: Run HDFS3 Configuration Tests |
||||
|
working-directory: other/java/hdfs3 |
||||
|
run: | |
||||
|
mvn test -Dtest=SeaweedFileSystemConfigTest -Dmaven.javadoc.skip=true -Dgpg.skip=true |
||||
|
|
||||
|
- name: Upload Test Reports |
||||
|
if: always() |
||||
|
uses: actions/upload-artifact@v5 |
||||
|
with: |
||||
|
name: test-reports-java-${{ matrix.java }} |
||||
|
path: | |
||||
|
other/java/client/target/surefire-reports/ |
||||
|
other/java/hdfs2/target/surefire-reports/ |
||||
|
other/java/hdfs3/target/surefire-reports/ |
||||
|
|
||||
@ -0,0 +1,323 @@ |
|||||
|
package seaweedfs.client; |
||||
|
|
||||
|
import org.junit.After; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.util.List; |
||||
|
|
||||
|
import static org.junit.Assert.*; |
||||
|
|
||||
|
/** |
||||
|
* Integration tests for FilerClient. |
||||
|
* |
||||
|
* These tests verify FilerClient operations against a running SeaweedFS filer |
||||
|
* instance. |
||||
|
* |
||||
|
* Prerequisites: |
||||
|
* - SeaweedFS master, volume server, and filer must be running |
||||
|
* - Default ports: filer HTTP 8888, filer gRPC 18888 |
||||
|
* |
||||
|
* To run tests: |
||||
|
* export SEAWEEDFS_TEST_ENABLED=true |
||||
|
* mvn test -Dtest=FilerClientIntegrationTest |
||||
|
*/ |
||||
|
public class FilerClientIntegrationTest { |
||||
|
|
||||
|
private FilerClient filerClient; |
||||
|
private static final String TEST_ROOT = "/test-client-integration"; |
||||
|
private static final boolean TESTS_ENABLED = "true".equalsIgnoreCase(System.getenv("SEAWEEDFS_TEST_ENABLED")); |
||||
|
|
||||
|
@Before |
||||
|
public void setUp() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
filerClient = new FilerClient("localhost", 18888); |
||||
|
|
||||
|
// Clean up any existing test directory |
||||
|
if (filerClient.exists(TEST_ROOT)) { |
||||
|
filerClient.rm(TEST_ROOT, true, true); |
||||
|
} |
||||
|
|
||||
|
// Create test root directory |
||||
|
filerClient.mkdirs(TEST_ROOT, 0755); |
||||
|
} |
||||
|
|
||||
|
@After |
||||
|
public void tearDown() throws Exception { |
||||
|
if (!TESTS_ENABLED || filerClient == null) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
// Clean up test directory |
||||
|
if (filerClient.exists(TEST_ROOT)) { |
||||
|
filerClient.rm(TEST_ROOT, true, true); |
||||
|
} |
||||
|
} finally { |
||||
|
filerClient.shutdown(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testMkdirs() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testDir = TEST_ROOT + "/testdir"; |
||||
|
boolean success = filerClient.mkdirs(testDir, 0755); |
||||
|
|
||||
|
assertTrue("Directory creation should succeed", success); |
||||
|
assertTrue("Directory should exist", filerClient.exists(testDir)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testTouch() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testFile = TEST_ROOT + "/testfile.txt"; |
||||
|
boolean success = filerClient.touch(testFile, 0644); |
||||
|
|
||||
|
assertTrue("Touch should succeed", success); |
||||
|
assertTrue("File should exist", filerClient.exists(testFile)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testExists() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
assertTrue("Root should exist", filerClient.exists("/")); |
||||
|
assertTrue("Test root should exist", filerClient.exists(TEST_ROOT)); |
||||
|
assertFalse("Non-existent path should not exist", |
||||
|
filerClient.exists(TEST_ROOT + "/nonexistent")); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testListEntries() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Create some test files and directories |
||||
|
filerClient.touch(TEST_ROOT + "/file1.txt", 0644); |
||||
|
filerClient.touch(TEST_ROOT + "/file2.txt", 0644); |
||||
|
filerClient.mkdirs(TEST_ROOT + "/subdir", 0755); |
||||
|
|
||||
|
List<FilerProto.Entry> entries = filerClient.listEntries(TEST_ROOT); |
||||
|
|
||||
|
assertNotNull("Entries should not be null", entries); |
||||
|
assertEquals("Should have 3 entries", 3, entries.size()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testListEntriesWithPrefix() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Create test files |
||||
|
filerClient.touch(TEST_ROOT + "/test1.txt", 0644); |
||||
|
filerClient.touch(TEST_ROOT + "/test2.txt", 0644); |
||||
|
filerClient.touch(TEST_ROOT + "/other.txt", 0644); |
||||
|
|
||||
|
List<FilerProto.Entry> entries = filerClient.listEntries(TEST_ROOT, "test", "", 100, false); |
||||
|
|
||||
|
assertNotNull("Entries should not be null", entries); |
||||
|
assertEquals("Should have 2 entries starting with 'test'", 2, entries.size()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDeleteFile() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testFile = TEST_ROOT + "/deleteme.txt"; |
||||
|
filerClient.touch(testFile, 0644); |
||||
|
|
||||
|
assertTrue("File should exist before delete", filerClient.exists(testFile)); |
||||
|
|
||||
|
boolean success = filerClient.rm(testFile, false, true); |
||||
|
|
||||
|
assertTrue("Delete should succeed", success); |
||||
|
assertFalse("File should not exist after delete", filerClient.exists(testFile)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDeleteDirectoryRecursive() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testDir = TEST_ROOT + "/deletedir"; |
||||
|
filerClient.mkdirs(testDir, 0755); |
||||
|
filerClient.touch(testDir + "/file.txt", 0644); |
||||
|
|
||||
|
assertTrue("Directory should exist", filerClient.exists(testDir)); |
||||
|
assertTrue("File should exist", filerClient.exists(testDir + "/file.txt")); |
||||
|
|
||||
|
boolean success = filerClient.rm(testDir, true, true); |
||||
|
|
||||
|
assertTrue("Delete should succeed", success); |
||||
|
assertFalse("Directory should not exist after delete", filerClient.exists(testDir)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testRename() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String srcFile = TEST_ROOT + "/source.txt"; |
||||
|
String dstFile = TEST_ROOT + "/destination.txt"; |
||||
|
|
||||
|
filerClient.touch(srcFile, 0644); |
||||
|
assertTrue("Source file should exist", filerClient.exists(srcFile)); |
||||
|
|
||||
|
boolean success = filerClient.mv(srcFile, dstFile); |
||||
|
|
||||
|
assertTrue("Rename should succeed", success); |
||||
|
assertFalse("Source file should not exist after rename", filerClient.exists(srcFile)); |
||||
|
assertTrue("Destination file should exist after rename", filerClient.exists(dstFile)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testGetEntry() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testFile = TEST_ROOT + "/getentry.txt"; |
||||
|
filerClient.touch(testFile, 0644); |
||||
|
|
||||
|
FilerProto.Entry entry = filerClient.lookupEntry(TEST_ROOT, "getentry.txt"); |
||||
|
|
||||
|
assertNotNull("Entry should not be null", entry); |
||||
|
assertEquals("Entry name should match", "getentry.txt", entry.getName()); |
||||
|
assertFalse("Entry should not be a directory", entry.getIsDirectory()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testGetEntryForDirectory() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testDir = TEST_ROOT + "/testsubdir"; |
||||
|
filerClient.mkdirs(testDir, 0755); |
||||
|
|
||||
|
FilerProto.Entry entry = filerClient.lookupEntry(TEST_ROOT, "testsubdir"); |
||||
|
|
||||
|
assertNotNull("Entry should not be null", entry); |
||||
|
assertEquals("Entry name should match", "testsubdir", entry.getName()); |
||||
|
assertTrue("Entry should be a directory", entry.getIsDirectory()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testCreateAndListNestedDirectories() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String nestedPath = TEST_ROOT + "/level1/level2/level3"; |
||||
|
boolean success = filerClient.mkdirs(nestedPath, 0755); |
||||
|
|
||||
|
assertTrue("Nested directory creation should succeed", success); |
||||
|
assertTrue("Nested directory should exist", filerClient.exists(nestedPath)); |
||||
|
|
||||
|
// Verify each level exists |
||||
|
assertTrue("Level 1 should exist", filerClient.exists(TEST_ROOT + "/level1")); |
||||
|
assertTrue("Level 2 should exist", filerClient.exists(TEST_ROOT + "/level1/level2")); |
||||
|
assertTrue("Level 3 should exist", filerClient.exists(nestedPath)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testMultipleFilesInDirectory() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testDir = TEST_ROOT + "/multifiles"; |
||||
|
filerClient.mkdirs(testDir, 0755); |
||||
|
|
||||
|
// Create 10 files |
||||
|
for (int i = 0; i < 10; i++) { |
||||
|
filerClient.touch(testDir + "/file" + i + ".txt", 0644); |
||||
|
} |
||||
|
|
||||
|
List<FilerProto.Entry> entries = filerClient.listEntries(testDir); |
||||
|
|
||||
|
assertNotNull("Entries should not be null", entries); |
||||
|
assertEquals("Should have 10 files", 10, entries.size()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testRenameDirectory() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String srcDir = TEST_ROOT + "/sourcedir"; |
||||
|
String dstDir = TEST_ROOT + "/destdir"; |
||||
|
|
||||
|
filerClient.mkdirs(srcDir, 0755); |
||||
|
filerClient.touch(srcDir + "/file.txt", 0644); |
||||
|
|
||||
|
boolean success = filerClient.mv(srcDir, dstDir); |
||||
|
|
||||
|
assertTrue("Directory rename should succeed", success); |
||||
|
assertFalse("Source directory should not exist", filerClient.exists(srcDir)); |
||||
|
assertTrue("Destination directory should exist", filerClient.exists(dstDir)); |
||||
|
assertTrue("File should exist in destination", filerClient.exists(dstDir + "/file.txt")); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testLookupNonExistentEntry() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
FilerProto.Entry entry = filerClient.lookupEntry(TEST_ROOT, "nonexistent.txt"); |
||||
|
|
||||
|
assertNull("Entry for non-existent file should be null", entry); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testEmptyDirectory() { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String emptyDir = TEST_ROOT + "/emptydir"; |
||||
|
filerClient.mkdirs(emptyDir, 0755); |
||||
|
|
||||
|
List<FilerProto.Entry> entries = filerClient.listEntries(emptyDir); |
||||
|
|
||||
|
assertNotNull("Entries should not be null", entries); |
||||
|
assertTrue("Empty directory should have no entries", entries.isEmpty()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,417 @@ |
|||||
|
package seaweedfs.client; |
||||
|
|
||||
|
import org.junit.After; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.util.Arrays; |
||||
|
import java.util.Random; |
||||
|
|
||||
|
import static org.junit.Assert.*; |
||||
|
|
||||
|
/** |
||||
|
* Integration tests for SeaweedInputStream and SeaweedOutputStream. |
||||
|
* |
||||
|
* These tests verify stream operations against a running SeaweedFS instance. |
||||
|
* |
||||
|
* Prerequisites: |
||||
|
* - SeaweedFS master, volume server, and filer must be running |
||||
|
* - Default ports: filer HTTP 8888, filer gRPC 18888 |
||||
|
* |
||||
|
* To run tests: |
||||
|
* export SEAWEEDFS_TEST_ENABLED=true |
||||
|
* mvn test -Dtest=SeaweedStreamIntegrationTest |
||||
|
*/ |
||||
|
public class SeaweedStreamIntegrationTest { |
||||
|
|
||||
|
private FilerClient filerClient; |
||||
|
private static final String TEST_ROOT = "/test-stream-integration"; |
||||
|
private static final boolean TESTS_ENABLED = |
||||
|
"true".equalsIgnoreCase(System.getenv("SEAWEEDFS_TEST_ENABLED")); |
||||
|
|
||||
|
@Before |
||||
|
public void setUp() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
filerClient = new FilerClient("localhost", 18888); |
||||
|
|
||||
|
// Clean up any existing test directory |
||||
|
if (filerClient.exists(TEST_ROOT)) { |
||||
|
filerClient.rm(TEST_ROOT, true, true); |
||||
|
} |
||||
|
|
||||
|
// Create test root directory |
||||
|
filerClient.mkdirs(TEST_ROOT, 0755); |
||||
|
} |
||||
|
|
||||
|
@After |
||||
|
public void tearDown() throws Exception { |
||||
|
if (!TESTS_ENABLED || filerClient == null) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
// Clean up test directory |
||||
|
if (filerClient.exists(TEST_ROOT)) { |
||||
|
filerClient.rm(TEST_ROOT, true, true); |
||||
|
} |
||||
|
} finally { |
||||
|
filerClient.shutdown(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testWriteAndReadSmallFile() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/small.txt"; |
||||
|
String testContent = "Hello, SeaweedFS!"; |
||||
|
|
||||
|
// Write file |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(testContent.getBytes(StandardCharsets.UTF_8)); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Verify file exists |
||||
|
assertTrue("File should exist", filerClient.exists(testPath)); |
||||
|
|
||||
|
// Read file |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
assertNotNull("Entry should not be null", entry); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
byte[] buffer = new byte[testContent.length()]; |
||||
|
int bytesRead = inputStream.read(buffer); |
||||
|
inputStream.close(); |
||||
|
|
||||
|
assertEquals("Should read all bytes", testContent.length(), bytesRead); |
||||
|
assertEquals("Content should match", testContent, new String(buffer, StandardCharsets.UTF_8)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testWriteAndReadLargeFile() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/large.bin"; |
||||
|
int fileSize = 10 * 1024 * 1024; // 10 MB |
||||
|
|
||||
|
// Generate random data |
||||
|
byte[] originalData = new byte[fileSize]; |
||||
|
new Random(42).nextBytes(originalData); // Use seed for reproducibility |
||||
|
|
||||
|
// Write file |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(originalData); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Verify file exists |
||||
|
assertTrue("File should exist", filerClient.exists(testPath)); |
||||
|
|
||||
|
// Read file |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
assertNotNull("Entry should not be null", entry); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
|
||||
|
// Read file in chunks to handle large files properly |
||||
|
byte[] readData = new byte[fileSize]; |
||||
|
int totalRead = 0; |
||||
|
int bytesRead; |
||||
|
byte[] buffer = new byte[8192]; // Read in 8KB chunks |
||||
|
|
||||
|
while ((bytesRead = inputStream.read(buffer)) > 0) { |
||||
|
System.arraycopy(buffer, 0, readData, totalRead, bytesRead); |
||||
|
totalRead += bytesRead; |
||||
|
} |
||||
|
inputStream.close(); |
||||
|
|
||||
|
assertEquals("Should read all bytes", fileSize, totalRead); |
||||
|
assertArrayEquals("Content should match", originalData, readData); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testWriteInChunks() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/chunked.txt"; |
||||
|
String[] chunks = {"First chunk. ", "Second chunk. ", "Third chunk."}; |
||||
|
|
||||
|
// Write file in chunks |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
for (String chunk : chunks) { |
||||
|
outputStream.write(chunk.getBytes(StandardCharsets.UTF_8)); |
||||
|
} |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Read and verify |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
byte[] buffer = new byte[1024]; |
||||
|
int bytesRead = inputStream.read(buffer); |
||||
|
inputStream.close(); |
||||
|
|
||||
|
String expected = String.join("", chunks); |
||||
|
String actual = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8); |
||||
|
|
||||
|
assertEquals("Content should match", expected, actual); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testReadWithOffset() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/offset.txt"; |
||||
|
String testContent = "0123456789ABCDEFGHIJ"; |
||||
|
|
||||
|
// Write file |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(testContent.getBytes(StandardCharsets.UTF_8)); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Read with offset |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
inputStream.seek(10); // Skip first 10 bytes |
||||
|
|
||||
|
byte[] buffer = new byte[10]; |
||||
|
int bytesRead = inputStream.read(buffer); |
||||
|
inputStream.close(); |
||||
|
|
||||
|
assertEquals("Should read 10 bytes", 10, bytesRead); |
||||
|
assertEquals("Should read from offset", "ABCDEFGHIJ", |
||||
|
new String(buffer, StandardCharsets.UTF_8)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testReadPartial() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/partial.txt"; |
||||
|
String testContent = "The quick brown fox jumps over the lazy dog"; |
||||
|
|
||||
|
// Write file |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(testContent.getBytes(StandardCharsets.UTF_8)); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Read partial |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
|
||||
|
// Read only "quick brown" |
||||
|
inputStream.seek(4); |
||||
|
byte[] buffer = new byte[11]; |
||||
|
int bytesRead = inputStream.read(buffer); |
||||
|
inputStream.close(); |
||||
|
|
||||
|
assertEquals("Should read 11 bytes", 11, bytesRead); |
||||
|
assertEquals("Should read partial content", "quick brown", |
||||
|
new String(buffer, StandardCharsets.UTF_8)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testEmptyFile() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/empty.txt"; |
||||
|
|
||||
|
// Write empty file |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Verify file exists |
||||
|
assertTrue("File should exist", filerClient.exists(testPath)); |
||||
|
|
||||
|
// Read empty file |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
assertNotNull("Entry should not be null", entry); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
byte[] buffer = new byte[100]; |
||||
|
int bytesRead = inputStream.read(buffer); |
||||
|
inputStream.close(); |
||||
|
|
||||
|
assertEquals("Should read 0 bytes from empty file", -1, bytesRead); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testOverwriteFile() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/overwrite.txt"; |
||||
|
String originalContent = "Original content"; |
||||
|
String newContent = "New content that overwrites the original"; |
||||
|
|
||||
|
// Write original file |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(originalContent.getBytes(StandardCharsets.UTF_8)); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Overwrite file |
||||
|
outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(newContent.getBytes(StandardCharsets.UTF_8)); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Read and verify |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
byte[] buffer = new byte[1024]; |
||||
|
int bytesRead = inputStream.read(buffer); |
||||
|
inputStream.close(); |
||||
|
|
||||
|
String actual = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8); |
||||
|
assertEquals("Should have new content", newContent, actual); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testMultipleReads() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/multireads.txt"; |
||||
|
String testContent = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
||||
|
|
||||
|
// Write file |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(testContent.getBytes(StandardCharsets.UTF_8)); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Read in multiple small chunks |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
|
||||
|
StringBuilder result = new StringBuilder(); |
||||
|
byte[] buffer = new byte[5]; |
||||
|
int bytesRead; |
||||
|
while ((bytesRead = inputStream.read(buffer)) > 0) { |
||||
|
result.append(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8)); |
||||
|
} |
||||
|
inputStream.close(); |
||||
|
|
||||
|
assertEquals("Should read entire content", testContent, result.toString()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testBinaryData() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/binary.bin"; |
||||
|
byte[] binaryData = new byte[256]; |
||||
|
for (int i = 0; i < 256; i++) { |
||||
|
binaryData[i] = (byte) i; |
||||
|
} |
||||
|
|
||||
|
// Write binary file |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(binaryData); |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Read and verify |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
byte[] readData = new byte[256]; |
||||
|
int bytesRead = inputStream.read(readData); |
||||
|
inputStream.close(); |
||||
|
|
||||
|
assertEquals("Should read all bytes", 256, bytesRead); |
||||
|
assertArrayEquals("Binary data should match", binaryData, readData); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testFlush() throws IOException { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String testPath = TEST_ROOT + "/flush.txt"; |
||||
|
String testContent = "Content to flush"; |
||||
|
|
||||
|
// Write file with flush |
||||
|
SeaweedOutputStream outputStream = new SeaweedOutputStream(filerClient, testPath); |
||||
|
outputStream.write(testContent.getBytes(StandardCharsets.UTF_8)); |
||||
|
outputStream.flush(); // Explicitly flush |
||||
|
outputStream.close(); |
||||
|
|
||||
|
// Verify file was written |
||||
|
assertTrue("File should exist after flush", filerClient.exists(testPath)); |
||||
|
|
||||
|
// Read and verify |
||||
|
FilerProto.Entry entry = filerClient.lookupEntry( |
||||
|
SeaweedOutputStream.getParentDirectory(testPath), |
||||
|
SeaweedOutputStream.getFileName(testPath) |
||||
|
); |
||||
|
|
||||
|
SeaweedInputStream inputStream = new SeaweedInputStream(filerClient, testPath, entry); |
||||
|
byte[] buffer = new byte[testContent.length()]; |
||||
|
int bytesRead = inputStream.read(buffer); |
||||
|
inputStream.close(); |
||||
|
|
||||
|
assertEquals("Content should match", testContent, |
||||
|
new String(buffer, 0, bytesRead, StandardCharsets.UTF_8)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,190 @@ |
|||||
|
# SeaweedFS Hadoop2 Client |
||||
|
|
||||
|
Hadoop FileSystem implementation for SeaweedFS, compatible with Hadoop 2.x/3.x. |
||||
|
|
||||
|
## Building |
||||
|
|
||||
|
```bash |
||||
|
mvn clean install |
||||
|
``` |
||||
|
|
||||
|
## Testing |
||||
|
|
||||
|
This project includes two types of tests: |
||||
|
|
||||
|
### 1. Configuration Tests (No SeaweedFS Required) |
||||
|
|
||||
|
These tests verify configuration handling and initialization logic without requiring a running SeaweedFS instance: |
||||
|
|
||||
|
```bash |
||||
|
mvn test -Dtest=SeaweedFileSystemConfigTest |
||||
|
``` |
||||
|
|
||||
|
### 2. Integration Tests (Requires SeaweedFS) |
||||
|
|
||||
|
These tests verify actual FileSystem operations against a running SeaweedFS instance. |
||||
|
|
||||
|
#### Prerequisites |
||||
|
|
||||
|
1. Start SeaweedFS with default ports: |
||||
|
```bash |
||||
|
# Terminal 1: Start master |
||||
|
weed master |
||||
|
|
||||
|
# Terminal 2: Start volume server |
||||
|
weed volume -mserver=localhost:9333 |
||||
|
|
||||
|
# Terminal 3: Start filer |
||||
|
weed filer -master=localhost:9333 |
||||
|
``` |
||||
|
|
||||
|
2. Verify services are running: |
||||
|
- Master: http://localhost:9333 |
||||
|
- Filer HTTP: http://localhost:8888 |
||||
|
- Filer gRPC: localhost:18888 |
||||
|
|
||||
|
#### Running Integration Tests |
||||
|
|
||||
|
```bash |
||||
|
# Enable integration tests |
||||
|
export SEAWEEDFS_TEST_ENABLED=true |
||||
|
|
||||
|
# Run all tests |
||||
|
mvn test |
||||
|
|
||||
|
# Run specific test |
||||
|
mvn test -Dtest=SeaweedFileSystemTest |
||||
|
``` |
||||
|
|
||||
|
### Test Configuration |
||||
|
|
||||
|
Integration tests can be configured via environment variables or system properties: |
||||
|
|
||||
|
- `SEAWEEDFS_TEST_ENABLED`: Set to `true` to enable integration tests (default: false) |
||||
|
- Tests use these default connection settings: |
||||
|
- Filer Host: localhost |
||||
|
- Filer HTTP Port: 8888 |
||||
|
- Filer gRPC Port: 18888 |
||||
|
|
||||
|
### Running Tests with Custom Configuration |
||||
|
|
||||
|
To test against a different SeaweedFS instance, modify the test code or use Hadoop configuration: |
||||
|
|
||||
|
```java |
||||
|
conf.set("fs.seaweed.filer.host", "your-host"); |
||||
|
conf.setInt("fs.seaweed.filer.port", 8888); |
||||
|
conf.setInt("fs.seaweed.filer.port.grpc", 18888); |
||||
|
``` |
||||
|
|
||||
|
## Test Coverage |
||||
|
|
||||
|
The test suite covers: |
||||
|
|
||||
|
- **Configuration & Initialization** |
||||
|
- URI parsing and configuration |
||||
|
- Default values |
||||
|
- Configuration overrides |
||||
|
- Working directory management |
||||
|
|
||||
|
- **File Operations** |
||||
|
- Create files |
||||
|
- Read files |
||||
|
- Write files |
||||
|
- Append to files |
||||
|
- Delete files |
||||
|
|
||||
|
- **Directory Operations** |
||||
|
- Create directories |
||||
|
- List directory contents |
||||
|
- Delete directories (recursive and non-recursive) |
||||
|
|
||||
|
- **Metadata Operations** |
||||
|
- Get file status |
||||
|
- Set permissions |
||||
|
- Set owner/group |
||||
|
- Rename files and directories |
||||
|
|
||||
|
## Usage in Hadoop |
||||
|
|
||||
|
1. Copy the built JAR to your Hadoop classpath: |
||||
|
```bash |
||||
|
cp target/seaweedfs-hadoop2-client-*.jar $HADOOP_HOME/share/hadoop/common/lib/ |
||||
|
``` |
||||
|
|
||||
|
2. Configure `core-site.xml`: |
||||
|
```xml |
||||
|
<configuration> |
||||
|
<property> |
||||
|
<name>fs.seaweedfs.impl</name> |
||||
|
<value>seaweed.hdfs.SeaweedFileSystem</value> |
||||
|
</property> |
||||
|
<property> |
||||
|
<name>fs.seaweed.filer.host</name> |
||||
|
<value>localhost</value> |
||||
|
</property> |
||||
|
<property> |
||||
|
<name>fs.seaweed.filer.port</name> |
||||
|
<value>8888</value> |
||||
|
</property> |
||||
|
<property> |
||||
|
<name>fs.seaweed.filer.port.grpc</name> |
||||
|
<value>18888</value> |
||||
|
</property> |
||||
|
</configuration> |
||||
|
``` |
||||
|
|
||||
|
3. Use SeaweedFS with Hadoop commands: |
||||
|
```bash |
||||
|
hadoop fs -ls seaweedfs://localhost:8888/ |
||||
|
hadoop fs -mkdir seaweedfs://localhost:8888/test |
||||
|
hadoop fs -put local.txt seaweedfs://localhost:8888/test/ |
||||
|
``` |
||||
|
|
||||
|
## Continuous Integration |
||||
|
|
||||
|
For CI environments, tests can be run in two modes: |
||||
|
|
||||
|
1. **Configuration Tests Only** (default, no SeaweedFS required): |
||||
|
```bash |
||||
|
mvn test -Dtest=SeaweedFileSystemConfigTest |
||||
|
``` |
||||
|
|
||||
|
2. **Full Integration Tests** (requires SeaweedFS): |
||||
|
```bash |
||||
|
# Start SeaweedFS in CI environment |
||||
|
# Then run: |
||||
|
export SEAWEEDFS_TEST_ENABLED=true |
||||
|
mvn test |
||||
|
``` |
||||
|
|
||||
|
## Troubleshooting |
||||
|
|
||||
|
### Tests are skipped |
||||
|
|
||||
|
If you see "Skipping test - SEAWEEDFS_TEST_ENABLED not set": |
||||
|
```bash |
||||
|
export SEAWEEDFS_TEST_ENABLED=true |
||||
|
``` |
||||
|
|
||||
|
### Connection refused errors |
||||
|
|
||||
|
Ensure SeaweedFS is running and accessible: |
||||
|
```bash |
||||
|
curl http://localhost:8888/ |
||||
|
``` |
||||
|
|
||||
|
### gRPC errors |
||||
|
|
||||
|
Verify the gRPC port is accessible: |
||||
|
```bash |
||||
|
# Should show the port is listening |
||||
|
netstat -an | grep 18888 |
||||
|
``` |
||||
|
|
||||
|
## Contributing |
||||
|
|
||||
|
When adding new features, please include: |
||||
|
1. Configuration tests (no SeaweedFS required) |
||||
|
2. Integration tests (with SEAWEEDFS_TEST_ENABLED guard) |
||||
|
3. Documentation updates |
||||
|
|
||||
@ -0,0 +1,90 @@ |
|||||
|
package seaweed.hdfs; |
||||
|
|
||||
|
import org.apache.hadoop.conf.Configuration; |
||||
|
import org.apache.hadoop.fs.Path; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
|
||||
|
import static org.junit.Assert.*; |
||||
|
|
||||
|
/** |
||||
|
* Unit tests for SeaweedFileSystem configuration that don't require a running SeaweedFS instance. |
||||
|
* |
||||
|
* These tests verify basic properties and constants. |
||||
|
*/ |
||||
|
public class SeaweedFileSystemConfigTest { |
||||
|
|
||||
|
private SeaweedFileSystem fs; |
||||
|
private Configuration conf; |
||||
|
|
||||
|
@Before |
||||
|
public void setUp() { |
||||
|
fs = new SeaweedFileSystem(); |
||||
|
conf = new Configuration(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testScheme() { |
||||
|
assertEquals("seaweedfs", fs.getScheme()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testConstants() { |
||||
|
// Test that constants are defined correctly |
||||
|
assertEquals("fs.seaweed.filer.host", SeaweedFileSystem.FS_SEAWEED_FILER_HOST); |
||||
|
assertEquals("fs.seaweed.filer.port", SeaweedFileSystem.FS_SEAWEED_FILER_PORT); |
||||
|
assertEquals("fs.seaweed.filer.port.grpc", SeaweedFileSystem.FS_SEAWEED_FILER_PORT_GRPC); |
||||
|
assertEquals(8888, SeaweedFileSystem.FS_SEAWEED_DEFAULT_PORT); |
||||
|
assertEquals("fs.seaweed.buffer.size", SeaweedFileSystem.FS_SEAWEED_BUFFER_SIZE); |
||||
|
assertEquals(4 * 1024 * 1024, SeaweedFileSystem.FS_SEAWEED_DEFAULT_BUFFER_SIZE); |
||||
|
assertEquals("fs.seaweed.replication", SeaweedFileSystem.FS_SEAWEED_REPLICATION); |
||||
|
assertEquals("fs.seaweed.volume.server.access", SeaweedFileSystem.FS_SEAWEED_VOLUME_SERVER_ACCESS); |
||||
|
assertEquals("fs.seaweed.filer.cn", SeaweedFileSystem.FS_SEAWEED_FILER_CN); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testWorkingDirectoryPathOperations() { |
||||
|
// Test path operations that don't require initialization |
||||
|
Path testPath = new Path("/test/path"); |
||||
|
assertTrue("Path should be absolute", testPath.isAbsolute()); |
||||
|
assertEquals("/test/path", testPath.toUri().getPath()); |
||||
|
|
||||
|
Path childPath = new Path(testPath, "child"); |
||||
|
assertEquals("/test/path/child", childPath.toUri().getPath()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testConfigurationProperties() { |
||||
|
// Test that configuration can be set and read |
||||
|
conf.set(SeaweedFileSystem.FS_SEAWEED_FILER_HOST, "testhost"); |
||||
|
assertEquals("testhost", conf.get(SeaweedFileSystem.FS_SEAWEED_FILER_HOST)); |
||||
|
|
||||
|
conf.setInt(SeaweedFileSystem.FS_SEAWEED_FILER_PORT, 9999); |
||||
|
assertEquals(9999, conf.getInt(SeaweedFileSystem.FS_SEAWEED_FILER_PORT, 0)); |
||||
|
|
||||
|
conf.setInt(SeaweedFileSystem.FS_SEAWEED_BUFFER_SIZE, 8 * 1024 * 1024); |
||||
|
assertEquals(8 * 1024 * 1024, conf.getInt(SeaweedFileSystem.FS_SEAWEED_BUFFER_SIZE, 0)); |
||||
|
|
||||
|
conf.set(SeaweedFileSystem.FS_SEAWEED_REPLICATION, "001"); |
||||
|
assertEquals("001", conf.get(SeaweedFileSystem.FS_SEAWEED_REPLICATION)); |
||||
|
|
||||
|
conf.set(SeaweedFileSystem.FS_SEAWEED_VOLUME_SERVER_ACCESS, "publicUrl"); |
||||
|
assertEquals("publicUrl", conf.get(SeaweedFileSystem.FS_SEAWEED_VOLUME_SERVER_ACCESS)); |
||||
|
|
||||
|
conf.set(SeaweedFileSystem.FS_SEAWEED_FILER_CN, "test-cn"); |
||||
|
assertEquals("test-cn", conf.get(SeaweedFileSystem.FS_SEAWEED_FILER_CN)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDefaultBufferSize() { |
||||
|
// Test default buffer size constant |
||||
|
int expected = 4 * 1024 * 1024; // 4MB |
||||
|
assertEquals(expected, SeaweedFileSystem.FS_SEAWEED_DEFAULT_BUFFER_SIZE); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDefaultPort() { |
||||
|
// Test default port constant |
||||
|
assertEquals(8888, SeaweedFileSystem.FS_SEAWEED_DEFAULT_PORT); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,379 @@ |
|||||
|
package seaweed.hdfs; |
||||
|
|
||||
|
import org.apache.hadoop.conf.Configuration; |
||||
|
import org.apache.hadoop.fs.FSDataInputStream; |
||||
|
import org.apache.hadoop.fs.FSDataOutputStream; |
||||
|
import org.apache.hadoop.fs.FileStatus; |
||||
|
import org.apache.hadoop.fs.Path; |
||||
|
import org.apache.hadoop.fs.permission.FsPermission; |
||||
|
import org.junit.After; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.net.URI; |
||||
|
|
||||
|
import static org.junit.Assert.*; |
||||
|
|
||||
|
/** |
||||
|
* Unit tests for SeaweedFileSystem. |
||||
|
* |
||||
|
* These tests verify basic FileSystem operations against a SeaweedFS backend. |
||||
|
* Note: These tests require a running SeaweedFS filer instance. |
||||
|
* |
||||
|
* To run tests, ensure SeaweedFS is running with default ports: |
||||
|
* - Filer HTTP: 8888 |
||||
|
* - Filer gRPC: 18888 |
||||
|
* |
||||
|
* Set environment variable SEAWEEDFS_TEST_ENABLED=true to enable these tests. |
||||
|
*/ |
||||
|
public class SeaweedFileSystemTest { |
||||
|
|
||||
|
private SeaweedFileSystem fs; |
||||
|
private Configuration conf; |
||||
|
private static final String TEST_ROOT = "/test-hdfs2"; |
||||
|
private static final boolean TESTS_ENABLED = |
||||
|
"true".equalsIgnoreCase(System.getenv("SEAWEEDFS_TEST_ENABLED")); |
||||
|
|
||||
|
@Before |
||||
|
public void setUp() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
conf = new Configuration(); |
||||
|
conf.set("fs.seaweed.filer.host", "localhost"); |
||||
|
conf.setInt("fs.seaweed.filer.port", 8888); |
||||
|
conf.setInt("fs.seaweed.filer.port.grpc", 18888); |
||||
|
|
||||
|
fs = new SeaweedFileSystem(); |
||||
|
URI uri = new URI("seaweedfs://localhost:8888/"); |
||||
|
fs.initialize(uri, conf); |
||||
|
|
||||
|
// Clean up any existing test directory |
||||
|
Path testPath = new Path(TEST_ROOT); |
||||
|
if (fs.exists(testPath)) { |
||||
|
fs.delete(testPath, true); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@After |
||||
|
public void tearDown() throws Exception { |
||||
|
if (!TESTS_ENABLED || fs == null) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Clean up test directory |
||||
|
Path testPath = new Path(TEST_ROOT); |
||||
|
if (fs.exists(testPath)) { |
||||
|
fs.delete(testPath, true); |
||||
|
} |
||||
|
|
||||
|
fs.close(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testInitialization() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
assertNotNull(fs); |
||||
|
assertEquals("seaweedfs", fs.getScheme()); |
||||
|
assertNotNull(fs.getUri()); |
||||
|
assertEquals("/", fs.getWorkingDirectory().toUri().getPath()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testMkdirs() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testDir = new Path(TEST_ROOT + "/testdir"); |
||||
|
assertTrue("Failed to create directory", fs.mkdirs(testDir)); |
||||
|
assertTrue("Directory should exist", fs.exists(testDir)); |
||||
|
|
||||
|
FileStatus status = fs.getFileStatus(testDir); |
||||
|
assertTrue("Path should be a directory", status.isDirectory()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testCreateAndReadFile() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/testfile.txt"); |
||||
|
String testContent = "Hello, SeaweedFS!"; |
||||
|
|
||||
|
// Create and write to file |
||||
|
FSDataOutputStream out = fs.create(testFile, FsPermission.getDefault(), |
||||
|
false, 4096, (short) 1, 4 * 1024 * 1024, null); |
||||
|
assertNotNull("Output stream should not be null", out); |
||||
|
out.write(testContent.getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
// Verify file exists |
||||
|
assertTrue("File should exist", fs.exists(testFile)); |
||||
|
|
||||
|
// Read and verify content |
||||
|
FSDataInputStream in = fs.open(testFile, 4096); |
||||
|
assertNotNull("Input stream should not be null", in); |
||||
|
byte[] buffer = new byte[testContent.length()]; |
||||
|
int bytesRead = in.read(buffer); |
||||
|
in.close(); |
||||
|
|
||||
|
assertEquals("Should read all bytes", testContent.length(), bytesRead); |
||||
|
assertEquals("Content should match", testContent, new String(buffer)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testFileStatus() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/statustest.txt"); |
||||
|
String content = "test content"; |
||||
|
|
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write(content.getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
FileStatus status = fs.getFileStatus(testFile); |
||||
|
assertNotNull("FileStatus should not be null", status); |
||||
|
assertFalse("Should not be a directory", status.isDirectory()); |
||||
|
assertTrue("Should be a file", status.isFile()); |
||||
|
assertEquals("File length should match", content.length(), status.getLen()); |
||||
|
assertNotNull("Path should not be null", status.getPath()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testListStatus() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testDir = new Path(TEST_ROOT + "/listtest"); |
||||
|
fs.mkdirs(testDir); |
||||
|
|
||||
|
// Create multiple files |
||||
|
for (int i = 0; i < 3; i++) { |
||||
|
Path file = new Path(testDir, "file" + i + ".txt"); |
||||
|
FSDataOutputStream out = fs.create(file); |
||||
|
out.write(("content" + i).getBytes()); |
||||
|
out.close(); |
||||
|
} |
||||
|
|
||||
|
FileStatus[] statuses = fs.listStatus(testDir); |
||||
|
assertNotNull("List should not be null", statuses); |
||||
|
assertEquals("Should have 3 files", 3, statuses.length); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testRename() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path srcFile = new Path(TEST_ROOT + "/source.txt"); |
||||
|
Path dstFile = new Path(TEST_ROOT + "/destination.txt"); |
||||
|
String content = "rename test"; |
||||
|
|
||||
|
// Create source file |
||||
|
FSDataOutputStream out = fs.create(srcFile); |
||||
|
out.write(content.getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
assertTrue("Source file should exist", fs.exists(srcFile)); |
||||
|
|
||||
|
// Rename |
||||
|
assertTrue("Rename should succeed", fs.rename(srcFile, dstFile)); |
||||
|
|
||||
|
// Verify |
||||
|
assertFalse("Source file should not exist", fs.exists(srcFile)); |
||||
|
assertTrue("Destination file should exist", fs.exists(dstFile)); |
||||
|
|
||||
|
// Verify content preserved |
||||
|
FSDataInputStream in = fs.open(dstFile); |
||||
|
byte[] buffer = new byte[content.length()]; |
||||
|
in.read(buffer); |
||||
|
in.close(); |
||||
|
assertEquals("Content should be preserved", content, new String(buffer)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDelete() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/deletetest.txt"); |
||||
|
|
||||
|
// Create file |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write("delete me".getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
assertTrue("File should exist before delete", fs.exists(testFile)); |
||||
|
|
||||
|
// Delete |
||||
|
assertTrue("Delete should succeed", fs.delete(testFile, false)); |
||||
|
assertFalse("File should not exist after delete", fs.exists(testFile)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDeleteDirectory() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testDir = new Path(TEST_ROOT + "/deletedir"); |
||||
|
Path testFile = new Path(testDir, "file.txt"); |
||||
|
|
||||
|
// Create directory with file |
||||
|
fs.mkdirs(testDir); |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write("content".getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
assertTrue("Directory should exist", fs.exists(testDir)); |
||||
|
assertTrue("File should exist", fs.exists(testFile)); |
||||
|
|
||||
|
// Recursive delete |
||||
|
assertTrue("Recursive delete should succeed", fs.delete(testDir, true)); |
||||
|
assertFalse("Directory should not exist after delete", fs.exists(testDir)); |
||||
|
assertFalse("File should not exist after delete", fs.exists(testFile)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testAppend() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/appendtest.txt"); |
||||
|
String initialContent = "initial"; |
||||
|
String appendContent = " appended"; |
||||
|
|
||||
|
// Create initial file |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write(initialContent.getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
// Append |
||||
|
FSDataOutputStream appendOut = fs.append(testFile, 4096, null); |
||||
|
assertNotNull("Append stream should not be null", appendOut); |
||||
|
appendOut.write(appendContent.getBytes()); |
||||
|
appendOut.close(); |
||||
|
|
||||
|
// Verify combined content |
||||
|
FSDataInputStream in = fs.open(testFile); |
||||
|
byte[] buffer = new byte[initialContent.length() + appendContent.length()]; |
||||
|
int bytesRead = in.read(buffer); |
||||
|
in.close(); |
||||
|
|
||||
|
String expected = initialContent + appendContent; |
||||
|
assertEquals("Should read all bytes", expected.length(), bytesRead); |
||||
|
assertEquals("Content should match", expected, new String(buffer)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSetWorkingDirectory() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path originalWd = fs.getWorkingDirectory(); |
||||
|
assertEquals("Original working directory should be /", "/", originalWd.toUri().getPath()); |
||||
|
|
||||
|
Path newWd = new Path(TEST_ROOT); |
||||
|
fs.mkdirs(newWd); |
||||
|
fs.setWorkingDirectory(newWd); |
||||
|
|
||||
|
Path currentWd = fs.getWorkingDirectory(); |
||||
|
assertTrue("Working directory should be updated", |
||||
|
currentWd.toUri().getPath().contains(TEST_ROOT)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSetPermission() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/permtest.txt"); |
||||
|
|
||||
|
// Create file |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write("permission test".getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
// Set permission |
||||
|
FsPermission newPerm = new FsPermission((short) 0644); |
||||
|
fs.setPermission(testFile, newPerm); |
||||
|
|
||||
|
FileStatus status = fs.getFileStatus(testFile); |
||||
|
assertNotNull("Permission should not be null", status.getPermission()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSetOwner() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/ownertest.txt"); |
||||
|
|
||||
|
// Create file |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write("owner test".getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
// Set owner - this may not fail even if not fully implemented |
||||
|
fs.setOwner(testFile, "testuser", "testgroup"); |
||||
|
|
||||
|
// Just verify the call doesn't throw an exception |
||||
|
FileStatus status = fs.getFileStatus(testFile); |
||||
|
assertNotNull("FileStatus should not be null", status); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testRenameToExistingDirectory() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path srcFile = new Path(TEST_ROOT + "/movefile.txt"); |
||||
|
Path dstDir = new Path(TEST_ROOT + "/movedir"); |
||||
|
|
||||
|
// Create source file and destination directory |
||||
|
FSDataOutputStream out = fs.create(srcFile); |
||||
|
out.write("move test".getBytes()); |
||||
|
out.close(); |
||||
|
fs.mkdirs(dstDir); |
||||
|
|
||||
|
// Rename file to existing directory (should move file into directory) |
||||
|
assertTrue("Rename to directory should succeed", fs.rename(srcFile, dstDir)); |
||||
|
|
||||
|
// File should be moved into the directory |
||||
|
Path expectedLocation = new Path(dstDir, srcFile.getName()); |
||||
|
assertTrue("File should exist in destination directory", fs.exists(expectedLocation)); |
||||
|
assertFalse("Source file should not exist", fs.exists(srcFile)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,190 @@ |
|||||
|
# SeaweedFS Hadoop3 Client |
||||
|
|
||||
|
Hadoop FileSystem implementation for SeaweedFS, compatible with Hadoop 3.x. |
||||
|
|
||||
|
## Building |
||||
|
|
||||
|
```bash |
||||
|
mvn clean install |
||||
|
``` |
||||
|
|
||||
|
## Testing |
||||
|
|
||||
|
This project includes two types of tests: |
||||
|
|
||||
|
### 1. Configuration Tests (No SeaweedFS Required) |
||||
|
|
||||
|
These tests verify configuration handling and initialization logic without requiring a running SeaweedFS instance: |
||||
|
|
||||
|
```bash |
||||
|
mvn test -Dtest=SeaweedFileSystemConfigTest |
||||
|
``` |
||||
|
|
||||
|
### 2. Integration Tests (Requires SeaweedFS) |
||||
|
|
||||
|
These tests verify actual FileSystem operations against a running SeaweedFS instance. |
||||
|
|
||||
|
#### Prerequisites |
||||
|
|
||||
|
1. Start SeaweedFS with default ports: |
||||
|
```bash |
||||
|
# Terminal 1: Start master |
||||
|
weed master |
||||
|
|
||||
|
# Terminal 2: Start volume server |
||||
|
weed volume -mserver=localhost:9333 |
||||
|
|
||||
|
# Terminal 3: Start filer |
||||
|
weed filer -master=localhost:9333 |
||||
|
``` |
||||
|
|
||||
|
2. Verify services are running: |
||||
|
- Master: http://localhost:9333 |
||||
|
- Filer HTTP: http://localhost:8888 |
||||
|
- Filer gRPC: localhost:18888 |
||||
|
|
||||
|
#### Running Integration Tests |
||||
|
|
||||
|
```bash |
||||
|
# Enable integration tests |
||||
|
export SEAWEEDFS_TEST_ENABLED=true |
||||
|
|
||||
|
# Run all tests |
||||
|
mvn test |
||||
|
|
||||
|
# Run specific test |
||||
|
mvn test -Dtest=SeaweedFileSystemTest |
||||
|
``` |
||||
|
|
||||
|
### Test Configuration |
||||
|
|
||||
|
Integration tests can be configured via environment variables or system properties: |
||||
|
|
||||
|
- `SEAWEEDFS_TEST_ENABLED`: Set to `true` to enable integration tests (default: false) |
||||
|
- Tests use these default connection settings: |
||||
|
- Filer Host: localhost |
||||
|
- Filer HTTP Port: 8888 |
||||
|
- Filer gRPC Port: 18888 |
||||
|
|
||||
|
### Running Tests with Custom Configuration |
||||
|
|
||||
|
To test against a different SeaweedFS instance, modify the test code or use Hadoop configuration: |
||||
|
|
||||
|
```java |
||||
|
conf.set("fs.seaweed.filer.host", "your-host"); |
||||
|
conf.setInt("fs.seaweed.filer.port", 8888); |
||||
|
conf.setInt("fs.seaweed.filer.port.grpc", 18888); |
||||
|
``` |
||||
|
|
||||
|
## Test Coverage |
||||
|
|
||||
|
The test suite covers: |
||||
|
|
||||
|
- **Configuration & Initialization** |
||||
|
- URI parsing and configuration |
||||
|
- Default values |
||||
|
- Configuration overrides |
||||
|
- Working directory management |
||||
|
|
||||
|
- **File Operations** |
||||
|
- Create files |
||||
|
- Read files |
||||
|
- Write files |
||||
|
- Append to files |
||||
|
- Delete files |
||||
|
|
||||
|
- **Directory Operations** |
||||
|
- Create directories |
||||
|
- List directory contents |
||||
|
- Delete directories (recursive and non-recursive) |
||||
|
|
||||
|
- **Metadata Operations** |
||||
|
- Get file status |
||||
|
- Set permissions |
||||
|
- Set owner/group |
||||
|
- Rename files and directories |
||||
|
|
||||
|
## Usage in Hadoop |
||||
|
|
||||
|
1. Copy the built JAR to your Hadoop classpath: |
||||
|
```bash |
||||
|
cp target/seaweedfs-hadoop3-client-*.jar $HADOOP_HOME/share/hadoop/common/lib/ |
||||
|
``` |
||||
|
|
||||
|
2. Configure `core-site.xml`: |
||||
|
```xml |
||||
|
<configuration> |
||||
|
<property> |
||||
|
<name>fs.seaweedfs.impl</name> |
||||
|
<value>seaweed.hdfs.SeaweedFileSystem</value> |
||||
|
</property> |
||||
|
<property> |
||||
|
<name>fs.seaweed.filer.host</name> |
||||
|
<value>localhost</value> |
||||
|
</property> |
||||
|
<property> |
||||
|
<name>fs.seaweed.filer.port</name> |
||||
|
<value>8888</value> |
||||
|
</property> |
||||
|
<property> |
||||
|
<name>fs.seaweed.filer.port.grpc</name> |
||||
|
<value>18888</value> |
||||
|
</property> |
||||
|
</configuration> |
||||
|
``` |
||||
|
|
||||
|
3. Use SeaweedFS with Hadoop commands: |
||||
|
```bash |
||||
|
hadoop fs -ls seaweedfs://localhost:8888/ |
||||
|
hadoop fs -mkdir seaweedfs://localhost:8888/test |
||||
|
hadoop fs -put local.txt seaweedfs://localhost:8888/test/ |
||||
|
``` |
||||
|
|
||||
|
## Continuous Integration |
||||
|
|
||||
|
For CI environments, tests can be run in two modes: |
||||
|
|
||||
|
1. **Configuration Tests Only** (default, no SeaweedFS required): |
||||
|
```bash |
||||
|
mvn test -Dtest=SeaweedFileSystemConfigTest |
||||
|
``` |
||||
|
|
||||
|
2. **Full Integration Tests** (requires SeaweedFS): |
||||
|
```bash |
||||
|
# Start SeaweedFS in CI environment |
||||
|
# Then run: |
||||
|
export SEAWEEDFS_TEST_ENABLED=true |
||||
|
mvn test |
||||
|
``` |
||||
|
|
||||
|
## Troubleshooting |
||||
|
|
||||
|
### Tests are skipped |
||||
|
|
||||
|
If you see "Skipping test - SEAWEEDFS_TEST_ENABLED not set": |
||||
|
```bash |
||||
|
export SEAWEEDFS_TEST_ENABLED=true |
||||
|
``` |
||||
|
|
||||
|
### Connection refused errors |
||||
|
|
||||
|
Ensure SeaweedFS is running and accessible: |
||||
|
```bash |
||||
|
curl http://localhost:8888/ |
||||
|
``` |
||||
|
|
||||
|
### gRPC errors |
||||
|
|
||||
|
Verify the gRPC port is accessible: |
||||
|
```bash |
||||
|
# Should show the port is listening |
||||
|
netstat -an | grep 18888 |
||||
|
``` |
||||
|
|
||||
|
## Contributing |
||||
|
|
||||
|
When adding new features, please include: |
||||
|
1. Configuration tests (no SeaweedFS required) |
||||
|
2. Integration tests (with SEAWEEDFS_TEST_ENABLED guard) |
||||
|
3. Documentation updates |
||||
|
|
||||
@ -0,0 +1,90 @@ |
|||||
|
package seaweed.hdfs; |
||||
|
|
||||
|
import org.apache.hadoop.conf.Configuration; |
||||
|
import org.apache.hadoop.fs.Path; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
|
||||
|
import static org.junit.Assert.*; |
||||
|
|
||||
|
/** |
||||
|
* Unit tests for SeaweedFileSystem configuration that don't require a running SeaweedFS instance. |
||||
|
* |
||||
|
* These tests verify basic properties and constants. |
||||
|
*/ |
||||
|
public class SeaweedFileSystemConfigTest { |
||||
|
|
||||
|
private SeaweedFileSystem fs; |
||||
|
private Configuration conf; |
||||
|
|
||||
|
@Before |
||||
|
public void setUp() { |
||||
|
fs = new SeaweedFileSystem(); |
||||
|
conf = new Configuration(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testScheme() { |
||||
|
assertEquals("seaweedfs", fs.getScheme()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testConstants() { |
||||
|
// Test that constants are defined correctly |
||||
|
assertEquals("fs.seaweed.filer.host", SeaweedFileSystem.FS_SEAWEED_FILER_HOST); |
||||
|
assertEquals("fs.seaweed.filer.port", SeaweedFileSystem.FS_SEAWEED_FILER_PORT); |
||||
|
assertEquals("fs.seaweed.filer.port.grpc", SeaweedFileSystem.FS_SEAWEED_FILER_PORT_GRPC); |
||||
|
assertEquals(8888, SeaweedFileSystem.FS_SEAWEED_DEFAULT_PORT); |
||||
|
assertEquals("fs.seaweed.buffer.size", SeaweedFileSystem.FS_SEAWEED_BUFFER_SIZE); |
||||
|
assertEquals(4 * 1024 * 1024, SeaweedFileSystem.FS_SEAWEED_DEFAULT_BUFFER_SIZE); |
||||
|
assertEquals("fs.seaweed.replication", SeaweedFileSystem.FS_SEAWEED_REPLICATION); |
||||
|
assertEquals("fs.seaweed.volume.server.access", SeaweedFileSystem.FS_SEAWEED_VOLUME_SERVER_ACCESS); |
||||
|
assertEquals("fs.seaweed.filer.cn", SeaweedFileSystem.FS_SEAWEED_FILER_CN); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testWorkingDirectoryPathOperations() { |
||||
|
// Test path operations that don't require initialization |
||||
|
Path testPath = new Path("/test/path"); |
||||
|
assertTrue("Path should be absolute", testPath.isAbsolute()); |
||||
|
assertEquals("/test/path", testPath.toUri().getPath()); |
||||
|
|
||||
|
Path childPath = new Path(testPath, "child"); |
||||
|
assertEquals("/test/path/child", childPath.toUri().getPath()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testConfigurationProperties() { |
||||
|
// Test that configuration can be set and read |
||||
|
conf.set(SeaweedFileSystem.FS_SEAWEED_FILER_HOST, "testhost"); |
||||
|
assertEquals("testhost", conf.get(SeaweedFileSystem.FS_SEAWEED_FILER_HOST)); |
||||
|
|
||||
|
conf.setInt(SeaweedFileSystem.FS_SEAWEED_FILER_PORT, 9999); |
||||
|
assertEquals(9999, conf.getInt(SeaweedFileSystem.FS_SEAWEED_FILER_PORT, 0)); |
||||
|
|
||||
|
conf.setInt(SeaweedFileSystem.FS_SEAWEED_BUFFER_SIZE, 8 * 1024 * 1024); |
||||
|
assertEquals(8 * 1024 * 1024, conf.getInt(SeaweedFileSystem.FS_SEAWEED_BUFFER_SIZE, 0)); |
||||
|
|
||||
|
conf.set(SeaweedFileSystem.FS_SEAWEED_REPLICATION, "001"); |
||||
|
assertEquals("001", conf.get(SeaweedFileSystem.FS_SEAWEED_REPLICATION)); |
||||
|
|
||||
|
conf.set(SeaweedFileSystem.FS_SEAWEED_VOLUME_SERVER_ACCESS, "publicUrl"); |
||||
|
assertEquals("publicUrl", conf.get(SeaweedFileSystem.FS_SEAWEED_VOLUME_SERVER_ACCESS)); |
||||
|
|
||||
|
conf.set(SeaweedFileSystem.FS_SEAWEED_FILER_CN, "test-cn"); |
||||
|
assertEquals("test-cn", conf.get(SeaweedFileSystem.FS_SEAWEED_FILER_CN)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDefaultBufferSize() { |
||||
|
// Test default buffer size constant |
||||
|
int expected = 4 * 1024 * 1024; // 4MB |
||||
|
assertEquals(expected, SeaweedFileSystem.FS_SEAWEED_DEFAULT_BUFFER_SIZE); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDefaultPort() { |
||||
|
// Test default port constant |
||||
|
assertEquals(8888, SeaweedFileSystem.FS_SEAWEED_DEFAULT_PORT); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,379 @@ |
|||||
|
package seaweed.hdfs; |
||||
|
|
||||
|
import org.apache.hadoop.conf.Configuration; |
||||
|
import org.apache.hadoop.fs.FSDataInputStream; |
||||
|
import org.apache.hadoop.fs.FSDataOutputStream; |
||||
|
import org.apache.hadoop.fs.FileStatus; |
||||
|
import org.apache.hadoop.fs.Path; |
||||
|
import org.apache.hadoop.fs.permission.FsPermission; |
||||
|
import org.junit.After; |
||||
|
import org.junit.Before; |
||||
|
import org.junit.Test; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.net.URI; |
||||
|
|
||||
|
import static org.junit.Assert.*; |
||||
|
|
||||
|
/** |
||||
|
* Unit tests for SeaweedFileSystem. |
||||
|
* |
||||
|
* These tests verify basic FileSystem operations against a SeaweedFS backend. |
||||
|
* Note: These tests require a running SeaweedFS filer instance. |
||||
|
* |
||||
|
* To run tests, ensure SeaweedFS is running with default ports: |
||||
|
* - Filer HTTP: 8888 |
||||
|
* - Filer gRPC: 18888 |
||||
|
* |
||||
|
* Set environment variable SEAWEEDFS_TEST_ENABLED=true to enable these tests. |
||||
|
*/ |
||||
|
public class SeaweedFileSystemTest { |
||||
|
|
||||
|
private SeaweedFileSystem fs; |
||||
|
private Configuration conf; |
||||
|
private static final String TEST_ROOT = "/test-hdfs3"; |
||||
|
private static final boolean TESTS_ENABLED = |
||||
|
"true".equalsIgnoreCase(System.getenv("SEAWEEDFS_TEST_ENABLED")); |
||||
|
|
||||
|
@Before |
||||
|
public void setUp() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
conf = new Configuration(); |
||||
|
conf.set("fs.seaweed.filer.host", "localhost"); |
||||
|
conf.setInt("fs.seaweed.filer.port", 8888); |
||||
|
conf.setInt("fs.seaweed.filer.port.grpc", 18888); |
||||
|
|
||||
|
fs = new SeaweedFileSystem(); |
||||
|
URI uri = new URI("seaweedfs://localhost:8888/"); |
||||
|
fs.initialize(uri, conf); |
||||
|
|
||||
|
// Clean up any existing test directory |
||||
|
Path testPath = new Path(TEST_ROOT); |
||||
|
if (fs.exists(testPath)) { |
||||
|
fs.delete(testPath, true); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@After |
||||
|
public void tearDown() throws Exception { |
||||
|
if (!TESTS_ENABLED || fs == null) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Clean up test directory |
||||
|
Path testPath = new Path(TEST_ROOT); |
||||
|
if (fs.exists(testPath)) { |
||||
|
fs.delete(testPath, true); |
||||
|
} |
||||
|
|
||||
|
fs.close(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testInitialization() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
assertNotNull(fs); |
||||
|
assertEquals("seaweedfs", fs.getScheme()); |
||||
|
assertNotNull(fs.getUri()); |
||||
|
assertEquals("/", fs.getWorkingDirectory().toUri().getPath()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testMkdirs() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testDir = new Path(TEST_ROOT + "/testdir"); |
||||
|
assertTrue("Failed to create directory", fs.mkdirs(testDir)); |
||||
|
assertTrue("Directory should exist", fs.exists(testDir)); |
||||
|
|
||||
|
FileStatus status = fs.getFileStatus(testDir); |
||||
|
assertTrue("Path should be a directory", status.isDirectory()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testCreateAndReadFile() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/testfile.txt"); |
||||
|
String testContent = "Hello, SeaweedFS!"; |
||||
|
|
||||
|
// Create and write to file |
||||
|
FSDataOutputStream out = fs.create(testFile, FsPermission.getDefault(), |
||||
|
false, 4096, (short) 1, 4 * 1024 * 1024, null); |
||||
|
assertNotNull("Output stream should not be null", out); |
||||
|
out.write(testContent.getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
// Verify file exists |
||||
|
assertTrue("File should exist", fs.exists(testFile)); |
||||
|
|
||||
|
// Read and verify content |
||||
|
FSDataInputStream in = fs.open(testFile, 4096); |
||||
|
assertNotNull("Input stream should not be null", in); |
||||
|
byte[] buffer = new byte[testContent.length()]; |
||||
|
int bytesRead = in.read(buffer); |
||||
|
in.close(); |
||||
|
|
||||
|
assertEquals("Should read all bytes", testContent.length(), bytesRead); |
||||
|
assertEquals("Content should match", testContent, new String(buffer)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testFileStatus() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/statustest.txt"); |
||||
|
String content = "test content"; |
||||
|
|
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write(content.getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
FileStatus status = fs.getFileStatus(testFile); |
||||
|
assertNotNull("FileStatus should not be null", status); |
||||
|
assertFalse("Should not be a directory", status.isDirectory()); |
||||
|
assertTrue("Should be a file", status.isFile()); |
||||
|
assertEquals("File length should match", content.length(), status.getLen()); |
||||
|
assertNotNull("Path should not be null", status.getPath()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testListStatus() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testDir = new Path(TEST_ROOT + "/listtest"); |
||||
|
fs.mkdirs(testDir); |
||||
|
|
||||
|
// Create multiple files |
||||
|
for (int i = 0; i < 3; i++) { |
||||
|
Path file = new Path(testDir, "file" + i + ".txt"); |
||||
|
FSDataOutputStream out = fs.create(file); |
||||
|
out.write(("content" + i).getBytes()); |
||||
|
out.close(); |
||||
|
} |
||||
|
|
||||
|
FileStatus[] statuses = fs.listStatus(testDir); |
||||
|
assertNotNull("List should not be null", statuses); |
||||
|
assertEquals("Should have 3 files", 3, statuses.length); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testRename() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path srcFile = new Path(TEST_ROOT + "/source.txt"); |
||||
|
Path dstFile = new Path(TEST_ROOT + "/destination.txt"); |
||||
|
String content = "rename test"; |
||||
|
|
||||
|
// Create source file |
||||
|
FSDataOutputStream out = fs.create(srcFile); |
||||
|
out.write(content.getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
assertTrue("Source file should exist", fs.exists(srcFile)); |
||||
|
|
||||
|
// Rename |
||||
|
assertTrue("Rename should succeed", fs.rename(srcFile, dstFile)); |
||||
|
|
||||
|
// Verify |
||||
|
assertFalse("Source file should not exist", fs.exists(srcFile)); |
||||
|
assertTrue("Destination file should exist", fs.exists(dstFile)); |
||||
|
|
||||
|
// Verify content preserved |
||||
|
FSDataInputStream in = fs.open(dstFile); |
||||
|
byte[] buffer = new byte[content.length()]; |
||||
|
in.read(buffer); |
||||
|
in.close(); |
||||
|
assertEquals("Content should be preserved", content, new String(buffer)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDelete() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/deletetest.txt"); |
||||
|
|
||||
|
// Create file |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write("delete me".getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
assertTrue("File should exist before delete", fs.exists(testFile)); |
||||
|
|
||||
|
// Delete |
||||
|
assertTrue("Delete should succeed", fs.delete(testFile, false)); |
||||
|
assertFalse("File should not exist after delete", fs.exists(testFile)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testDeleteDirectory() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testDir = new Path(TEST_ROOT + "/deletedir"); |
||||
|
Path testFile = new Path(testDir, "file.txt"); |
||||
|
|
||||
|
// Create directory with file |
||||
|
fs.mkdirs(testDir); |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write("content".getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
assertTrue("Directory should exist", fs.exists(testDir)); |
||||
|
assertTrue("File should exist", fs.exists(testFile)); |
||||
|
|
||||
|
// Recursive delete |
||||
|
assertTrue("Recursive delete should succeed", fs.delete(testDir, true)); |
||||
|
assertFalse("Directory should not exist after delete", fs.exists(testDir)); |
||||
|
assertFalse("File should not exist after delete", fs.exists(testFile)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testAppend() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/appendtest.txt"); |
||||
|
String initialContent = "initial"; |
||||
|
String appendContent = " appended"; |
||||
|
|
||||
|
// Create initial file |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write(initialContent.getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
// Append |
||||
|
FSDataOutputStream appendOut = fs.append(testFile, 4096, null); |
||||
|
assertNotNull("Append stream should not be null", appendOut); |
||||
|
appendOut.write(appendContent.getBytes()); |
||||
|
appendOut.close(); |
||||
|
|
||||
|
// Verify combined content |
||||
|
FSDataInputStream in = fs.open(testFile); |
||||
|
byte[] buffer = new byte[initialContent.length() + appendContent.length()]; |
||||
|
int bytesRead = in.read(buffer); |
||||
|
in.close(); |
||||
|
|
||||
|
String expected = initialContent + appendContent; |
||||
|
assertEquals("Should read all bytes", expected.length(), bytesRead); |
||||
|
assertEquals("Content should match", expected, new String(buffer)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSetWorkingDirectory() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path originalWd = fs.getWorkingDirectory(); |
||||
|
assertEquals("Original working directory should be /", "/", originalWd.toUri().getPath()); |
||||
|
|
||||
|
Path newWd = new Path(TEST_ROOT); |
||||
|
fs.mkdirs(newWd); |
||||
|
fs.setWorkingDirectory(newWd); |
||||
|
|
||||
|
Path currentWd = fs.getWorkingDirectory(); |
||||
|
assertTrue("Working directory should be updated", |
||||
|
currentWd.toUri().getPath().contains(TEST_ROOT)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSetPermission() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/permtest.txt"); |
||||
|
|
||||
|
// Create file |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write("permission test".getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
// Set permission |
||||
|
FsPermission newPerm = new FsPermission((short) 0644); |
||||
|
fs.setPermission(testFile, newPerm); |
||||
|
|
||||
|
FileStatus status = fs.getFileStatus(testFile); |
||||
|
assertNotNull("Permission should not be null", status.getPermission()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testSetOwner() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path testFile = new Path(TEST_ROOT + "/ownertest.txt"); |
||||
|
|
||||
|
// Create file |
||||
|
FSDataOutputStream out = fs.create(testFile); |
||||
|
out.write("owner test".getBytes()); |
||||
|
out.close(); |
||||
|
|
||||
|
// Set owner - this may not fail even if not fully implemented |
||||
|
fs.setOwner(testFile, "testuser", "testgroup"); |
||||
|
|
||||
|
// Just verify the call doesn't throw an exception |
||||
|
FileStatus status = fs.getFileStatus(testFile); |
||||
|
assertNotNull("FileStatus should not be null", status); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
public void testRenameToExistingDirectory() throws Exception { |
||||
|
if (!TESTS_ENABLED) { |
||||
|
System.out.println("Skipping test - SEAWEEDFS_TEST_ENABLED not set"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Path srcFile = new Path(TEST_ROOT + "/movefile.txt"); |
||||
|
Path dstDir = new Path(TEST_ROOT + "/movedir"); |
||||
|
|
||||
|
// Create source file and destination directory |
||||
|
FSDataOutputStream out = fs.create(srcFile); |
||||
|
out.write("move test".getBytes()); |
||||
|
out.close(); |
||||
|
fs.mkdirs(dstDir); |
||||
|
|
||||
|
// Rename file to existing directory (should move file into directory) |
||||
|
assertTrue("Rename to directory should succeed", fs.rename(srcFile, dstDir)); |
||||
|
|
||||
|
// File should be moved into the directory |
||||
|
Path expectedLocation = new Path(dstDir, srcFile.getName()); |
||||
|
assertTrue("File should exist in destination directory", fs.exists(expectedLocation)); |
||||
|
assertFalse("Source file should not exist", fs.exists(srcFile)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue