refactor: move tests folder structure and update pytest commands (#2785)
* refactor: move tests folder to src/backend * chore(Makefile): update pytest commands to run tests from the correct directory paths for unit and integration tests * refactor: update file path in test_custom_component.py The file path in the test_custom_component.py file has been updated to use the correct relative path to the component_multiple_outputs.py file. This change ensures that the test code can access the correct file and improves the reliability of the test.
This commit is contained in:
parent
afdff210b3
commit
0122a50a35
56 changed files with 5 additions and 5 deletions
0
src/backend/tests/integration/__init__.py
Normal file
0
src/backend/tests/integration/__init__.py
Normal file
0
src/backend/tests/integration/astra/__init__.py
Normal file
0
src/backend/tests/integration/astra/__init__.py
Normal file
290
src/backend/tests/integration/astra/test_astra_component.py
Normal file
290
src/backend/tests/integration/astra/test_astra_component.py
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
import os
|
||||
|
||||
from langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions
|
||||
from langflow.components.embeddings.AstraVectorize import AstraVectorizeComponent
|
||||
import pytest
|
||||
from integration.utils import MockEmbeddings, check_env_vars
|
||||
from langchain_core.documents import Document
|
||||
|
||||
# from langflow.components.memories.AstraDBMessageReader import AstraDBMessageReaderComponent
|
||||
# from langflow.components.memories.AstraDBMessageWriter import AstraDBMessageWriterComponent
|
||||
from langflow.components.vectorstores.AstraDB import AstraVectorStoreComponent
|
||||
from langflow.schema.data import Data
|
||||
|
||||
COLLECTION = "test_basic"
|
||||
SEARCH_COLLECTION = "test_search"
|
||||
# MEMORY_COLLECTION = "test_memory"
|
||||
VECTORIZE_COLLECTION = "test_vectorize"
|
||||
VECTORIZE_COLLECTION_OPENAI = "test_vectorize_openai"
|
||||
VECTORIZE_COLLECTION_OPENAI_WITH_AUTH = "test_vectorize_openai_auth"
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def astra_fixture(request):
|
||||
"""
|
||||
Sets up the astra collection and cleans up after
|
||||
"""
|
||||
try:
|
||||
from langchain_astradb import AstraDBVectorStore
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Could not import langchain Astra DB integration package. Please install it with `pip install langchain-astradb`."
|
||||
)
|
||||
|
||||
store = AstraDBVectorStore(
|
||||
collection_name=request.param,
|
||||
embedding=MockEmbeddings(),
|
||||
api_endpoint=os.getenv("ASTRA_DB_API_ENDPOINT"),
|
||||
token=os.getenv("ASTRA_DB_APPLICATION_TOKEN"),
|
||||
)
|
||||
|
||||
yield
|
||||
|
||||
store.delete_collection()
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT"),
|
||||
reason="missing astra env vars",
|
||||
)
|
||||
@pytest.mark.parametrize("astra_fixture", [COLLECTION], indirect=True)
|
||||
def test_astra_setup(astra_fixture):
|
||||
application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN")
|
||||
api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT")
|
||||
embedding = MockEmbeddings()
|
||||
|
||||
component = AstraVectorStoreComponent()
|
||||
component.build(
|
||||
token=application_token,
|
||||
api_endpoint=api_endpoint,
|
||||
collection_name=COLLECTION,
|
||||
embedding=embedding,
|
||||
)
|
||||
component.build_vector_store()
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT"),
|
||||
reason="missing astra env vars",
|
||||
)
|
||||
@pytest.mark.parametrize("astra_fixture", [SEARCH_COLLECTION], indirect=True)
|
||||
def test_astra_embeds_and_search(astra_fixture):
|
||||
application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN")
|
||||
api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT")
|
||||
embedding = MockEmbeddings()
|
||||
|
||||
documents = [Document(page_content="test1"), Document(page_content="test2")]
|
||||
records = [Data.from_document(d) for d in documents]
|
||||
|
||||
component = AstraVectorStoreComponent()
|
||||
component.build(
|
||||
token=application_token,
|
||||
api_endpoint=api_endpoint,
|
||||
collection_name=SEARCH_COLLECTION,
|
||||
embedding=embedding,
|
||||
ingest_data=records,
|
||||
search_input="test1",
|
||||
number_of_results=1,
|
||||
)
|
||||
component.build_vector_store()
|
||||
records = component.search_documents()
|
||||
|
||||
assert len(records) == 1
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT"),
|
||||
reason="missing astra env vars",
|
||||
)
|
||||
def test_astra_vectorize():
|
||||
store = None
|
||||
try:
|
||||
options = {"provider": "nvidia", "modelName": "NV-Embed-QA", "parameters": {}, "authentication": {}}
|
||||
store = AstraDBVectorStore(
|
||||
collection_name=VECTORIZE_COLLECTION,
|
||||
api_endpoint=os.getenv("ASTRA_DB_API_ENDPOINT"),
|
||||
token=os.getenv("ASTRA_DB_APPLICATION_TOKEN"),
|
||||
collection_vector_service_options=CollectionVectorServiceOptions.from_dict(options),
|
||||
)
|
||||
|
||||
application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN")
|
||||
api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT")
|
||||
|
||||
documents = [Document(page_content="test1"), Document(page_content="test2")]
|
||||
records = [Data.from_document(d) for d in documents]
|
||||
|
||||
vectorize = AstraVectorizeComponent()
|
||||
vectorize.build(provider="NVIDIA", model_name="NV-Embed-QA")
|
||||
vectorize_options = vectorize.build_options()
|
||||
|
||||
component = AstraVectorStoreComponent()
|
||||
component.build(
|
||||
token=application_token,
|
||||
api_endpoint=api_endpoint,
|
||||
collection_name=VECTORIZE_COLLECTION,
|
||||
ingest_data=records,
|
||||
embedding=vectorize_options,
|
||||
search_input="test",
|
||||
number_of_results=2,
|
||||
)
|
||||
component.build_vector_store()
|
||||
records = component.search_documents()
|
||||
|
||||
assert len(records) == 2
|
||||
finally:
|
||||
if store is not None:
|
||||
store.delete_collection()
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT", "OPENAI_API_KEY"),
|
||||
reason="missing env vars",
|
||||
)
|
||||
def test_astra_vectorize_with_provider_api_key():
|
||||
"""tests vectorize using an openai api key"""
|
||||
store = None
|
||||
try:
|
||||
application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN")
|
||||
api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT")
|
||||
options = {"provider": "openai", "modelName": "text-embedding-3-small", "parameters": {}, "authentication": {}}
|
||||
store = AstraDBVectorStore(
|
||||
collection_name=VECTORIZE_COLLECTION_OPENAI,
|
||||
api_endpoint=api_endpoint,
|
||||
token=application_token,
|
||||
collection_vector_service_options=CollectionVectorServiceOptions.from_dict(options),
|
||||
collection_embedding_api_key=os.getenv("OPENAI_API_KEY"),
|
||||
)
|
||||
documents = [Document(page_content="test1"), Document(page_content="test2")]
|
||||
records = [Data.from_document(d) for d in documents]
|
||||
|
||||
vectorize = AstraVectorizeComponent()
|
||||
vectorize.build(
|
||||
provider="OpenAI", model_name="text-embedding-3-small", provider_api_key=os.getenv("OPENAI_API_KEY")
|
||||
)
|
||||
vectorize_options = vectorize.build_options()
|
||||
|
||||
component = AstraVectorStoreComponent()
|
||||
component.build(
|
||||
token=application_token,
|
||||
api_endpoint=api_endpoint,
|
||||
collection_name=VECTORIZE_COLLECTION_OPENAI,
|
||||
ingest_data=records,
|
||||
embedding=vectorize_options,
|
||||
search_input="test",
|
||||
)
|
||||
component.build_vector_store()
|
||||
records = component.search_documents()
|
||||
assert len(records) == 2
|
||||
finally:
|
||||
if store is not None:
|
||||
store.delete_collection()
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT", "OPENAI_API_KEY"),
|
||||
reason="missing env vars",
|
||||
)
|
||||
def test_astra_vectorize_passes_authentication():
|
||||
"""tests vectorize using the authentication parameter"""
|
||||
store = None
|
||||
try:
|
||||
application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN")
|
||||
api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT")
|
||||
options = {
|
||||
"provider": "openai",
|
||||
"modelName": "text-embedding-3-small",
|
||||
"parameters": {},
|
||||
"authentication": {"providerKey": "providerKey"},
|
||||
}
|
||||
store = AstraDBVectorStore(
|
||||
collection_name=VECTORIZE_COLLECTION_OPENAI_WITH_AUTH,
|
||||
api_endpoint=api_endpoint,
|
||||
token=application_token,
|
||||
collection_vector_service_options=CollectionVectorServiceOptions.from_dict(options),
|
||||
)
|
||||
documents = [Document(page_content="test1"), Document(page_content="test2")]
|
||||
records = [Data.from_document(d) for d in documents]
|
||||
|
||||
vectorize = AstraVectorizeComponent()
|
||||
vectorize.build(
|
||||
provider="OpenAI", model_name="text-embedding-3-small", authentication={"providerKey": "providerKey"}
|
||||
)
|
||||
vectorize_options = vectorize.build_options()
|
||||
|
||||
component = AstraVectorStoreComponent()
|
||||
component.build(
|
||||
token=application_token,
|
||||
api_endpoint=api_endpoint,
|
||||
collection_name=VECTORIZE_COLLECTION_OPENAI_WITH_AUTH,
|
||||
ingest_data=records,
|
||||
embedding=vectorize_options,
|
||||
search_input="test",
|
||||
)
|
||||
component.build_vector_store()
|
||||
records = component.search_documents()
|
||||
assert len(records) == 2
|
||||
finally:
|
||||
if store is not None:
|
||||
store.delete_collection()
|
||||
|
||||
|
||||
# @pytest.mark.skipif(
|
||||
# not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT"),
|
||||
# reason="missing astra env vars",
|
||||
# )
|
||||
# def test_astra_memory():
|
||||
# application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN")
|
||||
# api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT")
|
||||
|
||||
# writer = AstraDBMessageWriterComponent()
|
||||
# reader = AstraDBMessageReaderComponent()
|
||||
|
||||
# input_value = Data.from_document(
|
||||
# Document(
|
||||
# page_content="memory1",
|
||||
# metadata={"session_id": 1, "sender": "human", "sender_name": "Bob"},
|
||||
# )
|
||||
# )
|
||||
# writer.build(
|
||||
# input_value=input_value,
|
||||
# session_id=1,
|
||||
# token=application_token,
|
||||
# api_endpoint=api_endpoint,
|
||||
# collection_name=MEMORY_COLLECTION,
|
||||
# )
|
||||
|
||||
# # verify reading w/ same session id pulls the same record
|
||||
# records = reader.build(
|
||||
# session_id=1,
|
||||
# token=application_token,
|
||||
# api_endpoint=api_endpoint,
|
||||
# collection_name=MEMORY_COLLECTION,
|
||||
# )
|
||||
# assert len(records) == 1
|
||||
# assert isinstance(records[0], Data)
|
||||
# content = records[0].get_text()
|
||||
# assert content == "memory1"
|
||||
|
||||
# # verify reading w/ different session id does not pull the same record
|
||||
# records = reader.build(
|
||||
# session_id=2,
|
||||
# token=application_token,
|
||||
# api_endpoint=api_endpoint,
|
||||
# collection_name=MEMORY_COLLECTION,
|
||||
# )
|
||||
# assert len(records) == 0
|
||||
|
||||
# # Cleanup store - doing here rather than fixture (see https://github.com/langchain-ai/langchain-datastax/pull/36)
|
||||
# try:
|
||||
# from langchain_astradb import AstraDBVectorStore
|
||||
# except ImportError:
|
||||
# raise ImportError(
|
||||
# "Could not import langchain Astra DB integration package. Please install it with `pip install langchain-astradb`."
|
||||
# )
|
||||
# store = AstraDBVectorStore(
|
||||
# collection_name=MEMORY_COLLECTION,
|
||||
# embedding=MockEmbeddings(),
|
||||
# api_endpoint=api_endpoint,
|
||||
# token=application_token,
|
||||
# )
|
||||
# store.delete_collection()
|
||||
88
src/backend/tests/integration/langflow.py
Normal file
88
src/backend/tests/integration/langflow.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from fastapi import status
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from langflow.graph.schema import RunOutputs
|
||||
from langflow.initial_setup.setup import load_starter_projects
|
||||
from langflow.load import run_flow_from_json
|
||||
|
||||
|
||||
@pytest.mark.api_key_required
|
||||
def test_run_flow_with_caching_success(client: TestClient, starter_project, created_api_key):
|
||||
flow_id = starter_project["id"]
|
||||
headers = {"x-api-key": created_api_key.api_key}
|
||||
payload = {
|
||||
"input_value": "value1",
|
||||
"input_type": "text",
|
||||
"output_type": "text",
|
||||
"tweaks": {"parameter_name": "value"},
|
||||
"stream": False,
|
||||
}
|
||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert "outputs" in data
|
||||
assert "session_id" in data
|
||||
|
||||
|
||||
@pytest.mark.api_key_required
|
||||
def test_run_flow_with_caching_invalid_flow_id(client: TestClient, created_api_key):
|
||||
invalid_flow_id = uuid4()
|
||||
headers = {"x-api-key": created_api_key.api_key}
|
||||
payload = {"input_value": "", "input_type": "text", "output_type": "text", "tweaks": {}, "stream": False}
|
||||
response = client.post(f"/api/v1/run/{invalid_flow_id}", json=payload, headers=headers)
|
||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
data = response.json()
|
||||
assert "detail" in data
|
||||
assert f"Flow identifier {invalid_flow_id} not found" in data["detail"]
|
||||
|
||||
|
||||
@pytest.mark.api_key_required
|
||||
def test_run_flow_with_caching_invalid_input_format(client: TestClient, starter_project, created_api_key):
|
||||
flow_id = starter_project["id"]
|
||||
headers = {"x-api-key": created_api_key.api_key}
|
||||
payload = {"input_value": {"key": "value"}, "input_type": "text", "output_type": "text", "tweaks": {}}
|
||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||
|
||||
|
||||
@pytest.mark.api_key_required
|
||||
def test_run_flow_with_invalid_tweaks(client, starter_project, created_api_key):
|
||||
headers = {"x-api-key": created_api_key.api_key}
|
||||
flow_id = starter_project["id"]
|
||||
payload = {
|
||||
"input_value": "value1",
|
||||
"input_type": "text",
|
||||
"output_type": "text",
|
||||
"tweaks": {"invalid_tweak": "value"},
|
||||
}
|
||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
|
||||
|
||||
@pytest.mark.api_key_required
|
||||
def test_run_with_inputs_and_outputs(client, starter_project, created_api_key):
|
||||
headers = {"x-api-key": created_api_key.api_key}
|
||||
flow_id = starter_project["id"]
|
||||
payload = {
|
||||
"input_value": "value1",
|
||||
"input_type": "text",
|
||||
"output_type": "text",
|
||||
"tweaks": {"parameter_name": "value"},
|
||||
"stream": False,
|
||||
}
|
||||
response = client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers)
|
||||
assert response.status_code == status.HTTP_200_OK, response.text
|
||||
|
||||
|
||||
@pytest.mark.noclient
|
||||
@pytest.mark.api_key_required
|
||||
def test_run_flow_from_json_object():
|
||||
"""Test loading a flow from a json file and applying tweaks"""
|
||||
_, projects = zip(*load_starter_projects())
|
||||
project = [project for project in projects if "Basic Prompting" in project["name"]][0]
|
||||
results = run_flow_from_json(project, input_value="test", fallback_to_env_vars=True)
|
||||
assert results is not None
|
||||
assert all(isinstance(result, RunOutputs) for result in results)
|
||||
35
src/backend/tests/integration/utils.py
Normal file
35
src/backend/tests/integration/utils.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import os
|
||||
from typing import List
|
||||
|
||||
from langflow.field_typing import Embeddings
|
||||
|
||||
|
||||
def check_env_vars(*vars):
|
||||
"""
|
||||
Check if all specified environment variables are set.
|
||||
|
||||
Args:
|
||||
*vars (str): The environment variables to check.
|
||||
|
||||
Returns:
|
||||
bool: True if all environment variables are set, False otherwise.
|
||||
"""
|
||||
return all(os.getenv(var) for var in vars)
|
||||
|
||||
|
||||
class MockEmbeddings(Embeddings):
|
||||
def __init__(self):
|
||||
self.embedded_documents = None
|
||||
self.embedded_query = None
|
||||
|
||||
@staticmethod
|
||||
def mock_embedding(text: str):
|
||||
return [len(text) / 2, len(text) / 5, len(text) / 10]
|
||||
|
||||
def embed_documents(self, texts: List[str]) -> List[List[float]]:
|
||||
self.embedded_documents = texts
|
||||
return [self.mock_embedding(text) for text in texts]
|
||||
|
||||
def embed_query(self, text: str) -> List[float]:
|
||||
self.embedded_query = text
|
||||
return self.mock_embedding(text)
|
||||
Loading…
Add table
Add a link
Reference in a new issue