From f491d55ca59eed033ec7f4a9d890a8761bc660fa Mon Sep 17 00:00:00 2001 From: VIliam Date: Thu, 26 Mar 2026 16:13:58 +0100 Subject: [PATCH] s --- backend/clear_cache.py | 29 --- backend/test_app.py | 563 ----------------------------------------- 2 files changed, 592 deletions(-) delete mode 100755 backend/clear_cache.py delete mode 100755 backend/test_app.py diff --git a/backend/clear_cache.py b/backend/clear_cache.py deleted file mode 100755 index 10f9a7a..0000000 --- a/backend/clear_cache.py +++ /dev/null @@ -1,29 +0,0 @@ -import sqlite3 -from database import DB_NAME - -def clear_cache(): - """Vymaže všetky záznamy z databázy""" - conn = sqlite3.connect(DB_NAME) - cursor = conn.cursor() - - # Vymaž všetky fact-checky - cursor.execute("DELETE FROM fact_checks") - deleted_checks = cursor.rowcount - - # Vymaž všetky verified facts - cursor.execute("DELETE FROM verified_facts") - deleted_facts = cursor.rowcount - - # Reset autoincrement - cursor.execute("DELETE FROM sqlite_sequence WHERE name='fact_checks'") - cursor.execute("DELETE FROM sqlite_sequence WHERE name='verified_facts'") - - conn.commit() - conn.close() - - print(f"✅ Cache vyčistená!") - print(f" - Vymazaných fact-checkov: {deleted_checks}") - print(f" - Vymazaných verified facts: {deleted_facts}") - -if __name__ == "__main__": - clear_cache() diff --git a/backend/test_app.py b/backend/test_app.py deleted file mode 100755 index 7f83127..0000000 --- a/backend/test_app.py +++ /dev/null @@ -1,563 +0,0 @@ -""" -Testy pre AI Fact Checker aplikáciu -Spustenie: python -m pytest test_app.py -v -Alebo: python test_app.py -""" - -import pytest -import json -import os -import sys -from datetime import datetime, timedelta - -# Nastavíme prostredie pre testovanie -os.environ['TESTING'] = 'True' - -# Importujeme aplikáciu -from app import app, load_model, MODELS -from database import ( - get_db_connection, - get_cached_result, - save_to_cache, - get_history, - get_stats, - add_verified_fact, - hash_claim, - init_db -) - - -# ============================================================================= -# FIXTURES - Pomocné funkcie pre testy -# ============================================================================= - -@pytest.fixture -def client(): - """Vytvorí testovacieho klienta pre Flask aplikáciu""" - app.config['TESTING'] = True - with app.test_client() as client: - yield client - - -@pytest.fixture -def init_test_db(): - """Inicializuje čistú databázu pre testy""" - init_db() - yield - # Cleanup - vymažeme testovacie dáta - conn = get_db_connection() - cursor = conn.cursor() - cursor.execute("DELETE FROM fact_checks") - cursor.execute("DELETE FROM verified_facts") - conn.commit() - conn.close() - - -# ============================================================================= -# TESTY DATABÁZY -# ============================================================================= - -class TestDatabase: - """Testy pre databázové operácie""" - - def test_hash_claim_consistency(self): - """Test: Hash toho istého výroku je vždy rovnaký""" - claim = "Bratislava je hlavné mesto Slovenska" - hash1 = hash_claim(claim) - hash2 = hash_claim(claim) - assert hash1 == hash2, "Hash by mal byť konzistentný" - - def test_hash_claim_case_insensitive(self): - """Test: Hash je case-insensitive""" - claim1 = "Bratislava je hlavné mesto Slovenska" - claim2 = "bratislava je hlavné mesto slovenska" - hash1 = hash_claim(claim1) - hash2 = hash_claim(claim2) - assert hash1 == hash2, "Hash by mal byť case-insensitive" - - def test_hash_claim_different_claims(self): - """Test: Rôzne výroky majú rôzny hash""" - claim1 = "Bratislava je hlavné mesto Slovenska" - claim2 = "Košice sú druhé najväčšie mesto" - hash1 = hash_claim(claim1) - hash2 = hash_claim(claim2) - assert hash1 != hash2, "Rôzne výroky by mali mať rôzny hash" - - def test_save_and_get_cached_result(self, init_test_db): - """Test: Uloženie a získanie cachovaného výsledku""" - claim = "Testovací výrok pre cache" - result = { - "verdict": "✅ Pravda", - "confidence": 0.85, - "nli_votes": {"entailment": 3, "contradiction": 1}, - "evidence_for": ["Dôkaz 1"], - "evidence_against": [], - "sources": ["https://example.com"] - } - - # Uložíme do cache - saved = save_to_cache(claim, result, model_name="roberta") - assert saved == True, "Uloženie do cache zlyhalo" - - # Získame z cache - cached = get_cached_result(claim) - assert cached is not None, "Cache by nemala byť prázdna" - assert cached["verdict"] == "✅ Pravda" - assert cached["cached"] == True - assert cached["model_name"] == "roberta" - - def test_cache_miss(self, init_test_db): - """Test: Získanie neexistujúceho cachovaného výsledku""" - claim = "Tento výrok ešte nebol overený" - cached = get_cached_result(claim) - assert cached is None, "Cache by mala byť prázdna pre nový výrok" - - def test_get_history(self, init_test_db): - """Test: Získanie histórie overení""" - # Pridáme niekoľko záznamov - for i in range(5): - claim = f"Testovací výrok {i}" - result = { - "verdict": "✅ Pravda" if i % 2 == 0 else "❌ Nepravda", - "sources": [f"https://example{i}.com"] - } - save_to_cache(claim, result, model_name="roberta") - - history = get_history(limit=10) - assert len(history) == 5, "História by mala obsahovať 5 záznamov" - - def test_get_stats(self, init_test_db): - """Test: Získanie štatistík""" - # Pridáme testovacie dáta - for i in range(3): - claim = f"Štatistický výrok {i}" - result = {"verdict": "✅ Pravda", "sources": []} - save_to_cache(claim, result, model_name="roberta") - - # Pridáme manuálne overený fakt - add_verified_fact("Manuálne overený fakt", "TRUE", "Vysvetlenie") - - stats = get_stats() - assert stats["unique_claims"] == 3 - assert stats["verified_facts"] == 1 - assert stats["total_checks"] >= 3 - - def test_add_verified_fact_duplicate(self, init_test_db): - """Test: Pridanie duplicitného manuálne overeného faktu""" - claim = "Duplicitný fakt" - result1 = add_verified_fact(claim, "TRUE", "Prvé vysvetlenie") - result2 = add_verified_fact(claim, "FALSE", "Druhé vysvetlenie") - - assert result1 == True, "Prvý fakt by sa mal pridať" - assert result2 == False, "Duplicitný fakt by sa nemal pridať" - - -# ============================================================================= -# TESTY API ENDPOINTOV -# ============================================================================= - -class TestAPIEndpoints: - """Testy pre REST API endpointy""" - - def test_empty_claim_validation(self, client): - """Test: Validácia prázdneho výroku""" - response = client.post('/api/check', - data=json.dumps({"claim": ""}), - content_type='application/json') - assert response.status_code == 400 - data = json.loads(response.data) - assert "error" in data - - def test_whitespace_only_claim(self, client): - """Test: Validácia výroku s iba medzerami""" - response = client.post('/api/check', - data=json.dumps({"claim": " "}), - content_type='application/json') - assert response.status_code == 400 - - def test_missing_claim_field(self, client): - """Test: Chýbajúce pole claim""" - response = client.post('/api/check', - data=json.dumps({"language": "sk"}), - content_type='application/json') - assert response.status_code == 400 - - def test_history_endpoint_empty(self, client, init_test_db): - """Test: História keď je prázdna""" - response = client.get('/api/history') - assert response.status_code == 200 - data = json.loads(response.data) - assert "history" in data - assert "count" in data - assert data["count"] == 0 - - def test_history_endpoint_with_data(self, client, init_test_db): - """Test: História s dátami""" - # Pridáme dáta cez cache - for i in range(3): - claim = f"História test {i}" - result = {"verdict": "✅ Pravda", "sources": []} - save_to_cache(claim, result, model_name="roberta") - - response = client.get('/api/history?limit=10') - assert response.status_code == 200 - data = json.loads(response.data) - assert data["count"] == 3 - - def test_stats_endpoint(self, client): - """Test: Štatistiky endpoint""" - response = client.get('/api/stats') - assert response.status_code == 200 - data = json.loads(response.data) - assert "unique_claims" in data - assert "total_checks" in data - assert "verified_facts" in data - - def test_admin_add_fact_success(self, client, init_test_db): - """Test: Pridanie manuálne overeného faktu (admin)""" - response = client.post('/api/admin/add-fact', - data=json.dumps({ - "claim": "Manuálne pridaný fakt", - "verdict": "TRUE", - "explanation": "Toto je vysvetlenie", - "source_url": "https://overenie.sk" - }), - content_type='application/json') - assert response.status_code == 200 - data = json.loads(response.data) - assert "message" in data - assert data["message"] == "Overený fakt pridaný" - - def test_admin_add_fact_missing_fields(self, client): - """Test: Chýbajúce povinné polia pre admin endpoint""" - response = client.post('/api/admin/add-fact', - data=json.dumps({ - "claim": "Neúplný fakt" - # Chýba verdict - }), - content_type='application/json') - assert response.status_code == 400 - - def test_admin_add_fact_duplicate(self, client, init_test_db): - """Test: Pridanie duplicitného faktu""" - # Prvýkrát úspech - response1 = client.post('/api/admin/add-fact', - data=json.dumps({ - "claim": "Duplicitný admin fakt", - "verdict": "TRUE" - }), - content_type='application/json') - assert response1.status_code == 200 - - # Druhýkrát chyba (duplicate) - response2 = client.post('/api/admin/add-fact', - data=json.dumps({ - "claim": "Duplicitný admin fakt", - "verdict": "FALSE" - }), - content_type='application/json') - assert response2.status_code == 409 - - -# ============================================================================= -# TESTY VALIDÁCIE VSTUPU -# ============================================================================= - -class TestInputValidation: - """Testy pre validáciu vstupov a filtre""" - - def test_forbidden_word_politician(self, client): - """Test: Zakázané slová - politici""" - response = client.post('/api/check', - data=json.dumps({ - "claim": "Fico je politik" - }), - content_type='application/json') - assert response.status_code == 400 - data = json.loads(response.data) - assert "forbidden_words" in data - - def test_forbidden_word_vulgar(self, client): - """Test: Zakázané slová - vulgárnosti""" - response = client.post('/api/check', - data=json.dumps({ - "claim": "Toto je kokotina" - }), - content_type='application/json') - assert response.status_code == 400 - - def test_forbidden_word_covid(self, client): - """Test: Zakázané slová - citlivé témy""" - response = client.post('/api/check', - data=json.dumps({ - "claim": "Vakcína spôsobuje neplodnosť" - }), - content_type='application/json') - assert response.status_code == 400 - - def test_forbidden_word_english(self, client): - """Test: Zakázané slová - anglické výrazy""" - response = client.post('/api/check', - data=json.dumps({ - "claim": "This is bullshit" - }), - content_type='application/json') - assert response.status_code == 400 - - def test_clean_claim_passes(self, client): - """Test: Čistý výrok prejde""" - # Tento test vyžaduje funkčný SerpAPI kľúč - # Ak nie je nastavený, vráti 500 - if not os.getenv('SERPAPI_API_KEY'): - pytest.skip("SERPAPI_API_KEY nie je nastavený") - - response = client.post('/api/check', - data=json.dumps({ - "claim": "Bratislava je hlavné mesto Slovenska" - }), - content_type='application/json') - # Môže byť 200 (úspech) alebo 429 (limit API) - assert response.status_code in [200, 429] - - -# ============================================================================= -# TESTY MODELOV -# ============================================================================= - -class TestModels: - """Testy pre AI modely""" - - def test_model_config_exists(self): - """Test: Konfigurácia modelov existuje""" - assert "roberta" in MODELS - assert "mdeberta" in MODELS - - def test_roberta_config(self): - """Test: RoBERTa konfigurácia""" - config = MODELS["roberta"] - assert config["needs_translation"] == True - assert "roberta" in config["name"].lower() - - def test_mdeberta_config(self): - """Test: mDeBERTa konfigurácia""" - config = MODELS["mdeberta"] - assert config["needs_translation"] == False - assert "mdeberta" in config["name"].lower() or "DeBERTa" in config["name"] - - def test_model_loading(self): - """Test: Načítanie modelu""" - # Testujeme že funkcia load_model existuje a nespôsobí chybu - try: - load_model("roberta") - assert True - except Exception as e: - pytest.fail(f"Načítanie modelu zlyhalo: {e}") - - -# ============================================================================= -# TESTY CACHE LOGIKY -# ============================================================================= - -class TestCacheLogic: - """Testy pre cachovaciu logiku""" - - def test_cache_increments_count(self, init_test_db): - """Test: Cache inkrementuje počet overení""" - claim = "Inkrementácia test" - result = {"verdict": "✅ Pravda", "sources": []} - - # Prvé uloženie - save_to_cache(claim, result, model_name="roberta") - cached1 = get_cached_result(claim) - count1 = cached1["check_count"] - - # Druhé získanie (inkrementuje) - cached2 = get_cached_result(claim) - count2 = cached2["check_count"] - - assert count2 == count1 + 1, "Počet overení by sa mal inkrementovať" - - def test_cache_updates_timestamp(self, init_test_db): - """Test: Cache aktualizuje časovú pečiatku""" - claim = "Timestamp test" - result = {"verdict": "✅ Pravda", "sources": []} - - save_to_cache(claim, result, model_name="roberta") - cached1 = get_cached_result(claim) - timestamp1 = cached1["checked_at"] - - import time - time.sleep(1) # Počkáme sekundu - - cached2 = get_cached_result(claim) - timestamp2 = cached2["checked_at"] - - # Timestamp by mal byť novší - assert timestamp2 >= timestamp1 - - def test_cache_serialization(self, init_test_db): - """Test: Serializácia JSON polí v cache""" - claim = "JSON serializácia test" - result = { - "verdict": "✅ Pravda", - "nli_votes": {"entailment": 0.8, "contradiction": 0.2}, - "evidence_for": [{"text": "Dôkaz 1", "confidence": 0.9}], - "evidence_against": [], - "sources": [{"url": "https://example.com", "label": "entailment"}] - } - - save_to_cache(claim, result, model_name="mdeberta") - cached = get_cached_result(claim) - - assert isinstance(cached["nli_votes"], dict) - assert isinstance(cached["evidence_for"], list) - assert isinstance(cached["evidence_against"], list) - - -# ============================================================================= -# INTEGRÁCNE TESTY -# ============================================================================= - -class TestIntegration: - """Integračné testy celého systému""" - - def test_full_request_cycle(self, client, init_test_db): - """Test: Celý cyklus požiadavky (bez SerpAPI)""" - # Testujeme validáciu a štruktúru odpovede - # Bez SerpAPI kľúča očakávame chybu 500 - - response = client.post('/api/check', - data=json.dumps({ - "claim": "Testovací výrok", - "language": "sk", - "model": "roberta" - }), - content_type='application/json') - - # Bez SerpAPI: 500, so SerpAPI: 200 alebo 429 - if os.getenv('SERPAPI_API_KEY'): - assert response.status_code in [200, 429] - else: - assert response.status_code == 500 - - def test_model_switching(self, client): - """Test: Prepínanie medzi modelmi""" - # Overíme že endpoint akceptuje parameter model - response = client.post('/api/check', - data=json.dumps({ - "claim": "", # Prázdne pre rýchly test - "model": "mdeberta" - }), - content_type='application/json') - - # Očakávame 400 (validation error) nie 500 (model error) - assert response.status_code == 400 - - def test_verified_fact_overrides_cache(self, client, init_test_db): - """Test: Manuálne overený fakt má prioritu pred cache""" - claim = "Prioritný fakt" - - # Najprv pridáme manuálne overený fakt - add_verified_fact(claim, "TRUE", "Oficiálne overené", "https://overenie.sk") - - # Potom pridáme do cache iný výsledok - cache_result = { - "verdict": "❌ Nepravda", - "sources": ["https://ine-zdroj.sk"] - } - save_to_cache(claim, cache_result, model_name="roberta") - - # Získanie by malo vrátiť manuálne overený fakt - cached = get_cached_result(claim) - assert cached is not None - assert cached["verified"] == True - assert "Overené" in cached["verdict"] - - -# ============================================================================= -# HRANIČNÉ PRÍPADY -# ============================================================================= - -class TestEdgeCases: - """Testy hraničných prípadov""" - - def test_very_long_claim(self, client): - """Test: Veľmi dlhý výrok""" - long_claim = "A" * 10000 # 10k znakov - response = client.post('/api/check', - data=json.dumps({"claim": long_claim}), - content_type='application/json') - # Aplikácia by mala zvládnuť dlhý vstup (vráti "nedostatok zdrojov" alebo spracuje) - assert response.status_code == 200 # Očakávame úspešné spracovanie - data = json.loads(response.data) - assert "verdict" in data # Mala by vrátiť verdikt - - def test_unicode_claim(self, client): - """Test: Výrok s Unicode znakmi""" - unicode_claim = "🌍 je guľatá 🌍" - response = client.post('/api/check', - data=json.dumps({"claim": unicode_claim}), - content_type='application/json') - # Aplikácia by mala správne spracovať Unicode (emoji, diakritika) - assert response.status_code == 200 - data = json.loads(response.data) - assert "verdict" in data # Mala by vrátiť verdikt - - def test_sql_injection_attempt(self, client): - """Test: Pokus o SQL injection""" - malicious_claim = "'; DROP TABLE fact_checks; --" - response = client.post('/api/check', - data=json.dumps({"claim": malicious_claim}), - content_type='application/json') - # Aplikácia by mala bezpečne spracovať vstup (parametrované dotazy) - assert response.status_code == 200 # Nemalo by to zhodiť server - # Overíme že databáza stále existuje - from database import get_stats - stats = get_stats() # Ak toto prejde, SQL injection zlyhal - assert stats is not None - - def test_special_characters_claim(self, client): - """Test: Výrok so špeciálnymi znakmi""" - special_claim = "Cena je 100€ (zľava 50%!) " - response = client.post('/api/check', - data=json.dumps({"claim": special_claim}), - content_type='application/json') - assert response.status_code in [400, 500, 429] - - def test_empty_json_body(self, client): - """Test: Prázdne JSON telo""" - response = client.post('/api/check', - data=json.dumps({}), - content_type='application/json') - assert response.status_code == 400 - - def test_invalid_json(self, client): - """Test: Neplatné JSON""" - response = client.post('/api/check', - data="nie je json", - content_type='application/json') - assert response.status_code == 400 - - def test_history_limit_zero(self, client, init_test_db): - """Test: História s limitom 0""" - # Pridáme dáta - save_to_cache("Test", {"verdict": "✅", "sources": []}, "roberta") - - response = client.get('/api/history?limit=0') - data = json.loads(response.data) - assert data["count"] == 0 - assert len(data["history"]) == 0 - - def test_history_large_limit(self, client, init_test_db): - """Test: História s veľkým limitom""" - response = client.get('/api/history?limit=999999') - assert response.status_code == 200 - - -# ============================================================================= -# SPUSTENIE TESTOV -# ============================================================================= - -if __name__ == '__main__': - # Spustenie priamym zavolaním: python test_app.py - pytest.main([__file__, '-v', '--tb=short'])