6 changed files with 1349 additions and 0 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
-
412other/java/client/src/test/java/seaweedfs/client/SeaweedStreamIntegrationTest.java
-
190other/java/hdfs2/README.md
-
190other/java/hdfs3/README.md
@ -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@v3 |
|||
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@v3 |
|||
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@v3 |
|||
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,412 @@ |
|||
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); |
|||
byte[] readData = new byte[fileSize]; |
|||
int totalRead = 0; |
|||
int bytesRead; |
|||
while ((bytesRead = inputStream.read(readData, totalRead, fileSize - totalRead)) > 0) { |
|||
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,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 |
|||
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue