e178470320
CRITICAL FIX: update.md was telling agents to uninstall bird CLI, which broke users who had working bird installations. Now: - twitter.py: prefers twitter-cli, falls back to bird/birdx if installed - update.md: removed "clean up deprecated tools" step entirely - Added explicit rule: "Never uninstall any existing tools the user already has" - Tests cover twitter-cli primary + bird fallback + preference order 78 tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
109 lines
3.4 KiB
Python
109 lines
3.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from unittest.mock import patch, Mock
|
|
|
|
from agent_reach.channels.twitter import TwitterChannel
|
|
|
|
|
|
def _cp(stdout="", stderr="", returncode=0):
|
|
m = Mock()
|
|
m.stdout = stdout
|
|
m.stderr = stderr
|
|
m.returncode = returncode
|
|
return m
|
|
|
|
|
|
# --- twitter-cli tests ---
|
|
|
|
def test_check_twitter_cli_found_and_auth_ok():
|
|
"""twitter-cli found + twitter status ok → ok."""
|
|
channel = TwitterChannel()
|
|
with patch("shutil.which", side_effect=lambda name: "/usr/local/bin/twitter" if name == "twitter" else None), patch(
|
|
"subprocess.run",
|
|
return_value=_cp(stdout="ok: true\nusername: testuser\n", returncode=0),
|
|
):
|
|
status, message = channel.check()
|
|
assert status == "ok"
|
|
assert "twitter-cli" in message
|
|
assert "完整可用" in message
|
|
|
|
|
|
def test_check_twitter_cli_found_auth_missing():
|
|
"""twitter-cli found + not_authenticated → warn about auth."""
|
|
channel = TwitterChannel()
|
|
with patch("shutil.which", side_effect=lambda name: "/usr/local/bin/twitter" if name == "twitter" else None), patch(
|
|
"subprocess.run",
|
|
return_value=_cp(
|
|
stderr="ok: false\nerror:\n code: not_authenticated\n",
|
|
returncode=1,
|
|
),
|
|
):
|
|
status, message = channel.check()
|
|
assert status == "warn"
|
|
assert "未认证" in message
|
|
|
|
|
|
# --- bird CLI fallback tests ---
|
|
|
|
def test_check_bird_fallback_auth_ok():
|
|
"""No twitter-cli, but bird found + bird check ok → ok."""
|
|
channel = TwitterChannel()
|
|
def which_side_effect(name):
|
|
if name == "bird":
|
|
return "/usr/local/bin/bird"
|
|
return None
|
|
with patch("shutil.which", side_effect=which_side_effect), patch(
|
|
"subprocess.run",
|
|
return_value=_cp(stdout="Authenticated as @user\n", returncode=0),
|
|
):
|
|
status, message = channel.check()
|
|
assert status == "ok"
|
|
assert "bird" in message
|
|
|
|
|
|
def test_check_bird_fallback_auth_missing():
|
|
"""No twitter-cli, bird found but Missing credentials → warn."""
|
|
channel = TwitterChannel()
|
|
def which_side_effect(name):
|
|
if name == "bird":
|
|
return "/usr/local/bin/bird"
|
|
return None
|
|
with patch("shutil.which", side_effect=which_side_effect), patch(
|
|
"subprocess.run",
|
|
return_value=_cp(stderr="Missing credentials\n", returncode=1),
|
|
):
|
|
status, message = channel.check()
|
|
assert status == "warn"
|
|
assert "未配置认证" in message
|
|
|
|
|
|
# --- neither installed ---
|
|
|
|
def test_check_nothing_installed():
|
|
"""Neither twitter-cli nor bird → warn with install hint."""
|
|
channel = TwitterChannel()
|
|
with patch("shutil.which", return_value=None):
|
|
status, message = channel.check()
|
|
assert status == "warn"
|
|
assert "twitter-cli" in message
|
|
|
|
|
|
# --- twitter-cli preferred over bird ---
|
|
|
|
def test_twitter_cli_preferred_over_bird():
|
|
"""When both are installed, twitter-cli is used."""
|
|
channel = TwitterChannel()
|
|
def which_side_effect(name):
|
|
if name == "twitter":
|
|
return "/usr/local/bin/twitter"
|
|
if name == "bird":
|
|
return "/usr/local/bin/bird"
|
|
return None
|
|
with patch("shutil.which", side_effect=which_side_effect), patch(
|
|
"subprocess.run",
|
|
return_value=_cp(stdout="ok: true\n", returncode=0),
|
|
):
|
|
status, message = channel.check()
|
|
assert status == "ok"
|
|
assert "twitter-cli" in message
|