2 changed files with 452 additions and 2 deletions
@ -1,3 +1,335 @@ |
|||||
from django.test import TestCase |
|
||||
|
from django.test import TestCase, override_settings |
||||
|
from django.urls import reverse, resolve |
||||
|
from rest_framework.test import APITestCase |
||||
|
from rest_framework import status |
||||
|
from django.test.utils import override_settings |
||||
|
|
||||
# Create your tests here. |
|
||||
|
|
||||
|
class HadisAPIConnectivityTests(APITestCase): |
||||
|
""" |
||||
|
Test suite for hadis app API endpoints connectivity. |
||||
|
Tests that all endpoints return proper HTTP responses. |
||||
|
""" |
||||
|
|
||||
|
# Comment out fixtures for now to avoid migration issues |
||||
|
# fixtures = [ |
||||
|
# 'backend/apps/hadis/fixtures/new_categories.json', |
||||
|
# 'backend/apps/hadis/fixtures/hadises1_reformatted.json', |
||||
|
# 'backend/apps/hadis/fixtures/transmitters_reformatted.json', |
||||
|
# ] |
||||
|
|
||||
|
def test_collections_endpoint(self): |
||||
|
"""Test collections endpoint returns 200""" |
||||
|
url = reverse('hadis-collection-list') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_sync_sects_endpoint(self): |
||||
|
"""Test sync sects endpoint returns 200""" |
||||
|
url = reverse('hadis-sect-list') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_sync_categories_tree_endpoint(self): |
||||
|
"""Test sync categories tree endpoint returns 200""" |
||||
|
url = reverse('hadis-category-tree') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_sync_hadis_endpoint(self): |
||||
|
"""Test sync hadis endpoint returns 200""" |
||||
|
url = reverse('hadis-sync') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_sync_narrators_endpoint(self): |
||||
|
"""Test sync narrators endpoint returns 200""" |
||||
|
url = reverse('transmitter-sync') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_sync_references_endpoint(self): |
||||
|
"""Test sync references endpoint returns 200""" |
||||
|
url = reverse('reference-sync') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_info_endpoint(self): |
||||
|
"""Test info endpoint returns 200""" |
||||
|
url = reverse('hadis-info') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_categories_tree_normal_endpoint(self): |
||||
|
"""Test categories tree normal endpoint returns 200""" |
||||
|
url = reverse('hadis-category-tree-normal') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_categories_endpoint(self): |
||||
|
"""Test categories endpoint returns 200""" |
||||
|
url = reverse('categories') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_categories_by_sect_endpoint(self): |
||||
|
"""Test categories by sect endpoint is accessible""" |
||||
|
# Using a common sect type |
||||
|
url = reverse('categories-by-sect', kwargs={'sect_type': '1'}) |
||||
|
response = self.client.get(url) |
||||
|
# May return 200 if data exists, or 404 if not - but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_categories_by_sect_with_slug_endpoint(self): |
||||
|
"""Test categories by sect with slug endpoint is accessible""" |
||||
|
# Using common parameters |
||||
|
url = reverse('categories-tree-by-sect', kwargs={ |
||||
|
'sect_type': '1', |
||||
|
'slug': 'test-category' |
||||
|
}) |
||||
|
response = self.client.get(url) |
||||
|
# May return 200 if data exists, or 404 if not - but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_categories_by_sect_source_endpoint(self): |
||||
|
"""Test categories by sect source endpoint is accessible""" |
||||
|
# Using common parameters |
||||
|
url = reverse('categories-tree-by-sect-source', kwargs={ |
||||
|
'sect_type': '1', |
||||
|
'slug': 'test-category', |
||||
|
'source_type': 'quran' |
||||
|
}) |
||||
|
response = self.client.get(url) |
||||
|
# May return 200 if data exists, or 404 if not - but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_hadis_main_list_endpoint(self): |
||||
|
"""Test hadis main list (arguments) endpoint returns 200""" |
||||
|
url = reverse('hadis-main-list') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_hadis_filters_endpoint(self): |
||||
|
"""Test hadis filters endpoint returns 200""" |
||||
|
url = reverse('hadis-filters') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_narrators_endpoint(self): |
||||
|
"""Test narrators endpoint returns 200""" |
||||
|
url = reverse('narrators') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_narrator_filters_endpoint(self): |
||||
|
"""Test narrator filters endpoint returns 200""" |
||||
|
url = reverse('narrator-filters') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_narrator_detail_endpoint(self): |
||||
|
"""Test narrator detail endpoint is accessible""" |
||||
|
# Using a test narrator slug |
||||
|
url = reverse('narrator-detail', kwargs={'narrator_slug': 'test-narrator'}) |
||||
|
response = self.client.get(url) |
||||
|
# May return 200 if narrator exists, or 404 if not - but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_narrator_opinions_endpoint(self): |
||||
|
"""Test narrator opinions endpoint is accessible""" |
||||
|
# Using a test narrator slug |
||||
|
url = reverse('narrator-opinions', kwargs={'narrator_slug': 'test-narrator'}) |
||||
|
response = self.client.get(url) |
||||
|
# May return 200 if narrator exists, or 404 if not - but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_narrator_original_texts_endpoint(self): |
||||
|
"""Test narrator original texts endpoint is accessible""" |
||||
|
# Using a test narrator slug |
||||
|
url = reverse('narrator-original-texts', kwargs={'narrator_slug': 'test-narrator'}) |
||||
|
response = self.client.get(url) |
||||
|
# May return 200 if narrator exists, or 404 if not - but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_references_endpoint(self): |
||||
|
"""Test references endpoint returns 200""" |
||||
|
url = reverse('references') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
|
||||
|
def test_category_hadis_list_endpoint(self): |
||||
|
"""Test category hadis list endpoint is accessible""" |
||||
|
# Using a test category slug |
||||
|
url = reverse('hadis-list', kwargs={'category_slug': 'test-category'}) |
||||
|
response = self.client.get(url) |
||||
|
# May return 200 if category exists, or 404 if not - but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
# Parameterized endpoints that may not have data - these might return 404 but should still be accessible |
||||
|
def test_reference_detail_endpoint(self): |
||||
|
"""Test reference detail endpoint is accessible (may return 404 if no data)""" |
||||
|
url = reverse('reference-detail', kwargs={'reference_slug': 'test-reference'}) |
||||
|
response = self.client.get(url) |
||||
|
# This might return 404 if reference doesn't exist, but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_hadis_basic_endpoint(self): |
||||
|
"""Test hadis basic endpoint is accessible (may return 404 if no data)""" |
||||
|
url = reverse('hadis-basic', kwargs={'hadis_slug': 'test-hadis'}) |
||||
|
response = self.client.get(url) |
||||
|
# This might return 404 if hadis doesn't exist, but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_hadis_detail_endpoint(self): |
||||
|
"""Test hadis detail endpoint is accessible (may return 404 if no data)""" |
||||
|
url = reverse('hadis-detail', kwargs={'hadis_slug': 'test-hadis'}) |
||||
|
response = self.client.get(url) |
||||
|
# This might return 404 if hadis doesn't exist, but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_hadis_transmitters_endpoint(self): |
||||
|
"""Test hadis transmitters endpoint is accessible (may return 404 if no data)""" |
||||
|
url = reverse('hadis-transmitters', kwargs={'hadis_slug': 'test-hadis'}) |
||||
|
response = self.client.get(url) |
||||
|
# This might return 404 if hadis doesn't exist, but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
def test_hadis_corrections_endpoint(self): |
||||
|
"""Test hadis corrections endpoint is accessible (may return 404 if no data)""" |
||||
|
url = reverse('hadis-corrections', kwargs={'hadis_slug': 'test-hadis'}) |
||||
|
response = self.client.get(url) |
||||
|
# This might return 404 if hadis doesn't exist, but endpoint should be accessible |
||||
|
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]) |
||||
|
|
||||
|
|
||||
|
class HadisAPIResponseStructureTests(APITestCase): |
||||
|
""" |
||||
|
Additional tests to ensure API responses have proper structure |
||||
|
""" |
||||
|
|
||||
|
# Comment out fixtures for now to avoid migration issues |
||||
|
# fixtures = [ |
||||
|
# 'backend/apps/hadis/fixtures/new_categories.json', |
||||
|
# 'backend/apps/hadis/fixtures/hadises1_reformatted.json', |
||||
|
# 'backend/apps/hadis/fixtures/transmitters_reformatted.json', |
||||
|
# ] |
||||
|
|
||||
|
def test_api_returns_json_content_type(self): |
||||
|
"""Test that API endpoints return JSON content type""" |
||||
|
endpoints = [ |
||||
|
reverse('hadis-collection-list'), |
||||
|
reverse('hadis-info'), |
||||
|
reverse('categories'), |
||||
|
reverse('hadis-main-list'), |
||||
|
reverse('narrators'), |
||||
|
] |
||||
|
|
||||
|
for url in endpoints: |
||||
|
with self.subTest(url=url): |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
self.assertEqual(response['Content-Type'], 'application/json') |
||||
|
|
||||
|
def test_api_endpoints_are_cached(self): |
||||
|
"""Test that API endpoints have cache headers (from cached_view decorator)""" |
||||
|
url = reverse('hadis-info') |
||||
|
response = self.client.get(url) |
||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK) |
||||
|
# Check if cache headers are present (this indicates caching is working) |
||||
|
cache_headers = ['Cache-Control', 'Expires', 'ETag'] |
||||
|
has_cache_header = any(header in response for header in cache_headers) |
||||
|
self.assertTrue(has_cache_header, "API endpoint should have cache headers") |
||||
|
|
||||
|
|
||||
|
class HadisURLResolutionTests(TestCase): |
||||
|
""" |
||||
|
Test that all hadis URLs are properly configured and resolvable. |
||||
|
These tests don't require database access. |
||||
|
""" |
||||
|
|
||||
|
def test_all_url_names_are_resolvable(self): |
||||
|
"""Test that all URL names can be reversed without parameters""" |
||||
|
url_names = [ |
||||
|
'hadis-collection-list', |
||||
|
'hadis-sect-list', |
||||
|
'hadis-category-tree', |
||||
|
'hadis-sync', |
||||
|
'transmitter-sync', |
||||
|
'reference-sync', |
||||
|
'hadis-info', |
||||
|
'hadis-category-tree-normal', |
||||
|
'categories', |
||||
|
'hadis-main-list', |
||||
|
'hadis-filters', |
||||
|
'narrator-filters', |
||||
|
'narrators', |
||||
|
'references', |
||||
|
] |
||||
|
|
||||
|
for url_name in url_names: |
||||
|
with self.subTest(url_name=url_name): |
||||
|
try: |
||||
|
url = reverse(url_name) |
||||
|
# If we get here, the URL is resolvable |
||||
|
self.assertIsInstance(url, str) |
||||
|
self.assertTrue(url.startswith('/')) |
||||
|
except Exception as e: |
||||
|
self.fail(f"URL name '{url_name}' could not be reversed: {e}") |
||||
|
|
||||
|
def test_parameterized_url_names_are_resolvable(self): |
||||
|
"""Test that parameterized URL names can be reversed with test parameters""" |
||||
|
parameterized_urls = [ |
||||
|
('categories-by-sect', {'sect_type': '1'}), |
||||
|
('categories-tree-by-sect', {'sect_type': '1', 'slug': 'test'}), |
||||
|
('categories-tree-by-sect-source', {'sect_type': '1', 'slug': 'test', 'source_type': 'quran'}), |
||||
|
('hadis-list', {'category_slug': 'test'}), |
||||
|
('narrator-detail', {'narrator_slug': 'test'}), |
||||
|
('narrator-opinions', {'narrator_slug': 'test'}), |
||||
|
('narrator-original-texts', {'narrator_slug': 'test'}), |
||||
|
('reference-detail', {'reference_slug': 'test'}), |
||||
|
('hadis-basic', {'hadis_slug': 'test'}), |
||||
|
('hadis-detail', {'hadis_slug': 'test'}), |
||||
|
('hadis-transmitters', {'hadis_slug': 'test'}), |
||||
|
('hadis-corrections', {'hadis_slug': 'test'}), |
||||
|
] |
||||
|
|
||||
|
for url_name, kwargs in parameterized_urls: |
||||
|
with self.subTest(url_name=url_name): |
||||
|
try: |
||||
|
url = reverse(url_name, kwargs=kwargs) |
||||
|
# If we get here, the URL is resolvable |
||||
|
self.assertIsInstance(url, str) |
||||
|
self.assertTrue(url.startswith('/')) |
||||
|
except Exception as e: |
||||
|
self.fail(f"URL name '{url_name}' could not be reversed with kwargs {kwargs}: {e}") |
||||
|
|
||||
|
def test_urls_resolve_to_correct_views(self): |
||||
|
"""Test that URLs resolve to the correct view functions/classes""" |
||||
|
test_urls = [ |
||||
|
('/hadis/collections/', 'hadis-collection-list'), |
||||
|
('/hadis/sync/sects/', 'hadis-sect-list'), |
||||
|
('/hadis/sync/categories/tree/', 'hadis-category-tree'), |
||||
|
('/hadis/sync/hadis/', 'hadis-sync'), |
||||
|
('/hadis/sync/narrators/', 'transmitter-sync'), |
||||
|
('/hadis/sync/references/', 'reference-sync'), |
||||
|
('/hadis/info/', 'hadis-info'), |
||||
|
('/hadis/categories/tree/', 'hadis-category-tree-normal'), |
||||
|
('/hadis/categories/', 'categories'), |
||||
|
('/hadis/arguments/', 'hadis-main-list'), |
||||
|
('/hadis/arguments/filters/', 'hadis-filters'), |
||||
|
('/hadis/narrators/filters/', 'narrator-filters'), |
||||
|
('/hadis/narrators/', 'narrators'), |
||||
|
('/hadis/references/', 'references'), |
||||
|
] |
||||
|
|
||||
|
for url_path, expected_url_name in test_urls: |
||||
|
with self.subTest(url_path=url_path): |
||||
|
try: |
||||
|
resolved = resolve(url_path) |
||||
|
# Check that the URL resolves |
||||
|
self.assertIsNotNone(resolved) |
||||
|
# Check that we can reverse back to the same URL |
||||
|
reversed_url = reverse(expected_url_name) |
||||
|
self.assertEqual(url_path, reversed_url) |
||||
|
except Exception as e: |
||||
|
self.fail(f"URL '{url_path}' could not be resolved: {e}") |
||||
@ -0,0 +1,118 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
""" |
||||
|
Simple script to test hadis API endpoints connectivity. |
||||
|
This script manually tests all hadis URLs to verify they return proper HTTP status codes. |
||||
|
""" |
||||
|
|
||||
|
import os |
||||
|
import sys |
||||
|
import django |
||||
|
from django.conf import settings |
||||
|
from django.test import override_settings |
||||
|
|
||||
|
# Setup Django |
||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.base') |
||||
|
django.setup() |
||||
|
|
||||
|
from django.test import Client |
||||
|
from django.urls import reverse |
||||
|
from rest_framework import status |
||||
|
|
||||
|
|
||||
|
def test_endpoint(client, url_name, kwargs=None, description=""): |
||||
|
"""Test a single endpoint and return the result""" |
||||
|
try: |
||||
|
if kwargs: |
||||
|
url = reverse(url_name, kwargs=kwargs) |
||||
|
else: |
||||
|
url = reverse(url_name) |
||||
|
|
||||
|
response = client.get(url) |
||||
|
status_code = response.status_code |
||||
|
|
||||
|
if status_code in [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND]: |
||||
|
result = "✅ PASS" |
||||
|
else: |
||||
|
result = f"❌ FAIL ({status_code})" |
||||
|
|
||||
|
print(f"{result} {description}: {url} -> {status_code}") |
||||
|
return status_code in [status.HTTP_200_OK, status.HTTP_404_NOT_FOUND] |
||||
|
|
||||
|
except Exception as e: |
||||
|
print(f"❌ ERROR {description}: {url_name} -> {str(e)}") |
||||
|
return False |
||||
|
|
||||
|
|
||||
|
def main(): |
||||
|
"""Main test function""" |
||||
|
print("🧪 Testing Hadis API Endpoints Connectivity") |
||||
|
print("=" * 60) |
||||
|
|
||||
|
# Override ALLOWED_HOSTS for testing |
||||
|
with override_settings(ALLOWED_HOSTS=['testserver']): |
||||
|
client = Client() |
||||
|
total_tests = 0 |
||||
|
passed_tests = 0 |
||||
|
|
||||
|
# Test non-parameterized endpoints |
||||
|
print("\n📋 Testing non-parameterized endpoints:") |
||||
|
non_param_endpoints = [ |
||||
|
('hadis-collection-list', None, 'Collections'), |
||||
|
('hadis-sect-list', None, 'Sync Sects'), |
||||
|
('hadis-category-tree', None, 'Sync Categories Tree'), |
||||
|
('hadis-sync', None, 'Sync Hadis'), |
||||
|
('transmitter-sync', None, 'Sync Narrators'), |
||||
|
('reference-sync', None, 'Sync References'), |
||||
|
('hadis-info', None, 'Info'), |
||||
|
('hadis-category-tree-normal', None, 'Categories Tree Normal'), |
||||
|
('categories', None, 'Categories'), |
||||
|
('hadis-main-list', None, 'Hadis Main List (Arguments)'), |
||||
|
('hadis-filters', None, 'Hadis Filters'), |
||||
|
('narrator-filters', None, 'Narrator Filters'), |
||||
|
('narrators', None, 'Narrators'), |
||||
|
('references', None, 'References'), |
||||
|
] |
||||
|
|
||||
|
for url_name, kwargs, description in non_param_endpoints: |
||||
|
total_tests += 1 |
||||
|
if test_endpoint(client, url_name, kwargs, description): |
||||
|
passed_tests += 1 |
||||
|
|
||||
|
# Test parameterized endpoints |
||||
|
print("\n📋 Testing parameterized endpoints:") |
||||
|
param_endpoints = [ |
||||
|
('categories-by-sect', {'sect_type': '1'}, 'Categories by Sect (type=1)'), |
||||
|
('categories-tree-by-sect', {'sect_type': '1', 'slug': 'test-category'}, 'Categories Tree by Sect'), |
||||
|
('categories-tree-by-sect-source', {'sect_type': '1', 'slug': 'test-category', 'source_type': 'quran'}, 'Categories Tree by Sect Source'), |
||||
|
('hadis-list', {'category_slug': 'test-category'}, 'Hadis List by Category'), |
||||
|
('narrator-detail', {'narrator_slug': 'test-narrator'}, 'Narrator Detail'), |
||||
|
('narrator-opinions', {'narrator_slug': 'test-narrator'}, 'Narrator Opinions'), |
||||
|
('narrator-original-texts', {'narrator_slug': 'test-narrator'}, 'Narrator Original Texts'), |
||||
|
('reference-detail', {'reference_slug': 'test-reference'}, 'Reference Detail'), |
||||
|
('hadis-basic', {'hadis_slug': 'test-hadis'}, 'Hadis Basic'), |
||||
|
('hadis-detail', {'hadis_slug': 'test-hadis'}, 'Hadis Detail'), |
||||
|
('hadis-transmitters', {'hadis_slug': 'test-hadis'}, 'Hadis Transmitters'), |
||||
|
('hadis-corrections', {'hadis_slug': 'test-hadis'}, 'Hadis Corrections'), |
||||
|
] |
||||
|
|
||||
|
for url_name, kwargs, description in param_endpoints: |
||||
|
total_tests += 1 |
||||
|
if test_endpoint(client, url_name, kwargs, description): |
||||
|
passed_tests += 1 |
||||
|
|
||||
|
# Summary |
||||
|
print("\n" + "=" * 60) |
||||
|
print(f"📊 Test Results: {passed_tests}/{total_tests} endpoints accessible") |
||||
|
success_rate = (passed_tests / total_tests) * 100 if total_tests > 0 else 0 |
||||
|
print(f"📈 Success Rate: {success_rate:.1f}%") |
||||
|
if passed_tests == total_tests: |
||||
|
print("✅ All endpoints are properly configured and accessible!") |
||||
|
else: |
||||
|
print("⚠️ Some endpoints may have issues") |
||||
|
|
||||
|
return passed_tests == total_tests |
||||
|
|
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
success = main() |
||||
|
sys.exit(0 if success else 1) |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue