File size: 6,530 Bytes
b262f99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Cloud tests for CarsRUS Space on Hugging Face.
Runs against: https://huggingface.co/spaces/galbendavids/CarsRUS

Requires: pip install gradio_client
Run: PYTHONPATH=. python tests/test_cloud.py
     or: bash tests/run_cloud_tests.sh
"""

import os
import sys

_tests_dir = os.path.dirname(os.path.abspath(__file__))
_project_root = os.path.dirname(_tests_dir)
if _project_root not in sys.path:
    sys.path.insert(0, _project_root)

# Space URL (public Space โ€“ no token needed for read)
SPACE_URL = os.environ.get("CARSRUS_SPACE_URL", "galbendavids/CarsRUS")


def get_client():
    """Create Gradio client for the Space. Uses HF token from env if set."""
    try:
        from gradio_client import Client
    except ImportError:
        print("โŒ gradio_client not installed. Run: pip install gradio_client")
        sys.exit(1)
    hf_token = os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN")
    return Client(SPACE_URL, hf_token=hf_token or None)


def collect_chat_response(client, message: str):
    """Call the chat endpoint and return the full response (streaming collected)."""
    # Space API: predict(message, api_name="/chat") -> response (str)
    result = client.predict(message, api_name="/chat")
    return result


def test_space_reachable():
    """Space is up and client can connect."""
    print("\n[Cloud] test_space_reachable...")
    client = get_client()
    # Just ensure we can get API info (view_api or similar)
    try:
        api_info = client.view_api()
        print(f"   Endpoints: {list(api_info.get('named_endpoints', api_info) if isinstance(api_info, dict) else 'ok')}")
    except Exception as e:
        print(f"   view_api: {e}")
    print("โœ… test_space_reachable passed")
    return client


def test_chat_supported_car(client):
    """Ask about a supported car (e.g. Audi RS3) โ€“ expect substantive answer, no config error."""
    print("\n[Cloud] test_chat_supported_car...")
    message = "Tell me about the Audi RS3"
    try:
        result = collect_chat_response(client, message)
    except Exception as e:
        print(f"   Call failed: {e}")
        try:
            api = client.view_api()
            print(f"   API: {api}")
        except Exception:
            pass
        raise
    text = result if isinstance(result, str) else str(result)
    # Should not be config/init error
    assert "Configuration Error" not in text and "Initialization Error" not in text, (
        f"Expected normal answer, got: {text[:200]}"
    )
    # Should mention something about the car or content
    assert len(text.strip()) > 50, f"Response too short: {text[:200]}"
    print(f"   Response length: {len(text)} chars")
    print("โœ… test_chat_supported_car passed")


def test_chat_unsupported_car(client):
    """Ask about an unsupported car โ€“ expect refusal or supported list."""
    print("\n[Cloud] test_chat_unsupported_car...")
    message = "What do you think about BMW X5?"
    try:
        result = collect_chat_response(client, message)
    except Exception as e:
        print(f"   Call failed: {e}")
        raise
    text = result if isinstance(result, str) else str(result)
    assert "Configuration Error" not in text and "Initialization Error" not in text
    # Refusal or supported list
    has_refusal = (
        "not in my knowledge" in text.lower()
        or "ืœื ื ืžืฆื" in text
        or "supported" in text.lower()
        or "ื ืชืžื›ื™ื" in text
        or "Citroen" in text
        or "Audi RS3" in text
    )
    assert has_refusal or len(text) > 20, f"Expected refusal/supported list, got: {text[:300]}"
    print("โœ… test_chat_unsupported_car passed")


def test_chat_comparison(client):
    """Ask to compare two supported cars โ€“ expect comparison content."""
    print("\n[Cloud] test_chat_comparison...")
    message = "Compare Audi RS3 vs Hyundai Elantra N"
    try:
        result = collect_chat_response(client, message)
    except Exception as e:
        print(f"   Call failed: {e}")
        raise
    text = result if isinstance(result, str) else str(result)
    assert "Configuration Error" not in text and "Initialization Error" not in text
    assert len(text.strip()) > 30, f"Response too short: {text[:200]}"
    print("โœ… test_chat_comparison passed")


def test_chat_hebrew(client):
    """Hebrew query โ€“ app should respond (Hebrew or English)."""
    print("\n[Cloud] test_chat_hebrew...")
    message = "ืกืคืจ ืœื™ ืขืœ ืื•ื“ื™ RS3"
    try:
        result = collect_chat_response(client, message)
    except Exception as e:
        print(f"   Call failed: {e}")
        raise
    text = result if isinstance(result, str) else str(result)
    assert "Configuration Error" not in text and "Initialization Error" not in text
    assert len(text.strip()) > 20, f"Response too short: {text[:200]}"
    print("โœ… test_chat_hebrew passed")


def test_chat_link_co_01(client):
    """Link & Co 01 is in the knowledge base โ€“ must NOT say 'not in my knowledge'."""
    print("\n[Cloud] test_chat_link_co_01...")
    for message in ["ืกืคืจ ืขืœ ืœื™ื ืง ืื ื“ ืงื• 01", "Tell me about Link and Co 01"]:
        try:
            result = collect_chat_response(client, message)
        except Exception as e:
            print(f"   Call failed for {message!r}: {e}")
            raise
        text = result if isinstance(result, str) else str(result)
        assert "Configuration Error" not in text and "Initialization Error" not in text
        assert "not in my knowledge" not in text and "ืœื ื ืžืฆื ื‘ื‘ืกื™ืก ื”ื™ื“ืข" not in text, (
            f"Link & Co 01 is in scraped_data (link-and-co-01-2026); got refusal: {text[:300]}"
        )
        assert len(text.strip()) > 50, f"Response too short for {message!r}: {text[:200]}"
    print("โœ… test_chat_link_co_01 passed")


def run_all():
    """Run all cloud tests. Exit 0 if all pass."""
    print("=" * 60)
    print("CarsRUS โ€“ Cloud tests")
    print(f"Space: {SPACE_URL}")
    print("=" * 60)
    try:
        client = test_space_reachable()
        test_chat_supported_car(client)
        test_chat_unsupported_car(client)
        test_chat_comparison(client)
        test_chat_hebrew(client)
        test_chat_link_co_01(client)
    except Exception as e:
        print(f"\nโŒ Cloud test failed: {e}")
        import traceback
        traceback.print_exc()
        return 1
    print("\nโœ… All cloud tests passed.")
    return 0


if __name__ == "__main__":
    sys.exit(run_all())