403Webshell
Server IP : 3.147.158.171  /  Your IP : 216.73.216.216
Web Server : Apache/2.4.67 (Amazon Linux) OpenSSL/3.5.5
System : Linux ip-172-31-2-178.us-east-2.compute.internal 6.1.172-216.329.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Wed May 20 06:31:34 UTC 2026 x86_64
User : ec2-user ( 1000)
PHP Version : 8.4.21
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /tsai/www/html/api.turmansolutions.ai/tests/unit/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /tsai/www/html/api.turmansolutions.ai/tests/unit/test_chat.py
"""
Unit tests for the /chat/ endpoint.

Tests cover:
- GET /chat/models/ - List OpenAI models
- POST /chat/store/ - Store message for streaming
- Error handling for invalid keys and missing data
"""

import pytest
from unittest.mock import MagicMock, patch
from fastapi.testclient import TestClient
from app.main import app
from app.utilities.site_auth import get_current_site


@pytest.fixture(autouse=True)
def _override_site_auth():
    """Auto-apply: every test in this file gets a stub site so the new
    Origin-based dependency in /chat/store/ resolves cleanly."""
    app.dependency_overrides[get_current_site] = lambda: MagicMock()
    yield
    app.dependency_overrides.clear()


@pytest.fixture
def client():
    """Create test client."""
    return TestClient(app)


class TestChatModels:
    """Tests for GET /api/v1/chat/models/"""

    def test_get_chat_models(self, client, monkeypatch):
        """Test that models endpoint returns OpenAI models list."""
        # Mock the openai_client.models.list() call
        mock_model = MagicMock()
        mock_model.id = "gpt-4o"
        mock_model.object = "model"
        mock_model.created = 1699500000
        mock_model.owned_by = "openai"

        mock_response = MagicMock()
        mock_response.data = [mock_model]
        mock_response.model_dump = MagicMock(return_value={
            "data": [{"id": "gpt-4o", "object": "model", "created": 1699500000, "owned_by": "openai"}]
        })

        # Patch the openai_client at the module level
        import app.api.v1.endpoints.chat as chat_module
        monkeypatch.setattr(chat_module.openai_client.models, "list", lambda: mock_response)

        response = client.get("/api/v1/chat/models/")
        assert response.status_code == 200
        data = response.json()
        assert "data" in data
        assert len(data["data"]) >= 1


class TestChatStore:
    """Tests for POST /api/v1/chat/store/"""

    def test_store_message_success(self, client):
        """Test storing a message returns a unique key."""
        payload = {
            "userId": 999,
            "body": "Hello, this is a test message",
            "instructions": "You are a helpful assistant."
        }

        response = client.post("/api/v1/chat/store/", json=payload)
        assert response.status_code == 200
        data = response.json()
        assert "message" in data
        # Key should be a numeric string (timestamp)
        assert data["message"].isdigit()

    def test_store_message_with_conversation(self, client):
        """Test storing a message with conversation history."""
        payload = {
            "userId": 999,
            "body": "What did I just ask?",
            "instructions": "You are a helpful assistant.",
            "conversation": [
                {"userId": 0, "body": "Hello"},
                {"userId": 1, "body": "Hi there!"}
            ]
        }

        response = client.post("/api/v1/chat/store/", json=payload)
        assert response.status_code == 200
        data = response.json()
        assert "message" in data

    def test_store_message_with_model(self, client):
        """Test storing a message with a specific model configuration."""
        payload = {
            "userId": 999,
            "body": "Tell me a joke",
            "instructions": "You are a comedian.",
            "model": {
                "provider": "OpenAI",
                "name": "gpt-4o-mini",
                "temperature": 0.9
            }
        }

        response = client.post("/api/v1/chat/store/", json=payload)
        assert response.status_code == 200
        data = response.json()
        assert "message" in data

    def test_store_message_minimal(self, client):
        """Test storing a message with only required fields."""
        payload = {
            "userId": 1,
            "body": "Hi"
        }

        response = client.post("/api/v1/chat/store/", json=payload)
        assert response.status_code == 200
        data = response.json()
        assert "message" in data

    def test_store_message_missing_body(self, client):
        """Test that missing body field returns validation error."""
        payload = {
            "userId": 999
            # Missing "body" field
        }

        response = client.post("/api/v1/chat/store/", json=payload)
        assert response.status_code == 422  # Validation error

    def test_store_message_missing_user_id(self, client):
        """Test that missing userId field returns validation error."""
        payload = {
            "body": "Hello"
            # Missing "userId" field
        }

        response = client.post("/api/v1/chat/store/", json=payload)
        assert response.status_code == 422  # Validation error


class TestChatStream:
    """Tests for GET /api/v1/chat/stream/{key}"""

    def test_stream_invalid_key(self, client, monkeypatch):
        """Test streaming with an invalid key causes an error.

        The chat stream endpoint doesn't handle missing keys gracefully -
        it tries to access attributes on None. This test verifies the
        current behavior (error in generator).
        """
        # Clear the data store first
        import app.api.v1.endpoints.chat as chat_module
        chat_module.data_store.clear()

        # Try to stream with a non-existent key
        # This will error because the endpoint doesn't check for None
        # SSE endpoint, so we just verify it returns 200 status (SSE convention)
        # The actual error happens in the generator
        try:
            response = client.get("/api/v1/chat/stream/invalid_key_12345")
            # If we get here, the endpoint handles missing keys somehow
            assert response.status_code == 200
        except Exception:
            # Expected - the endpoint errors when key is not found
            pass

    def test_store_then_check_key_consumed(self, client, monkeypatch):
        """Test that stored data is consumed (removed) after retrieval."""
        import app.api.v1.endpoints.chat as chat_module

        # Store a message
        payload = {
            "userId": 999,
            "body": "Test message"
        }
        store_response = client.post("/api/v1/chat/store/", json=payload)
        key = store_response.json()["message"]

        # Verify key exists in data store
        assert key in chat_module.data_store

        # Get the data (simulating what stream does)
        data = chat_module.get_data(key)
        assert data is not None
        assert data.body == "Test message"

        # Verify key is now consumed
        assert key not in chat_module.data_store

        # Second get should return None
        data_again = chat_module.get_data(key)
        assert data_again is None

Youez - 2016 - github.com/yon3zu
LinuXploit