-
Notifications
You must be signed in to change notification settings - Fork 4
chore(tests): increase code coverage for low-coverage modules #134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
89292dc
c550e2a
a101022
760202e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,116 @@ | ||||
| """Tests for device-code authentication helpers.""" | ||||
|
|
||||
| import json | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unused import The pipeline reports this import is unused. Remove it to fix the CI failure. Proposed fix-import json📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Actions: Pre-commit[error] 3-3: flake8 F401: 'json' imported but unused 🤖 Prompt for AI Agents |
||||
| from unittest.mock import MagicMock, patch | ||||
| from urllib.error import HTTPError | ||||
|
|
||||
| import pytest | ||||
|
|
||||
| from refactron.core.device_auth import ( | ||||
| DeviceAuthorization, | ||||
| TokenResponse, | ||||
| _normalize_base_url, | ||||
| _post_json, | ||||
| poll_for_token, | ||||
| start_device_authorization, | ||||
| ) | ||||
|
|
||||
|
|
||||
| def test_normalize_base_url(): | ||||
| """Test URL normalization.""" | ||||
| assert _normalize_base_url("https://api.test.com/") == "https://api.test.com" | ||||
| assert _normalize_base_url("https://api.test.com") == "https://api.test.com" | ||||
| assert _normalize_base_url(" https://api.test.com/ ") == "https://api.test.com" | ||||
| assert _normalize_base_url(None) == "" | ||||
|
|
||||
|
|
||||
| @patch("refactron.core.device_auth.urlopen") | ||||
| def test_post_json_success(mock_urlopen): | ||||
| """Test successful JSON POST.""" | ||||
| mock_response = MagicMock() | ||||
| mock_response.read.return_value = b'{"status": "ok"}' | ||||
| mock_response.__enter__.return_value = mock_response | ||||
| mock_urlopen.return_value = mock_response | ||||
|
|
||||
| result = _post_json("https://api.test.com", {"data": "test"}) | ||||
| assert result == {"status": "ok"} | ||||
|
|
||||
|
|
||||
| @patch("refactron.core.device_auth.urlopen") | ||||
| def test_post_json_http_error(mock_urlopen): | ||||
| """Test HTTP error handling in _post_json.""" | ||||
| error_response = MagicMock() | ||||
| error_response.read.return_value = b'{"error": "forbidden"}' | ||||
| mock_error = HTTPError("url", 403, "Forbidden", {}, error_response) | ||||
| mock_urlopen.side_effect = mock_error | ||||
|
|
||||
| result = _post_json("https://api.test.com", {"data": "test"}) | ||||
| assert result == {"error": "forbidden"} | ||||
|
|
||||
|
|
||||
| @patch("refactron.core.device_auth._post_json") | ||||
| def test_start_device_authorization(mock_post): | ||||
| """Test starting device authorization.""" | ||||
| mock_post.return_value = { | ||||
| "device_code": "dev_123", | ||||
| "user_code": "USER-123", | ||||
| "verification_uri": "https://refactron.dev/verify", | ||||
| "expires_in": 900, | ||||
| "interval": 5, | ||||
| } | ||||
|
|
||||
| auth = start_device_authorization() | ||||
| assert isinstance(auth, DeviceAuthorization) | ||||
| assert auth.device_code == "dev_123" | ||||
| assert auth.user_code == "USER-123" | ||||
|
|
||||
|
|
||||
| @patch("refactron.core.device_auth._post_json") | ||||
| def test_start_device_authorization_invalid_response(mock_post): | ||||
| """Test handling of invalid authorization response.""" | ||||
| mock_post.return_value = {"error": "invalid_client"} | ||||
| with pytest.raises(RuntimeError, match="Invalid /oauth/device response"): | ||||
| start_device_authorization() | ||||
|
|
||||
|
|
||||
| @patch("refactron.core.device_auth._post_json") | ||||
| def test_poll_for_token_success(mock_post): | ||||
| """Test successful token polling.""" | ||||
| # First response is pending, second is success | ||||
| mock_post.side_effect = [ | ||||
| {"error": "authorization_pending"}, | ||||
| { | ||||
| "access_token": "token_123", | ||||
| "token_type": "Bearer", | ||||
| "expires_in": 3600, | ||||
| "user": {"email": "test@example.com", "plan": "pro"}, | ||||
| }, | ||||
| ] | ||||
|
|
||||
| # Mock sleep to avoid waiting | ||||
| with patch("time.sleep"): | ||||
| token = poll_for_token("dev_123") | ||||
| assert isinstance(token, TokenResponse) | ||||
| assert token.access_token == "token_123" | ||||
| assert token.email == "test@example.com" | ||||
| assert token.plan == "pro" | ||||
|
Comment on lines
+90
to
+96
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check how poll_for_token handles sleep - look for the function signature and sleep usage
ast-grep --pattern 'def poll_for_token($$$) {
$$$
}'
# Also search for how sleep_fn is defined/used
rg -n "sleep_fn|time\.sleep" --type py -C3Repository: Refactron-ai/Refactron_lib Length of output: 8930 🏁 Script executed: #!/bin/bash
# Check test file structure and imports
head -50 tests/test_device_auth.py
# Check if there's a conftest.py with shared fixtures
find . -name "conftest.py" -type f
# Look for the specific test function
grep -n "def test_poll_for_token_success" tests/test_device_auth.py -A 30Repository: Refactron-ai/Refactron_lib Length of output: 2852 🏁 Script executed: #!/bin/bash
# Check for conftest.py
cat conftest.py 2>/dev/null || echo "No conftest.py at root"
# Check in tests directory
ls -la tests/conftest.py 2>/dev/null || echo "No conftest.py in tests/"
# Look for any module reload or import mechanics
rg -n "reload|importlib" tests/test_device_auth.pyRepository: Refactron-ai/Refactron_lib Length of output: 117 Patch target The function signature has 🧰 Tools🪛 Ruff (0.15.7)[error] 94-94: Possible hardcoded password assigned to: "access_token" (S105) 🤖 Prompt for AI Agents |
||||
|
|
||||
|
|
||||
| @patch("refactron.core.device_auth._post_json") | ||||
| def test_poll_for_token_timeout(mock_post): | ||||
| """Test token polling timeout.""" | ||||
| mock_post.return_value = {"error": "authorization_pending"} | ||||
|
|
||||
| with patch("time.monotonic") as mock_time: | ||||
| # Simulate time passing quickly | ||||
| mock_time.side_effect = [0, 1000] | ||||
| with pytest.raises(RuntimeError, match="Login timed out"): | ||||
| poll_for_token("dev_123", expires_in_seconds=10) | ||||
|
|
||||
|
|
||||
| @patch("refactron.core.device_auth._post_json") | ||||
| def test_poll_for_token_expired(mock_post): | ||||
| """Test token polling with expired code.""" | ||||
| mock_post.return_value = {"error": "expired_token"} | ||||
| with pytest.raises(RuntimeError, match="Device code expired"): | ||||
| poll_for_token("dev_123") | ||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
repo_idcan silently becomeNonedespiteintannotation.At Line 49,
data.get("repo_id")returnsNonewhen missing, which breaks theWorkspaceMapping.repo_id: intcontract and can propagate invalid state.Proposed fix
🤖 Prompt for AI Agents