Skip to content

Conversation

@arvi18
Copy link

@arvi18 arvi18 commented Apr 21, 2025

What's changed?

Benefit from testcontainers' rich jdbc driver support (SPI implementation), add jdbc common collect e2e code (postgresql/mysql supported for now)

Checklist

  • I have read the Contributing Guide
  • I have written the necessary doc or comment.
  • I have added the necessary unit tests and all cases have passed.

Add or update API

  • I have added the necessary e2e tests and all cases have passed.

Summary by CodeRabbit

  • New Features

    • Added support for constructing JDBC URLs for "testcontainers" database platforms.
    • Introduced a new enum for managing database image types and default tags.
    • Added end-to-end tests for collecting metrics from PostgreSQL databases running in test containers.
  • Chores

    • Updated project dependencies to support database testing with Testcontainers, including centralized version management and new test-scoped dependencies.

@arvi18
Copy link
Author

arvi18 commented Apr 21, 2025

please fix ci

@coderabbitai
Copy link

coderabbitai bot commented Apr 21, 2025

Walkthrough

The changes introduce enhanced support for database testing using Testcontainers within the Hertzbeat collector modules. A new enum for database image management is added, and a new end-to-end test class is implemented to verify JDBC metric collection against a PostgreSQL Testcontainer. The JDBC URL construction logic is extended to handle "testcontainers" as a platform. Maven configuration files are updated to manage Testcontainers dependencies via a BOM and to include specific JDBC drivers and Testcontainers modules for MySQL and PostgreSQL, ensuring consistent versions and improved test isolation.

Changes

File(s) Change Summary
hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/database/JdbcCommonCollect.java Added a new case to handle "testcontainers" in the database URL construction logic, enabling JDBC URLs compatible with Testcontainers.
hertzbeat-e2e/hertzbeat-collector-basic-e2e/pom.xml Updated Maven POM: added properties for MySQL and PostgreSQL JDBC driver versions; added test-scoped dependencies for Testcontainers (JUnit, JDBC, MySQL, PostgreSQL); switched Testcontainers dependency from generic to JDBC module; added explicit JDBC driver dependencies as optional and test-scoped.
hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/DatabaseImagesEnum.java Introduced a new enum DatabaseImagesEnum for managing supported database images and their default tags, with utility methods for lookup and string representation.
hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/JdbcCommonCollectE2eTest.java Added a new end-to-end test class for validating JDBC metric collection using Testcontainers, specifically targeting PostgreSQL, with custom setup, protocol configuration, and metric validation logic.
hertzbeat-e2e/pom.xml Added a <dependencyManagement> section to import the Testcontainers BOM, centralizing Testcontainers dependency version management for the project.

Sequence Diagram(s)

sequenceDiagram
    participant TestRunner
    participant JdbcCommonCollectE2eTest
    participant Testcontainer(PostgreSQL)
    participant JdbcCommonCollect

    TestRunner->>JdbcCommonCollectE2eTest: setUp()
    JdbcCommonCollectE2eTest->>Testcontainer(PostgreSQL): Start container
    JdbcCommonCollectE2eTest->>JdbcCommonCollect: Initialize with test config
    loop For each metric
        JdbcCommonCollectE2eTest->>JdbcCommonCollect: collectMetrics(metric)
        JdbcCommonCollect->>Testcontainer(PostgreSQL): Connect via JDBC (testcontainers URL)
        JdbcCommonCollect-->>JdbcCommonCollectE2eTest: Return collected data
        JdbcCommonCollectE2eTest->>JdbcCommonCollectE2eTest: Validate results
    end
    JdbcCommonCollectE2eTest-->>TestRunner: Test results
Loading

Poem

In tunnels of code where the test containers spin,
A rabbit hops in, with a whiskered grin.
Databases in jars, enum names set,
URLs constructed, no errors to fret.
Metrics are gathered, the tests all pass through—
A hop, a leap, and a cheer for the new!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@visz11
Copy link
Collaborator

visz11 commented Apr 21, 2025

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Apr 21, 2025

✅ Actions performed

Full review triggered.

@visz11
Copy link
Collaborator

visz11 commented Apr 22, 2025

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Apr 22, 2025

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/DatabaseImagesEnum.java (2)

56-63: Consider supporting custom tags in lookup.

The current implementation only matches exact "imageName:defaultTag" combinations. Consider enhancing the method to parse custom tags.

 public static DatabaseImagesEnum fromFullImageName(String fullImageName) {
+    // Split the image name and tag
+    String[] parts = fullImageName.split(":");
+    if (parts.length > 0) {
+        // Match by image name only, ignoring tag differences
+        return fromImageName(parts[0]);
+    }
     for (DatabaseImagesEnum value : values()) {
         if (value.getFullImageName().equalsIgnoreCase(fullImageName)) {
             return value;
         }
     }
     throw new IllegalArgumentException("Unknown full database image name: " + fullImageName);
 }

65-71: Fix class name in toString method.

The toString method references an incorrect class name "DatabaseImageNameEnum" which doesn't match the actual class name "DatabaseImagesEnum".

 @Override
 public String toString() {
-    return "DatabaseImageNameEnum{" +
+    return "DatabaseImagesEnum{" +
             "imageName='" + imageName + '\'' +
             ", defaultTag='" + defaultTag + '\'' +
             '}';
 }
hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/database/JdbcCommonCollect.java (2)

386-387: Good implementation of Testcontainers JDBC URL support.

The addition of the "testcontainers" case to the URL construction switch statement enables integration with Testcontainers for end-to-end testing. However, hard-coding credentials limits flexibility.

Consider parameterizing the credentials rather than hard-coding them:

-case "testcontainers" -> "jdbc:tc:" + host + ":" + port
-        + ":///" + (jdbcProtocol.getDatabase() == null ? "" : jdbcProtocol.getDatabase()) + "?user=root&password=root";
+case "testcontainers" -> "jdbc:tc:" + host + ":" + port
+        + ":///" + (jdbcProtocol.getDatabase() == null ? "" : jdbcProtocol.getDatabase()) 
+        + "?user=" + (StringUtils.hasText(jdbcProtocol.getUsername()) ? jdbcProtocol.getUsername() : "root") 
+        + "&password=" + (StringUtils.hasText(jdbcProtocol.getPassword()) ? jdbcProtocol.getPassword() : "root");

386-387: Add explanatory comment for the Testcontainers case.

Adding a comment explaining the purpose and usage of the Testcontainers case would improve maintainability.

+// Special case for test containers JDBC URL format (jdbc:tc:postgresql:15:///test?user=root&password=root)
 case "testcontainers" -> "jdbc:tc:" + host + ":" + port
         + ":///" + (jdbcProtocol.getDatabase() == null ? "" : jdbcProtocol.getDatabase()) + "?user=root&password=root";
hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/JdbcCommonCollectE2eTest.java (3)

48-53: Consider adding a comment explaining the database image selection

The code references a DatabaseImagesEnum class which appears to be used for selecting test container images. I recommend adding a brief comment explaining the purpose of this enum and why PostgreSQL was chosen as the default test database.


86-94: Document why 'slow_sql' metric requires special handling

The code has special handling for the "slow_sql" metric, only verifying that it doesn't throw an exception. Please add a comment explaining why this metric needs different validation logic than other metrics.

 if ("slow_sql".equals(metricName)) {
+    // The slow_sql metric requires special handling because it depends on database-specific features
+    // that may not be available in the test container or requires additional setup.
+    // For E2E testing purposes, we only verify it doesn't throw exceptions.
     Metrics finalMetricsDef = metricsDef;
     assertDoesNotThrow(() -> collectMetrics(finalMetricsDef),
             String.format("%s failed to collect metrics)", metricName));
     log.info("{} metrics validation passed", metricName);
     continue;  // skip slow_sql, extra extensions
 }

54-69: Consider adding more specific assertions for collection results

The test effectively sets up the collection environment, but could benefit from more specific assertions to validate the collected data, not just that collection occurred without errors.

For example, you could enhance the test by validating specific fields or values in the collected metrics:

// Example of more specific validation
CollectRep.MetricsData metricsData = validateMetricsCollection(metricsDef, metricName, true);
// Verify specific metrics were collected
if ("database_size".equals(metricName)) {
    assertFalse(metricsData.getValuesList().isEmpty(), "Should have collected database size metrics");
    // Further specific assertions based on expected values
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b02837b and 729e4a3.

📒 Files selected for processing (5)
  • hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/database/JdbcCommonCollect.java (1 hunks)
  • hertzbeat-e2e/hertzbeat-collector-basic-e2e/pom.xml (2 hunks)
  • hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/DatabaseImagesEnum.java (1 hunks)
  • hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/JdbcCommonCollectE2eTest.java (1 hunks)
  • hertzbeat-e2e/pom.xml (1 hunks)
🔇 Additional comments (8)
hertzbeat-e2e/pom.xml (1)

77-88: Well-structured dependency management addition.

Adding the Testcontainers BOM (Bill of Materials) as part of dependencyManagement is a great practice. This centralizes version management for all Testcontainers dependencies across the project, ensuring consistency and simplifying future version upgrades.

hertzbeat-e2e/hertzbeat-collector-basic-e2e/pom.xml (3)

34-35: Good versioning practice.

Defining database driver versions as properties follows Maven best practices, enabling centralized version management.


59-81: Well-organized Testcontainers dependencies.

The dependencies are properly organized with clear comments, correct scoping as "test", and appropriate module selection for database testing with Testcontainers.


83-97: Appropriate JDBC driver configuration.

The JDBC drivers are correctly configured with:

  • Specific versions tied to properties
  • Test scope to limit their inclusion to test classpath only
  • Optional flag to prevent transitive inclusion in dependent projects
hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/DatabaseImagesEnum.java (2)

23-26: Clean enum design for test database types.

The enum effectively defines the supported database types with appropriate image names and default tags for testing.


47-54: Well-implemented lookup method.

The lookup method correctly handles case-insensitive matching of database image names, ensuring flexibility in how tests reference image types.

hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/JdbcCommonCollectE2eTest.java (2)

1-47: Good implementation of E2E tests for JDBC collection

The class structure and test setup with Mockito look good. The class extends AbstractCollectE2eTest which is appropriate for E2E testing.


81-85: LGTM: Test method initialization looks good

The test initialization correctly retrieves the job definition and sets up the collection environment.

Comment on lines +95 to +97
CollectRep.MetricsData metricsData = validateMetricsCollection(metricsDef, metricName, true);
CollectUtil.getConfigmapFromPreCollectData(metricsData);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

The return value of getConfigmapFromPreCollectData is not used

Line 96 calls CollectUtil.getConfigmapFromPreCollectData(metricsData) but doesn't use the return value. Consider either storing and using the return value or adding a comment explaining why it's called without using the result.

-CollectUtil.getConfigmapFromPreCollectData(metricsData);
+// Extract configmap data for potential use in subsequent test iterations
+Map<String, Configmap> configmap = CollectUtil.getConfigmapFromPreCollectData(metricsData);
+if (!configmap.isEmpty()) {
+    configmapFromPreCollectData.add(configmap);
+}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +71 to +79
@Override
protected Protocol buildProtocol(Metrics metricsDef) {
JdbcProtocol jdbcProtocol = metricsDef.getJdbc();
jdbcProtocol.setHost(DATABASE_IMAGE_NAME);
jdbcProtocol.setPort(DATABASE_IMAGE_TAG);
jdbcProtocol.setDatabase("test");
jdbcProtocol.setPlatform("testcontainers");
return jdbcProtocol;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify if port assignment is correct

Line 75 assigns DATABASE_IMAGE_TAG to the port property, which seems unusual as ports are typically numeric values. Consider verifying if this is the intended behavior or if it should be using an actual port number.


🏁 Script executed:

#!/bin/bash
# Check how DATABASE_IMAGE_TAG is used and if it's appropriate for port configuration
echo "Checking DatabaseImagesEnum class for tag definition..."
fd -t f -e java "DatabaseImagesEnum.java" | xargs cat

echo "Checking JdbcProtocol class for port field type..."
fd -t f -e java "JdbcProtocol.java" | xargs cat | grep -A 10 "private.*port"

Length of output: 2986


🏁 Script executed:

#!/bin/bash
# Display the relevant test file context around the buildProtocol method
fd -t f -e java "JdbcCommonCollectE2eTest.java" | xargs sed -n '1,200p'

Length of output: 4427


🏁 Script executed:

#!/bin/bash
# Locate and display AbstractCollectE2eTest class implementation context around container setup or protocol handling
fd -t f -e java "AbstractCollectE2eTest.java" | xargs sed -n '1,200p'

Length of output: 6135


Confirm port assignment in buildProtocol

The test currently does:

jdbcProtocol.setHost(DATABASE_IMAGE_NAME);
jdbcProtocol.setPort(DATABASE_IMAGE_TAG);

Here, DATABASE_IMAGE_TAG comes from DatabaseImagesEnum.getDefaultTag() (e.g. "15"), which is the Docker image version—not a TCP port. Since JdbcProtocol.port is the port used to connect to the database, this will direct the driver to port 15 rather than the actual database port (e.g. 5432 or the Testcontainers–mapped port).

Please verify and update accordingly:

  • If you’re using Testcontainers, start the container and set:
    jdbcProtocol.setPort(String.valueOf(container.getFirstMappedPort()));
  • Otherwise, use the default database port (e.g. "5432") or inject it via configuration.

Location:

  • hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/JdbcCommonCollectE2eTest.java
    protected Protocol buildProtocol(Metrics metricsDef) { … }

@atharvsabdeai
Copy link

/refacto-test

@refacto-test
Copy link

refacto-test bot commented Jul 23, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

@refacto-test
Copy link

refacto-test bot commented Jul 31, 2025

Strong Foundation - Connection Check Enhancement for Better Reliability!

Review Summary

This PR introduces an important reliability improvement to the connection management system by adding connection validation checks before returning connections from the cache. The implementation consistently applies the new check() method across all connection types, ensuring connections are verified as valid before use. This change will significantly reduce the risk of runtime errors from using stale or closed connections. The code is well-structured with a consistent implementation pattern across all connection types.

Well Done!!!

  • Excellent consistency in implementing the connection check pattern across all connection implementations
  • Smart error handling that logs issues but doesn't throw exceptions in the connection getter methods
  • Good abstraction with the new abstract method in the base class that enforces implementation across all subclasses
  • Clean code structure with minimal changes focused on a single responsibility

Files Processed

collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/AbstractConnection.java 17-48
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JdbcConnect.java 18-64
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/JmxConnect.java 40-64
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/MongodbConnect.java 19-60
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedfishConnect.java 38-62
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/RedisConnect.java 39-63
collector/src/main/java/org/apache/hertzbeat/collector/collect/common/cache/SshConnect.java 38-60
collector/src/main/java/org/apache/hertzbeat/collector/collect/redis/RedisCommonCollectImpl.java 236-261
collector/src/test/java/org/apache/hertzbeat/collector/collect/common/cache/CommonCacheTest.java 45-53

📌 Additional Comments (3)

Reliability

Consider Adding Null Checks in Other Connection Implementations

Explanation: Similar to the JmxConnect issue, other connection implementations like RedisConnect, RedfishConnect, and SshConnect don't check if the connection is null before accessing its methods. While the main issue is addressed in the actionable finding for JmxConnect, it would be good practice to add similar null checks in all implementations for consistency and robustness.

@Override
    public void check() throws Exception {

        if (!connection.isOpen()) {
            throw new RuntimeException("Connection is closed");

Fix Suggestion: Add null checks in all connection check() implementations.

+         if (connection == null) {
+             throw new RuntimeException("Connection is null");
+         }
+         if (!connection.isOpen()) {
+             throw new RuntimeException("Connection is closed");
Rationale
  • Ensures consistent null checking across all connection implementations
  • Prevents potential NullPointerExceptions in edge cases
  • Improves error messages by distinguishing between null and closed connections
  • Follows defensive programming best practices
References
  • Standard: Defensive Programming - Null Safety
---

Maintainability

Consider Adding Logging to AbstractConnection

Explanation: The PR removes the @slf4j annotation and logging capabilities from AbstractConnection. While each implementation now has its own logging, having logging capability in the abstract class could provide consistent logging patterns across all implementations, especially for common operations like connection closing.

package org.apache.hertzbeat.collector.collect.common.cache;

/**
 * AbstractConnection
 */

public abstract class AbstractConnection<T> implements AutoCloseable  {

Fix Suggestion: Restore logging capability to AbstractConnection.

+ import lombok.extern.slf4j.Slf4j;
+ 
+ /**
+  * AbstractConnection
+  */
+ @Slf4j
+ public abstract class AbstractConnection<T> implements AutoCloseable  {
Rationale
  • Enables consistent logging patterns across all connection implementations
  • Allows for centralized logging of common operations in the abstract class
  • Follows the principle that base classes should provide common functionality
  • Makes it easier to add common logging features in the future
References
  • Standard: Logging Best Practices - Inheritance Hierarchies
---
Consider Adding Unit Tests for Connection Check Logic

Explanation: While the PR adds an empty implementation of the check() method to the test class, it doesn't include actual tests for the new connection check functionality. Adding unit tests that verify the behavior of the check() method in various connection implementations would help ensure the reliability of this important feature.

@Override
            public void closeConnection() throws Exception {
            }

            @Override
            public void check() throws Exception {
            }

Fix Suggestion: Add unit tests for connection check functionality.

+ // Consider adding tests like:
+ // @Test
+ // public void testConnectionCheckWithInvalidConnection() {
+ //     // Test that check() correctly identifies invalid connections
+ // }
Rationale
  • Ensures the new connection check functionality works as expected
  • Verifies error handling behavior for invalid connections
  • Improves test coverage for critical connection management code
  • Helps prevent future regressions in connection validation logic
References
  • Standard: Unit Testing Best Practices - Feature Coverage
---

@arvi18
Copy link
Author

arvi18 commented Aug 5, 2025

/refacto-test

1 similar comment
@arvi18
Copy link
Author

arvi18 commented Aug 5, 2025

/refacto-test

@refacto-test
Copy link

refacto-test bot commented Aug 5, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

@refacto-test
Copy link

refacto-test bot commented Aug 5, 2025

Solid Implementation - Let's Address Database Testing Resource Management!

Review Summary

This PR introduces a well-structured implementation of E2E testing for JDBC collectors using TestContainers, with good separation of concerns and proper database abstraction. The code demonstrates thoughtful design with the DatabaseImagesEnum pattern for managing different database configurations. Our analysis identified several reliability and maintainability issues that should be addressed before merging, primarily focusing on proper resource management and error handling in the test implementation. Addressing these items will ensure the test framework is robust and maintainable for the long term.

Well Done!!!

  • Excellent use of TestContainers for database testing, providing isolated and reproducible test environments
  • Well-structured database image enumeration with proper version control for consistent test environments
  • The PR correctly adds the necessary dependencies in the POM files with appropriate scoping

Files Processed

hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/JdbcCommonCollectE2eTest.java 1-99
hertzbeat-e2e/hertzbeat-collector-basic-e2e/src/test/java/org/apache/hertzbeat/collector/collect/basic/database/DatabaseImagesEnum.java 1-72
hertzbeat-collector/hertzbeat-collector-basic/src/main/java/org/apache/hertzbeat/collector/collect/database/JdbcCommonCollect.java 383-387

📌 Additional Comments (3)

Performance Enhancement

Inefficient Database Connection Management in Test

Explanation: The test method creates new database connections for each metric test without connection pooling or reuse. For test suites with multiple metrics, this can lead to connection overhead of 100-200ms per test iteration. While acceptable for small test suites, this approach doesn't scale efficiently for larger test suites with many metrics or when running tests in parallel, potentially increasing test execution time by 15-30% under heavy test loads.

@Test
public void testWithJdbcTcUrl() {
    Job dockerJob = appService.getAppDefine(DATABASE_IMAGE_NAME);
    List<Map<String, Configmap>> configmapFromPreCollectData = new LinkedList<>();

Fix Suggestion: Implement connection pooling for test database connections

+ private Connection connection;

+ 
@BeforeEach
public void setupConnection() throws SQLException {
    // Reuse connection across test methods
    if (connection == null || connection.isClosed()) {
        connection = DriverManager.getConnection("jdbc:tc:" + DATABASE_IMAGE_NAME + ":" + DATABASE_IMAGE_TAG + "://test");
    }
}

Logical Correctness Enhancement

Incomplete Image Name Validation in fromFullImageName Method

Explanation: The current implementation of fromFullImageName() only checks for exact matches with the default image tags (e.g., 'mysql:8.0.36'). This method will fail to recognize valid image names that use different tags (e.g., 'mysql:8.0.35' or 'mysql:latest'). This logical error means that valid database images with non-default tags cannot be properly identified by the enum, potentially causing test failures when using custom database versions.

public static DatabaseImagesEnum fromFullImageName(String fullImageName) {
        for (DatabaseImagesEnum value : values()) {
            if (value.getFullImageName().equalsIgnoreCase(fullImageName)) {
                return value;
            }
        }
        throw new IllegalArgumentException("Unknown full database image name: " + fullImageName);

Fix Suggestion: Enhance image name validation to support custom image tags

+ public static DatabaseImagesEnum fromFullImageName(String fullImageName) {
+         // Extract image name without tag
+         String imageName = fullImageName.split(":")[0];
+         
+         for (DatabaseImagesEnum value : values()) {
+             if (value.getImageName().equalsIgnoreCase(imageName)) {
+                 return value;
+             }
+         }
+         throw new IllegalArgumentException("Unknown full database image name: " + fullImageName);

Documentation Enhancement

Incomplete Documentation in DatabaseImagesEnum

Explanation: The class-level documentation for DatabaseImagesEnum is minimal and contains a typo ('mame' instead of 'name'). It doesn't provide sufficient context about the purpose of the enum, its usage pattern, or how to extend it with new database types. This makes it harder for developers to understand and maintain the code, especially when adding support for new database types in the future.

/**
 * Database type (image mame) and image tag enumeration class
 */

Fix Suggestion: Enhance class documentation for DatabaseImagesEnum with more context and usage information

+ /**
+  * Enumeration of supported database types for testcontainers-based E2E testing.
+  * Each entry defines the Docker image name and default tag to use for testing.
+  * 
+  * Usage: DatabaseImagesEnum.MYSQL.getFullImageName() returns the complete image reference.
+  * To add new database support, add a new enum constant with appropriate image name and tag.
+  */

Comment on lines +38 to +43
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

/**
* E2e test monitored by Jdbc Common
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Container Cleanup in JdbcCommonCollectE2eTest

The test class uses TestContainers for database testing but doesn't properly manage container lifecycle. TestContainers typically requires explicit container initialization and cleanup. Without proper container management, tests may leave containers running after completion, causing resource leaks, potential port conflicts, and increased resource consumption during test execution. This violates resource management best practices and could lead to unstable test environments.

@Testcontainers
public class JdbcCommonCollectE2eTest extends AbstractCollectE2eTest {
    private static final DatabaseImagesEnum databaseImage = DatabaseImagesEnum.fromImageName("postgresql");

    private static final String DATABASE_IMAGE_NAME = databaseImage.getImageName();

    private static final String DATABASE_IMAGE_TAG = databaseImage.getDefaultTag();

    @Container
    private static final PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>(databaseImage.getFullImageName())
            .withDatabaseName("test")
            .withUsername("root")
            .withPassword("root");

References

Standard: ISO/IEC 25010 Reliability - Resource Utilization

Comment on lines +45 to +52
}

public static DatabaseImagesEnum fromImageName(String imageName) {
for (DatabaseImagesEnum value : values()) {
if (value.getImageName().equalsIgnoreCase(imageName)) {
return value;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Error Handling in TestContainers Database Type Resolution

The DatabaseImagesEnum.fromImageName method throws an IllegalArgumentException when an unknown database image name is provided, but there's no error handling in the JdbcCommonCollectE2eTest that uses this method with a hardcoded value. If the database type is changed or removed in the future, tests will fail with an uncaught exception rather than gracefully handling the error. This violates error handling best practices and could lead to difficult-to-diagnose test failures.

    public static DatabaseImagesEnum fromImageName(String imageName) {
        if (imageName == null || imageName.trim().isEmpty()) {
            return POSTGRESQL; // Default to PostgreSQL if no name provided
        }
        
        for (DatabaseImagesEnum value : values()) {
            if (value.getImageName().equalsIgnoreCase(imageName)) {
                return value;
            }
        }
        throw new IllegalArgumentException("Unknown database image name: " + imageName);
    }

References

Standard: Design by Contract - Precondition Validation

Comment on lines 385 to +386
case "dm" -> "jdbc:dm://" + host + ":" + port;
case "testcontainers" -> "jdbc:tc:" + host + ":" + port
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded Database Credentials in JDBC URL

The code adds a new case for testcontainers that includes hardcoded database credentials ('root'/'root') directly in the JDBC URL. While this is only used for testing purposes, hardcoded credentials in source code are generally considered a security risk as they could be inadvertently exposed or reused in non-test environments.

            case "testcontainers" -> "jdbc:tc:" + host + ":" + port
                    + "://" + (jdbcProtocol.getDatabase() == null ? "" : jdbcProtocol.getDatabase()) + "?user=" + 
                    (jdbcProtocol.getUsername() == null ? "root" : jdbcProtocol.getUsername()) + "&password=" + 
                    (jdbcProtocol.getPassword() == null ? "root" : jdbcProtocol.getPassword());

References

Standard: CWE-798
Standard: OWASP Top 10 2021: A07 - Identification and Authentication Failures

Comment on lines +91 to +98
String.format("%s failed to collect metrics)", metricName));
log.info("{} metrics validation passed", metricName);
continue; // skip slow_sql, extra extensions
}
CollectRep.MetricsData metricsData = validateMetricsCollection(metricsDef, metricName, true);
CollectUtil.getConfigmapFromPreCollectData(metricsData);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Error Handling in Database Test Implementation

The test method handles the 'slow_sql' metric case differently but doesn't provide sufficient error handling or logging for diagnostic purposes. While the code uses assertDoesNotThrow() to verify execution, it doesn't capture or validate the actual result of the metrics collection. This makes it harder to diagnose test failures and understand what specifically went wrong with slow_sql metric collection.

            if ("slow_sql".equals(metricName)) {
                Metrics finalMetricsDef = metricsDef;
                try {
                    CollectRep.MetricsData metricsData = collectMetrics(finalMetricsDef).build();
                    assertNotNull(metricsData, String.format("%s metrics data should not be null", metricName));
                    log.info("{} metrics validation passed with {} rows", metricName,
                             metricsData.getValuesCount() > 0 ? metricsData.getValuesCount() : "no");
                } catch (Exception e) {
                    log.error("Error collecting {} metrics: {}", metricName, e.getMessage());
                    fail(String.format("%s metrics collection failed: %s", metricName, e.getMessage()));
                }
                continue;  // skip slow_sql, extra extensions
            }

References

Standard: JUnit Best Practices - Error Diagnostics, Clean Code - Error Handling

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.

6 participants