Skip to main content
Glama

Convex MCP server

Official
by get-convex
tests.rs10.8 kB
use common::{ runtime::Runtime, types::IndexId, }; use runtime::testing::TestRuntime; use value::{ DeveloperDocumentId, InternalId, ResolvedDocumentId, TableNamespace, TabletId, }; use crate::{ bootstrap_model::index_backfills::{ types::IndexBackfillMetadata, IndexBackfillModel, }, test_helpers::new_test_database, TableModel, Transaction, }; async fn setup_test_tx<RT: Runtime>(rt: RT) -> anyhow::Result<Transaction<RT>> { let db = new_test_database(rt).await; db.begin_system().await } fn create_test_index_id() -> IndexId { InternalId::MIN } fn create_test_tablet_id() -> TabletId { TabletId::MIN } #[convex_macro::test_runtime] async fn test_initialize_backfill_creates_new_entry(rt: TestRuntime) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; let index_id = create_test_index_id(); let total_docs = Some(1000u64); let backfill_id = IndexBackfillModel::new(&mut tx) .initialize_backfill(index_id, total_docs) .await?; // Verify the backfill was created let backfill_doc = tx.get(backfill_id).await?; assert!(backfill_doc.is_some()); let backfill_metadata: IndexBackfillMetadata = backfill_doc.unwrap().into_value().into_value().try_into()?; assert_eq!(backfill_metadata.num_docs_indexed, 0); assert_eq!(backfill_metadata.total_docs, total_docs); Ok(()) } #[convex_macro::test_runtime] async fn test_initialize_backfill_with_none_total_docs(rt: TestRuntime) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; let index_id = create_test_index_id(); let total_docs = None; let backfill_id = IndexBackfillModel::new(&mut tx) .initialize_backfill(index_id, total_docs) .await?; // Verify the backfill was created with None total_docs let backfill_doc = tx.get(backfill_id).await?; assert!(backfill_doc.is_some()); let backfill_metadata: IndexBackfillMetadata = backfill_doc.unwrap().into_value().into_value().try_into()?; assert_eq!(backfill_metadata.num_docs_indexed, 0); assert_eq!(backfill_metadata.total_docs, None); Ok(()) } #[convex_macro::test_runtime] async fn test_initialize_backfill_resets_existing_entry(rt: TestRuntime) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; let index_id = create_test_index_id(); // Create initial backfill let first_backfill_id = IndexBackfillModel::new(&mut tx) .initialize_backfill(index_id, Some(500)) .await?; // Update progress IndexBackfillModel::new(&mut tx) .update_index_backfill_progress(index_id, create_test_tablet_id(), 100) .await?; // Verify progress was updated let backfill_doc = tx.get(first_backfill_id).await?; let backfill_metadata: IndexBackfillMetadata = backfill_doc.unwrap().into_value().into_value().try_into()?; assert_eq!(backfill_metadata.num_docs_indexed, 100); // Initialize again with different total_docs - should reset progress let second_backfill_id = IndexBackfillModel::new(&mut tx) .initialize_backfill(index_id, Some(1000)) .await?; // Should return the same ID assert_eq!(first_backfill_id, second_backfill_id); // Verify the backfill was reset let backfill_doc = tx.get(second_backfill_id).await?; let backfill_metadata: IndexBackfillMetadata = backfill_doc.unwrap().into_value().into_value().try_into()?; assert_eq!(backfill_metadata.num_docs_indexed, 0); assert_eq!(backfill_metadata.total_docs, Some(1000)); Ok(()) } #[convex_macro::test_runtime] async fn test_update_index_backfill_progress_with_total_docs( rt: TestRuntime, ) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; let index_id = create_test_index_id(); let tablet_id = create_test_tablet_id(); let total_docs = Some(1000u64); // Initialize backfill let backfill_id = IndexBackfillModel::new(&mut tx) .initialize_backfill(index_id, total_docs) .await?; // Update progress IndexBackfillModel::new(&mut tx) .update_index_backfill_progress(index_id, tablet_id, 250) .await?; // Verify progress was updated let backfill_doc = tx.get(backfill_id).await?; let backfill_metadata: IndexBackfillMetadata = backfill_doc.unwrap().into_value().into_value().try_into()?; assert_eq!(backfill_metadata.num_docs_indexed, 250); assert_eq!(backfill_metadata.total_docs, total_docs); // Update progress again IndexBackfillModel::new(&mut tx) .update_index_backfill_progress(index_id, tablet_id, 150) .await?; // Verify progress was accumulated let backfill_doc = tx.get(backfill_id).await?; let backfill_metadata: IndexBackfillMetadata = backfill_doc.unwrap().into_value().into_value().try_into()?; assert_eq!(backfill_metadata.num_docs_indexed, 400); assert_eq!(backfill_metadata.total_docs, total_docs); Ok(()) } #[convex_macro::test_runtime] async fn test_update_index_backfill_progress_nonexistent_backfill( rt: TestRuntime, ) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; let index_id = create_test_index_id(); let tablet_id = create_test_tablet_id(); // Try to update progress for non-existent backfill let result = IndexBackfillModel::new(&mut tx) .update_index_backfill_progress(index_id, tablet_id, 100) .await; // Should return an error assert!(result.is_err()); assert!(result .unwrap_err() .to_string() .contains("Index backfill not found")); Ok(()) } #[convex_macro::test_runtime] async fn test_update_index_backfill_progress_with_none_total_docs( rt: TestRuntime, ) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; let index_id = create_test_index_id(); let tablet_id = TableModel::new(&mut tx) .insert_table_metadata_for_test(TableNamespace::Global, &"table".parse()?) .await? .tablet_id; // Initialize backfill without total_docs let backfill_id = IndexBackfillModel::new(&mut tx) .initialize_backfill(index_id, None) .await?; // In a test environment, table mapping for a non-existent tablet will fail, // so this tests that the method handles the error gracefully IndexBackfillModel::new(&mut tx) .update_index_backfill_progress(index_id, tablet_id, 100) .await?; let backfill_doc = tx.get(backfill_id).await?; let backfill_metadata: IndexBackfillMetadata = backfill_doc.unwrap().into_value().into_value().try_into()?; assert_eq!(backfill_metadata.total_docs, Some(0)); Ok(()) } #[convex_macro::test_runtime] async fn test_delete_index_backfill_existing(rt: TestRuntime) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; let index_id = create_test_index_id(); let total_docs = Some(1000u64); // Initialize backfill let backfill_id = IndexBackfillModel::new(&mut tx) .initialize_backfill(index_id, total_docs) .await?; // Verify it exists let backfill_doc = tx.get(backfill_id).await?; assert!(backfill_doc.is_some()); // For delete_index_backfill, we need to pass the index's ResolvedDocumentId, // not the backfill document's ID. Create a fake index document ID. let index_table_id = tx.bootstrap_tables().index_id; let index_developer_id = DeveloperDocumentId::new(index_table_id.table_number, index_id); let index_resolved_id = ResolvedDocumentId::new(index_table_id.tablet_id, index_developer_id); // Delete the backfill IndexBackfillModel::new(&mut tx) .delete_index_backfill(index_resolved_id) .await?; // Verify it was deleted let backfill_doc = tx.get(backfill_id).await?; assert!(backfill_doc.is_none()); Ok(()) } #[convex_macro::test_runtime] async fn test_delete_index_backfill_nonexistent(rt: TestRuntime) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; // Create a fake index document ID that doesn't exist let index_table_id = tx.bootstrap_tables().index_id; let fake_developer_id = DeveloperDocumentId::new(index_table_id.table_number, InternalId::MAX); let fake_resolved_id = ResolvedDocumentId::new(index_table_id.tablet_id, fake_developer_id); // Delete non-existent backfill - should not error (method handles missing // gracefully) IndexBackfillModel::new(&mut tx) .delete_index_backfill(fake_resolved_id) .await?; Ok(()) } #[convex_macro::test_runtime] async fn test_multiple_backfills_different_indexes(rt: TestRuntime) -> anyhow::Result<()> { let mut tx = setup_test_tx(rt).await?; let index_id1 = InternalId::MIN; let index_id2 = InternalId::MAX; let tablet_id = create_test_tablet_id(); // Initialize backfills for different indexes let mut model = IndexBackfillModel::new(&mut tx); let backfill_id1 = model.initialize_backfill(index_id1, Some(1000)).await?; let backfill_id2 = model.initialize_backfill(index_id2, Some(2000)).await?; // Update progress for both model .update_index_backfill_progress(index_id1, tablet_id, 100) .await?; model .update_index_backfill_progress(index_id2, tablet_id, 200) .await?; // Verify both backfills exist with correct progress let backfill_doc1 = tx.get(backfill_id1).await?; let backfill_metadata1: IndexBackfillMetadata = backfill_doc1 .unwrap() .into_value() .into_value() .try_into()?; assert_eq!(backfill_metadata1.num_docs_indexed, 100); assert_eq!(backfill_metadata1.total_docs, Some(1000)); let backfill_doc2 = tx.get(backfill_id2).await?; let backfill_metadata2: IndexBackfillMetadata = backfill_doc2 .unwrap() .into_value() .into_value() .try_into()?; assert_eq!(backfill_metadata2.num_docs_indexed, 200); assert_eq!(backfill_metadata2.total_docs, Some(2000)); // Delete one backfill using the index's ResolvedDocumentId let index_table_id = tx.bootstrap_tables().index_id; let index1_developer_id = DeveloperDocumentId::new(index_table_id.table_number, index_id1); let index1_resolved_id = ResolvedDocumentId::new(index_table_id.tablet_id, index1_developer_id); IndexBackfillModel::new(&mut tx) .delete_index_backfill(index1_resolved_id) .await?; // Verify only one was deleted let backfill_doc1 = tx.get(backfill_id1).await?; assert!(backfill_doc1.is_none()); let backfill_doc2 = tx.get(backfill_id2).await?; assert!(backfill_doc2.is_some()); Ok(()) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server