Skip to content

Stabilize lock bypass tests in lightweight backend env#7789

Open
tianmind-studio wants to merge 2 commits into
BasedHardware:mainfrom
tianmind-studio:codex/lock-bypass-test-lightweight-stubs
Open

Stabilize lock bypass tests in lightweight backend env#7789
tianmind-studio wants to merge 2 commits into
BasedHardware:mainfrom
tianmind-studio:codex/lock-bypass-test-lightweight-stubs

Conversation

@tianmind-studio

@tianmind-studio tianmind-studio commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add lightweight stubs for optional transitive dependencies imported by the lock bypass regression test file.
  • Provide a tiny LangChain @tool stand-in so .invoke(...) tests still exercise the wrapped tool functions, including non-dict positional input.
  • Provide a minimal pytz stand-in with .localize(...) and datetime.now(tz) support so scheduled-summary tests keep exercising timezone-aware code paths.
  • Update the stale goal suggestion mock to patch get_llm, and keep scheduled summary tests focused on locked-conversation filtering.

Why

On a minimal Windows backend setup, tests/unit/test_lock_bypass_fixes.py could fail during import or branch into unrelated paywall/duplicate-summary guards before reaching the lock filtering assertions. These changes make the file runnable without installing optional audio, LLM, Deepgram, Twilio, and related SDKs while keeping the relevant test paths faithful enough to exercise the intended behavior.

Testing

  • python -m pytest tests\unit\test_lock_bypass_fixes.py -q -> 57 passed, 23 warnings
  • python -m black --line-length 120 --skip-string-normalization tests\unit\test_lock_bypass_fixes.py --check
  • python -m py_compile tests\unit\test_lock_bypass_fixes.py
  • git diff --check -- backend/tests/unit/test_lock_bypass_fixes.py

@greptile-apps

greptile-apps Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes tests/unit/test_lock_bypass_fixes.py runnable on minimal Windows backend setups by stub-inserting ~30 optional transitive dependencies (anthropic, av, deepgram, twilio, langchain_core, etc.) into sys.modules before any application code is imported.

  • A tiny _ToolWrapper / _tool decorator stand-in is added so @tool-decorated functions can still be exercised via .invoke(...) without installing langchain_core.
  • Two scheduled-summary tests gain required patches (is_trial_paywalled, get_daily_summary_by_date) that the production code checks before reaching the lock-filtering assertion, preventing silent early returns.
  • The TestSuggestGoalLockFilter mock is corrected from the removed llm_mini module-level variable to the get_llm function actually used in goals.py.

Confidence Score: 4/5

Safe to merge; all changes are test-only and do not touch production code paths.

The stub additions and mock corrections are well-targeted and the lock-filtering assertions remain valid. The pytz.timezone = ZoneInfo substitution causes the timezone-aware branch in _send_summary_notification to silently fall back to the UTC path during every summary test, so that branch is never actually exercised. The _ToolWrapper.invoke helper also only handles dict inputs and would fail unexpectedly for string inputs. Neither issue invalidates the current passing assertions, but both reduce test fidelity.

backend/tests/unit/test_lock_bypass_fixes.py — the pytz stub and _ToolWrapper.invoke edge case are worth a follow-up.

Important Files Changed

Filename Overview
backend/tests/unit/test_lock_bypass_fixes.py Adds lightweight stubs for ~30 optional dependencies so the lock-bypass regression suite runs without optional SDKs; introduces a minimal LangChain @tool stand-in (_ToolWrapper), patches pytz.timezone with ZoneInfo (silently breaks the timezone-aware code path via missing localize()), and corrects the goal-suggestion mock from llm_mini to get_llm.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[pytest collects test file] --> B[Stub injection: 30+ optional deps into sys.modules]
    B --> C[Concrete overrides: ZoneInfo for pytz.timezone, _tool wrapper]
    C --> D[Test class executes]
    D --> E{Daily summary test?}
    E -->|Yes| F[Patch is_trial_paywalled, try_acquire_daily_summary_lock, get_daily_summary_by_date]
    F --> G[_send_summary_notification called with UTC tz arg]
    G --> H[ZoneInfo.localize raises AttributeError]
    H -->|caught silently| I[Falls back to UTC date window]
    I --> J[Filter conversations by is_locked]
    J --> K[Assert LLM called only with unlocked conversations]
    E -->|No| L[Other lock bypass assertions: suggest_goal, MCP endpoints, routers]
Loading

Reviews (1): Last reviewed commit: "test(backend): stub optional deps for lo..." | Re-trigger Greptile

Comment on lines +147 to +148
sys.modules['pytz'].timezone = ZoneInfo
sys.modules['pytz'].utc = timezone.utc

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 ZoneInfo lacks localize(), silently falling back to UTC path in all tests

sys.modules['pytz'].timezone = ZoneInfo means _send_summary_notification executes ZoneInfo('UTC').localize(datetime.combine(...)), which raises AttributeError because ZoneInfo objects don't have a localize method. This error is silently caught by the try/except Exception block in _send_summary_notification, causing both summary tests to exercise the UTC fallback path rather than the timezone-aware branch. The lock-filtering assertions still pass, but the test never actually exercises the pytz.timezone-based date window calculation. A simple alternative is to use a minimal localize-aware wrapper if the timezone-aware path is meant to be covered.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 8301e85d5. The pytz stand-in is now _PytzZoneInfo, a minimal tzinfo wrapper around ZoneInfo/fixed offsets that supports .localize(...) and datetime.now(tz), so the summary tests exercise the timezone-aware path instead of falling through to UTC via AttributeError.

Revalidated on the Windows backend venv:

  • python -m pytest tests\unit\test_lock_bypass_fixes.py -q -> 57 passed
  • python -m black --line-length 120 --skip-string-normalization tests\unit\test_lock_bypass_fixes.py --check
  • python -m py_compile tests\unit\test_lock_bypass_fixes.py

Comment on lines +42 to +46
def invoke(self, args=None, config=None):
kwargs = dict(args or {})
if config is not None:
kwargs['config'] = config
return self.fn(**kwargs)

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 _ToolWrapper.invoke silently breaks for non-dict inputs

dict(args or {}) works when args is a dict, but raises ValueError if args is a plain string (e.g. tool.invoke("my_input")). The real LangChain StructuredTool.invoke accepts Union[str, dict] as input, so any future test that calls a stubbed @tool function with a string argument will get a confusing error pointing inside _ToolWrapper rather than at the failing test. Adding an isinstance(args, dict) branch would make the stub more robust.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 8301e85d5. _ToolWrapper.invoke now branches on non-dict input and forwards it as a positional argument, matching the stubbed LangChain tool use case instead of trying dict(args). I also added a regression check that wrapped.invoke('hello') == 'hello'.

Revalidated on the Windows backend venv:

  • python -m pytest tests\unit\test_lock_bypass_fixes.py -q -> 57 passed
  • python -m black --line-length 120 --skip-string-normalization tests\unit\test_lock_bypass_fixes.py --check
  • python -m py_compile tests\unit\test_lock_bypass_fixes.py

@tianmind-studio tianmind-studio left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The current head includes the stub-fidelity follow-up: the pytz stand-in now supports .localize(...) and datetime.now(tz), and the LangChain tool wrapper handles non-dict positional input. I updated the PR description to make that clear.

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.

1 participant