Skip to content

test: add direct unit tests for _start_input_reader_thread (#1056)#1057

Open
microsasa wants to merge 6 commits intomainfrom
add-start-input-reader-thread-tests-1056-db8f5823463fa346
Open

test: add direct unit tests for _start_input_reader_thread (#1056)#1057
microsasa wants to merge 6 commits intomainfrom
add-start-input-reader-thread-tests-1056-db8f5823463fa346

Conversation

@microsasa
Copy link
Copy Markdown
Owner

Closes #1056

Summary

Adds TestStartInputReaderThread class in tests/copilot_usage/test_cli.py with five isolated unit tests for _start_input_reader_thread:

Test What it asserts
test_thread_is_daemon Thread is created with daemon=True — regression guard for the CI hang from issue #1012
test_normal_input_is_stripped_and_queued Happy path: stripped user input lands on the queue, then EOF sentinel
test_eoferror_puts_fallback_sentinel EOFError_FALLBACK_EOF on queue
test_keyboard_interrupt_puts_fallback_sentinel KeyboardInterrupt_FALLBACK_EOF on queue (previously untested at any level)
test_unexpected_exception_puts_fallback_and_logs_warning Unexpected RuntimeError_FALLBACK_EOF + logger.warning called

Approach

  • Tests monkeypatch builtins.input to inject specific behaviors
  • Daemon-flag test spies on threading.Thread.__init__ to capture daemon before the thread starts
  • All tests drain the queue with a 2s timeout to avoid hanging if the contract is broken

Warning

⚠️ Firewall blocked 2 domains

The following domains were blocked by the firewall during workflow execution:

  • astral.sh
  • pypi.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "astral.sh"
    - "pypi.org"

See Network Configuration for more information.

Generated by Issue Implementer · ● 11M ·

Add TestStartInputReaderThread class with five isolated tests:
- daemon flag assertion (regression guard for issue #1012)
- normal input stripped and queued
- EOFError → _FALLBACK_EOF sentinel
- KeyboardInterrupt → _FALLBACK_EOF sentinel (previously untested)
- unexpected exception → _FALLBACK_EOF + warning logged

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 22, 2026 20:40
@microsasa microsasa added the aw Created by agentic workflow label Apr 22, 2026
@microsasa microsasa enabled auto-merge April 22, 2026 20:40
Copy link
Copy Markdown

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 direct unit-test coverage for the interactive-mode fallback input reader thread to prevent regressions like the prior CI hang and to validate sentinel + logging behavior across error paths.

Changes:

  • Adds a new TestStartInputReaderThread test class with five focused unit tests for _start_input_reader_thread.
  • Verifies the thread is created as daemon=True, and validates queue behavior for normal input, EOFError, KeyboardInterrupt, and unexpected exceptions (including logger.warning).

Comment thread tests/copilot_usage/test_cli.py Outdated
Comment on lines +2206 to +2213
inputs = iter([" hello ", EOFError()])

def _fake_input() -> str:
val = next(inputs)
if isinstance(val, BaseException):
raise val
return val # type: ignore[return-value]

Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

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

_fake_input() needs a # type: ignore[return-value] because inputs is untyped; in strict typing it’s better to type inputs as an iterator/iterable of str | BaseException (or similar) so pyright can narrow after the isinstance(..., BaseException) check and the ignore can be removed.

Copilot uses AI. Check for mistakes.
@microsasa microsasa added the aw-ci-fix-attempted CI fixer has attempted to fix CI label Apr 22, 2026
- Collapse two EOFError monkeypatch.setattr calls to single lines
  (exactly 88 chars, within ruff format line-length limit)
- Remove unnecessary `# type: ignore[return-value]` (isinstance
  already narrows val to str)
- Add `assert warn_spy.call_args is not None` guard before accessing
  .args to satisfy pyright reportOptionalMemberAccess

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: cb6d2d6

Generated by CI Fixer

@microsasa
Copy link
Copy Markdown
Owner Author

CI Fix Applied

Fixed three issues causing CI failures:

  1. ruff format: Collapsed two multi-line monkeypatch.setattr calls (EOFError pattern) to single lines — they fit exactly at the 88-char limit, so the formatter expects them on one line without a magic trailing comma.

  2. pyright reportUnnecessaryTypeIgnoreComment: Removed # type: ignore[return-value] from _fake_input() — the isinstance(val, BaseException) guard already narrows val to str, making the suppress unnecessary.

  3. pyright reportOptionalMemberAccess: Added assert warn_spy.call_args is not None before accessing .args[0], since MagicMock.call_args is typed as _Call | None.

Warning

⚠️ Firewall blocked 2 domains

The following domains were blocked by the firewall during workflow execution:

  • pypi.org
  • releaseassets.githubusercontent.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pypi.org"
    - "releaseassets.githubusercontent.com"

See Network Configuration for more information.

Generated by CI Fixer · ● 15.2M ·

@microsasa
Copy link
Copy Markdown
Owner Author

❌ Pipeline orchestrator: CI still failing after ci-fixer attempt. Marking as stuck for human review.

@microsasa
Copy link
Copy Markdown
Owner Author

CI fix already attempted once — stopping to prevent loops. Manual intervention needed.

Generated by CI Fixer · ● 371.2K ·

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 23, 2026 05:27
@microsasa microsasa removed aw-pr-stuck:ci aw-ci-fix-attempted CI fixer has attempted to fix CI labels Apr 23, 2026
@microsasa
Copy link
Copy Markdown
Owner Author

Manual unstick: applied ruff format/ruff check --fix locally, CI should now pass. Stripped aw-pr-stuck:ci + aw-ci-fix-attempted so the pipeline can resume if another round is needed.

@microsasa microsasa added the aw-review-response-1 Review response round 1 label Apr 23, 2026
Copy link
Copy Markdown

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread tests/copilot_usage/test_cli.py Outdated
Comment on lines +2184 to +2192
captured_daemon: list[bool] = []
_real_thread_init = threading.Thread.__init__

def _spy_init(self_thread: threading.Thread, *args: Any, **kwargs: Any) -> None:
_real_thread_init(self_thread, *args, **kwargs)
if self_thread.name == "input-fallback":
captured_daemon.append(self_thread.daemon)

monkeypatch.setattr(threading.Thread, "__init__", _spy_init)
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

test_thread_is_daemon monkeypatches threading.Thread.__init__ globally and filters by self_thread.name == "input-fallback", which makes the test more brittle (e.g., if the thread name changes) and can potentially affect other threads created during the test. Prefer patching the constructor in the module under test (e.g. copilot_usage.cli.threading.Thread) or wrapping threading.Thread to capture the daemon kwarg directly, avoiding reliance on the thread name and minimizing global side effects.

Suggested change
captured_daemon: list[bool] = []
_real_thread_init = threading.Thread.__init__
def _spy_init(self_thread: threading.Thread, *args: Any, **kwargs: Any) -> None:
_real_thread_init(self_thread, *args, **kwargs)
if self_thread.name == "input-fallback":
captured_daemon.append(self_thread.daemon)
monkeypatch.setattr(threading.Thread, "__init__", _spy_init)
captured_daemon: list[bool | None] = []
_real_thread = threading.Thread
def _spy_thread(*args: Any, **kwargs: Any) -> threading.Thread:
captured_daemon.append(kwargs.get("daemon"))
return _real_thread(*args, **kwargs)
monkeypatch.setattr("copilot_usage.cli.threading.Thread", _spy_thread)

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: fc17c8a

Generated by Review Responder

@microsasa microsasa added the aw-ci-fix-attempted CI fixer has attempted to fix CI label Apr 23, 2026
The annotated iter() expression fits within 88 chars (79 + 8 indent = 87),
so ruff format expects it on a single line without a trailing comma.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: 3240f3e

Generated by CI Fixer

Copilot AI review requested due to automatic review settings April 23, 2026 05:46
@microsasa
Copy link
Copy Markdown
Owner Author

CI Fix Applied

ruff format: Collapsed the multi-line iter() expression in test_normal_input_is_stripped_and_queued to a single line — the annotated assignment fits within 88 chars (79 content + 8 indent = 87), so the formatter expects it unsplit.

Warning

⚠️ Firewall blocked 2 domains

The following domains were blocked by the firewall during workflow execution:

  • astral.sh
  • pypi.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "astral.sh"
    - "pypi.org"

See Network Configuration for more information.

Generated by CI Fixer · ● 10.1M ·

Copy link
Copy Markdown

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

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@microsasa
Copy link
Copy Markdown
Owner Author

CI fix already attempted once — stopping to prevent loops. Manual intervention needed.

Generated by CI Fixer · ● 376.4K ·

Refactor test_thread_is_daemon to patch copilot_usage.cli.threading.Thread
instead of globally patching threading.Thread.__init__. This avoids reliance
on the thread name for filtering and minimizes global side effects.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: a4f9b81

Generated by Review Responder

@microsasa microsasa added aw-review-response-3 Review response round 3 aw-review-response-4 Responder dispatch round 4 (orchestrator-managed) aw-review-response-5 Responder dispatch round 5 (orchestrator-managed) aw-pr-stuck:review labels Apr 23, 2026
@microsasa
Copy link
Copy Markdown
Owner Author

❌ Pipeline orchestrator: review-response loop reached 5 rounds. Marking as stuck for human review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

aw Created by agentic workflow aw-ci-fix-attempted CI fixer has attempted to fix CI aw-pr-stuck:review aw-review-response-1 Review response round 1 aw-review-response-2 Review response round 2 aw-review-response-3 Review response round 3 aw-review-response-4 Responder dispatch round 4 (orchestrator-managed) aw-review-response-5 Responder dispatch round 5 (orchestrator-managed)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[aw][test audit] _start_input_reader_thread lacks direct unit tests for daemon flag and KeyboardInterrupt path

2 participants