Skip to content

Conversation

@leavesster
Copy link
Contributor

Summary

Add 15 unit tests for Mainframe callback management:

  • add_report_callback() adds callable and rejects non-callable
  • remove_report_callback() removes existing and logs warning for missing
  • add_session_callback() adds callable, rejects non-callable, subscribes once
  • remove_session_callback() removes existing and unsubscribes on last
  • add_request_response_callback() full lifecycle
  • Multiple callbacks for same session
  • Removing one callback keeps others intact

Problem

Mainframe callback management had only placeholder tests (commented out).

Solution

Created tests/test_mainframe_callbacks.py with mocked MQTT client.

Test Results

Ran 15 tests in 0.044s
OK

Files Added

  • tests/test_mainframe_callbacks.py (159 lines)

- Test add/remove for report, session, and request_response callbacks
- Test non-callable rejection with ValueError
- Test subscription/unsubscription lifecycle
- Test multiple callbacks for same session
- Test removing one callback keeps others intact
Copilot AI review requested due to automatic review settings January 31, 2026 09:29
@coderabbitai
Copy link

coderabbitai bot commented Jan 31, 2026

Warning

Rate limit exceeded

@leavesster has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 37 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
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

Adds a new unit test suite to cover Mainframe callback registration/removal behavior without requiring a real MQTT broker.

Changes:

  • Introduces 15 unittest cases validating callback add/remove flows for report, session, and request/response callbacks.
  • Uses a mocked MQTT client to verify subscription/unsubscription interactions.

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

@@ -0,0 +1,159 @@
import unittest
from unittest.mock import Mock, MagicMock, patch
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

patch is imported but never used. If the project runs any linting/static checks, this will fail; even without linting it adds noise. Remove the unused import (or use it in the tests if intended).

Suggested change
from unittest.mock import Mock, MagicMock, patch
from unittest.mock import Mock, MagicMock

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +45
def test_remove_report_callback_logs_warning_for_missing(self):
"""Test remove_report_callback logs warning for non-existent callback."""
callback = Mock()
# Should not raise, just log warning
self.mainframe.remove_report_callback(callback)

Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

test_remove_report_callback_logs_warning_for_missing currently has no assertion that a warning was logged, so it can pass even if logging is removed or the code logs at a different level. If the intent is to verify the warning behavior, assert it explicitly (e.g., via assertLogs on the module logger or by patching self.mainframe._logger.warning).

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +94
self.mainframe.remove_session_callback(session_id, callback)
self.mock_mqtt_client.unsubscribe.assert_called_once()

Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

These unsubscribe assertions only check the call count (assert_called_once()), not that the correct topic was unsubscribed. Since Mainframe.unsubscribe() passes a topic argument, this test should assert the expected argument(s) (and ideally also assert message_callback_remove was called with the same topic) to avoid false positives.

Suggested change
self.mainframe.remove_session_callback(session_id, callback)
self.mock_mqtt_client.unsubscribe.assert_called_once()
self.mainframe.remove_session_callback(session_id, callback)
# Ensure unsubscribe and message_callback_remove are each called once
self.mock_mqtt_client.unsubscribe.assert_called_once()
self.mock_mqtt_client.message_callback_remove.assert_called_once()
# Ensure both operations use the same topic argument
unsubscribe_args, _ = self.mock_mqtt_client.unsubscribe.call_args
remove_args, _ = self.mock_mqtt_client.message_callback_remove.call_args
self.assertGreaterEqual(len(unsubscribe_args), 1)
self.assertGreaterEqual(len(remove_args), 1)
self.assertEqual(unsubscribe_args[0], remove_args[0])

Copilot uses AI. Check for mistakes.
self.mock_mqtt_client.reset_mock()

self.mainframe.remove_request_response_callback(session_id, request_id, callback)
self.mock_mqtt_client.unsubscribe.assert_called_once()
Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

Same issue here: assert_called_once() doesn’t verify which topic was unsubscribed. Consider asserting unsubscribe/message_callback_remove were called with f"session/{session_id}/request/{request_id}/response" so the test actually validates the request/response lifecycle behavior.

Suggested change
self.mock_mqtt_client.unsubscribe.assert_called_once()
self.mock_mqtt_client.unsubscribe.assert_called_once_with(
f"session/{session_id}/request/{request_id}/response"
)

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +26
# Internal check - callback should be in the set
self.assertIn(callback, self.mainframe._Mainframe__report_callbacks)

Copy link

Copilot AI Jan 31, 2026

Choose a reason for hiding this comment

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

These tests assert internal state via name-mangled private attributes (e.g. _Mainframe__session_callbacks). This couples the tests to implementation details and will break on refactors (rename, type change, etc.). Prefer asserting externally observable behavior (e.g. message_callback_add/subscribe/unsubscribe calls and callback invocation), or add a small public/intended-for-testing accessor on Mainframe if state inspection is required.

Copilot uses AI. Check for mistakes.
@leavesster leavesster changed the title test: add comprehensive tests for Mainframe callback management test(oocana): add comprehensive tests for Mainframe callback management Jan 31, 2026
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