修改为东南天坐标系
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,282 @@
|
||||
from time import sleep
|
||||
import threading
|
||||
from chromadb.api import ClientAPI
|
||||
from chromadb.api.types import IndexingStatus
|
||||
from chromadb.test.conftest import skip_if_not_cluster
|
||||
from chromadb.test.utils.wait_for_version_increase import (
|
||||
get_collection_version,
|
||||
wait_for_version_increase,
|
||||
)
|
||||
|
||||
|
||||
@skip_if_not_cluster()
|
||||
def test_indexing_status_empty_collection(client: ClientAPI) -> None:
|
||||
"""Test indexing status on empty collection"""
|
||||
client.reset()
|
||||
|
||||
collection = client.create_collection(name="test_collection")
|
||||
status = collection.get_indexing_status()
|
||||
|
||||
assert isinstance(status, IndexingStatus)
|
||||
assert status.num_indexed_ops == 0
|
||||
assert status.num_unindexed_ops == 0
|
||||
assert status.total_ops == 0
|
||||
assert status.op_indexing_progress == 1.0
|
||||
|
||||
|
||||
@skip_if_not_cluster()
|
||||
def test_indexing_status_after_add(client: ClientAPI) -> None:
|
||||
"""Test indexing status after adding embeddings"""
|
||||
client.reset()
|
||||
|
||||
collection = client.create_collection(name="test_collection")
|
||||
|
||||
ids = [f"id_{i}" for i in range(300)]
|
||||
embeddings = [[float(i), float(i + 1), float(i + 2)] for i in range(300)]
|
||||
initial_version = get_collection_version(client, collection.name)
|
||||
collection.add(ids=ids, embeddings=embeddings) # type: ignore
|
||||
|
||||
status = collection.get_indexing_status()
|
||||
assert status.total_ops == 300
|
||||
|
||||
if initial_version == get_collection_version(client, collection.name):
|
||||
assert isinstance(status, IndexingStatus)
|
||||
assert status.num_unindexed_ops == 300
|
||||
assert status.num_indexed_ops == 0
|
||||
assert status.op_indexing_progress == 0.0
|
||||
wait_for_version_increase(client, collection.name, initial_version)
|
||||
# Give some time to invalidate the frontend query cache
|
||||
sleep(60)
|
||||
|
||||
# Check status after indexing completes
|
||||
final_status = collection.get_indexing_status()
|
||||
assert isinstance(final_status, IndexingStatus)
|
||||
assert final_status.num_indexed_ops == 300
|
||||
assert final_status.num_unindexed_ops == 0
|
||||
assert final_status.op_indexing_progress == 1.0
|
||||
|
||||
|
||||
@skip_if_not_cluster()
|
||||
def test_indexing_status_after_upsert(client: ClientAPI) -> None:
|
||||
"""Test indexing status after upsert operations"""
|
||||
client.reset()
|
||||
|
||||
collection = client.create_collection(name="test_collection")
|
||||
initial_version = get_collection_version(client, collection.name)
|
||||
|
||||
collection.upsert(ids=["id1", "id2"], embeddings=[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) # type: ignore
|
||||
|
||||
status = collection.get_indexing_status()
|
||||
assert status.total_ops == 2
|
||||
|
||||
if initial_version == get_collection_version(client, collection.name):
|
||||
assert isinstance(status, IndexingStatus)
|
||||
assert status.num_unindexed_ops == 2
|
||||
assert status.num_indexed_ops == 0
|
||||
assert status.op_indexing_progress == 0.0
|
||||
wait_for_version_increase(client, collection.name, initial_version)
|
||||
sleep(60)
|
||||
|
||||
collection.upsert(ids=["id1", "id3"], embeddings=[[1.1, 2.1, 3.1], [7.0, 8.0, 9.0]]) # type: ignore
|
||||
|
||||
status = collection.get_indexing_status()
|
||||
assert status.total_ops == 4
|
||||
|
||||
|
||||
@skip_if_not_cluster()
|
||||
def test_indexing_status_after_delete(client: ClientAPI) -> None:
|
||||
"""Test indexing status after delete operations"""
|
||||
client.reset()
|
||||
|
||||
collection = client.create_collection(name="test_collection")
|
||||
initial_version = get_collection_version(client, collection.name)
|
||||
|
||||
collection.add(
|
||||
ids=["id1", "id2", "id3"],
|
||||
embeddings=[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]], # type: ignore
|
||||
)
|
||||
|
||||
if initial_version == get_collection_version(client, collection.name):
|
||||
status = collection.get_indexing_status()
|
||||
assert isinstance(status, IndexingStatus)
|
||||
assert status.num_unindexed_ops == 3
|
||||
assert status.num_indexed_ops == 0
|
||||
assert status.op_indexing_progress == 0.0
|
||||
wait_for_version_increase(client, collection.name, initial_version)
|
||||
sleep(60)
|
||||
|
||||
initial_status = collection.get_indexing_status()
|
||||
assert initial_status.total_ops == 3
|
||||
|
||||
collection.delete(ids=["id1", "id2"])
|
||||
|
||||
# Delete adds operations to the log, so total_ops increases
|
||||
status_after_delete = collection.get_indexing_status()
|
||||
assert status_after_delete.total_ops == 5
|
||||
|
||||
|
||||
@skip_if_not_cluster()
|
||||
def test_indexing_status_field_types(client: ClientAPI) -> None:
|
||||
"""Test that indexing status returns correct field types"""
|
||||
client.reset()
|
||||
|
||||
collection = client.create_collection(name="field_types_collection")
|
||||
initial_version = get_collection_version(client, collection.name)
|
||||
|
||||
collection.add(ids=["type_test_id"], embeddings=[[1.0, 2.0, 3.0]]) # type: ignore
|
||||
|
||||
status = collection.get_indexing_status()
|
||||
|
||||
if initial_version == get_collection_version(client, collection.name):
|
||||
assert isinstance(status, IndexingStatus)
|
||||
assert status.num_unindexed_ops == 1
|
||||
assert status.num_indexed_ops == 0
|
||||
assert status.op_indexing_progress == 0.0
|
||||
wait_for_version_increase(client, collection.name, initial_version)
|
||||
sleep(60)
|
||||
|
||||
final_status = collection.get_indexing_status()
|
||||
|
||||
assert isinstance(final_status.num_indexed_ops, int)
|
||||
assert isinstance(final_status.num_unindexed_ops, int)
|
||||
assert isinstance(final_status.total_ops, int)
|
||||
assert isinstance(final_status.op_indexing_progress, float)
|
||||
|
||||
assert final_status.num_indexed_ops >= 0
|
||||
assert final_status.num_unindexed_ops >= 0
|
||||
assert final_status.total_ops >= 0
|
||||
assert 0.0 <= final_status.op_indexing_progress <= 1.0
|
||||
|
||||
|
||||
@skip_if_not_cluster()
|
||||
def test_indexing_status_batch_progression(client: ClientAPI) -> None:
|
||||
"""Test indexing status with 2000 records based on index version progression"""
|
||||
client.reset()
|
||||
|
||||
collection = client.create_collection(name="batch_test_collection")
|
||||
get_collection_version(client, collection.name)
|
||||
|
||||
# Insert 2000 records in two batches of 1000 (max batch size)
|
||||
ids_1 = [f"batch_id_{i}" for i in range(1000)]
|
||||
embeddings_1 = [[float(i), float(i + 1), float(i + 2)] for i in range(1000)]
|
||||
collection.add(ids=ids_1, embeddings=embeddings_1) # type: ignore
|
||||
|
||||
ids_2 = [f"batch_id_{i}" for i in range(1000, 2000)]
|
||||
embeddings_2 = [[float(i), float(i + 1), float(i + 2)] for i in range(1000, 2000)]
|
||||
collection.add(ids=ids_2, embeddings=embeddings_2) # type: ignore
|
||||
|
||||
current_version = get_collection_version(client, collection.name)
|
||||
|
||||
allowed_statuses = [
|
||||
IndexingStatus(
|
||||
num_indexed_ops=0,
|
||||
num_unindexed_ops=2000,
|
||||
total_ops=2000,
|
||||
op_indexing_progress=0.0,
|
||||
),
|
||||
IndexingStatus(
|
||||
num_indexed_ops=1000,
|
||||
num_unindexed_ops=1000,
|
||||
total_ops=2000,
|
||||
op_indexing_progress=0.5,
|
||||
),
|
||||
IndexingStatus(
|
||||
num_indexed_ops=2000,
|
||||
num_unindexed_ops=0,
|
||||
total_ops=2000,
|
||||
op_indexing_progress=1.0,
|
||||
),
|
||||
]
|
||||
|
||||
ops_indexed = 0
|
||||
while ops_indexed < 2000:
|
||||
status = collection.get_indexing_status()
|
||||
assert status in allowed_statuses
|
||||
print("witnessed status: ", status)
|
||||
ops_indexed = status.num_indexed_ops
|
||||
wait_for_version_increase(client, collection.name, current_version)
|
||||
sleep(60)
|
||||
|
||||
|
||||
@skip_if_not_cluster()
|
||||
def test_indexing_status_not_found(client: ClientAPI) -> None:
|
||||
"""Test indexing status on non-existent collection"""
|
||||
client.reset()
|
||||
|
||||
collection = client.create_collection(name="temp_collection")
|
||||
client.delete_collection("temp_collection")
|
||||
|
||||
try:
|
||||
collection.get_indexing_status()
|
||||
assert False, "Expected exception for non-existent collection"
|
||||
except Exception as e:
|
||||
assert (
|
||||
"not found" in str(e).lower()
|
||||
or "does not exist" in str(e).lower()
|
||||
or "soft deleted" in str(e).lower()
|
||||
or "collection not found" in str(e).lower()
|
||||
)
|
||||
|
||||
|
||||
@skip_if_not_cluster()
|
||||
def test_indexing_status_concurrent_progress_variation(client: ClientAPI) -> None:
|
||||
"""Test that progress values vary during concurrent operations"""
|
||||
client.reset()
|
||||
|
||||
collection = client.create_collection(name="concurrent_test_collection")
|
||||
|
||||
progress_values = []
|
||||
stop_monitoring = threading.Event()
|
||||
|
||||
def progress_monitor() -> None:
|
||||
"""Thread that continuously monitors indexing progress"""
|
||||
while not stop_monitoring.is_set():
|
||||
try:
|
||||
status = collection.get_indexing_status()
|
||||
progress_values.append(status.op_indexing_progress)
|
||||
sleep(0.1) # Poll every 100ms
|
||||
except Exception:
|
||||
break
|
||||
|
||||
def record_adder() -> None:
|
||||
"""Thread that adds records one at a time"""
|
||||
for i in range(50): # Add 50 records one by one
|
||||
collection.add(
|
||||
ids=[f"concurrent_id_{i}"],
|
||||
embeddings=[[float(i), float(i + 1), float(i + 2)]], # type: ignore
|
||||
)
|
||||
sleep(0.05) # Small delay between additions
|
||||
|
||||
# Start both threads
|
||||
monitor_thread = threading.Thread(target=progress_monitor)
|
||||
adder_thread = threading.Thread(target=record_adder)
|
||||
|
||||
monitor_thread.start()
|
||||
adder_thread.start()
|
||||
|
||||
# Wait for record addition to complete
|
||||
adder_thread.join()
|
||||
|
||||
# Give a moment for final progress updates
|
||||
sleep(1.0)
|
||||
|
||||
# Stop monitoring and wait for thread to finish
|
||||
stop_monitoring.set()
|
||||
monitor_thread.join()
|
||||
|
||||
# Assert that we collected progress values
|
||||
assert len(progress_values) > 0, "No progress values were collected"
|
||||
|
||||
# Assert that not all progress values are 0
|
||||
non_zero_progress = [p for p in progress_values if p > 0.0]
|
||||
assert len(non_zero_progress) > 0, "All progress values remained at 0"
|
||||
|
||||
# Assert that there's variation in progress values
|
||||
unique_progress = set(progress_values)
|
||||
assert (
|
||||
len(unique_progress) > 1
|
||||
), f"Expected variation in progress values, but only got: {unique_progress}"
|
||||
|
||||
print(f"Collected {len(progress_values)} progress values")
|
||||
print(f"Unique progress values: {sorted(unique_progress)}")
|
||||
print(f"Progress range: {min(progress_values):.3f} - {max(progress_values):.3f}")
|
||||
@@ -0,0 +1,102 @@
|
||||
"""Tests for the Search API endpoint."""
|
||||
|
||||
from typing import Tuple
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
from chromadb.api import ClientAPI
|
||||
from chromadb.api.models.Collection import Collection
|
||||
from chromadb.api.types import Embeddings, ReadLevel
|
||||
from chromadb.execution.expression import Knn, Search
|
||||
from chromadb.test.conftest import (
|
||||
ClientFactories,
|
||||
is_spann_disabled_mode,
|
||||
skip_reason_spann_disabled,
|
||||
)
|
||||
|
||||
|
||||
def _create_test_collection(
|
||||
client_factories: ClientFactories,
|
||||
) -> Tuple[Collection, ClientAPI]:
|
||||
"""Create a test collection with some data."""
|
||||
client = client_factories.create_client_from_system()
|
||||
client.reset()
|
||||
|
||||
collection_name = f"search_api_test_{uuid4().hex}"
|
||||
collection = client.get_or_create_collection(name=collection_name)
|
||||
|
||||
return collection, client
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_spann_disabled_mode, reason=skip_reason_spann_disabled)
|
||||
def test_search_with_read_level_index_and_wal(
|
||||
client_factories: ClientFactories,
|
||||
) -> None:
|
||||
"""Test search with ReadLevel.INDEX_AND_WAL (default) returns results."""
|
||||
collection, _ = _create_test_collection(client_factories)
|
||||
|
||||
# Add some data
|
||||
collection.add(
|
||||
ids=["doc1", "doc2", "doc3"],
|
||||
documents=["apple fruit", "banana fruit", "car vehicle"],
|
||||
embeddings=[[0.1, 0.2, 0.3, 0.4], [0.2, 0.3, 0.4, 0.5], [0.9, 0.8, 0.7, 0.6]],
|
||||
)
|
||||
|
||||
# Search with explicit INDEX_AND_WAL (default behavior)
|
||||
search = Search().rank(Knn(query=[0.1, 0.2, 0.3, 0.4], limit=10))
|
||||
results = collection.search(search, read_level=ReadLevel.INDEX_AND_WAL)
|
||||
|
||||
assert results["ids"] is not None
|
||||
assert len(results["ids"]) == 1
|
||||
assert len(results["ids"][0]) > 0
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_spann_disabled_mode, reason=skip_reason_spann_disabled)
|
||||
def test_search_with_read_level_index_only(
|
||||
client_factories: ClientFactories,
|
||||
) -> None:
|
||||
"""Test search with ReadLevel.INDEX_ONLY returns results."""
|
||||
collection, _ = _create_test_collection(client_factories)
|
||||
|
||||
# Add some data
|
||||
collection.add(
|
||||
ids=["doc1", "doc2", "doc3"],
|
||||
documents=["apple fruit", "banana fruit", "car vehicle"],
|
||||
embeddings=[[0.1, 0.2, 0.3, 0.4], [0.2, 0.3, 0.4, 0.5], [0.9, 0.8, 0.7, 0.6]],
|
||||
)
|
||||
|
||||
# Search with INDEX_ONLY - this skips the WAL
|
||||
# Note: Results may or may not include recent writes depending on compaction state
|
||||
search = Search().rank(Knn(query=[0.1, 0.2, 0.3, 0.4], limit=10))
|
||||
results = collection.search(search, read_level=ReadLevel.INDEX_ONLY)
|
||||
|
||||
# Just verify the API works and returns a valid response structure
|
||||
assert results["ids"] is not None
|
||||
assert len(results["ids"]) == 1
|
||||
# Results may be empty if data hasn't been compacted yet, which is expected behavior
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_spann_disabled_mode, reason=skip_reason_spann_disabled)
|
||||
def test_search_default_read_level(
|
||||
client_factories: ClientFactories,
|
||||
) -> None:
|
||||
"""Test search without explicit read_level uses default (INDEX_AND_WAL)."""
|
||||
collection, _ = _create_test_collection(client_factories)
|
||||
|
||||
# Add some data
|
||||
collection.add(
|
||||
ids=["doc1", "doc2"],
|
||||
documents=["hello world", "goodbye world"],
|
||||
embeddings=[[0.1, 0.2, 0.3, 0.4], [0.5, 0.6, 0.7, 0.8]],
|
||||
)
|
||||
|
||||
# Search without specifying read_level (should use default)
|
||||
search = Search().rank(Knn(query=[0.1, 0.2, 0.3, 0.4], limit=10))
|
||||
results = collection.search(search)
|
||||
|
||||
# Should return results since default is INDEX_AND_WAL (full consistency)
|
||||
assert results["ids"] is not None
|
||||
assert len(results["ids"]) == 1
|
||||
assert len(results["ids"][0]) > 0
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
from chromadb.api.shared_system_client import SharedSystemClient
|
||||
from chromadb.api.base_http_client import BaseHTTPClient
|
||||
from chromadb.config import System
|
||||
from typing import Optional, Dict, Generator
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clear_cache() -> Generator[None, None, None]:
|
||||
"""Automatically clear the system cache before and after each test."""
|
||||
SharedSystemClient.clear_system_cache()
|
||||
yield
|
||||
SharedSystemClient.clear_system_cache()
|
||||
|
||||
|
||||
def create_mock_http_client(
|
||||
api_url: Optional[str] = None,
|
||||
headers: Optional[Dict[str, str]] = None,
|
||||
) -> MagicMock:
|
||||
"""Create a mock BaseHTTPClient instance with the specified configuration."""
|
||||
mock_server_api = MagicMock(spec=BaseHTTPClient)
|
||||
|
||||
mock_server_api.get_api_url.return_value = api_url or ""
|
||||
mock_server_api.get_request_headers.return_value = headers or {}
|
||||
|
||||
return mock_server_api
|
||||
|
||||
|
||||
def register_mock_system(system_id: str, mock_server_api: MagicMock) -> MagicMock:
|
||||
"""Register a mock system with the given ID and server API."""
|
||||
mock_system = MagicMock(spec=System)
|
||||
mock_system.instance.return_value = mock_server_api
|
||||
SharedSystemClient._identifier_to_system[system_id] = mock_system
|
||||
return mock_system
|
||||
|
||||
|
||||
def test_extracts_api_key_from_chroma_cloud_client() -> None:
|
||||
mock_server_api = create_mock_http_client(
|
||||
api_url="https://api.trychroma.com/api/v2",
|
||||
headers={"X-Chroma-Token": "test-api-key-123"},
|
||||
)
|
||||
register_mock_system("test-id", mock_server_api)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key == "test-api-key-123"
|
||||
|
||||
|
||||
def test_extracts_api_key_with_lowercase_header() -> None:
|
||||
mock_server_api = create_mock_http_client(
|
||||
api_url="https://api.trychroma.com/api/v2",
|
||||
headers={"x-chroma-token": "test-api-key-456"},
|
||||
)
|
||||
register_mock_system("test-id", mock_server_api)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key == "test-api-key-456"
|
||||
|
||||
|
||||
def test_extracts_api_key_from_gcp_chroma_cloud_client() -> None:
|
||||
mock_server_api = create_mock_http_client(
|
||||
api_url="https://dummy.gcp.trychroma.com/api/v2",
|
||||
headers={"X-Chroma-Token": "gcp-test-api-key"},
|
||||
)
|
||||
register_mock_system("test-id", mock_server_api)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key == "gcp-test-api-key"
|
||||
|
||||
|
||||
def test_skips_non_chroma_cloud_clients() -> None:
|
||||
mock_server_api = create_mock_http_client(
|
||||
api_url="https://localhost:8000/api/v2",
|
||||
headers={"X-Chroma-Token": "local-api-key"},
|
||||
)
|
||||
register_mock_system("test-id", mock_server_api)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key is None
|
||||
|
||||
|
||||
def test_skips_clients_without_api_url() -> None:
|
||||
mock_server_api = create_mock_http_client(
|
||||
api_url=None,
|
||||
headers={"X-Chroma-Token": "test-api-key"},
|
||||
)
|
||||
register_mock_system("test-id", mock_server_api)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key is None
|
||||
|
||||
|
||||
def test_returns_none_when_no_api_key_in_headers() -> None:
|
||||
mock_server_api = create_mock_http_client(
|
||||
api_url="https://api.trychroma.com/api/v2",
|
||||
headers={},
|
||||
)
|
||||
register_mock_system("test-id", mock_server_api)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key is None
|
||||
|
||||
|
||||
def test_returns_first_api_key_found_from_multiple_clients() -> None:
|
||||
mock_server_api_1 = create_mock_http_client(
|
||||
api_url="https://api.trychroma.com/api/v2",
|
||||
headers={"X-Chroma-Token": "first-key"},
|
||||
)
|
||||
mock_server_api_2 = create_mock_http_client(
|
||||
api_url="https://api.trychroma.com/api/v2",
|
||||
headers={"X-Chroma-Token": "second-key"},
|
||||
)
|
||||
register_mock_system("test-id-1", mock_server_api_1)
|
||||
register_mock_system("test-id-2", mock_server_api_2)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key == "first-key"
|
||||
|
||||
|
||||
def test_handles_exception_gracefully() -> None:
|
||||
mock_system = MagicMock(spec=System)
|
||||
mock_system.instance.side_effect = Exception("Test exception")
|
||||
SharedSystemClient._identifier_to_system["test-id"] = mock_system
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key is None
|
||||
|
||||
|
||||
def test_returns_none_when_no_clients_exist() -> None:
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key is None
|
||||
|
||||
|
||||
def test_skips_non_http_clients() -> None:
|
||||
"""Test that non-BaseHTTPClient instances are skipped."""
|
||||
mock_server_api = MagicMock() # Not a BaseHTTPClient
|
||||
register_mock_system("test-id", mock_server_api)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key is None
|
||||
|
||||
|
||||
def test_extracts_api_key_with_mixed_case_header() -> None:
|
||||
mock_server_api = create_mock_http_client(
|
||||
api_url="https://api.trychroma.com/api/v2",
|
||||
headers={"X-CHROMA-TOKEN": "mixed-case-key"},
|
||||
)
|
||||
register_mock_system("test-id", mock_server_api)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key == "mixed-case-key"
|
||||
|
||||
|
||||
def test_multiple_clients_returns_one_key() -> None:
|
||||
"""Test that multiple clients return one of the available keys."""
|
||||
mock_api_1 = create_mock_http_client(
|
||||
api_url="https://api.trychroma.com/api/v2",
|
||||
headers={"X-Chroma-Token": "key-1"},
|
||||
)
|
||||
mock_api_2 = create_mock_http_client(
|
||||
api_url="https://api.trychroma.com/api/v2",
|
||||
headers={"X-Chroma-Token": "key-2"},
|
||||
)
|
||||
register_mock_system("id-1", mock_api_1)
|
||||
register_mock_system("id-2", mock_api_2)
|
||||
|
||||
api_key = SharedSystemClient.get_chroma_cloud_api_key_from_clients()
|
||||
|
||||
assert api_key in ["key-1", "key-2"]
|
||||
Reference in New Issue
Block a user