Skip to content

Add S3 storage sync#16

Merged
Menelion merged 5 commits into
masterfrom
claude/work-in-progress-011CUwEb9iyrcqvD5WSH6ake
Nov 8, 2025
Merged

Add S3 storage sync#16
Menelion merged 5 commits into
masterfrom
claude/work-in-progress-011CUwEb9iyrcqvD5WSH6ake

Conversation

@Menelion

@Menelion Menelion commented Nov 8, 2025

Copy link
Copy Markdown
Contributor

…egration

This commit adds full Amazon S3 and S3-compatible storage support to SharpSync, completing all major storage backend implementations.

New Features

S3Storage Implementation:

  • Full AWS S3 support with access key/secret key authentication
  • S3-compatible service support (MinIO, LocalStack, etc.) with custom endpoints
  • Multipart upload for large files with progress reporting
  • Automatic retry logic with exponential backoff
  • Support for bucket prefixes (virtual directories)
  • SHA256 hash computation for file integrity
  • Comprehensive error handling and network resilience

Integration Testing:

  • Docker-based LocalStack integration for S3 testing
  • Comprehensive unit and integration tests (30+ test cases)
  • Updated docker-compose.test.yml with LocalStack service
  • Updated CI/CD workflow to include S3 tests
  • Updated integration test scripts for all three services (SFTP, FTP, S3)

Changes

Core:

  • src/SharpSync/Storage/S3Storage.cs: Complete S3 storage implementation (850+ lines)
  • tests/SharpSync.Tests/Storage/S3StorageTests.cs: Comprehensive test suite

Dependencies:

  • Added AWSSDK.S3 (v3.7.407.14) to support S3 operations
  • Updated package description to include S3 support
  • Updated package tags to include s3 and aws

Testing Infrastructure:

  • docker-compose.test.yml: Added LocalStack service for S3 testing
  • scripts/run-integration-tests.sh: Updated to support SFTP, FTP, and S3
  • scripts/run-integration-tests.ps1: Updated for Windows users
  • .github/workflows/dotnet.yml: Added LocalStack and S3 test configuration

Documentation:

  • CLAUDE.md: Updated to reflect S3 implementation completion
  • Updated roadmap: S3 now implemented (was planned for v1.1+)
  • Updated architecture overview with S3 storage details
  • Updated integration test instructions

Technical Details

The S3Storage implementation includes:

  • Two constructors: AWS region-based and custom endpoint-based
  • ISyncStorage interface compliance
  • Progress events for large file operations
  • Virtual directory support using S3 key prefixes
  • Batch delete operations for recursive directory removal
  • Copy-then-delete pattern for move operations
  • Proper disposal of AWS SDK resources

Impact

This completes all major storage backend implementations for v1.0:

  • ✅ Local filesystem (LocalFileStorage)
  • ✅ WebDAV (WebDavStorage)
  • ✅ SFTP (SftpStorage)
  • ✅ FTP/FTPS (FtpStorage)
  • ✅ S3/S3-compatible (S3Storage)

Quality score improved: 5/9 criteria met (56%)

…egration

This commit adds full Amazon S3 and S3-compatible storage support to SharpSync,
completing all major storage backend implementations.

### New Features

**S3Storage Implementation:**
- Full AWS S3 support with access key/secret key authentication
- S3-compatible service support (MinIO, LocalStack, etc.) with custom endpoints
- Multipart upload for large files with progress reporting
- Automatic retry logic with exponential backoff
- Support for bucket prefixes (virtual directories)
- SHA256 hash computation for file integrity
- Comprehensive error handling and network resilience

**Integration Testing:**
- Docker-based LocalStack integration for S3 testing
- Comprehensive unit and integration tests (30+ test cases)
- Updated docker-compose.test.yml with LocalStack service
- Updated CI/CD workflow to include S3 tests
- Updated integration test scripts for all three services (SFTP, FTP, S3)

### Changes

**Core:**
- src/SharpSync/Storage/S3Storage.cs: Complete S3 storage implementation (850+ lines)
- tests/SharpSync.Tests/Storage/S3StorageTests.cs: Comprehensive test suite

**Dependencies:**
- Added AWSSDK.S3 (v3.7.407.14) to support S3 operations
- Updated package description to include S3 support
- Updated package tags to include s3 and aws

**Testing Infrastructure:**
- docker-compose.test.yml: Added LocalStack service for S3 testing
- scripts/run-integration-tests.sh: Updated to support SFTP, FTP, and S3
- scripts/run-integration-tests.ps1: Updated for Windows users
- .github/workflows/dotnet.yml: Added LocalStack and S3 test configuration

**Documentation:**
- CLAUDE.md: Updated to reflect S3 implementation completion
- Updated roadmap: S3 now implemented (was planned for v1.1+)
- Updated architecture overview with S3 storage details
- Updated integration test instructions

### Technical Details

The S3Storage implementation includes:
- Two constructors: AWS region-based and custom endpoint-based
- ISyncStorage interface compliance
- Progress events for large file operations
- Virtual directory support using S3 key prefixes
- Batch delete operations for recursive directory removal
- Copy-then-delete pattern for move operations
- Proper disposal of AWS SDK resources

### Impact

This completes all major storage backend implementations for v1.0:
- ✅ Local filesystem (LocalFileStorage)
- ✅ WebDAV (WebDavStorage)
- ✅ SFTP (SftpStorage)
- ✅ FTP/FTPS (FtpStorage)
- ✅ S3/S3-compatible (S3Storage)

Quality score improved: 5/9 criteria met (56%)
@Menelion Menelion changed the title Define Session Goals and Requirements Add S3 storage sync Nov 8, 2025
The specific version 3.7.407.14 is no longer available on NuGet, causing
CI/CD pipeline failures. Updated to use 3.7.* wildcard to automatically
resolve to the latest available patch version in the 3.7.x series.

This fixes the restore error:
'AWSSDK.S3 3.7.407.14 was not found. AWSSDK.S3 3.7.408 was resolved instead.'

Files updated:
- src/SharpSync/SharpSync.csproj: Changed version from 3.7.407.14 to 3.7.*
- CLAUDE.md: Updated dependency version in documentation
Resolves three analyzer warnings that were causing CI build failures:

1. CA1868: Use HashSet.Add return value instead of Contains + Add pattern
   - Changed lines 230-231 in ListItemsAsync to use the boolean return
     value of HashSet.Add() directly, eliminating the redundant Contains check

2. CA1835: Use Memory-based Stream overloads (2 instances)
   - Changed lines 332-333 in ReadFileAsync to use ReadAsync(Memory<byte>)
     and WriteAsync(ReadOnlyMemory<byte>) instead of array-based overloads
   - These overloads are more efficient and are the recommended pattern
     for .NET 8.0 (our target framework)

Technical details:
- HashSet.Add returns false if item already exists, true if added
- Memory<T> overloads reduce allocations and improve performance
- Both changes maintain identical functionality while satisfying analyzers

Files changed:
- src/SharpSync/Storage/S3Storage.cs: Fixed 3 analyzer warnings
Resolves build failure in S3StorageTests where ToArray() was called on
a Stream object. The ToArray() method only exists on MemoryStream,
not on the base Stream class.

Change in ProgressChanged_LargeFileDownload_RaisesEvents test:
- Before: readStream.ToArray() (invalid - Stream has no ToArray method)
- After: Copy stream to MemoryStream using CopyToAsync()

This properly consumes the stream and triggers progress events as intended,
while fixing the compilation error CS1061.

Technical details:
- Stream is an abstract base class without ToArray()
- MemoryStream inherits from Stream and provides ToArray()
- CopyToAsync() fully reads the stream, triggering progress reporting
- Using statement ensures proper disposal of both streams

Files changed:
- tests/SharpSync.Tests/Storage/S3StorageTests.cs: Fixed line 550
Resolves failing integration tests where ListItemsAsync was not returning
file objects, only directory markers.

Root cause:
- S3 prefix was missing trailing slash when listing directories
- This caused S3 to treat the prefix as a string match rather than a
  directory boundary, returning incorrect results
- Objects were being incorrectly filtered out

Changes:
1. Add trailing slash to listPrefix for directory listings
   - Root listing: use "prefix/" if prefix exists, "" otherwise
   - Subdirectory listing: ensure "path/" format with trailing slash

2. Simplified object filtering
   - Only skip keys ending with '/' (directory markers)
   - Remove check for exact prefix match (already handled by trailing slash)

3. Improved comments explaining S3 prefix/delimiter behavior

Technical details:
- S3 ListObjectsV2 with Delimiter="/" returns:
  - S3Objects: actual file objects in this "directory"
  - CommonPrefixes: subdirectories (keys with trailing /)
- Prefix MUST end with '/' to list directory contents correctly
- Without trailing slash, S3 returns all keys starting with prefix string

This fixes tests:
- ListItemsAsync_WithFiles_ReturnsFiles (expected file1.txt, file2.txt, subdir)
- ListItemsAsync_Subdirectory_ReturnsOnlySubdirectoryContents (expected 2 files)

Files changed:
- src/SharpSync/Storage/S3Storage.cs: Fixed ListItemsAsync prefix handling
@Menelion Menelion merged commit 20330f3 into master Nov 8, 2025
1 check passed
@Menelion Menelion deleted the claude/work-in-progress-011CUwEb9iyrcqvD5WSH6ake branch November 8, 2025 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants