|
|
import tempfile |
|
|
from pathlib import Path |
|
|
from unittest.mock import ANY, Mock, patch |
|
|
|
|
|
import httpx |
|
|
import pytest |
|
|
import respx |
|
|
from httpx import Response |
|
|
from langflow.components import data |
|
|
|
|
|
|
|
|
@pytest.fixture |
|
|
def api_request(): |
|
|
|
|
|
return data.APIRequestComponent() |
|
|
|
|
|
|
|
|
@respx.mock |
|
|
async def test_successful_get_request(api_request): |
|
|
|
|
|
url = "https://example.com/api/test" |
|
|
method = "GET" |
|
|
mock_response = {"success": True} |
|
|
respx.get(url).mock(return_value=Response(200, json=mock_response)) |
|
|
|
|
|
|
|
|
result = await api_request.make_request( |
|
|
client=httpx.AsyncClient(), |
|
|
method=method, |
|
|
url=url, |
|
|
include_httpx_metadata=True, |
|
|
) |
|
|
|
|
|
|
|
|
assert result.data["status_code"] == 200 |
|
|
assert result.data["result"] == mock_response |
|
|
|
|
|
|
|
|
def test_parse_curl(api_request): |
|
|
|
|
|
field_value = ( |
|
|
"curl -X GET https://example.com/api/test -H 'Content-Type: application/json' -d '{\"key\": \"value\"}'" |
|
|
) |
|
|
build_config = { |
|
|
"method": {"value": ""}, |
|
|
"urls": {"value": []}, |
|
|
"headers": {}, |
|
|
"body": {}, |
|
|
} |
|
|
|
|
|
new_build_config = api_request.parse_curl(field_value, build_config.copy()) |
|
|
|
|
|
|
|
|
assert new_build_config["method"]["value"] == "GET" |
|
|
assert new_build_config["urls"]["value"] == ["https://example.com/api/test"] |
|
|
assert new_build_config["headers"]["value"] == {"Content-Type": "application/json"} |
|
|
assert new_build_config["body"]["value"] == {"key": "value"} |
|
|
|
|
|
|
|
|
@respx.mock |
|
|
async def test_failed_request(api_request): |
|
|
|
|
|
url = "https://example.com/api/test" |
|
|
method = "GET" |
|
|
respx.get(url).mock(return_value=Response(404)) |
|
|
|
|
|
|
|
|
result = await api_request.make_request( |
|
|
client=httpx.AsyncClient(), method=method, url=url, include_httpx_metadata=True |
|
|
) |
|
|
|
|
|
|
|
|
assert result.data["status_code"] == 404 |
|
|
|
|
|
|
|
|
@respx.mock |
|
|
async def test_timeout(api_request): |
|
|
|
|
|
url = "https://example.com/api/timeout" |
|
|
method = "GET" |
|
|
respx.get(url).mock(side_effect=httpx.TimeoutException(message="Timeout", request=None)) |
|
|
|
|
|
|
|
|
result = await api_request.make_request( |
|
|
client=httpx.AsyncClient(), method=method, url=url, timeout=1, include_httpx_metadata=True |
|
|
) |
|
|
|
|
|
|
|
|
assert result.data["status_code"] == 408 |
|
|
assert result.data["error"] == "Request timed out" |
|
|
|
|
|
|
|
|
@respx.mock |
|
|
async def test_build_with_multiple_urls(api_request): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
method = "GET" |
|
|
urls = ["https://example.com/api/one", "https://example.com/api/two"] |
|
|
|
|
|
for url in urls: |
|
|
respx.get(url).mock(return_value=Response(200, json={"success": True})) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
api_request.set_attributes( |
|
|
{ |
|
|
"method": method, |
|
|
"urls": urls, |
|
|
} |
|
|
) |
|
|
results = await api_request.make_requests() |
|
|
|
|
|
|
|
|
assert len(results) == len(urls) |
|
|
|
|
|
|
|
|
@patch("langflow.components.data.directory.parallel_load_data") |
|
|
@patch("langflow.components.data.directory.retrieve_file_paths") |
|
|
@patch("langflow.components.data.DirectoryComponent.resolve_path") |
|
|
def test_directory_component_build_with_multithreading( |
|
|
mock_resolve_path, mock_retrieve_file_paths, mock_parallel_load_data |
|
|
): |
|
|
|
|
|
directory_component = data.DirectoryComponent() |
|
|
path = Path(__file__).resolve().parent |
|
|
depth = 1 |
|
|
max_concurrency = 2 |
|
|
load_hidden = False |
|
|
recursive = True |
|
|
silent_errors = False |
|
|
use_multithreading = True |
|
|
|
|
|
mock_resolve_path.return_value = str(path) |
|
|
|
|
|
mock_retrieve_file_paths.return_value = [str(p) for p in path.iterdir() if p.suffix == ".py"] |
|
|
mock_parallel_load_data.return_value = [Mock()] |
|
|
|
|
|
|
|
|
directory_component.set_attributes( |
|
|
{ |
|
|
"path": str(path), |
|
|
"depth": depth, |
|
|
"max_concurrency": max_concurrency, |
|
|
"load_hidden": load_hidden, |
|
|
"recursive": recursive, |
|
|
"silent_errors": silent_errors, |
|
|
"use_multithreading": use_multithreading, |
|
|
} |
|
|
) |
|
|
directory_component.load_directory() |
|
|
|
|
|
|
|
|
mock_resolve_path.assert_called_once_with(str(path)) |
|
|
mock_retrieve_file_paths.assert_called_once_with( |
|
|
str(path), load_hidden=load_hidden, recursive=recursive, depth=depth, types=ANY |
|
|
) |
|
|
mock_parallel_load_data.assert_called_once_with( |
|
|
mock_retrieve_file_paths.return_value, silent_errors=silent_errors, max_concurrency=max_concurrency |
|
|
) |
|
|
|
|
|
|
|
|
def test_directory_without_mocks(): |
|
|
directory_component = data.DirectoryComponent() |
|
|
|
|
|
with tempfile.TemporaryDirectory() as temp_dir: |
|
|
(Path(temp_dir) / "test.txt").write_text("test", encoding="utf-8") |
|
|
|
|
|
(Path(temp_dir) / "test.json").write_text('{"test": "test"}', encoding="utf-8") |
|
|
|
|
|
directory_component.set_attributes({"path": str(temp_dir), "use_multithreading": False}) |
|
|
results = directory_component.load_directory() |
|
|
assert len(results) == 2 |
|
|
values = ["test", '{"test":"test"}'] |
|
|
assert all(result.text in values for result in results), [ |
|
|
(len(result.text), len(val)) for result, val in zip(results, values, strict=True) |
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
directory_component = data.DirectoryComponent() |
|
|
docs_path = Path(__file__).parent.parent.parent.parent.parent / "docs" / "docs" / "Components" |
|
|
directory_component.set_attributes({"path": str(docs_path), "use_multithreading": False}) |
|
|
results = directory_component.load_directory() |
|
|
docs_files = list(docs_path.glob("*.md")) + list(docs_path.glob("*.json")) |
|
|
assert len(results) == len(docs_files) |
|
|
|
|
|
|
|
|
def test_url_component(): |
|
|
url_component = data.URLComponent() |
|
|
url_component.set_attributes({"urls": ["https://langflow.org"]}) |
|
|
|
|
|
data_ = url_component.fetch_content() |
|
|
assert all(value.data for value in data_) |
|
|
assert all(value.text for value in data_) |
|
|
assert all(value.source for value in data_) |
|
|
|