mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-07 15:18:29 +00:00
* fix: normalize project names by stripping trailing slashes in crew creation - Strip trailing slashes from project names in create_folder_structure - Add comprehensive tests for trailing slash scenarios - Fixes #3059 The issue occurred because trailing slashes in project names like 'hello/' were directly incorporated into pyproject.toml, creating invalid package names and script entries. This fix silently normalizes project names by stripping trailing slashes before processing, maintaining backward compatibility while fixing the invalid template generation. Co-Authored-By: João <joao@crewai.com> * trigger CI re-run to check for flaky test issue Co-Authored-By: João <joao@crewai.com> * fix: resolve circular import in CLI authentication module - Move ToolCommand import to be local inside _poll_for_token method - Update test mock to patch ToolCommand at correct location - Resolves Python 3.11 test collection failure in CI Co-Authored-By: João <joao@crewai.com> * feat: add comprehensive class name validation for Python identifiers - Ensure generated class names are always valid Python identifiers - Handle edge cases: names starting with numbers, special characters, keywords, built-ins - Add sanitization logic to remove invalid characters and prefix with 'Crew' when needed - Add comprehensive test coverage for class name validation edge cases - Addresses GitHub PR comment from lucasgomide about class name validity Fixes include: - Names starting with numbers: '123project' -> 'Crew123Project' - Python built-ins: 'True' -> 'TrueCrew', 'False' -> 'FalseCrew' - Special characters: 'hello@world' -> 'HelloWorld' - Empty/whitespace: ' ' -> 'DefaultCrew' - All generated class names pass isidentifier() and keyword checks Co-Authored-By: João <joao@crewai.com> * refactor: change class name validation to raise errors instead of generating defaults - Remove default value generation (Crew prefix/suffix, DefaultCrew fallback) - Raise ValueError with descriptive messages for invalid class names - Update tests to expect validation errors instead of default corrections - Addresses GitHub comment feedback from lucasgomide about strict validation Co-Authored-By: João <joao@crewai.com> * fix: add working directory safety checks to prevent test interference Co-Authored-By: João <joao@crewai.com> * fix: standardize working directory handling in tests to prevent corruption Co-Authored-By: João <joao@crewai.com> * fix: eliminate os.chdir() usage in tests to prevent working directory corruption - Replace os.chdir() with parent_folder parameter for create_folder_structure tests - Mock create_folder_structure directly for create_crew tests to avoid directory changes - All 12 tests now pass locally without working directory corruption - Should resolve the 103 failing tests in Python 3.12 CI Co-Authored-By: João <joao@crewai.com> * fix: remove unused os import to resolve lint failure - Remove unused 'import os' statement from test_create_crew.py - All tests still pass locally after removing unused import - Should resolve F401 lint error in CI Co-Authored-By: João <joao@crewai.com> * feat: add folder name validation for Python module names - Implement validation to ensure folder_name is valid Python identifier - Check that folder names don't start with digits - Validate folder names are not Python keywords - Sanitize invalid characters from folder names - Raise ValueError with descriptive messages for invalid cases - Update tests to validate both folder and class name requirements - Addresses GitHub comment requiring folder names to be valid Python module names Co-Authored-By: João <joao@crewai.com> * fix: correct folder name validation logic to match test expectations - Fix validation regex to catch names starting with invalid characters like '@#/' - Ensure validation properly raises ValueError for cases expected by tests - Maintain support for valid cases like 'my.project/' -> 'myproject' - Address lucasgomide's comment about valid Python module names Co-Authored-By: João <joao@crewai.com> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: João <joao@crewai.com> Co-authored-by: Lucas Gomide <lucaslg200@gmail.com>
104 lines
3.8 KiB
Python
104 lines
3.8 KiB
Python
import unittest
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import requests
|
|
|
|
from crewai.cli.authentication.main import AuthenticationCommand
|
|
|
|
|
|
class TestAuthenticationCommand(unittest.TestCase):
|
|
def setUp(self):
|
|
self.auth_command = AuthenticationCommand()
|
|
|
|
@patch("crewai.cli.authentication.main.requests.post")
|
|
def test_get_device_code(self, mock_post):
|
|
mock_response = MagicMock()
|
|
mock_response.json.return_value = {
|
|
"device_code": "123456",
|
|
"user_code": "ABCDEF",
|
|
"verification_uri_complete": "https://example.com",
|
|
"interval": 5,
|
|
}
|
|
mock_post.return_value = mock_response
|
|
|
|
device_code_data = self.auth_command._get_device_code()
|
|
|
|
self.assertEqual(device_code_data["device_code"], "123456")
|
|
self.assertEqual(device_code_data["user_code"], "ABCDEF")
|
|
self.assertEqual(
|
|
device_code_data["verification_uri_complete"], "https://example.com"
|
|
)
|
|
self.assertEqual(device_code_data["interval"], 5)
|
|
|
|
@patch("crewai.cli.authentication.main.console.print")
|
|
@patch("crewai.cli.authentication.main.webbrowser.open")
|
|
def test_display_auth_instructions(self, mock_open, mock_print):
|
|
device_code_data = {
|
|
"verification_uri_complete": "https://example.com",
|
|
"user_code": "ABCDEF",
|
|
}
|
|
|
|
self.auth_command._display_auth_instructions(device_code_data)
|
|
|
|
mock_print.assert_any_call("1. Navigate to: ", "https://example.com")
|
|
mock_print.assert_any_call("2. Enter the following code: ", "ABCDEF")
|
|
mock_open.assert_called_once_with("https://example.com")
|
|
|
|
@patch("crewai.cli.tools.main.ToolCommand")
|
|
@patch("crewai.cli.authentication.main.requests.post")
|
|
@patch("crewai.cli.authentication.main.validate_token")
|
|
@patch("crewai.cli.authentication.main.console.print")
|
|
def test_poll_for_token_success(
|
|
self, mock_print, mock_validate_token, mock_post, mock_tool
|
|
):
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {
|
|
"id_token": "TOKEN",
|
|
"access_token": "ACCESS_TOKEN",
|
|
}
|
|
mock_post.return_value = mock_response
|
|
|
|
mock_instance = mock_tool.return_value
|
|
mock_instance.login.return_value = None
|
|
|
|
self.auth_command._poll_for_token({"device_code": "123456"})
|
|
|
|
mock_validate_token.assert_called_once_with("TOKEN")
|
|
mock_print.assert_called_once_with(
|
|
"\n[bold green]Welcome to CrewAI Enterprise![/bold green]\n"
|
|
)
|
|
|
|
@patch("crewai.cli.authentication.main.requests.post")
|
|
@patch("crewai.cli.authentication.main.console.print")
|
|
def test_poll_for_token_error(self, mock_print, mock_post):
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 400
|
|
mock_response.json.return_value = {
|
|
"error": "invalid_request",
|
|
"error_description": "Invalid request",
|
|
}
|
|
mock_post.return_value = mock_response
|
|
|
|
with self.assertRaises(requests.HTTPError):
|
|
self.auth_command._poll_for_token({"device_code": "123456"})
|
|
|
|
mock_print.assert_not_called()
|
|
|
|
@patch("crewai.cli.authentication.main.requests.post")
|
|
@patch("crewai.cli.authentication.main.console.print")
|
|
def test_poll_for_token_timeout(self, mock_print, mock_post):
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 400
|
|
mock_response.json.return_value = {
|
|
"error": "authorization_pending",
|
|
"error_description": "Authorization pending",
|
|
}
|
|
mock_post.return_value = mock_response
|
|
|
|
self.auth_command._poll_for_token({"device_code": "123456", "interval": 0.01})
|
|
|
|
mock_print.assert_called_once_with(
|
|
"Timeout: Failed to get the token. Please try again.", style="bold red"
|
|
)
|