Skip to content

Commit 7c2cf97

Browse files
committed
Add langchain standard integration tests
1 parent 9b7c35c commit 7c2cf97

File tree

5 files changed

+1121
-203
lines changed

5 files changed

+1121
-203
lines changed

langchain/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dev = [
3434
"mypy>=1.13.0",
3535
"pytest>=8.3.3",
3636
"ruff>=0.9.0,<0.10",
37+
"langchain-tests>=0.3.20",
3738
]
3839

3940
[tool.ruff.lint]

langchain/tests/conftest.py

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import json
2+
import logging
3+
import os
4+
import time
5+
from collections.abc import Iterator
6+
from pathlib import Path
7+
from typing import Literal
8+
9+
import pytest
10+
import urllib3
11+
import vectorize_client as v
12+
from urllib3.exceptions import HTTPError
13+
from vectorize_client import ApiClient, RetrieveDocumentsRequest
14+
15+
16+
@pytest.fixture(scope="session")
17+
def api_token() -> str:
18+
token = os.getenv("VECTORIZE_TOKEN")
19+
if not token:
20+
msg = "Please set the VECTORIZE_TOKEN environment variable"
21+
raise ValueError(msg)
22+
return token
23+
24+
25+
@pytest.fixture(scope="session")
26+
def org_id() -> str:
27+
org = os.getenv("VECTORIZE_ORG")
28+
if not org:
29+
msg = "Please set the VECTORIZE_ORG environment variable"
30+
raise ValueError(msg)
31+
return org
32+
33+
34+
@pytest.fixture(scope="session")
35+
def environment() -> Literal["prod", "dev", "local", "staging"]:
36+
env = os.getenv("VECTORIZE_ENV", "prod")
37+
if env not in ["prod", "dev", "local", "staging"]:
38+
msg = "Invalid VECTORIZE_ENV environment variable."
39+
raise ValueError(msg)
40+
return env
41+
42+
43+
@pytest.fixture(scope="session")
44+
def api_client(api_token: str, environment: str) -> Iterator[ApiClient]:
45+
header_name = None
46+
header_value = None
47+
if environment == "prod":
48+
host = "https://api.vectorize.io/v1"
49+
elif environment == "dev":
50+
host = "https://api-dev.vectorize.io/v1"
51+
elif environment == "local":
52+
host = "http://localhost:3000/api"
53+
header_name = "x-lambda-api-key"
54+
header_value = api_token
55+
else:
56+
host = "https://api-staging.vectorize.io/v1"
57+
58+
with v.ApiClient(
59+
v.Configuration(host=host, access_token=api_token, debug=True),
60+
header_name,
61+
header_value,
62+
) as api:
63+
yield api
64+
65+
66+
@pytest.fixture(scope="session")
67+
def pipeline_id(api_client: v.ApiClient, org_id: str) -> Iterator[str]:
68+
pipelines = v.PipelinesApi(api_client)
69+
70+
connectors_api = v.SourceConnectorsApi(api_client)
71+
response = connectors_api.create_source_connector(
72+
org_id,
73+
v.CreateSourceConnectorRequest(
74+
v.FileUpload(name="from api", type="FILE_UPLOAD")
75+
),
76+
)
77+
source_connector_id = response.connector.id
78+
logging.info("Created source connector %s", source_connector_id)
79+
80+
uploads_api = v.UploadsApi(api_client)
81+
upload_response = uploads_api.start_file_upload_to_connector(
82+
org_id,
83+
source_connector_id,
84+
v.StartFileUploadToConnectorRequest(
85+
name="research.pdf",
86+
content_type="application/pdf",
87+
metadata=json.dumps({"created-from-api": True}),
88+
),
89+
)
90+
91+
http = urllib3.PoolManager()
92+
this_dir = Path(__file__).parent
93+
file_path = this_dir / "research.pdf"
94+
95+
with file_path.open("rb") as f:
96+
http_response = http.request(
97+
"PUT",
98+
upload_response.upload_url,
99+
body=f,
100+
headers={
101+
"Content-Type": "application/pdf",
102+
"Content-Length": str(file_path.stat().st_size),
103+
},
104+
)
105+
if http_response.status != 200:
106+
msg = "Upload failed:"
107+
raise ValueError(msg)
108+
else:
109+
logging.info("Upload successful")
110+
111+
ai_platforms = v.AIPlatformConnectorsApi(api_client).get_ai_platform_connectors(
112+
org_id
113+
)
114+
builtin_ai_platform = next(
115+
c.id for c in ai_platforms.ai_platform_connectors if c.type == "VECTORIZE"
116+
)
117+
logging.info("Using AI platform %s", builtin_ai_platform)
118+
119+
vector_databases = v.DestinationConnectorsApi(
120+
api_client
121+
).get_destination_connectors(org_id)
122+
builtin_vector_db = next(
123+
c.id for c in vector_databases.destination_connectors if c.type == "VECTORIZE"
124+
)
125+
logging.info("Using destination connector %s", builtin_vector_db)
126+
127+
pipeline_response = pipelines.create_pipeline(
128+
org_id,
129+
v.PipelineConfigurationSchema(
130+
source_connectors=[
131+
v.PipelineSourceConnectorSchema(
132+
id=source_connector_id,
133+
type=v.SourceConnectorType.FILE_UPLOAD,
134+
config={},
135+
)
136+
],
137+
destination_connector=v.PipelineDestinationConnectorSchema(
138+
id=builtin_vector_db,
139+
type="VECTORIZE",
140+
config={},
141+
),
142+
ai_platform_connector=v.PipelineAIPlatformConnectorSchema(
143+
id=builtin_ai_platform,
144+
type="VECTORIZE",
145+
config={},
146+
),
147+
pipeline_name="Test pipeline",
148+
schedule=v.ScheduleSchema(type="manual"),
149+
),
150+
)
151+
pipeline_id = pipeline_response.data.id
152+
logging.info("Created pipeline %s", pipeline_id)
153+
154+
yield pipeline_id
155+
156+
try:
157+
pipelines.delete_pipeline(org_id, pipeline_id)
158+
except Exception:
159+
logging.exception("Failed to delete pipeline %s", pipeline_id)
160+
161+
# Wait for the pipeline to be created
162+
request = RetrieveDocumentsRequest(
163+
question="query",
164+
num_results=2,
165+
)
166+
start = time.time()
167+
while True:
168+
try:
169+
response = pipelines.retrieve_documents(org_id, pipeline_id, request)
170+
except HTTPError as e:
171+
if "503" not in str(e):
172+
raise
173+
else:
174+
docs = response.documents
175+
if len(docs) == 2:
176+
break
177+
if time.time() - start > 180:
178+
msg = "Docs not retrieved in time"
179+
raise RuntimeError(msg)
180+
time.sleep(1)
181+
182+
yield pipeline_id
183+
184+
try:
185+
pipelines.delete_pipeline(org_id, pipeline_id)
186+
except Exception:
187+
logging.exception("Failed to delete pipeline %s", pipeline_id)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from typing import Literal
2+
3+
import pytest
4+
from langchain_tests.integration_tests import RetrieversIntegrationTests
5+
6+
from langchain_vectorize import VectorizeRetriever
7+
8+
9+
class TestVectorizeRetrieverIntegration(RetrieversIntegrationTests):
10+
@classmethod
11+
@pytest.fixture(autouse=True, scope="class")
12+
def setup(
13+
cls,
14+
environment: Literal["prod", "dev", "local", "staging"],
15+
api_token: str,
16+
org_id: str,
17+
pipeline_id: str,
18+
) -> None:
19+
cls.environment = environment
20+
cls.api_token = api_token
21+
cls.org_id = org_id
22+
cls.pipeline_id = pipeline_id
23+
24+
@property
25+
def retriever_constructor(self) -> type[VectorizeRetriever]:
26+
return VectorizeRetriever
27+
28+
@property
29+
def retriever_constructor_params(self) -> dict:
30+
return {
31+
"environment": self.environment,
32+
"api_token": self.api_token,
33+
"organization": self.org_id,
34+
"pipeline_id": self.pipeline_id,
35+
}
36+
37+
@property
38+
def retriever_query_example(self) -> str:
39+
return "What are you?"
40+
41+
@pytest.mark.xfail(
42+
reason="VectorizeRetriever does not support k parameter in constructor"
43+
)
44+
def test_k_constructor_param(self) -> None:
45+
raise NotImplementedError
46+
47+
@pytest.mark.xfail(
48+
reason="VectorizeRetriever does not support k parameter in invoke"
49+
)
50+
def test_invoke_with_k_kwarg(self) -> None:
51+
raise NotImplementedError

0 commit comments

Comments
 (0)