test_api_automation.py
1 import pytest 2 from apscheduler.schedulers.background import BackgroundScheduler 3 from django_apscheduler.jobstores import DjangoJobStore 4 from fastapi.testclient import TestClient 5 6 from khoj.utils import state 7 from tests.helpers import AiModelApiFactory, ChatModelFactory, get_chat_api_key 8 9 10 @pytest.fixture(autouse=True) 11 def setup_scheduler(): 12 state.scheduler = BackgroundScheduler() 13 state.scheduler.add_jobstore(DjangoJobStore(), "default") 14 state.scheduler.start() 15 yield 16 state.scheduler.shutdown() 17 18 19 def create_test_automation(client: TestClient) -> str: 20 """Helper function to create a test automation and return its ID.""" 21 state.anonymous_mode = True 22 ChatModelFactory( 23 name="gemini-2.5-flash", model_type="google", ai_model_api=AiModelApiFactory(api_key=get_chat_api_key("google")) 24 ) 25 params = { 26 "q": "test automation", 27 "crontime": "0 0 * * *", 28 } 29 response = client.post("/api/automation", params=params) 30 assert response.status_code == 200 31 return response.json()["id"] 32 33 34 @pytest.mark.django_db(transaction=True) 35 @pytest.mark.skipif(not get_chat_api_key("google"), reason="Requires GEMINI_API_KEY to be set") 36 def test_create_automation(client: TestClient): 37 """Test that creating an automation works as expected.""" 38 # Arrange 39 state.anonymous_mode = True 40 ChatModelFactory( 41 name="gemini-2.5-flash", model_type="google", ai_model_api=AiModelApiFactory(api_key=get_chat_api_key("google")) 42 ) 43 params = { 44 "q": "test automation", 45 "crontime": "0 0 * * *", 46 } 47 48 # Act 49 response = client.post("/api/automation", params=params) 50 51 # Assert 52 assert response.status_code == 200 53 response_json = response.json() 54 assert response_json["scheduling_request"] == "test automation" 55 assert response_json["crontime"] == "0 0 * * *" 56 57 58 @pytest.mark.django_db(transaction=True) 59 @pytest.mark.skipif(not get_chat_api_key("google"), reason="Requires GEMINI_API_KEY to be set") 60 def test_get_automations(client: TestClient): 61 """Test that getting a list of automations works.""" 62 automation_id = create_test_automation(client) 63 64 # Act 65 response = client.get("/api/automation") 66 67 # Assert 68 assert response.status_code == 200 69 automations = response.json() 70 assert isinstance(automations, list) 71 assert len(automations) > 0 72 assert any(a["id"] == automation_id for a in automations) 73 74 75 @pytest.mark.django_db(transaction=True) 76 @pytest.mark.skipif(not get_chat_api_key("google"), reason="Requires GEMINI_API_KEY to be set") 77 def test_delete_automation(client: TestClient): 78 """Test that deleting an automation works.""" 79 automation_id = create_test_automation(client) 80 81 # Act 82 response = client.delete(f"/api/automation?automation_id={automation_id}") 83 84 # Assert 85 assert response.status_code == 200 86 87 # Verify it's gone 88 response = client.get("/api/automation") 89 assert response.status_code == 200 90 automations = response.json() 91 assert not any(a["id"] == automation_id for a in automations) 92 93 94 @pytest.mark.django_db(transaction=True) 95 @pytest.mark.skipif(not get_chat_api_key("google"), reason="Requires GEMINI_API_KEY to be set") 96 def test_edit_automation(client: TestClient): 97 """Test that editing an automation works.""" 98 automation_id = create_test_automation(client) 99 100 edit_params = { 101 "automation_id": automation_id, 102 "q": "edited automation", 103 "crontime": "0 1 * * *", 104 "subject": "edited subject", 105 "timezone": "UTC", 106 } 107 108 # Act 109 response = client.put("/api/automation", params=edit_params) 110 111 # Assert 112 if response.status_code != 200: 113 print(response.text) 114 assert response.status_code == 200 115 edited_automation = response.json() 116 assert edited_automation["scheduling_request"] == "edited automation" 117 assert edited_automation["crontime"] == "0 1 * * *" 118 assert edited_automation["subject"] == "edited subject" 119 120 121 @pytest.mark.django_db(transaction=True) 122 @pytest.mark.skipif(not get_chat_api_key("google"), reason="Requires GEMINI_API_KEY to be set") 123 def test_trigger_automation(client: TestClient): 124 """Test that triggering an automation works.""" 125 automation_id = create_test_automation(client) 126 127 # Act 128 response = client.post(f"/api/automation/trigger?automation_id={automation_id}") 129 130 # Assert 131 assert response.status_code == 200 132 # NOTE: We are not testing the execution of the triggered job itself, 133 # as that would require a more complex test setup with mocking. 134 # A 200 response is sufficient to indicate that the trigger was received. 135 assert response.text == "Automation triggered"