Browse Source

add java integration tests

pull/7512/head
chrislu 2 weeks ago
parent
commit
d9be928558
  1. 170
      .github/workflows/java_integration_tests.yml
  2. 64
      .github/workflows/java_unit_tests.yml
  3. 323
      other/java/client/src/test/java/seaweedfs/client/FilerClientIntegrationTest.java
  4. 412
      other/java/client/src/test/java/seaweedfs/client/SeaweedStreamIntegrationTest.java
  5. 190
      other/java/hdfs2/README.md
  6. 190
      other/java/hdfs3/README.md

170
.github/workflows/java_integration_tests.yml

@ -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

64
.github/workflows/java_unit_tests.yml

@ -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/

323
other/java/client/src/test/java/seaweedfs/client/FilerClientIntegrationTest.java

@ -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());
}
}

412
other/java/client/src/test/java/seaweedfs/client/SeaweedStreamIntegrationTest.java

@ -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));
}
}

190
other/java/hdfs2/README.md

@ -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

190
other/java/hdfs3/README.md

@ -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
Loading…
Cancel
Save