Skip to content

tests(kafka): add unit tests for KafkaTopicHealthTool and KafkaConsumerGroupTool#1264

Merged
Devesh36 merged 3 commits intomainfrom
feat/kafka-tool-tests
May 4, 2026
Merged

tests(kafka): add unit tests for KafkaTopicHealthTool and KafkaConsumerGroupTool#1264
Devesh36 merged 3 commits intomainfrom
feat/kafka-tool-tests

Conversation

@yashksaini-coder
Copy link
Copy Markdown
Collaborator

@yashksaini-coder yashksaini-coder commented May 4, 2026

Summary

Adds full unit-test coverage for both Kafka tools:

  • KafkaTopicHealthTooltests/tools/test_kafka_topic_health_tool.py (27 tests)
  • KafkaConsumerGroupTooltests/tools/test_kafka_consumer_group_tool.py (16 tests)

What's tested

Each file covers four layers:

Layer What it asserts
Contract (BaseToolContract) name, description, input schema, source, is_available returns bool, extract_params returns dict
is_available true when connection_verified is set, false for all missing/falsy variants
extract_params all five connection fields are extracted; empty strings when Kafka key is absent; whitespace stripped from bootstrap servers
run happy path (all topics / specific topic / SASL-SSL), error path (exception → unavailable dict), not-configured path (empty bootstrap servers → early return without touching the broker)

Technical notes

Mocks are applied at the tool-module boundary (app.tools.KafkaTopicHealthTool.get_topic_health), not at the integration module, because both tool files use from app.integrations.kafka import ... which binds the name locally.

confluent_kafka is not installed in the dev venv. All happy-path tests mock the integration function before confluent_kafka is reached; the not-configured path returns before any broker contact.

Results

43 passed in 0.17s  (kafka tests only)
4907 passed, 2 skipped  (full suite — no regressions)

Closes #1267

…erGroupTool

Covers contract, is_available, extract_params, and run paths
(happy, error, and not-configured) for both tools. Mocks applied
at the tool-module boundary to correctly intercept imported names.

Closes #994
Copilot AI review requested due to automatic review settings May 4, 2026 12:15
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

Greptile Summary

This PR adds unit test coverage for KafkaTopicHealthTool and KafkaConsumerGroupTool, closing the gap left when issue #994 was resolved. Both files follow the established BaseToolContract pattern and correctly mock at the tool-module boundary (app.tools.KafkaTopicHealthTool.get_topic_health / app.tools.KafkaConsumerGroupTool.get_consumer_group_lag) to handle the local name binding from from app.integrations.kafka import .... All four layers (contract, is_available, extract_params, and run) are covered, and the not-configured early-exit path is exercised without requiring confluent_kafka to be installed.

Confidence Score: 4/5

Safe to merge — tests are logically correct, mock targets are accurate, and all critical paths are covered; remaining gaps are non-blocking style suggestions.

Only P2 findings: missing limit forwarding assertion in the topic-health tests and shallow SASL-SSL tests in both files that don't verify call-args. No logic errors, no incorrect mock targets, no broken test paths detected.

Both new test files warrant a second look on the SASL-SSL and limit parameter assertions, but neither blocks the merge.

Important Files Changed

Filename Overview
tests/tools/test_kafka_topic_health_tool.py Adds 27 unit tests covering contract, is_available, extract_params, happy path, error, and not-configured paths for KafkaTopicHealthTool; limit parameter forwarding is untested and the SASL-SSL test provides no call-args verification.
tests/tools/test_kafka_consumer_group_tool.py Adds 16 unit tests covering contract, is_available, extract_params, happy path (including partition-level lag detail and zero-lag case), error, and not-configured paths; SASL-SSL test only checks the mock return value, not actual parameter forwarding.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Test calls tool function] --> B{bootstrap_servers empty?}
    B -- Yes --> C[KafkaConfig.is_configured == False]
    C --> D[Integration returns early\navailable=False, no broker contact]
    B -- No --> E[KafkaConfig built from params]
    E --> F{Mock patched at\ntool-module boundary?}
    F -- Yes\nhappy/error tests --> G[Mocked integration function returns\nfixture dict]
    G --> H[Tool returns dict to test\nassertions run on result]
    F -- No\nnot-configured tests --> I[Real integration called\nearly return before confluent_kafka]
    I --> H
Loading

Reviews (1): Last reviewed commit: "tests(kafka): add unit tests for KafkaTo..." | Re-trigger Greptile

assert params["bootstrap_servers"] == "broker:9092"


# ---------------------------------------------------------------------------
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Missing coverage for limit parameter

get_kafka_topic_health accepts a limit parameter (default 20) that is forwarded directly to get_topic_health. None of the tests pass a non-default limit or assert that the argument is forwarded to the integration call. A call-args assertion similar to the topic forwarding test (test_happy_path_specific_topic_forwards_topic_arg) would close this gap and prevent a silent regression if the wiring is broken.

Comment on lines +225 to +240

assert result["available"] is True
assert result["topics"][0]["name"] == "payments"
# Verify the topic argument was forwarded to the integration function.
_, call_kwargs = mock_fn.call_args
assert call_kwargs.get("topic") == "payments"

def test_happy_path_sasl_ssl_connection(self) -> None:
with patch(
"app.tools.KafkaTopicHealthTool.get_topic_health",
return_value=_TOPIC_HEALTH_RESPONSE,
):
result = get_kafka_topic_health(
bootstrap_servers="broker1:9093",
security_protocol="SASL_SSL",
sasl_mechanism="PLAIN",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 SASL-SSL test only asserts availability, not parameter forwarding

test_happy_path_sasl_ssl_connection verifies only that result["available"] is True, which is fully determined by the mock return value. It doesn't verify that security_protocol, sasl_mechanism, sasl_username, or sasl_password were actually constructed into the KafkaConfig and forwarded to get_topic_health. Inspecting mock_fn.call_args for those fields (like the topic-forwarding test does) would make this test meaningful rather than a pass-through check.

Comment on lines +189 to +203
):
result = get_kafka_consumer_group_lag(
bootstrap_servers="broker1:9092",
group_id="events-consumer",
)

assert result["available"] is True
assert result["total_lag"] == 0
assert result["partitions"][0]["lag"] == 0
assert result["partitions"][0]["committed_offset"] == result["partitions"][0]["high_watermark"]

def test_happy_path_forwards_group_id_to_integration(self) -> None:
with patch(
"app.tools.KafkaConsumerGroupTool.get_consumer_group_lag",
return_value=_CONSUMER_GROUP_ZERO_LAG_RESPONSE,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 SASL-SSL test only asserts availability, not parameter forwarding

Same concern as in the topic-health file: test_happy_path_sasl_ssl_connection mocks the integration and only checks result["available"] is True, which is driven entirely by the mock fixture. The actual SASL credentials passed to the tool (security_protocol, sasl_mechanism, sasl_username, sasl_password) are never verified to reach the integration call. Asserting on mock_fn.call_args[0][0] (the KafkaConfig positional argument) would confirm the wiring is intact.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds missing unit tests for the two Kafka diagnostic tool wrappers so their tool registration, availability, parameter extraction, and mocked run paths are covered alongside the existing Kafka integration tests.

Changes:

  • Added a new test module for KafkaTopicHealthTool.
  • Added a new test module for KafkaConsumerGroupTool.
  • Covered tool contract metadata, is_available, extract_params, and several mocked run scenarios.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

File Description
tests/tools/test_kafka_topic_health_tool.py Adds wrapper-level tests for Kafka topic health tool metadata, availability, param extraction, and mocked run behavior.
tests/tools/test_kafka_consumer_group_tool.py Adds wrapper-level tests for Kafka consumer group lag tool metadata, availability, param extraction, and mocked run behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +7 to +8
- run happy path: all topics, specific topic, limit param
- run error path: integration returns available=False
Comment on lines +252 to +262
fake_error = {
"source": "kafka",
"available": False,
"error": "Connection refused by broker.",
}
with patch("app.tools.KafkaTopicHealthTool.get_topic_health", return_value=fake_error):
result = get_kafka_topic_health(bootstrap_servers="bad-host:9092")

assert result["available"] is False
assert "error" in result
assert result["source"] == "kafka"
Comment on lines +233 to +239
def test_error_path_returns_unavailable_dict(self) -> None:
fake_error = {
"source": "kafka",
"available": False,
"error": "Group 'stale-consumer' does not exist.",
}
with patch("app.tools.KafkaConsumerGroupTool.get_consumer_group_lag", return_value=fake_error):
Comment on lines +232 to +237
def test_happy_path_sasl_ssl_connection(self) -> None:
with patch(
"app.tools.KafkaTopicHealthTool.get_topic_health",
return_value=_TOPIC_HEALTH_RESPONSE,
):
result = get_kafka_topic_health(
Comment on lines +213 to +218
def test_happy_path_sasl_ssl_connection(self) -> None:
with patch(
"app.tools.KafkaConsumerGroupTool.get_consumer_group_lag",
return_value=_CONSUMER_GROUP_LAG_RESPONSE,
):
result = get_kafka_consumer_group_lag(
Comment on lines +267 to +269
result = get_kafka_topic_health(bootstrap_servers="")
assert result["available"] is False
assert result["source"] == "kafka"
Comment on lines +251 to +257
# get_consumer_group_lag returns early before any confluent_kafka import.
result = get_kafka_consumer_group_lag(
bootstrap_servers="",
group_id="payments-consumer",
)
assert result["available"] is False
assert result["source"] == "kafka"
…ring, exception propagation, short-circuit guard

- Add test for limit argument forwarding to KafkaTopicHealthTool
- Expand SASL-SSL tests in both tools to assert KafkaConfig fields
  (security_protocol, sasl_mechanism, sasl_username, sasl_password)
  are correctly wired via call_args inspection
- Add exception-propagation tests to both tools: if the integration
  raises instead of returning an error dict, the tool must not swallow it
- Update not-configured tests to use wraps= so the integration call is
  tracked, confirming the early-exit branch was entered not bypassed
@yashksaini-coder yashksaini-coder force-pushed the feat/kafka-tool-tests branch from ae8d079 to 3f9ae8c Compare May 4, 2026 13:28
@yashksaini-coder
Copy link
Copy Markdown
Collaborator Author

All 10 inline review threads from @greptile-apps and @copilot-pull-request-reviewer were addressed in commit 3ec1798a (and confirmed intact at the current head 3f9ae8c7). Pasting the resolution map for visibility, since neither bot auto-re-evaluates after a fixup.

Concern Addressed by File:line
limit param not exercised (Greptile #1, Copilot #4) new test_happy_path_forwards_limit_arg — passes limit=5, asserts call_kwargs["limit"] == 5 test_kafka_topic_health_tool.py:191-199
SASL-SSL test only checks availability (Greptile #2, Copilot #7) — topic_health test_happy_path_sasl_ssl_connection now extracts mock_fn.call_args[0][0] (the KafkaConfig) and asserts all 4 SASL fields propagated test_kafka_topic_health_tool.py:239-258
Same for consumer_group (Greptile #3, Copilot #8) Identical fix on consumer_group test_kafka_consumer_group_tool.py:217-237
Error-path test is fake (Copilot #5, #6) new test_error_path_propagates_exception_from_integration — uses side_effect=RuntimeError(...) + pytest.raises(...) instead of returning a fake error dict test_kafka_topic_health_tool.py:277-287 and test_kafka_consumer_group_tool.py:261-274
Short-circuit doesn't prove broker isn't touched (Copilot #9, #10) not-configured tests now use wraps= to spy on the real integration and assert mock_fn.assert_called_once() — proves the integration is entered but short-circuits before broker contact test_kafka_topic_health_tool.py:289-304 and test_kafka_consumer_group_tool.py:276-293

The latest commit (3f9ae8c7) is a ruff format cleanup only — same content, no review-relevant changes. Local quality gates all green: ruff check, ruff format --check, mypy app/ (456 source files), pytest tests/tools/ (1587 passed).

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

All five concerns are properly resolved. Here's a quick verification against the resolution map:

1. limit forwarding (test_happy_path_forwards_limit_arg): Correctly unpacks call_args and asserts call_kwargs.get("limit") == 5. ✓

2 & 3. SASL-SSL config propagation (both tools): Both tests extract config_arg = mock_fn.call_args[0][0] and assert all four SASL fields on the KafkaConfig object — this is the right approach since it validates the struct being passed to the integration, not just the tool's return value. ✓

4 & 5. Exception propagation (both tools): Switched from returning a fake error dict to side_effect=RuntimeError(...) + pytest.raises(...). This correctly tests that the tool doesn't silently swallow exceptions from the integration layer. ✓

Not-configured short-circuit (both tools): The wraps= spy pattern is the right call here — mock_fn.assert_called_once() proves the integration was entered (no code path bypassed it), while the empty bootstrap_servers guarantees it returned early before any broker I/O. ✓

One minor note on style: the inline __import__(...) in the wraps= argument is a bit unusual — a module-level import aliased as _kafka_integration would be more readable. That said, it's functionally correct and not a blocker.

The test suite is in good shape. All original concerns addressed, exception behavior properly validated, and SASL credential wiring verified at the struct level rather than just the return value. LGTM.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

Copy link
Copy Markdown
Contributor

Copilot AI commented May 4, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • us.i.posthog.com
    • Triggering command: /usr/bin/python3 python3 -m app.analytics.install (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copy link
Copy Markdown
Collaborator

@Devesh36 Devesh36 left a comment

Choose a reason for hiding this comment

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

ran test locally , looks good 👍

@Devesh36 Devesh36 merged commit 321e708 into main May 4, 2026
14 checks passed
@Devesh36 Devesh36 deleted the feat/kafka-tool-tests branch May 4, 2026 15:26
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

🧠 @yashksaini-coder opened a PR. Maintainers feared them. CI genuflected. It merged. 🚨


👋 Join us on Discord - OpenSRE : hang out, contribute, or hunt for features and issues. Everyone's welcome.

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.

Add unit tests for Kafka tools

5 participants