feat: Setup Testcontainers infrastructure for vector search tests (#528)#533
feat: Setup Testcontainers infrastructure for vector search tests (#528)#533
Conversation
Implemented Phase 1 of test refactoring plan to replace Mockito mocks with real production code using Testcontainers + ArcadeDB. Changes: - Added Awaitility 4.2.0 dependency for async test verification - Created ArcadeDbContainer: Custom Testcontainer for ArcadeDB 25.11.1 - Configures database with vector index (LSM_VECTOR, COSINE, 384 dimensions) - Provides clean database creation and schema initialization - Created ArcadeDbTestBase: Abstract base class for integration tests - Uses shared container for performance - Provides real ContentPersistenceAdapter and ArcadeContentRepository - Created FakeEmbeddingGenerator: Deterministic fake for EmbeddingGenerator - Generates consistent 384-dimensional embeddings - Provides test helpers for caching and error injection - Added verification tests to ensure infrastructure works correctly Benefits achieved: - Reuses production code (ContentPersistenceAdapter, ArcadeContentRepository) - Catches real SQL errors, schema issues, and vector index configuration problems - Lower maintenance (~50 lines container code vs ~200 lines stub code) - All 424 existing tests pass (0 failures, 0 errors) Discovered issues for Phase 2: - ContentMapper null field handling needs improvement - Embedding type conversion (List<Float> vs float[]) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Summary of ChangesHello @robfrank, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request marks the completion of Phase 1 of a test refactoring plan, focusing on enhancing the reliability and realism of vector search tests. By integrating Testcontainers with ArcadeDB, the project moves from mock-based testing to using actual production code and a real database environment. This change not only provides a more robust testing foundation but has also proactively identified critical mapping issues that will be addressed in subsequent phases. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
🧪 CI InsightsHere's what we observed from your CI run for 084a67f. 🟢 All jobs passed!But CI Insights is watching 👀 |
There was a problem hiding this comment.
Code Review
This pull request does a great job of setting up the Testcontainers infrastructure for integration tests, which is a solid step towards more reliable testing. The new components like ArcadeDbContainer and ArcadeDbTestBase are well-structured. I've left a few comments with suggestions for improvement, mainly focusing on thread-safety in the FakeEmbeddingGenerator and ensuring proper resource management in the ArcadeDbContainer. There's also a minor point about a redundant cleanup step in the test base class. Overall, this is a strong contribution that will improve the project's test quality.
| private final Map<String, List<Float>> embeddingCache = new HashMap<>(); | ||
| private final Function<String, List<Float>> embeddingFunction; | ||
| private @Nullable RuntimeException exceptionToThrow = null; |
There was a problem hiding this comment.
This class has a couple of thread-safety issues that could lead to flaky tests in concurrent scenarios:
embeddingCacheusesHashMap, which is not thread-safe. Operations likecomputeIfAbsentcan behave unexpectedly under concurrent load. It's better to usejava.util.concurrent.ConcurrentHashMap.- The
exceptionToThrowfield is accessed from multiple threads without any memory synchronization (volatileorsynchronized). This can lead to visibility problems where one thread doesn't see the update from another.
I'd recommend making the field volatile to ensure visibility.
| private final Map<String, List<Float>> embeddingCache = new HashMap<>(); | |
| private final Function<String, List<Float>> embeddingFunction; | |
| private @Nullable RuntimeException exceptionToThrow = null; | |
| private final Map<String, List<Float>> embeddingCache = new java.util.concurrent.ConcurrentHashMap<>(); | |
| private final Function<String, List<Float>> embeddingFunction; | |
| private volatile @Nullable RuntimeException exceptionToThrow = null; |
| public @NonNull RemoteDatabase createDatabase() { | ||
| // Create database if it doesn't exist | ||
| RemoteServer server = new RemoteServer(getHost(), getMappedPort(ARCADE_PORT), "root", getRootPassword()); | ||
|
|
||
| // Always drop and recreate database for clean state | ||
| if (server.exists(getDatabaseName())) { | ||
| server.drop(getDatabaseName()); | ||
| } | ||
| server.create(getDatabaseName()); | ||
|
|
||
| // Connect to database | ||
| RemoteDatabase db = new RemoteDatabase(getHost(), getMappedPort(ARCADE_PORT), getDatabaseName(), "root", getRootPassword()); | ||
|
|
||
| // Initialize schema with vector index | ||
| initializeSchema(db); | ||
|
|
||
| return db; | ||
| } |
There was a problem hiding this comment.
The RemoteServer instance created here is not being closed after use. RemoteServer manages network connections and should be closed to release resources and prevent potential leaks, which can be problematic in CI environments. A try-finally block would ensure it's always closed.
public @NonNull RemoteDatabase createDatabase() {
// Create database if it doesn't exist
RemoteServer server = new RemoteServer(getHost(), getMappedPort(ARCADE_PORT), "root", getRootPassword());
try {
// Always drop and recreate database for clean state
if (server.exists(getDatabaseName())) {
server.drop(getDatabaseName());
}
server.create(getDatabaseName());
} finally {
server.close();
}
// Connect to database
RemoteDatabase db = new RemoteDatabase(getHost(), getMappedPort(ARCADE_PORT), getDatabaseName(), "root", getRootPassword());
// Initialize schema with vector index
initializeSchema(db);
return db;
}| @AfterEach | ||
| void tearDownDatabase() { | ||
| // Clean up test data | ||
| arcadeDb.cleanDatabase(database); |
There was a problem hiding this comment.
Pull Request Review: Testcontainers Infrastructure (#533)Great work on implementing Phase 1 of the test refactoring plan! This PR introduces solid infrastructure for integration testing with real ArcadeDB instances. Here's my detailed review: ✅ Strengths
🔍 Code Quality Issues1. Null Handling in ContentMapper (Critical)The PR description correctly identifies this issue. In vertex.set("htmlContent", content.htmlContent()); // Could be null
vertex.set("textContent", content.textContent()); // Could be null
vertex.set("contentLength", content.contentLength()); // Could be null
vertex.set("mimeType", content.mimeType()); // Could be nullRecommendation: Either:
2. Thread.sleep() Anti-pattern in TestsWhile Good news: The Awaitility dependency is correctly added for future Phase 2 work. 3. Inconsistent Exception HandlingIn } catch (Exception e) {
// Ignore errors during cleanup (e.g., if Content type doesn't exist yet)
}Recommendation:
🐛 Potential Bugs1. Database Recreation on Every Test MethodIn if (server.exists(getDatabaseName())) {
server.drop(getDatabaseName());
}
server.create(getDatabaseName());Issues:
Recommendation:
2. Resource Leak RiskIn RemoteServer server = new RemoteServer(...);
// ... uses server ...
// No server.close() callRecommendation: Use try-with-resources or ensure the server connection is properly closed. ⚡ Performance Considerations
🔒 Security Concerns
🧪 Test CoverageCurrent Coverage: Minimal but appropriate for infrastructure verification
Recommendations for Phase 2:
📋 Best PracticesExcellent Practices:
Could Improve:
📝 Minor Issues
🎯 Recommendations SummaryMust Fix Before Merge:
Should Fix Before Merge:
Consider for Phase 2:
✨ Overall AssessmentThis is a high-quality PR that successfully achieves Phase 1 goals. The infrastructure is well-designed and follows project conventions. The main concerns are around database lifecycle management and null handling, which should be addressed before merging. Recommendation: Request Changes - Fix the critical database recreation issue and resource leak, then this will be ready to merge. Great work on identifying the ContentMapper issues through this infrastructure - that's exactly the kind of benefit integration tests provide! 🎉 🤖 Generated with Claude Code |
PR Review: Testcontainers Infrastructure for Vector Search TestsSummaryThis PR implements Phase 1 of a test refactoring plan, introducing Testcontainers infrastructure to replace Mockito mocks with real production code. The changes are well-implemented and demonstrate a solid testing architecture improvement. ✅ StrengthsArchitecture & Design
Code Quality
🔍 Issues & Recommendations🔴 Critical Issues1. Resource Leak in
|
Coverage summary from CodacySee diff coverage on Codacy
Coverage variation details
Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: Diff coverage details
Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: See your quality gate settings Change summary preferencesFootnotes
|
Implemented Phase 1 of test refactoring plan to replace Mockito mocks with real production code using Testcontainers + ArcadeDB.
Changes:
Benefits achieved:
Discovered issues for Phase 2:
🤖 Generated with Claude Code