mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-10-22 18:03:10 +02:00
* feat(cli): crewai deploy push --force, and why AMP held a push back
AMP now holds back a redeploy while a models comparison is running on the
deployment (crewAIInc/crewai-plus#4776): a redeploy restarts the workers
and the comparison loses its runs (pr_security_reviewer, 2026-10-14). It
answers 409 {"error": "comparison_running", "message": ...}.
- `crewai deploy push --force` goes ahead anyway: deploy_by_uuid /
deploy_by_name send {"force": true} and update_crew_from_zip a force field
(crewai-core and the CLI's own copy), only when asked — an unforced push
sends exactly what it always did, and an older AMP ignores the field.
- A push AMP held back prints AMP's sentence (which names --force) and
"Nothing was deployed.", and exits 1 — not the bare error code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(llms): Claude 3.5 Sonnet v2 on Bedrock has a 200k window in the refreshed catalog
The 1.15.28 release refreshed the packaged LiteLLM catalog, which now lists
anthropic.claude-3-5-sonnet-20241022-v2:0 at 200,000 input tokens (it had
1,000,000), the model's documented window. The test still expected 1M, so
every PR's test job failed on main's own catalog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(cli): AMP's hold-back sentence is printed literally
Review on #8150: the comparison_running message went through Rich markup,
so a bracketed word in it vanished and a stray closing tag raised
MarkupError before "Nothing was deployed." could print. It is printed with
markup=False now; a test sends one with both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
572 lines
21 KiB
Python
572 lines
21 KiB
Python
from collections.abc import Callable
|
|
import os
|
|
import unittest
|
|
from unittest.mock import ANY, MagicMock, patch
|
|
|
|
from crewai_cli.plus_api import PlusAPI
|
|
import httpx
|
|
import pytest
|
|
|
|
|
|
_RealHttpxClient = httpx.Client
|
|
|
|
|
|
class TestPlusAPI(unittest.TestCase):
|
|
def setUp(self):
|
|
self.api_key = "test_api_key"
|
|
self.api = PlusAPI(self.api_key)
|
|
self.org_uuid = "test-org-uuid"
|
|
|
|
def test_init(self):
|
|
self.assertEqual(self.api.api_key, self.api_key)
|
|
self.assertEqual(self.api.headers["Authorization"], f"Bearer {self.api_key}")
|
|
self.assertEqual(self.api.headers["Content-Type"], "application/json")
|
|
self.assertIn("CrewAI-CLI/", self.api.headers["User-Agent"])
|
|
self.assertTrue(self.api.headers["X-Crewai-Version"])
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_create_evaluation(self, mock_make_request):
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
|
|
response = self.api.create_evaluation("6f31fe1a-20bd-4bfe-a011-25d6b9341f62")
|
|
|
|
mock_make_request.assert_called_once_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/tracing/evaluations",
|
|
json={"execution_id": "6f31fe1a-20bd-4bfe-a011-25d6b9341f62"},
|
|
timeout=120.0, # AMP reads the run's spans inside this request
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_create_evaluation_files_it_under_the_project(self, mock_make_request):
|
|
self.api.create_evaluation("run-1", eval_config="{}", project_id="proj-1")
|
|
|
|
mock_make_request.assert_called_once_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/tracing/evaluations",
|
|
json={"execution_id": "run-1", "eval_config": "{}", "project_id": "proj-1"},
|
|
timeout=120.0,
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_create_models_evaluation(self, mock_make_request):
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
|
|
response = self.api.create_models_evaluation(
|
|
["openai/gpt-4o-mini", "anthropic/claude-haiku-4-5"],
|
|
project_id="proj-1",
|
|
eval_config="// ours\n{}",
|
|
deployment_id="dep-1",
|
|
)
|
|
|
|
mock_make_request.assert_called_once_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/tracing/evaluations",
|
|
json={
|
|
"kind": "models",
|
|
"project_id": "proj-1",
|
|
"models": ["openai/gpt-4o-mini", "anthropic/claude-haiku-4-5"],
|
|
"eval_config": "// ours\n{}",
|
|
"deployment_id": "dep-1",
|
|
},
|
|
timeout=120.0,
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_create_models_evaluation_sends_only_what_it_was_given(
|
|
self, mock_make_request
|
|
):
|
|
self.api.create_models_evaluation(["openai/gpt-4o-mini"], project_id="proj-1")
|
|
|
|
mock_make_request.assert_called_once_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/tracing/evaluations",
|
|
json={
|
|
"kind": "models",
|
|
"project_id": "proj-1",
|
|
"models": ["openai/gpt-4o-mini"],
|
|
},
|
|
timeout=120.0,
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_get_evaluation(self, mock_make_request):
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
|
|
response = self.api.get_evaluation("ev-1")
|
|
|
|
mock_make_request.assert_called_once_with(
|
|
"GET", "/crewai_plus/api/v1/tracing/evaluations/ev-1", timeout=30.0
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_login_to_tool_repository(self, mock_make_request):
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
|
|
response = self.api.login_to_tool_repository()
|
|
|
|
mock_make_request.assert_called_once_with(
|
|
"POST", "/crewai_plus/api/v1/tools/login", json={}
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
def assert_request_with_org_id(
|
|
self, mock_client_instance, method: str, endpoint: str, **kwargs
|
|
):
|
|
mock_client_instance.request.assert_called_once_with(
|
|
method,
|
|
f"{os.getenv('CREWAI_PLUS_URL')}{endpoint}",
|
|
headers={
|
|
"Authorization": ANY,
|
|
"Content-Type": ANY,
|
|
"User-Agent": ANY,
|
|
"X-Crewai-Version": ANY,
|
|
"X-Crewai-Organization-Id": self.org_uuid,
|
|
},
|
|
**kwargs,
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.Settings")
|
|
@patch("crewai_core.plus_api.httpx.Client")
|
|
def test_login_to_tool_repository_with_org_uuid(
|
|
self, mock_client_class, mock_settings_class
|
|
):
|
|
mock_settings = MagicMock()
|
|
mock_settings.org_uuid = self.org_uuid
|
|
mock_settings.enterprise_base_url = os.getenv('CREWAI_PLUS_URL')
|
|
mock_settings_class.return_value = mock_settings
|
|
self.api = PlusAPI(self.api_key)
|
|
|
|
mock_client_instance = MagicMock()
|
|
mock_response = MagicMock()
|
|
mock_client_instance.request.return_value = mock_response
|
|
mock_client_class.return_value.__enter__.return_value = mock_client_instance
|
|
|
|
response = self.api.login_to_tool_repository()
|
|
|
|
self.assert_request_with_org_id(
|
|
mock_client_instance, "POST", "/crewai_plus/api/v1/tools/login", json={}
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_get_tool(self, mock_make_request):
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
|
|
response = self.api.get_tool("test_tool_handle")
|
|
mock_make_request.assert_called_once_with(
|
|
"GET", "/crewai_plus/api/v1/tools/test_tool_handle"
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.Settings")
|
|
@patch("crewai_core.plus_api.httpx.Client")
|
|
def test_get_tool_with_org_uuid(self, mock_client_class, mock_settings_class):
|
|
mock_settings = MagicMock()
|
|
mock_settings.org_uuid = self.org_uuid
|
|
mock_settings.enterprise_base_url = os.getenv('CREWAI_PLUS_URL')
|
|
mock_settings_class.return_value = mock_settings
|
|
self.api = PlusAPI(self.api_key)
|
|
|
|
mock_client_instance = MagicMock()
|
|
mock_response = MagicMock()
|
|
mock_client_instance.request.return_value = mock_response
|
|
mock_client_class.return_value.__enter__.return_value = mock_client_instance
|
|
|
|
response = self.api.get_tool("test_tool_handle")
|
|
|
|
self.assert_request_with_org_id(
|
|
mock_client_instance, "GET", "/crewai_plus/api/v1/tools/test_tool_handle"
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_publish_tool(self, mock_make_request):
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
handle = "test_tool_handle"
|
|
public = True
|
|
version = "1.0.0"
|
|
description = "Test tool description"
|
|
encoded_file = "encoded_test_file"
|
|
|
|
response = self.api.publish_tool(
|
|
handle, public, version, description, encoded_file
|
|
)
|
|
|
|
params = {
|
|
"handle": handle,
|
|
"public": public,
|
|
"version": version,
|
|
"file": encoded_file,
|
|
"description": description,
|
|
"available_exports": None,
|
|
"tools_metadata": None,
|
|
}
|
|
mock_make_request.assert_called_once_with(
|
|
"POST", "/crewai_plus/api/v1/tools", json=params
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.Settings")
|
|
@patch("crewai_core.plus_api.httpx.Client")
|
|
def test_publish_tool_with_org_uuid(self, mock_client_class, mock_settings_class):
|
|
mock_settings = MagicMock()
|
|
mock_settings.org_uuid = self.org_uuid
|
|
mock_settings.enterprise_base_url = os.getenv('CREWAI_PLUS_URL')
|
|
mock_settings_class.return_value = mock_settings
|
|
self.api = PlusAPI(self.api_key)
|
|
|
|
mock_client_instance = MagicMock()
|
|
mock_response = MagicMock()
|
|
mock_client_instance.request.return_value = mock_response
|
|
mock_client_class.return_value.__enter__.return_value = mock_client_instance
|
|
|
|
handle = "test_tool_handle"
|
|
public = True
|
|
version = "1.0.0"
|
|
description = "Test tool description"
|
|
encoded_file = "encoded_test_file"
|
|
|
|
response = self.api.publish_tool(
|
|
handle, public, version, description, encoded_file
|
|
)
|
|
|
|
expected_params = {
|
|
"handle": handle,
|
|
"public": public,
|
|
"version": version,
|
|
"file": encoded_file,
|
|
"description": description,
|
|
"available_exports": None,
|
|
"tools_metadata": None,
|
|
}
|
|
|
|
self.assert_request_with_org_id(
|
|
mock_client_instance, "POST", "/crewai_plus/api/v1/tools", json=expected_params
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_publish_tool_without_description(self, mock_make_request):
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
handle = "test_tool_handle"
|
|
public = False
|
|
version = "2.0.0"
|
|
description = None
|
|
encoded_file = "encoded_test_file"
|
|
|
|
response = self.api.publish_tool(
|
|
handle, public, version, description, encoded_file
|
|
)
|
|
|
|
params = {
|
|
"handle": handle,
|
|
"public": public,
|
|
"version": version,
|
|
"file": encoded_file,
|
|
"description": description,
|
|
"available_exports": None,
|
|
"tools_metadata": None,
|
|
}
|
|
mock_make_request.assert_called_once_with(
|
|
"POST", "/crewai_plus/api/v1/tools", json=params
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.httpx.Client")
|
|
def test_make_request(self, mock_client_class):
|
|
mock_client_instance = MagicMock()
|
|
mock_response = MagicMock()
|
|
mock_client_instance.request.return_value = mock_response
|
|
mock_client_class.return_value.__enter__.return_value = mock_client_instance
|
|
|
|
response = self.api._make_request("GET", "test_endpoint")
|
|
|
|
mock_client_class.assert_called_once_with(trust_env=False, verify=True)
|
|
mock_client_instance.request.assert_called_once_with(
|
|
"GET", f"{self.api.base_url}/test_endpoint", headers=self.api.headers
|
|
)
|
|
self.assertEqual(response, mock_response)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_deploy_by_name(self, mock_make_request):
|
|
self.api.deploy_by_name("test_project")
|
|
mock_make_request.assert_called_once_with(
|
|
"POST", "/crewai_plus/api/v1/crews/by-name/test_project/deploy"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_deploy_by_uuid(self, mock_make_request):
|
|
self.api.deploy_by_uuid("test_uuid")
|
|
mock_make_request.assert_called_once_with(
|
|
"POST", "/crewai_plus/api/v1/crews/test_uuid/deploy"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_a_forced_push_says_so_and_an_unforced_one_sends_what_it_always_did(self, mock_make_request):
|
|
self.api.deploy_by_uuid("test_uuid", force=True)
|
|
mock_make_request.assert_called_with(
|
|
"POST", "/crewai_plus/api/v1/crews/test_uuid/deploy", json={"force": True}
|
|
)
|
|
self.api.deploy_by_name("test_project", project_id="proj-1", force=True)
|
|
mock_make_request.assert_called_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/crews/by-name/test_project/deploy",
|
|
json={"project_id": "proj-1", "force": True},
|
|
)
|
|
self.api.deploy_by_uuid("test_uuid", force=False)
|
|
mock_make_request.assert_called_with(
|
|
"POST", "/crewai_plus/api/v1/crews/test_uuid/deploy"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_deploy_sends_the_project_id_when_there_is_one(self, mock_make_request):
|
|
self.api.deploy_by_name("test_project", project_id="proj-1")
|
|
mock_make_request.assert_called_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/crews/by-name/test_project/deploy",
|
|
json={"project_id": "proj-1"},
|
|
)
|
|
self.api.deploy_by_uuid("test_uuid", project_id="proj-1")
|
|
mock_make_request.assert_called_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/crews/test_uuid/deploy",
|
|
json={"project_id": "proj-1"},
|
|
)
|
|
|
|
@patch("crewai_cli.plus_api.PlusAPI._make_multipart_request")
|
|
def test_zip_deploys_send_the_project_id_when_there_is_one(
|
|
self, mock_make_multipart_request
|
|
):
|
|
self.api.create_crew_from_zip("/tmp/test.zip", name="c", project_id="proj-1")
|
|
mock_make_multipart_request.assert_called_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/crews/zip",
|
|
zip_file_path="/tmp/test.zip",
|
|
data={"name": "c", "project_id": "proj-1"},
|
|
timeout=300,
|
|
)
|
|
self.api.update_crew_from_zip("u", "/tmp/test.zip", project_id="proj-1")
|
|
mock_make_multipart_request.assert_called_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/crews/u/zip_update",
|
|
zip_file_path="/tmp/test.zip",
|
|
data={"project_id": "proj-1"},
|
|
timeout=300,
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_crew_status_by_name(self, mock_make_request):
|
|
self.api.crew_status_by_name("test_project")
|
|
mock_make_request.assert_called_once_with(
|
|
"GET", "/crewai_plus/api/v1/crews/by-name/test_project/status"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_crew_status_by_uuid(self, mock_make_request):
|
|
self.api.crew_status_by_uuid("test_uuid")
|
|
mock_make_request.assert_called_once_with(
|
|
"GET", "/crewai_plus/api/v1/crews/test_uuid/status"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_crew_by_name(self, mock_make_request):
|
|
self.api.crew_by_name("test_project")
|
|
mock_make_request.assert_called_once_with(
|
|
"GET", "/crewai_plus/api/v1/crews/by-name/test_project/logs/deployment"
|
|
)
|
|
|
|
self.api.crew_by_name("test_project", "custom_log")
|
|
mock_make_request.assert_called_with(
|
|
"GET", "/crewai_plus/api/v1/crews/by-name/test_project/logs/custom_log"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_crew_by_uuid(self, mock_make_request):
|
|
self.api.crew_by_uuid("test_uuid")
|
|
mock_make_request.assert_called_once_with(
|
|
"GET", "/crewai_plus/api/v1/crews/test_uuid/logs/deployment"
|
|
)
|
|
|
|
self.api.crew_by_uuid("test_uuid", "custom_log")
|
|
mock_make_request.assert_called_with(
|
|
"GET", "/crewai_plus/api/v1/crews/test_uuid/logs/custom_log"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_delete_crew_by_name(self, mock_make_request):
|
|
self.api.delete_crew_by_name("test_project")
|
|
mock_make_request.assert_called_once_with(
|
|
"DELETE", "/crewai_plus/api/v1/crews/by-name/test_project"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_delete_crew_by_uuid(self, mock_make_request):
|
|
self.api.delete_crew_by_uuid("test_uuid")
|
|
mock_make_request.assert_called_once_with(
|
|
"DELETE", "/crewai_plus/api/v1/crews/test_uuid"
|
|
)
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_list_crews(self, mock_make_request):
|
|
self.api.list_crews()
|
|
mock_make_request.assert_called_once_with("GET", "/crewai_plus/api/v1/crews")
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_create_crew(self, mock_make_request):
|
|
payload = {"name": "test_crew"}
|
|
self.api.create_crew(payload)
|
|
mock_make_request.assert_called_once_with(
|
|
"POST", "/crewai_plus/api/v1/crews", json=payload
|
|
)
|
|
|
|
@patch("crewai_cli.plus_api.PlusAPI._make_multipart_request")
|
|
def test_create_crew_from_zip(self, mock_make_multipart_request):
|
|
self.api.create_crew_from_zip(
|
|
"/tmp/test.zip",
|
|
name="test_crew",
|
|
env={"ENV_VAR": "value"},
|
|
)
|
|
mock_make_multipart_request.assert_called_once_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/crews/zip",
|
|
zip_file_path="/tmp/test.zip",
|
|
data={"name": "test_crew", "env[ENV_VAR]": "value"},
|
|
timeout=300,
|
|
)
|
|
|
|
@patch("crewai_cli.plus_api.PlusAPI._make_multipart_request")
|
|
def test_update_crew_from_zip(self, mock_make_multipart_request):
|
|
self.api.update_crew_from_zip(
|
|
"test_uuid",
|
|
"/tmp/test.zip",
|
|
env={"ENV_VAR": "value"},
|
|
)
|
|
mock_make_multipart_request.assert_called_once_with(
|
|
"POST",
|
|
"/crewai_plus/api/v1/crews/test_uuid/zip_update",
|
|
zip_file_path="/tmp/test.zip",
|
|
data={"env[ENV_VAR]": "value"},
|
|
timeout=300,
|
|
)
|
|
self.api.update_crew_from_zip("test_uuid", "/tmp/test.zip", force=True)
|
|
assert mock_make_multipart_request.call_args.kwargs["data"] == {"force": "true"}
|
|
|
|
@patch("crewai_core.plus_api.Settings")
|
|
@patch.dict(os.environ, {"CREWAI_PLUS_URL": ""})
|
|
def test_custom_base_url(self, mock_settings_class):
|
|
mock_settings = MagicMock()
|
|
mock_settings.enterprise_base_url = "https://custom-url.com/api"
|
|
mock_settings_class.return_value = mock_settings
|
|
custom_api = PlusAPI("test_key")
|
|
self.assertEqual(
|
|
custom_api.base_url,
|
|
"https://custom-url.com/api",
|
|
)
|
|
|
|
@patch.dict(os.environ, {"CREWAI_PLUS_URL": "https://custom-url-from-env.com"})
|
|
def test_custom_base_url_from_env(self):
|
|
custom_api = PlusAPI("test_key")
|
|
self.assertEqual(
|
|
custom_api.base_url,
|
|
"https://custom-url-from-env.com",
|
|
)
|
|
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
def test_get_agent(mock_make_request):
|
|
api = PlusAPI("test_api_key")
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
|
|
response = api.get_agent("test_agent_handle")
|
|
|
|
mock_make_request.assert_called_once_with(
|
|
"GET", "/crewai_plus/api/v1/agents/test_agent_handle"
|
|
)
|
|
assert response == mock_response
|
|
|
|
|
|
@patch("crewai_core.plus_api.PlusAPI._make_request")
|
|
@patch("crewai_core.plus_api.Settings")
|
|
def test_get_agent_with_org_uuid(mock_settings_class, mock_make_request):
|
|
org_uuid = "test-org-uuid"
|
|
mock_settings = MagicMock()
|
|
mock_settings.org_uuid = org_uuid
|
|
mock_settings.enterprise_base_url = os.getenv("CREWAI_PLUS_URL")
|
|
mock_settings_class.return_value = mock_settings
|
|
|
|
api = PlusAPI("test_api_key")
|
|
|
|
mock_response = MagicMock()
|
|
mock_make_request.return_value = mock_response
|
|
|
|
response = api.get_agent("test_agent_handle")
|
|
|
|
mock_make_request.assert_called_once_with(
|
|
"GET", "/crewai_plus/api/v1/agents/test_agent_handle"
|
|
)
|
|
assert "X-Crewai-Organization-Id" in api.headers
|
|
assert api.headers["X-Crewai-Organization-Id"] == org_uuid
|
|
assert response == mock_response
|
|
|
|
|
|
def _requests_sent_by(call: Callable[[PlusAPI], object]) -> list[httpx.Request]:
|
|
"""Run ``call`` against a PlusAPI whose HTTP client answers locally."""
|
|
sent: list[httpx.Request] = []
|
|
|
|
def answer(request: httpx.Request) -> httpx.Response:
|
|
sent.append(request)
|
|
return httpx.Response(200, json={})
|
|
|
|
transport = httpx.MockTransport(answer)
|
|
with patch(
|
|
"crewai_core.plus_api.httpx.Client",
|
|
side_effect=lambda **kwargs: _RealHttpxClient(transport=transport, **kwargs),
|
|
):
|
|
call(PlusAPI("test_api_key"))
|
|
return sent
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("call", "path"),
|
|
[
|
|
(
|
|
lambda api: api.get_triggers(),
|
|
"/crewai_plus/api/v1/integrations/apps",
|
|
),
|
|
(
|
|
lambda api: api.get_trigger_payload("hubspot", "contact_created"),
|
|
"/crewai_plus/api/v1/integrations/hubspot/contact_created/payload",
|
|
),
|
|
],
|
|
ids=["get_triggers", "get_trigger_payload"],
|
|
)
|
|
def test_trigger_requests_wait_60_seconds_only_for_the_response(call, path):
|
|
(request,) = _requests_sent_by(call)
|
|
|
|
assert request.url.path == path
|
|
assert request.extensions["timeout"] == {
|
|
"connect": 5.0,
|
|
"read": 60.0,
|
|
"write": 5.0,
|
|
"pool": 5.0,
|
|
}
|
|
|
|
|
|
def test_requests_without_their_own_timeout_keep_the_httpx_default():
|
|
(request,) = _requests_sent_by(lambda api: api.get_agent("an_agent"))
|
|
|
|
assert request.url.path == "/crewai_plus/api/v1/agents/an_agent"
|
|
assert request.extensions["timeout"]["read"] == 5.0
|