Skip to main content
Glama
test_create_update_delete.py12.8 kB
#!/usr/bin/env python3 """Integration tests for create, update, and delete entity tools.""" import asyncio import sys from base_direct import IntegrationTestBase class TestCreateUpdateDelete(IntegrationTestBase): """Test entity CRUD operations with real Kanka API.""" async def test_create_single_entity(self): """Test creating a single entity with all fields.""" # Create a character with all fields result = await self.call_tool( "create_entities", entities=[ { "entity_type": "character", "name": "Integration Test Hero - DELETE ME", "type": "Player Character", "entry": "# Background\n\nA brave **hero** from the integration tests.\n\nHas connections to [entity:123|The King].", "tags": ["hero", "test", "player"], "is_hidden": False, } ], ) self.assert_equal(len(result), 1) self.assert_true( result[0]["success"], f"Create failed: {result[0].get('error')}" ) entity_id = result[0]["entity_id"] self.assert_not_none(entity_id) self.track_entity(entity_id) # Verify the entity was created correctly await self.wait_for_api() get_result = await self.call_tool("get_entities", entity_ids=[entity_id]) self.assert_equal(len(get_result), 1) self.assert_true(get_result[0]["success"]) entity = get_result[0] self.assert_equal(entity["name"], "Integration Test Hero - DELETE ME") self.assert_equal(entity["type"], "Player Character") self.assert_in("brave **hero**", entity["entry"]) self.assert_in("[entity:123|The King]", entity["entry"]) # Mention preserved self.assert_in("hero", entity["tags"]) self.assert_in("test", entity["tags"]) self.assert_equal(entity["is_hidden"], False) async def test_create_multiple_entities(self): """Test creating multiple entities in one call.""" # Create multiple entities of different types result = await self.call_tool( "create_entities", entities=[ { "entity_type": "location", "name": "Integration Test City - DELETE ME", "type": "Capital", "entry": "The grand capital of the test realm.", }, { "entity_type": "organization", "name": "Integration Test Guild - DELETE ME", "type": "Merchant Guild", "tags": ["guild", "test"], }, { "entity_type": "quest", "name": "Integration Test Quest - DELETE ME", "type": "Main Quest", "is_hidden": True, }, ], ) self.assert_equal(len(result), 3) # Check all succeeded and track for cleanup for i, r in enumerate(result): self.assert_true(r["success"], f"Entity {i} failed: {r.get('error')}") self.assert_not_none(r["entity_id"]) self.track_entity(r["entity_id"]) # Verify different entity types were created self.assert_equal(result[0]["name"], "Integration Test City - DELETE ME") self.assert_equal(result[1]["name"], "Integration Test Guild - DELETE ME") self.assert_equal(result[2]["name"], "Integration Test Quest - DELETE ME") async def test_update_entity(self): """Test updating an existing entity.""" # First create an entity create_result = await self.call_tool( "create_entities", entities=[ { "entity_type": "character", "name": "Integration Test Update Me - DELETE ME", "type": "NPC", "entry": "Original description", "tags": ["original"], "is_hidden": False, } ], ) self.assert_true(create_result[0]["success"]) entity_id = create_result[0]["entity_id"] self.track_entity(entity_id) await self.wait_for_api() # Update the entity update_result = await self.call_tool( "update_entities", updates=[ { "entity_id": entity_id, "name": "Integration Test Updated - DELETE ME", # Required by API "type": "Boss NPC", "entry": "# Updated Description\n\nThis character has been **updated**!", "tags": ["updated", "boss"], "is_hidden": True, } ], ) self.assert_equal(len(update_result), 1) self.assert_true( update_result[0]["success"], f"Update failed: {update_result[0].get('error')}", ) await self.wait_for_api() # Verify the update get_result = await self.call_tool("get_entities", entity_ids=[entity_id]) entity = get_result[0] self.assert_equal(entity["name"], "Integration Test Updated - DELETE ME") self.assert_equal(entity["type"], "Boss NPC") self.assert_in("Updated Description", entity["entry"]) self.assert_in("updated", entity["tags"]) self.assert_in("boss", entity["tags"]) self.assert_equal(entity["is_hidden"], True) async def test_partial_update(self): """Test updating only some fields of an entity.""" # Create an entity create_result = await self.call_tool( "create_entities", entities=[ { "entity_type": "location", "name": "Integration Test Partial Update - DELETE ME", "type": "Village", "entry": "A small village", "tags": ["village", "small"], } ], ) entity_id = create_result[0]["entity_id"] self.track_entity(entity_id) await self.wait_for_api() # Update only the type and add a tag update_result = await self.call_tool( "update_entities", updates=[ { "entity_id": entity_id, "name": "Integration Test Partial Update - DELETE ME", # Required "type": "Town", # Changed "tags": ["village", "small", "growing"], # Added one } ], ) self.assert_true(update_result[0]["success"]) await self.wait_for_api() # Verify partial update get_result = await self.call_tool("get_entities", entity_ids=[entity_id]) entity = get_result[0] self.assert_equal(entity["type"], "Town") # Changed self.assert_in("A small village", entity["entry"]) # Unchanged self.assert_in("growing", entity["tags"]) # New tag added async def test_delete_entity(self): """Test deleting a single entity.""" # Create an entity to delete create_result = await self.call_tool( "create_entities", entities=[ { "entity_type": "note", "name": "Integration Test Delete Me - DELETE ME", "entry": "This will be deleted", "is_hidden": True, } ], ) entity_id = create_result[0]["entity_id"] # Track it in case delete fails self.track_entity(entity_id) await self.wait_for_api() # Delete the entity delete_result = await self.call_tool("delete_entities", entity_ids=[entity_id]) self.assert_equal(len(delete_result), 1) self.assert_true( delete_result[0]["success"], f"Delete failed: {delete_result[0].get('error')}", ) self.assert_equal(delete_result[0]["entity_id"], entity_id) # Remove from tracking since it was successfully deleted if delete_result[0]["success"]: self._created_entities.remove(entity_id) await self.wait_for_api() # Verify it's gone get_result = await self.call_tool("get_entities", entity_ids=[entity_id]) self.assert_false(get_result[0]["success"]) self.assert_in("not found", get_result[0]["error"].lower()) async def test_batch_operations(self): """Test batch create, update, and delete operations.""" # Batch create create_result = await self.call_tool( "create_entities", entities=[ { "entity_type": "creature", "name": f"Integration Test Monster {i} - DELETE ME", "type": "Goblin", } for i in range(5) ], ) # Collect entity IDs entity_ids = [] for r in create_result: self.assert_true(r["success"]) entity_ids.append(r["entity_id"]) await self.wait_for_api() # Batch update first 3 update_result = await self.call_tool( "update_entities", updates=[ { "entity_id": entity_ids[i], "name": f"Integration Test Monster {i} - DELETE ME", "type": "Hobgoblin", # Evolved! } for i in range(3) ], ) for r in update_result: self.assert_true(r["success"]) await self.wait_for_api() # Batch delete last 2 delete_result = await self.call_tool( "delete_entities", entity_ids=entity_ids[3:] ) for r in delete_result: self.assert_true(r["success"]) # Track remaining for cleanup for entity_id in entity_ids[:3]: self.track_entity(entity_id) # Verify the updates get_result = await self.call_tool("get_entities", entity_ids=entity_ids[:3]) for r in get_result: self.assert_true(r["success"]) self.assert_equal(r["type"], "Hobgoblin") async def test_error_handling(self): """Test error handling in CRUD operations.""" # Try to create with missing required field result = await self.call_tool( "create_entities", entities=[ { "entity_type": "character", # Missing required "name" field "type": "NPC", } ], ) self.assert_equal(len(result), 1) self.assert_false(result[0]["success"]) self.assert_not_none(result[0]["error"]) # Try to update non-existent entity update_result = await self.call_tool( "update_entities", updates=[ { "entity_id": 9999999, # Doesn't exist "name": "Won't work", } ], ) self.assert_false(update_result[0]["success"]) self.assert_in("not found", update_result[0]["error"].lower()) # Try to delete non-existent entity delete_result = await self.call_tool("delete_entities", entity_ids=[9999999]) self.assert_false(delete_result[0]["success"]) self.assert_not_none(delete_result[0]["error"]) def assert_false(self, condition: bool, message: str = ""): """Assert that a condition is false.""" if condition: raise AssertionError(f"Expected False but got True: {message}") async def main(): """Run all tests.""" test = TestCreateUpdateDelete() tests = [ ("Create single entity", test.test_create_single_entity), ("Create multiple entities", test.test_create_multiple_entities), ("Update entity", test.test_update_entity), ("Partial update", test.test_partial_update), ("Delete entity", test.test_delete_entity), ("Batch operations", test.test_batch_operations), ("Error handling", test.test_error_handling), ] passed = 0 failed = 0 for test_name, test_func in tests: if await test.run_test(test_name, test_func): passed += 1 else: failed += 1 print(f"\n{'='*60}") print(f"Test Results: {passed} passed, {failed} failed") print(f"{'='*60}") return failed == 0 if __name__ == "__main__": success = asyncio.run(main()) sys.exit(0 if success else 1)

Latest Blog Posts

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/ervwalter/mcp-kanka'

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