返回 last30days-skill
test_env_cookies.py
根目录 / tests / test_env_cookies.py
1 """Tests for browser cookie extraction integration in env.py."""
2
3 import os
4 from unittest.mock import patch
5
6 import pytest
7
8 from lib.env import ConfigLoadPolicy, extract_browser_credentials, COOKIE_DOMAINS
9
10
11 def _base_config(**overrides):
12 """Return a minimal config dict with common defaults."""
13 cfg = {
14 "AUTH_TOKEN": None,
15 "CT0": None,
16 "TRUTHSOCIAL_TOKEN": None,
17 "FROM_BROWSER": None,
18 "SETUP_COMPLETE": None,
19 }
20 cfg.update(overrides)
21 return cfg
22
23
24 class TestExtractBrowserCredentials:
25 """Unit tests for extract_browser_credentials()."""
26
27 @patch("lib.cookie_extract.extract_cookies")
28 def test_auto_populates_credentials(self, mock_extract):
29 mock_extract.return_value = {"auth_token": "tok123", "ct0": "ct0val"}
30 config = _base_config(FROM_BROWSER="auto")
31 result = extract_browser_credentials(config)
32 assert result["AUTH_TOKEN"] == "tok123"
33 assert result["CT0"] == "ct0val"
34 # auto mode tries firefox first, then safari, then chrome
35 mock_extract.assert_any_call("firefox", ".x.com", ["auth_token", "ct0"])
36
37 @patch("lib.cookie_extract.extract_cookies")
38 def test_explicit_auth_token_skips_x_extraction(self, mock_extract):
39 mock_extract.return_value = None
40 config = _base_config(
41 AUTH_TOKEN="explicit_token", CT0="explicit_ct0",
42 FROM_BROWSER="auto",
43 )
44 result = extract_browser_credentials(config)
45 assert "AUTH_TOKEN" not in result
46 assert "CT0" not in result
47 for call in mock_extract.call_args_list:
48 assert call[0][1] != ".x.com"
49
50 @patch("lib.cookie_extract.extract_cookies")
51 def test_from_browser_off_skips_all(self, mock_extract):
52 config = _base_config(FROM_BROWSER="off")
53 result = extract_browser_credentials(config)
54 assert result == {}
55 mock_extract.assert_not_called()
56
57 @patch("lib.cookie_extract.extract_cookies")
58 def test_no_from_browser_skips_all(self, mock_extract):
59 """Default (no FROM_BROWSER): reads no browser cookies."""
60 mock_extract.return_value = None
61 config = _base_config()
62 result = extract_browser_credentials(config)
63 assert result == {}
64 mock_extract.assert_not_called()
65
66 @patch("lib.cookie_extract.extract_cookies")
67 def test_from_browser_firefox_only(self, mock_extract):
68 mock_extract.return_value = {"auth_token": "ff_tok", "ct0": "ff_ct0"}
69 config = _base_config(FROM_BROWSER="firefox")
70 result = extract_browser_credentials(config)
71 assert result["AUTH_TOKEN"] == "ff_tok"
72 for call in mock_extract.call_args_list:
73 assert call[0][0] == "firefox"
74
75 @patch("lib.cookie_extract.extract_cookies")
76 def test_extraction_returns_none_config_unchanged(self, mock_extract):
77 mock_extract.return_value = None
78 config = _base_config(FROM_BROWSER="auto")
79 result = extract_browser_credentials(config)
80 assert "AUTH_TOKEN" not in result
81 assert "CT0" not in result
82
83 @patch("lib.cookie_extract.extract_cookies")
84 def test_extraction_raises_exception_caught(self, mock_extract):
85 mock_extract.side_effect = RuntimeError("database locked")
86 config = _base_config(FROM_BROWSER="auto")
87 result = extract_browser_credentials(config)
88 assert "AUTH_TOKEN" not in result
89 assert "CT0" not in result
90
91 @patch("lib.cookie_extract.extract_cookies")
92 def test_partial_credentials_only_fills_missing(self, mock_extract):
93 mock_extract.return_value = {"auth_token": "cookie_tok", "ct0": "cookie_ct0"}
94 config = _base_config(
95 AUTH_TOKEN="explicit", CT0=None,
96 FROM_BROWSER="auto",
97 )
98 result = extract_browser_credentials(config)
99 assert "AUTH_TOKEN" not in result
100 assert result["CT0"] == "cookie_ct0"
101
102
103 class TestGetConfigCookieIntegration:
104 """Integration tests for policy-gated cookie extraction in get_config()."""
105
106 @patch("lib.cookie_extract.extract_cookies")
107 @patch("lib.env._find_project_env", return_value=None)
108 @patch("lib.env.load_env_file", return_value={})
109 @patch("lib.env._load_keychain", return_value={})
110 @patch("lib.env.get_openai_auth")
111 def test_get_config_default_does_not_extract_cookies(
112 self, mock_openai, mock_keychain, mock_load, mock_proj, mock_extract
113 ):
114 from lib.env import get_config, OpenAIAuth
115 mock_openai.return_value = OpenAIAuth(
116 token=None, source="none", status="missing",
117 )
118 mock_extract.return_value = {"auth_token": "browser_tok", "ct0": "browser_ct0"}
119 env_patch = {
120 "SETUP_COMPLETE": "true",
121 "FROM_BROWSER": "auto",
122 "LAST30DAYS_CONFIG_DIR": "",
123 }
124 with patch.dict(os.environ, env_patch, clear=False):
125 config = get_config()
126 assert config["AUTH_TOKEN"] is None
127 assert config["CT0"] is None
128 mock_extract.assert_not_called()
129
130 @patch("lib.cookie_extract.extract_cookies")
131 @patch("lib.env._find_project_env", return_value=None)
132 @patch("lib.env.load_env_file", return_value={})
133 @patch("lib.env._load_keychain", return_value={})
134 @patch("lib.env.get_openai_auth")
135 def test_get_config_with_cookie_policy_injects_cookies(
136 self, mock_openai, mock_keychain, mock_load, mock_proj, mock_extract
137 ):
138 from lib.env import get_config, OpenAIAuth
139 mock_openai.return_value = OpenAIAuth(
140 token=None, source="none", status="missing",
141 )
142 mock_extract.return_value = {"auth_token": "browser_tok", "ct0": "browser_ct0"}
143 env_patch = {
144 "SETUP_COMPLETE": "true",
145 "FROM_BROWSER": "auto",
146 "LAST30DAYS_CONFIG_DIR": "",
147 }
148 with patch.dict(os.environ, env_patch, clear=False):
149 config = get_config(policy=ConfigLoadPolicy(browser_cookies="read"))
150 assert config["AUTH_TOKEN"] == "browser_tok"
151 assert config["CT0"] == "browser_ct0"
152
152 lines PYTHON