Creado Tests
This commit is contained in:
parent
79194e0f61
commit
b48058e495
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
Simple script to generate a test report.
|
||||
This is a simplified version of run_tests.py focused on generating the JSON report.
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def main():
|
||||
"""Run tests and generate JSON report."""
|
||||
# Create directories if they don't exist
|
||||
os.makedirs("test_reports", exist_ok=True)
|
||||
|
||||
# Generate timestamp for current run
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
|
||||
print(f"Running tests and generating JSON report with timestamp: {timestamp}")
|
||||
|
||||
# Run pytest with the JSON reporter plugin loaded
|
||||
cmd = [
|
||||
"pytest",
|
||||
"-v",
|
||||
"--tb=short",
|
||||
f"--junitxml=test_reports/junit_{timestamp}.xml",
|
||||
"-p",
|
||||
"tests.json_reporter",
|
||||
"tests/",
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd, capture_output=False)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("\nTests completed successfully!")
|
||||
else:
|
||||
print(f"\nTests completed with some failures (exit code: {result.returncode})")
|
||||
|
||||
print(
|
||||
f"JSON report should be available at: test_reports/test_results_{timestamp}.json"
|
||||
)
|
||||
|
||||
return result.returncode
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
66
run_tests.py
66
run_tests.py
|
@ -11,63 +11,73 @@ import json
|
|||
import shutil
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def run_tests(args):
|
||||
"""Run pytest with specified arguments and generate reports."""
|
||||
# Create test reports directory if needed
|
||||
os.makedirs('test_reports', exist_ok=True)
|
||||
|
||||
os.makedirs("test_reports", exist_ok=True)
|
||||
|
||||
# Generate timestamp for report files
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
|
||||
# Base pytest arguments
|
||||
pytest_args = [
|
||||
'-v', # Verbose output
|
||||
'--no-header', # No header in the output
|
||||
'--tb=short', # Short traceback
|
||||
f'--junitxml=test_reports/junit_{timestamp}.xml', # JUnit XML report
|
||||
'--cov=app', # Coverage for app module
|
||||
'--cov=routes', # Coverage for routes
|
||||
'--cov=services', # Coverage for services
|
||||
'--cov=utils', # Coverage for utils
|
||||
'--cov-report=html:test_reports/coverage', # HTML coverage report
|
||||
"-v", # Verbose output
|
||||
"--no-header", # No header in the output
|
||||
"--tb=short", # Short traceback
|
||||
f"--junitxml=test_reports/junit_{timestamp}.xml", # JUnit XML report
|
||||
"--cov=app", # Coverage for app module
|
||||
"--cov=routes", # Coverage for routes
|
||||
"--cov=services", # Coverage for services
|
||||
"--cov=utils", # Coverage for utils
|
||||
"--cov-report=html:test_reports/coverage", # HTML coverage report
|
||||
"-p",
|
||||
"tests.json_reporter", # Load the JSON reporter plugin explicitly
|
||||
]
|
||||
|
||||
|
||||
# Add test files/directories
|
||||
if args.tests:
|
||||
pytest_args.extend(args.tests)
|
||||
else:
|
||||
pytest_args.append('tests/')
|
||||
|
||||
pytest_args.append("tests/")
|
||||
|
||||
# Execute tests
|
||||
print(f"\n{'='*80}")
|
||||
print(f"Running tests at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f"{'='*80}")
|
||||
|
||||
|
||||
result = pytest.main(pytest_args)
|
||||
|
||||
|
||||
# Generate JSON report
|
||||
print(f"\n{'='*80}")
|
||||
print(f"Test report available at: test_reports/test_results_{timestamp}.json")
|
||||
print(f"Coverage report available at: test_reports/coverage/index.html")
|
||||
print(f"{'='*80}\n")
|
||||
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Run tests for ARCH application")
|
||||
parser.add_argument('tests', nargs='*', help='Specific test files or directories to run')
|
||||
parser.add_argument('--clean', action='store_true', help='Clean test storage and results before running')
|
||||
|
||||
parser.add_argument(
|
||||
"tests", nargs="*", help="Specific test files or directories to run"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--clean",
|
||||
action="store_true",
|
||||
help="Clean test storage and results before running",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
if args.clean:
|
||||
# Clean temporary test storage
|
||||
if os.path.exists('test_storage'):
|
||||
shutil.rmtree('test_storage')
|
||||
if os.path.exists("test_storage"):
|
||||
shutil.rmtree("test_storage")
|
||||
# Clean previous test reports
|
||||
if os.path.exists('test_reports'):
|
||||
shutil.rmtree('test_reports')
|
||||
if os.path.exists("test_reports"):
|
||||
shutil.rmtree("test_reports")
|
||||
print("Cleaned test storage and reports.")
|
||||
|
||||
|
||||
# Run tests and exit with the pytest result code
|
||||
sys.exit(run_tests(args))
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"max_project_id": 0,
|
||||
"max_document_id": 0
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"ESQ001": {
|
||||
"codigo": "ESQ001",
|
||||
"descripcion": "Proyecto estándar",
|
||||
"fecha_creacion": "2025-03-04T10:17:09.979764+00:00",
|
||||
"creado_por": "admin",
|
||||
"documentos": [
|
||||
{
|
||||
"tipo": "pdf",
|
||||
"nombre": "Manual de Usuario",
|
||||
"nivel_ver": 0,
|
||||
"nivel_editar": 5000
|
||||
},
|
||||
{
|
||||
"tipo": "dwg",
|
||||
"nombre": "Planos Técnicos",
|
||||
"nivel_ver": 0,
|
||||
"nivel_editar": 5000
|
||||
},
|
||||
{
|
||||
"tipo": "zip",
|
||||
"nombre": "Archivos Fuente",
|
||||
"nivel_ver": 1000,
|
||||
"nivel_editar": 5000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"admin": {
|
||||
"nombre": "Administrador",
|
||||
"username": "admin",
|
||||
"email": "admin@example.com",
|
||||
"password_hash": "$2b$04$MDmmt/Wr5K0vEpL0I2gfVOQb6af8xHtympw8lbDUjuTA8mY4wEJ7K",
|
||||
"nivel": 9999,
|
||||
"idioma": "es",
|
||||
"fecha_caducidad": null,
|
||||
"empresa": "",
|
||||
"estado": "activo",
|
||||
"ultimo_acceso": "2025-03-04T10:17:09.978287+00:00"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
# This file makes the tests directory a Python package
|
||||
# allowing the json_reporter module to be imported
|
|
@ -2,68 +2,132 @@ import pytest
|
|||
import os
|
||||
import json
|
||||
import shutil
|
||||
import time
|
||||
import tempfile
|
||||
from app import create_app
|
||||
|
||||
|
||||
def init_test_environment(storage_path):
|
||||
"""Initialize the test environment with required directories."""
|
||||
if os.path.exists(storage_path):
|
||||
try:
|
||||
shutil.rmtree(storage_path)
|
||||
except PermissionError:
|
||||
# Try to handle Windows file locking issues
|
||||
print(f"Warning: Could not remove {storage_path} directory, retrying...")
|
||||
time.sleep(1)
|
||||
try:
|
||||
shutil.rmtree(storage_path)
|
||||
except Exception as e:
|
||||
print(f"Failed to remove directory: {e}")
|
||||
|
||||
# Create main storage directory
|
||||
os.makedirs(storage_path, exist_ok=True)
|
||||
|
||||
# Create required subdirectories
|
||||
for dir_name in ["users", "schemas", "filetypes", "projects", "logs"]:
|
||||
os.makedirs(os.path.join(storage_path, dir_name), exist_ok=True)
|
||||
|
||||
# Initialize test data
|
||||
initialize_test_data(storage_path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app():
|
||||
"""Create a Flask application instance for testing."""
|
||||
# Test configuration
|
||||
test_config = {
|
||||
'TESTING': True,
|
||||
'STORAGE_PATH': 'test_storage',
|
||||
'SECRET_KEY': 'test_key',
|
||||
'WTF_CSRF_ENABLED': False
|
||||
}
|
||||
|
||||
# Create test storage directory
|
||||
if not os.path.exists('test_storage'):
|
||||
os.makedirs('test_storage')
|
||||
|
||||
# Create basic directory structure
|
||||
for dir_name in ['users', 'schemas', 'filetypes', 'projects', 'logs', 'exports']:
|
||||
if not os.path.exists(f'test_storage/{dir_name}'):
|
||||
os.makedirs(f'test_storage/{dir_name}')
|
||||
|
||||
# Use a unique temporary directory for each test session
|
||||
storage_path = tempfile.mkdtemp(prefix="arch_test_")
|
||||
|
||||
# Set up the test environment
|
||||
init_test_environment(storage_path)
|
||||
|
||||
# Create app with test configuration
|
||||
app = create_app('testing')
|
||||
|
||||
# Create context
|
||||
app = create_app("testing")
|
||||
|
||||
# Update the app's config with our test settings
|
||||
app.config.update(
|
||||
{
|
||||
"TESTING": True,
|
||||
"STORAGE_PATH": storage_path,
|
||||
"WTF_CSRF_ENABLED": False, # Disable CSRF protection for testing
|
||||
"SERVER_NAME": "localhost.localdomain", # Set server name to ensure correct URLs
|
||||
}
|
||||
)
|
||||
|
||||
# Create app context
|
||||
with app.app_context():
|
||||
# Set up test data
|
||||
initialize_test_data()
|
||||
|
||||
yield app
|
||||
|
||||
# Clean up after tests
|
||||
shutil.rmtree('test_storage', ignore_errors=True)
|
||||
yield app
|
||||
|
||||
# Clean up after tests - with retry mechanism for Windows
|
||||
max_retries = 3
|
||||
retry_delay = 1
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
if os.path.exists(storage_path):
|
||||
shutil.rmtree(storage_path)
|
||||
break
|
||||
except PermissionError:
|
||||
if attempt < max_retries - 1:
|
||||
print(
|
||||
f"Cleanup attempt {attempt+1} failed, retrying in {retry_delay}s..."
|
||||
)
|
||||
time.sleep(retry_delay)
|
||||
else:
|
||||
print(f"Warning: Could not clean up {storage_path}")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(app):
|
||||
"""Create a test client for the application."""
|
||||
return app.test_client()
|
||||
with app.test_client() as client:
|
||||
# Enable cookies and sessions for the test client
|
||||
client.testing = True
|
||||
yield client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def auth(client):
|
||||
"""Helper for authentication tests."""
|
||||
|
||||
class AuthActions:
|
||||
def login(self, username='admin', password='admin123'):
|
||||
return client.post('/auth/login', data={
|
||||
'username': username,
|
||||
'password': password
|
||||
}, follow_redirects=True)
|
||||
|
||||
def login(self, username="admin", password="admin123"):
|
||||
# Use session for better cookie handling
|
||||
with client.session_transaction() as session:
|
||||
# Pre-clear any existing session data
|
||||
session.clear()
|
||||
|
||||
response = client.post(
|
||||
"/auth/login",
|
||||
data={"username": username, "password": password},
|
||||
follow_redirects=True,
|
||||
)
|
||||
return response
|
||||
|
||||
def logout(self):
|
||||
return client.get('/auth/logout', follow_redirects=True)
|
||||
|
||||
return client.get("/auth/logout", follow_redirects=True)
|
||||
|
||||
return AuthActions()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def logged_in_client(client, auth):
|
||||
"""Client that's already logged in as admin."""
|
||||
auth.login()
|
||||
response = auth.login()
|
||||
|
||||
# Verify login was successful
|
||||
assert response.status_code == 200
|
||||
|
||||
# Check for expected content in response to confirm logged in state
|
||||
assert (
|
||||
b"Cerrar" in response.data
|
||||
or b"Logout" in response.data
|
||||
or b"Panel" in response.data
|
||||
)
|
||||
|
||||
return client
|
||||
|
||||
def initialize_test_data():
|
||||
|
||||
def initialize_test_data(storage_path):
|
||||
"""Initialize test data files."""
|
||||
# Create test users
|
||||
users_data = {
|
||||
|
@ -76,7 +140,7 @@ def initialize_test_data():
|
|||
"idioma": "es",
|
||||
"fecha_caducidad": None,
|
||||
"empresa": "ARCH",
|
||||
"estado": "activo"
|
||||
"estado": "activo",
|
||||
},
|
||||
"user1": {
|
||||
"nombre": "Usuario Normal",
|
||||
|
@ -87,32 +151,32 @@ def initialize_test_data():
|
|||
"idioma": "es",
|
||||
"fecha_caducidad": None,
|
||||
"empresa": "ARCH",
|
||||
"estado": "activo"
|
||||
}
|
||||
"estado": "activo",
|
||||
},
|
||||
}
|
||||
|
||||
with open('test_storage/users/users.json', 'w', encoding='utf-8') as f:
|
||||
|
||||
with open(f"{storage_path}/users/users.json", "w", encoding="utf-8") as f:
|
||||
json.dump(users_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
# Create test file types
|
||||
filetypes_data = {
|
||||
"pdf": {
|
||||
"extension": "pdf",
|
||||
"descripcion": "Documento PDF",
|
||||
"mime_type": "application/pdf",
|
||||
"tamano_maximo": 20971520
|
||||
"tamano_maximo": 20971520,
|
||||
},
|
||||
"txt": {
|
||||
"extension": "txt",
|
||||
"descripcion": "Documento de texto",
|
||||
"mime_type": "text/plain",
|
||||
"tamano_maximo": 5242880
|
||||
}
|
||||
"tamano_maximo": 5242880,
|
||||
},
|
||||
}
|
||||
|
||||
with open('test_storage/filetypes/filetypes.json', 'w', encoding='utf-8') as f:
|
||||
|
||||
with open(f"{storage_path}/filetypes/filetypes.json", "w", encoding="utf-8") as f:
|
||||
json.dump(filetypes_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
# Create test schemas
|
||||
schemas_data = {
|
||||
"TEST001": {
|
||||
|
@ -125,20 +189,17 @@ def initialize_test_data():
|
|||
"tipo": "pdf",
|
||||
"nombre": "Documento de Prueba",
|
||||
"nivel_ver": 0,
|
||||
"nivel_editar": 1000
|
||||
"nivel_editar": 1000,
|
||||
}
|
||||
]
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
with open('test_storage/schemas/schema.json', 'w', encoding='utf-8') as f:
|
||||
|
||||
with open(f"{storage_path}/schemas/schema.json", "w", encoding="utf-8") as f:
|
||||
json.dump(schemas_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
# Create indices file
|
||||
indices_data = {
|
||||
"max_project_id": 0,
|
||||
"max_document_id": 0
|
||||
}
|
||||
|
||||
with open('test_storage/indices.json', 'w', encoding='utf-8') as f:
|
||||
indices_data = {"max_project_id": 0, "max_document_id": 0}
|
||||
|
||||
with open(f"{storage_path}/indices.json", "w", encoding="utf-8") as f:
|
||||
json.dump(indices_data, f, ensure_ascii=False, indent=2)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
"""Helper functions for tests."""
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def ensure_clean_session(client):
|
||||
"""Ensure we have a clean session before each test."""
|
||||
# Get the root URL to reset application state
|
||||
with client.session_transaction() as session:
|
||||
session.clear()
|
||||
|
||||
# Make a request to reset client state
|
||||
client.get("/")
|
||||
|
||||
return client
|
|
@ -5,97 +5,104 @@ import os
|
|||
import time
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class JSONReporter:
|
||||
"""
|
||||
Custom pytest plugin to generate JSON test reports.
|
||||
Based on the specification in section 9.4 of descripcion.md.
|
||||
"""
|
||||
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.start_time = time.time()
|
||||
self.results = {
|
||||
'summary': {
|
||||
'total': 0,
|
||||
'passed': 0,
|
||||
'failed': 0,
|
||||
'skipped': 0,
|
||||
'error': 0,
|
||||
'duration': 0,
|
||||
'timestamp': datetime.datetime.now().isoformat()
|
||||
"summary": {
|
||||
"total": 0,
|
||||
"passed": 0,
|
||||
"failed": 0,
|
||||
"skipped": 0,
|
||||
"error": 0,
|
||||
"duration": 0,
|
||||
"timestamp": datetime.datetime.now().isoformat(),
|
||||
},
|
||||
'tests': []
|
||||
"tests": [],
|
||||
}
|
||||
|
||||
|
||||
def pytest_runtest_logreport(self, report):
|
||||
"""Handle the reporting of a test run."""
|
||||
if report.when == 'call' or (report.when == 'setup' and report.skipped):
|
||||
self.results['summary']['total'] += 1
|
||||
|
||||
if report.when == "call" or (report.when == "setup" and report.skipped):
|
||||
self.results["summary"]["total"] += 1
|
||||
|
||||
if report.passed:
|
||||
result = 'passed'
|
||||
self.results['summary']['passed'] += 1
|
||||
result = "passed"
|
||||
self.results["summary"]["passed"] += 1
|
||||
elif report.failed:
|
||||
if report.when != 'call':
|
||||
result = 'error'
|
||||
self.results['summary']['error'] += 1
|
||||
if report.when != "call":
|
||||
result = "error"
|
||||
self.results["summary"]["error"] += 1
|
||||
else:
|
||||
result = 'failed'
|
||||
self.results['summary']['failed'] += 1
|
||||
result = "failed"
|
||||
self.results["summary"]["failed"] += 1
|
||||
elif report.skipped:
|
||||
result = 'skipped'
|
||||
self.results['summary']['skipped'] += 1
|
||||
|
||||
result = "skipped"
|
||||
self.results["summary"]["skipped"] += 1
|
||||
|
||||
# Extract test metadata
|
||||
test_module = report.nodeid.split('::')[0]
|
||||
test_class = report.nodeid.split('::')[1] if '::' in report.nodeid else None
|
||||
test_name = report.nodeid.split('::')[-1]
|
||||
|
||||
test_module = report.nodeid.split("::")[0]
|
||||
test_class = report.nodeid.split("::")[1] if "::" in report.nodeid else None
|
||||
test_name = report.nodeid.split("::")[-1]
|
||||
|
||||
# Extract error details if present
|
||||
error_message = None
|
||||
error_trace = None
|
||||
if hasattr(report, 'longrepr') and report.longrepr:
|
||||
if hasattr(report.longrepr, 'reprcrash') and report.longrepr.reprcrash:
|
||||
if hasattr(report, "longrepr") and report.longrepr:
|
||||
if hasattr(report.longrepr, "reprcrash") and report.longrepr.reprcrash:
|
||||
error_message = report.longrepr.reprcrash.message
|
||||
error_trace = str(report.longrepr)
|
||||
|
||||
|
||||
# Add test result to list
|
||||
self.results['tests'].append({
|
||||
'id': report.nodeid,
|
||||
'module': test_module,
|
||||
'class': test_class,
|
||||
'name': test_name,
|
||||
'result': result,
|
||||
'duration': report.duration,
|
||||
'error_message': error_message,
|
||||
'error_trace': error_trace
|
||||
})
|
||||
|
||||
self.results["tests"].append(
|
||||
{
|
||||
"id": report.nodeid,
|
||||
"module": test_module,
|
||||
"class": test_class,
|
||||
"name": test_name,
|
||||
"result": result,
|
||||
"duration": report.duration,
|
||||
"error_message": error_message,
|
||||
"error_trace": error_trace,
|
||||
}
|
||||
)
|
||||
|
||||
def pytest_sessionfinish(self, session):
|
||||
"""Generate report at end of test session."""
|
||||
self.results['summary']['duration'] = time.time() - self.start_time
|
||||
|
||||
self.results["summary"]["duration"] = time.time() - self.start_time
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
output_dir = Path('test_reports')
|
||||
output_dir = Path("test_reports")
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
|
||||
# Generate timestamp for file name
|
||||
timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
output_path = output_dir / f'test_results_{timestamp}.json'
|
||||
|
||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
output_path = output_dir / f"test_results_{timestamp}.json"
|
||||
|
||||
# Write results to file
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
json.dump(self.results, f, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
# Also create a symlink/copy to latest results
|
||||
latest_path = output_dir / 'test_results_latest.json'
|
||||
latest_path = output_dir / "test_results_latest.json"
|
||||
if os.path.exists(latest_path):
|
||||
os.remove(latest_path)
|
||||
with open(latest_path, 'w', encoding='utf-8') as f:
|
||||
with open(latest_path, "w", encoding="utf-8") as f:
|
||||
json.dump(self.results, f, indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
print(f"\nJSON test report generated: {output_path}")
|
||||
|
||||
@pytest.hookimpl(tryfirst=True)
|
||||
|
||||
# Register the plugin
|
||||
@pytest.hookimpl(trylast=True)
|
||||
def pytest_configure(config):
|
||||
"""Register the JSON reporter plugin."""
|
||||
config.pluginmanager.register(JSONReporter(config), 'json_reporter')
|
||||
config._json_reporter = JSONReporter(config)
|
||||
config.pluginmanager.register(config._json_reporter, "json_reporter")
|
||||
|
|
|
@ -1,99 +1,132 @@
|
|||
import pytest
|
||||
import json
|
||||
import os
|
||||
from .helpers import ensure_clean_session
|
||||
|
||||
|
||||
class TestAdminFunctions:
|
||||
"""Test administrative functions."""
|
||||
|
||||
|
||||
def test_admin_dashboard(self, logged_in_client):
|
||||
"""Test access to admin dashboard."""
|
||||
response = logged_in_client.get('/admin/')
|
||||
"""Test accessing admin dashboard."""
|
||||
# Ensure we have a clean, authenticated session
|
||||
logged_in_client = ensure_clean_session(logged_in_client)
|
||||
|
||||
# Access the admin dashboard
|
||||
response = logged_in_client.get("/admin/dashboard")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert b'Panel de Administraci' in response.data # "Panel de Administración"
|
||||
|
||||
assert b"Administraci" in response.data or b"Dashboard" in response.data
|
||||
|
||||
def test_filetypes_management(self, logged_in_client):
|
||||
"""Test file types management page."""
|
||||
response = logged_in_client.get('/admin/filetypes')
|
||||
response = logged_in_client.get("/admin/filetypes")
|
||||
assert response.status_code == 200
|
||||
assert b'Tipos de Archivo' in response.data
|
||||
|
||||
assert b"Tipos de Archivo" in response.data
|
||||
|
||||
def test_system_status(self, logged_in_client):
|
||||
"""Test system status page."""
|
||||
response = logged_in_client.get('/admin/system')
|
||||
response = logged_in_client.get("/admin/system")
|
||||
assert response.status_code == 200
|
||||
assert b'Estado del Sistema' in response.data
|
||||
|
||||
assert b"Estado del Sistema" in response.data
|
||||
|
||||
def test_add_filetype(self, logged_in_client, app):
|
||||
"""Test adding a new file type."""
|
||||
response = logged_in_client.post('/admin/filetypes/add', data={
|
||||
'extension': 'docx',
|
||||
'descripcion': 'Documento Word',
|
||||
'mime_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'tamano_maximo': 15728640 # 15MB in bytes
|
||||
}, follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
"/admin/filetypes/add",
|
||||
data={
|
||||
"extension": "docx",
|
||||
"descripcion": "Documento Word",
|
||||
"mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"tamano_maximo": 15728640, # 15MB in bytes
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Verify file type was added
|
||||
with app.app_context():
|
||||
filetypes_path = os.path.join(app.config['STORAGE_PATH'], 'filetypes', 'filetypes.json')
|
||||
with open(filetypes_path, 'r') as f:
|
||||
filetypes_path = os.path.join(
|
||||
app.config["STORAGE_PATH"], "filetypes", "filetypes.json"
|
||||
)
|
||||
with open(filetypes_path, "r") as f:
|
||||
filetypes = json.load(f)
|
||||
assert 'docx' in filetypes
|
||||
assert filetypes['docx']['descripcion'] == 'Documento Word'
|
||||
|
||||
assert "docx" in filetypes
|
||||
assert filetypes["docx"]["descripcion"] == "Documento Word"
|
||||
|
||||
def test_delete_filetype(self, logged_in_client, app):
|
||||
"""Test deleting a file type."""
|
||||
# First add a file type to delete
|
||||
logged_in_client.post('/admin/filetypes/add', data={
|
||||
'extension': 'xlsx',
|
||||
'descripcion': 'Hoja de cálculo Excel',
|
||||
'mime_type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'tamano_maximo': 15728640
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/admin/filetypes/add",
|
||||
data={
|
||||
"extension": "xlsx",
|
||||
"descripcion": "Hoja de cálculo Excel",
|
||||
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"tamano_maximo": 15728640,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Verify it was added
|
||||
with app.app_context():
|
||||
filetypes_path = os.path.join(app.config['STORAGE_PATH'], 'filetypes', 'filetypes.json')
|
||||
with open(filetypes_path, 'r') as f:
|
||||
filetypes_path = os.path.join(
|
||||
app.config["STORAGE_PATH"], "filetypes", "filetypes.json"
|
||||
)
|
||||
with open(filetypes_path, "r") as f:
|
||||
filetypes = json.load(f)
|
||||
assert 'xlsx' in filetypes
|
||||
|
||||
assert "xlsx" in filetypes
|
||||
|
||||
# Now delete it
|
||||
response = logged_in_client.post('/admin/filetypes/xlsx/delete', follow_redirects=True)
|
||||
response = logged_in_client.post(
|
||||
"/admin/filetypes/xlsx/delete", follow_redirects=True
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Verify it was deleted
|
||||
with app.app_context():
|
||||
filetypes_path = os.path.join(app.config['STORAGE_PATH'], 'filetypes', 'filetypes.json')
|
||||
with open(filetypes_path, 'r') as f:
|
||||
filetypes_path = os.path.join(
|
||||
app.config["STORAGE_PATH"], "filetypes", "filetypes.json"
|
||||
)
|
||||
with open(filetypes_path, "r") as f:
|
||||
filetypes = json.load(f)
|
||||
assert 'xlsx' not in filetypes
|
||||
|
||||
assert "xlsx" not in filetypes
|
||||
|
||||
def test_update_filetype(self, logged_in_client, app):
|
||||
"""Test updating a file type."""
|
||||
# First add a file type to update
|
||||
logged_in_client.post('/admin/filetypes/add', data={
|
||||
'extension': 'png',
|
||||
'descripcion': 'Imagen PNG',
|
||||
'mime_type': 'image/png',
|
||||
'tamano_maximo': 5242880 # 5MB
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/admin/filetypes/add",
|
||||
data={
|
||||
"extension": "png",
|
||||
"descripcion": "Imagen PNG",
|
||||
"mime_type": "image/png",
|
||||
"tamano_maximo": 5242880, # 5MB
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Now update it
|
||||
response = logged_in_client.post('/admin/filetypes/png/update', data={
|
||||
'descripcion': 'Imagen PNG Actualizada',
|
||||
'mime_type': 'image/png',
|
||||
'tamano_maximo': 10485760 # 10MB (increased)
|
||||
}, follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
"/admin/filetypes/png/update",
|
||||
data={
|
||||
"descripcion": "Imagen PNG Actualizada",
|
||||
"mime_type": "image/png",
|
||||
"tamano_maximo": 10485760, # 10MB (increased)
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Verify changes
|
||||
with app.app_context():
|
||||
filetypes_path = os.path.join(app.config['STORAGE_PATH'], 'filetypes', 'filetypes.json')
|
||||
with open(filetypes_path, 'r') as f:
|
||||
filetypes_path = os.path.join(
|
||||
app.config["STORAGE_PATH"], "filetypes", "filetypes.json"
|
||||
)
|
||||
with open(filetypes_path, "r") as f:
|
||||
filetypes = json.load(f)
|
||||
assert 'png' in filetypes
|
||||
assert filetypes['png']['descripcion'] == 'Imagen PNG Actualizada'
|
||||
assert filetypes['png']['tamano_maximo'] == 10485760
|
||||
assert "png" in filetypes
|
||||
assert filetypes["png"]["descripcion"] == "Imagen PNG Actualizada"
|
||||
assert filetypes["png"]["tamano_maximo"] == 10485760
|
||||
|
|
|
@ -1,67 +1,72 @@
|
|||
import pytest
|
||||
from flask import session, g
|
||||
|
||||
|
||||
class TestAuth:
|
||||
"""Test authentication functionality."""
|
||||
|
||||
|
||||
def test_login_page(self, client):
|
||||
"""Test that login page loads correctly."""
|
||||
response = client.get('/auth/login')
|
||||
response = client.get("/auth/login")
|
||||
assert response.status_code == 200
|
||||
assert b'Iniciar sesi' in response.data # 'Iniciar sesión' in Spanish
|
||||
|
||||
assert b"Iniciar sesi" in response.data # 'Iniciar sesión' in Spanish
|
||||
|
||||
def test_login_success(self, client):
|
||||
"""Test successful login with correct credentials."""
|
||||
response = client.post(
|
||||
'/auth/login',
|
||||
data={'username': 'admin', 'password': 'admin123'},
|
||||
follow_redirects=True
|
||||
"/auth/login",
|
||||
data={"username": "admin", "password": "admin123"},
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
# Check that we're redirected to the right page after login
|
||||
assert b'Panel' in response.data or b'Proyectos' in response.data
|
||||
|
||||
assert b"Panel" in response.data or b"Proyectos" in response.data
|
||||
|
||||
def test_login_invalid_credentials(self, client):
|
||||
"""Test login with invalid credentials."""
|
||||
response = client.post(
|
||||
'/auth/login',
|
||||
data={'username': 'admin', 'password': 'wrongpassword'},
|
||||
follow_redirects=True
|
||||
"/auth/login",
|
||||
data={"username": "admin", "password": "wrongpassword"},
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert b'credenciales' in response.data.lower() # Error message about credentials
|
||||
|
||||
assert (
|
||||
b"credenciales" in response.data.lower()
|
||||
) # Error message about credentials
|
||||
|
||||
def test_logout(self, auth, client):
|
||||
"""Test logout functionality."""
|
||||
# First login
|
||||
auth.login()
|
||||
|
||||
|
||||
# Then logout
|
||||
response = auth.logout()
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Check if logged out - try to access a protected page
|
||||
response = client.get('/users/', follow_redirects=True)
|
||||
assert b'iniciar sesi' in response.data.lower() # Should see login page
|
||||
|
||||
response = client.get("/users/", follow_redirects=True)
|
||||
assert b"iniciar sesi" in response.data.lower() # Should see login page
|
||||
|
||||
def test_access_protected_route(self, client):
|
||||
"""Test accessing a protected route without login."""
|
||||
# Try to access users list without login
|
||||
response = client.get('/users/', follow_redirects=True)
|
||||
response = client.get("/users/", follow_redirects=True)
|
||||
assert response.status_code == 200
|
||||
assert b'iniciar sesi' in response.data.lower() # Should be redirected to login
|
||||
|
||||
assert b"iniciar sesi" in response.data.lower() # Should be redirected to login
|
||||
|
||||
def test_access_protected_route_with_login(self, logged_in_client):
|
||||
"""Test accessing a protected route with login."""
|
||||
# Admin should be able to access users list
|
||||
response = logged_in_client.get('/admin/dashboard')
|
||||
response = logged_in_client.get("/admin/dashboard")
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_permission_levels(self, client, auth):
|
||||
"""Test different permission levels."""
|
||||
# Login as regular user
|
||||
auth.login(username='user1', password='admin123')
|
||||
|
||||
auth.login(username="user1", password="admin123")
|
||||
|
||||
# Try to access admin-only page
|
||||
response = client.get('/admin/dashboard', follow_redirects=True)
|
||||
assert response.status_code == 403 or b'acceso denegado' in response.data.lower()
|
||||
response = client.get("/admin/dashboard", follow_redirects=True)
|
||||
assert (
|
||||
response.status_code == 403 or b"acceso denegado" in response.data.lower()
|
||||
)
|
||||
|
|
|
@ -4,151 +4,153 @@ import io
|
|||
import json
|
||||
from werkzeug.datastructures import FileStorage
|
||||
|
||||
|
||||
class TestDocuments:
|
||||
"""Test document management functionality."""
|
||||
|
||||
|
||||
def setup_project(self, logged_in_client, app):
|
||||
"""Helper to create a test project."""
|
||||
# Create a project
|
||||
logged_in_client.post('/projects/create', data={
|
||||
'codigo': 'TESTDOC',
|
||||
'descripcion': 'Proyecto para documentos',
|
||||
'cliente': 'Cliente Test',
|
||||
'esquema': 'TEST001',
|
||||
'destinacion': 'Pruebas',
|
||||
'notas': 'Proyecto para pruebas de documentos'
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/projects/create",
|
||||
data={
|
||||
"codigo": "TESTDOC",
|
||||
"descripcion": "Proyecto para documentos",
|
||||
"cliente": "Cliente Test",
|
||||
"esquema": "TEST001",
|
||||
"destinacion": "Pruebas",
|
||||
"notas": "Proyecto para pruebas de documentos",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Find the project ID
|
||||
with app.app_context():
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
project_dirs = [d for d in os.listdir(projects_dir) if 'TESTDOC' in d]
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
project_dirs = [d for d in os.listdir(projects_dir) if "TESTDOC" in d]
|
||||
assert len(project_dirs) > 0
|
||||
|
||||
|
||||
project_dir = project_dirs[0]
|
||||
return project_dir.split('_')[0].replace('@', '')
|
||||
|
||||
return project_dir.split("_")[0].replace("@", "")
|
||||
|
||||
def test_upload_document(self, logged_in_client, app):
|
||||
"""Test uploading a document to a project."""
|
||||
# Create a project and get its ID
|
||||
project_id = self.setup_project(logged_in_client, app)
|
||||
|
||||
|
||||
# Create a test file
|
||||
test_file = FileStorage(
|
||||
stream=io.BytesIO(b'This is a test document content.'),
|
||||
filename='test_document.txt',
|
||||
content_type='text/plain',
|
||||
stream=io.BytesIO(b"This is a test document content."),
|
||||
filename="test_document.txt",
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
|
||||
# Upload the document
|
||||
response = logged_in_client.post(
|
||||
f'/projects/{project_id}/documents/upload',
|
||||
f"/projects/{project_id}/documents/upload",
|
||||
data={
|
||||
'tipo_doc': 'Documento de Prueba', # Match schema type from TEST001
|
||||
'descripcion': 'Documento de prueba para tests',
|
||||
'file': test_file
|
||||
"tipo_doc": "Documento de Prueba", # Match schema type from TEST001
|
||||
"descripcion": "Documento de prueba para tests",
|
||||
"file": test_file,
|
||||
},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
content_type="multipart/form-data",
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Verify document was created
|
||||
with app.app_context():
|
||||
project_path = None
|
||||
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
for dir_name in os.listdir(projects_dir):
|
||||
if dir_name.startswith(f'@{project_id}_'):
|
||||
if dir_name.startswith(f"@{project_id}_"):
|
||||
project_path = os.path.join(projects_dir, dir_name)
|
||||
break
|
||||
|
||||
|
||||
assert project_path is not None
|
||||
|
||||
|
||||
# Check for documents directory with content
|
||||
docs_path = os.path.join(project_path, 'documents')
|
||||
docs_path = os.path.join(project_path, "documents")
|
||||
assert os.path.exists(docs_path)
|
||||
|
||||
|
||||
# Should have at least one document folder
|
||||
assert len(os.listdir(docs_path)) > 0
|
||||
|
||||
|
||||
def test_document_versions(self, logged_in_client, app):
|
||||
"""Test document versioning functionality."""
|
||||
# Create a project and upload first version
|
||||
project_id = self.setup_project(logged_in_client, app)
|
||||
|
||||
|
||||
# Upload first version
|
||||
test_file1 = FileStorage(
|
||||
stream=io.BytesIO(b'Document content version 1'),
|
||||
filename='test_versioning.txt',
|
||||
content_type='text/plain',
|
||||
stream=io.BytesIO(b"Document content version 1"),
|
||||
filename="test_versioning.txt",
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
|
||||
logged_in_client.post(
|
||||
f'/projects/{project_id}/documents/upload',
|
||||
f"/projects/{project_id}/documents/upload",
|
||||
data={
|
||||
'tipo_doc': 'Documento de Prueba',
|
||||
'descripcion': 'Documento para pruebas de versiones',
|
||||
'file': test_file1
|
||||
"tipo_doc": "Documento de Prueba",
|
||||
"descripcion": "Documento para pruebas de versiones",
|
||||
"file": test_file1,
|
||||
},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
content_type="multipart/form-data",
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
|
||||
# Find the document ID
|
||||
doc_id = None
|
||||
with app.app_context():
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
for dir_name in os.listdir(projects_dir):
|
||||
if dir_name.startswith(f'@{project_id}_'):
|
||||
if dir_name.startswith(f"@{project_id}_"):
|
||||
project_path = os.path.join(projects_dir, dir_name)
|
||||
docs_path = os.path.join(project_path, 'documents')
|
||||
|
||||
docs_path = os.path.join(project_path, "documents")
|
||||
|
||||
# Get first document directory
|
||||
doc_dirs = os.listdir(docs_path)
|
||||
if doc_dirs:
|
||||
doc_id = doc_dirs[0].split('_')[0].replace('@', '')
|
||||
doc_id = doc_dirs[0].split("_")[0].replace("@", "")
|
||||
break
|
||||
|
||||
|
||||
assert doc_id is not None
|
||||
|
||||
|
||||
# Upload second version of the same document
|
||||
test_file2 = FileStorage(
|
||||
stream=io.BytesIO(b'Document content version 2 - UPDATED'),
|
||||
filename='test_versioning_v2.txt',
|
||||
content_type='text/plain',
|
||||
stream=io.BytesIO(b"Document content version 2 - UPDATED"),
|
||||
filename="test_versioning_v2.txt",
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
|
||||
response = logged_in_client.post(
|
||||
f'/projects/{project_id}/documents/{doc_id}/upload',
|
||||
data={
|
||||
'descripcion': 'Segunda versión del documento',
|
||||
'file': test_file2
|
||||
},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
f"/projects/{project_id}/documents/{doc_id}/upload",
|
||||
data={"descripcion": "Segunda versión del documento", "file": test_file2},
|
||||
content_type="multipart/form-data",
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Check for multiple versions in metadata
|
||||
with app.app_context():
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
for dir_name in os.listdir(projects_dir):
|
||||
if dir_name.startswith(f'@{project_id}_'):
|
||||
if dir_name.startswith(f"@{project_id}_"):
|
||||
project_path = os.path.join(projects_dir, dir_name)
|
||||
docs_path = os.path.join(project_path, 'documents')
|
||||
|
||||
docs_path = os.path.join(project_path, "documents")
|
||||
|
||||
# Find document directory
|
||||
for doc_dir in os.listdir(docs_path):
|
||||
if doc_dir.startswith(f'@{doc_id}_'):
|
||||
if doc_dir.startswith(f"@{doc_id}_"):
|
||||
doc_path = os.path.join(docs_path, doc_dir)
|
||||
meta_path = os.path.join(doc_path, 'meta.json')
|
||||
|
||||
meta_path = os.path.join(doc_path, "meta.json")
|
||||
|
||||
# Check metadata for versions
|
||||
if os.path.exists(meta_path):
|
||||
with open(meta_path, 'r') as f:
|
||||
with open(meta_path, "r") as f:
|
||||
metadata = json.load(f)
|
||||
assert 'versions' in metadata
|
||||
assert len(metadata['versions']) >= 2
|
||||
assert "versions" in metadata
|
||||
assert len(metadata["versions"]) >= 2
|
||||
|
|
|
@ -3,160 +3,177 @@ import os
|
|||
import io
|
||||
from werkzeug.datastructures import FileStorage
|
||||
|
||||
|
||||
class TestIntegration:
|
||||
"""Test integrations between different components."""
|
||||
|
||||
|
||||
def test_complete_workflow(self, logged_in_client, app):
|
||||
"""Test a complete workflow from project creation to document download."""
|
||||
# 1. Create a new project
|
||||
logged_in_client.post('/projects/create', data={
|
||||
'codigo': 'WORKFLOW',
|
||||
'descripcion': 'Proyecto de flujo completo',
|
||||
'cliente': 'Cliente Integración',
|
||||
'esquema': 'TEST001',
|
||||
'destinacion': 'Pruebas de integración',
|
||||
'notas': 'Notas de proyecto de prueba'
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/projects/create",
|
||||
data={
|
||||
"codigo": "WORKFLOW",
|
||||
"descripcion": "Proyecto de flujo completo",
|
||||
"cliente": "Cliente Integración",
|
||||
"esquema": "TEST001",
|
||||
"destinacion": "Pruebas de integración",
|
||||
"notas": "Notas de proyecto de prueba",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# 2. Find the project ID
|
||||
project_id = None
|
||||
with app.app_context():
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
project_dirs = [d for d in os.listdir(projects_dir) if 'WORKFLOW' in d]
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
project_dirs = [d for d in os.listdir(projects_dir) if "WORKFLOW" in d]
|
||||
assert len(project_dirs) > 0
|
||||
project_dir = project_dirs[0]
|
||||
project_id = project_dir.split('_')[0].replace('@', '')
|
||||
|
||||
project_id = project_dir.split("_")[0].replace("@", "")
|
||||
|
||||
assert project_id is not None
|
||||
|
||||
|
||||
# 3. Upload a document to the project
|
||||
test_file = FileStorage(
|
||||
stream=io.BytesIO(b'Content for integration test document'),
|
||||
filename='integration_doc.txt',
|
||||
content_type='text/plain',
|
||||
stream=io.BytesIO(b"Content for integration test document"),
|
||||
filename="integration_doc.txt",
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
|
||||
response = logged_in_client.post(
|
||||
f'/projects/{project_id}/documents/upload',
|
||||
f"/projects/{project_id}/documents/upload",
|
||||
data={
|
||||
'tipo_doc': 'Documento de Prueba',
|
||||
'descripcion': 'Documento de flujo de integración',
|
||||
'file': test_file
|
||||
"tipo_doc": "Documento de Prueba",
|
||||
"descripcion": "Documento de flujo de integración",
|
||||
"file": test_file,
|
||||
},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
content_type="multipart/form-data",
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# 4. Find the document ID
|
||||
doc_id = None
|
||||
with app.app_context():
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
for dir_name in os.listdir(projects_dir):
|
||||
if dir_name.startswith(f'@{project_id}_'):
|
||||
if dir_name.startswith(f"@{project_id}_"):
|
||||
project_path = os.path.join(projects_dir, dir_name)
|
||||
docs_path = os.path.join(project_path, 'documents')
|
||||
|
||||
docs_path = os.path.join(project_path, "documents")
|
||||
|
||||
doc_dirs = os.listdir(docs_path)
|
||||
if doc_dirs:
|
||||
doc_id = doc_dirs[0].split('_')[0].replace('@', '')
|
||||
doc_id = doc_dirs[0].split("_")[0].replace("@", "")
|
||||
break
|
||||
|
||||
|
||||
assert doc_id is not None
|
||||
|
||||
|
||||
# 5. View document details
|
||||
response = logged_in_client.get(f'/projects/{project_id}/documents/{doc_id}')
|
||||
response = logged_in_client.get(f"/projects/{project_id}/documents/{doc_id}")
|
||||
assert response.status_code == 200
|
||||
assert b'Documento de flujo de integraci' in response.data
|
||||
|
||||
assert b"Documento de flujo de integraci" in response.data
|
||||
|
||||
# 6. Upload a new version of the document
|
||||
test_file2 = FileStorage(
|
||||
stream=io.BytesIO(b'Updated content for version 2'),
|
||||
filename='integration_doc_v2.txt',
|
||||
content_type='text/plain',
|
||||
stream=io.BytesIO(b"Updated content for version 2"),
|
||||
filename="integration_doc_v2.txt",
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
|
||||
response = logged_in_client.post(
|
||||
f'/projects/{project_id}/documents/{doc_id}/upload',
|
||||
f"/projects/{project_id}/documents/{doc_id}/upload",
|
||||
data={
|
||||
'descripcion': 'Segunda versión del documento de integración',
|
||||
'file': test_file2
|
||||
"descripcion": "Segunda versión del documento de integración",
|
||||
"file": test_file2,
|
||||
},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
content_type="multipart/form-data",
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# 7. Download the document
|
||||
response = logged_in_client.get(f'/projects/{project_id}/documents/{doc_id}/download/latest')
|
||||
response = logged_in_client.get(
|
||||
f"/projects/{project_id}/documents/{doc_id}/download/latest"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert b'Updated content for version 2' in response.data
|
||||
|
||||
assert b"Updated content for version 2" in response.data
|
||||
|
||||
# 8. Download a specific version (the first one)
|
||||
response = logged_in_client.get(f'/projects/{project_id}/documents/{doc_id}/download/1')
|
||||
response = logged_in_client.get(
|
||||
f"/projects/{project_id}/documents/{doc_id}/download/1"
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert b'Content for integration test document' in response.data
|
||||
|
||||
assert b"Content for integration test document" in response.data
|
||||
|
||||
def test_schema_project_document_integration(self, logged_in_client, app):
|
||||
"""Test integration between schemas, projects and documents."""
|
||||
# 1. Create a custom schema
|
||||
logged_in_client.post('/schemas/create', data={
|
||||
'codigo': 'CUSTOM',
|
||||
'descripcion': 'Esquema personalizado para integración',
|
||||
'documentos-0-tipo': 'pdf',
|
||||
'documentos-0-nombre': 'Informe Principal',
|
||||
'documentos-0-nivel_ver': 0,
|
||||
'documentos-0-nivel_editar': 5000,
|
||||
'documentos-1-tipo': 'txt',
|
||||
'documentos-1-nombre': 'Notas Adicionales',
|
||||
'documentos-1-nivel_ver': 0,
|
||||
'documentos-1-nivel_editar': 1000
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/schemas/create",
|
||||
data={
|
||||
"codigo": "CUSTOM",
|
||||
"descripcion": "Esquema personalizado para integración",
|
||||
"documentos-0-tipo": "pdf",
|
||||
"documentos-0-nombre": "Informe Principal",
|
||||
"documentos-0-nivel_ver": 0,
|
||||
"documentos-0-nivel_editar": 5000,
|
||||
"documentos-1-tipo": "txt",
|
||||
"documentos-1-nombre": "Notas Adicionales",
|
||||
"documentos-1-nivel_ver": 0,
|
||||
"documentos-1-nivel_editar": 1000,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# 2. Create a project with the custom schema
|
||||
logged_in_client.post('/projects/create', data={
|
||||
'codigo': 'PROJ_SCHEMA',
|
||||
'descripcion': 'Proyecto con esquema personalizado',
|
||||
'cliente': 'Cliente Test',
|
||||
'esquema': 'CUSTOM',
|
||||
'destinacion': 'Pruebas',
|
||||
'notas': 'Proyecto para probar integración de esquemas'
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/projects/create",
|
||||
data={
|
||||
"codigo": "PROJ_SCHEMA",
|
||||
"descripcion": "Proyecto con esquema personalizado",
|
||||
"cliente": "Cliente Test",
|
||||
"esquema": "CUSTOM",
|
||||
"destinacion": "Pruebas",
|
||||
"notas": "Proyecto para probar integración de esquemas",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# 3. Find the project ID
|
||||
project_id = None
|
||||
with app.app_context():
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
project_dirs = [d for d in os.listdir(projects_dir) if 'PROJ_SCHEMA' in d]
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
project_dirs = [d for d in os.listdir(projects_dir) if "PROJ_SCHEMA" in d]
|
||||
assert len(project_dirs) > 0
|
||||
project_dir = project_dirs[0]
|
||||
project_id = project_dir.split('_')[0].replace('@', '')
|
||||
|
||||
project_id = project_dir.split("_")[0].replace("@", "")
|
||||
|
||||
# 4. Verify project uses the custom schema
|
||||
response = logged_in_client.get(f'/projects/{project_id}')
|
||||
response = logged_in_client.get(f"/projects/{project_id}")
|
||||
assert response.status_code == 200
|
||||
assert b'CUSTOM' in response.data
|
||||
assert b'Informe Principal' in response.data
|
||||
assert b'Notas Adicionales' in response.data
|
||||
|
||||
assert b"CUSTOM" in response.data
|
||||
assert b"Informe Principal" in response.data
|
||||
assert b"Notas Adicionales" in response.data
|
||||
|
||||
# 5. Upload a document of the specified type
|
||||
test_file = FileStorage(
|
||||
stream=io.BytesIO(b'Notes content for schema integration'),
|
||||
filename='notes.txt',
|
||||
content_type='text/plain',
|
||||
stream=io.BytesIO(b"Notes content for schema integration"),
|
||||
filename="notes.txt",
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
|
||||
response = logged_in_client.post(
|
||||
f'/projects/{project_id}/documents/upload',
|
||||
f"/projects/{project_id}/documents/upload",
|
||||
data={
|
||||
'tipo_doc': 'Notas Adicionales', # This should match schema document type
|
||||
'descripcion': 'Notas para prueba de esquema',
|
||||
'file': test_file
|
||||
"tipo_doc": "Notas Adicionales", # This should match schema document type
|
||||
"descripcion": "Notas para prueba de esquema",
|
||||
"file": test_file,
|
||||
},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
content_type="multipart/form-data",
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
|
||||
assert response.status_code == 200
|
||||
|
|
|
@ -2,92 +2,109 @@ import pytest
|
|||
import json
|
||||
import os
|
||||
|
||||
|
||||
class TestProjects:
|
||||
"""Test project-related functionality."""
|
||||
|
||||
|
||||
def test_project_list(self, logged_in_client):
|
||||
"""Test listing projects."""
|
||||
response = logged_in_client.get('/projects/')
|
||||
response = logged_in_client.get("/projects/")
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_create_project(self, logged_in_client, app):
|
||||
"""Test creating a new project."""
|
||||
response = logged_in_client.post('/projects/create', data={
|
||||
'codigo': 'TEST123',
|
||||
'descripcion': 'Proyecto de Prueba',
|
||||
'cliente': 'Cliente Test',
|
||||
'esquema': 'TEST001',
|
||||
'destinacion': 'Pruebas',
|
||||
'notas': 'Notas de prueba'
|
||||
}, follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
"/projects/create",
|
||||
data={
|
||||
"codigo": "TEST123",
|
||||
"descripcion": "Proyecto de Prueba",
|
||||
"cliente": "Cliente Test",
|
||||
"esquema": "TEST001",
|
||||
"destinacion": "Pruebas",
|
||||
"notas": "Notas de prueba",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Check if project was created in storage
|
||||
with app.app_context():
|
||||
# Check indices
|
||||
indices_path = os.path.join(app.config['STORAGE_PATH'], 'indices.json')
|
||||
with open(indices_path, 'r') as f:
|
||||
indices_path = os.path.join(app.config["STORAGE_PATH"], "indices.json")
|
||||
with open(indices_path, "r") as f:
|
||||
indices = json.load(f)
|
||||
assert indices['max_project_id'] > 0
|
||||
|
||||
assert indices["max_project_id"] > 0
|
||||
|
||||
def test_view_project(self, logged_in_client, app):
|
||||
"""Test viewing a project (requires creating one first)."""
|
||||
# Create a project first
|
||||
logged_in_client.post('/projects/create', data={
|
||||
'codigo': 'TEST456',
|
||||
'descripcion': 'Proyecto para visualizar',
|
||||
'cliente': 'Cliente Test',
|
||||
'esquema': 'TEST001',
|
||||
'destinacion': 'Pruebas',
|
||||
'notas': 'Notas de prueba'
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/projects/create",
|
||||
data={
|
||||
"codigo": "TEST456",
|
||||
"descripcion": "Proyecto para visualizar",
|
||||
"cliente": "Cliente Test",
|
||||
"esquema": "TEST001",
|
||||
"destinacion": "Pruebas",
|
||||
"notas": "Notas de prueba",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Now find the project ID
|
||||
with app.app_context():
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
project_dirs = os.listdir(projects_dir)
|
||||
assert len(project_dirs) > 0
|
||||
|
||||
|
||||
# Get first project directory
|
||||
project_dir = project_dirs[0]
|
||||
project_id = project_dir.split('_')[0].replace('@', '')
|
||||
|
||||
project_id = project_dir.split("_")[0].replace("@", "")
|
||||
|
||||
# Try to view it
|
||||
response = logged_in_client.get(f'/projects/{project_id}')
|
||||
response = logged_in_client.get(f"/projects/{project_id}")
|
||||
assert response.status_code == 200
|
||||
assert b'Proyecto para visualizar' in response.data
|
||||
|
||||
assert b"Proyecto para visualizar" in response.data
|
||||
|
||||
def test_edit_project(self, logged_in_client, app):
|
||||
"""Test editing a project."""
|
||||
# Create a project first
|
||||
logged_in_client.post('/projects/create', data={
|
||||
'codigo': 'TESTEDIT',
|
||||
'descripcion': 'Proyecto para editar',
|
||||
'cliente': 'Cliente Test',
|
||||
'esquema': 'TEST001',
|
||||
'destinacion': 'Pruebas',
|
||||
'notas': 'Notas originales'
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/projects/create",
|
||||
data={
|
||||
"codigo": "TESTEDIT",
|
||||
"descripcion": "Proyecto para editar",
|
||||
"cliente": "Cliente Test",
|
||||
"esquema": "TEST001",
|
||||
"destinacion": "Pruebas",
|
||||
"notas": "Notas originales",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Find the project ID
|
||||
with app.app_context():
|
||||
projects_dir = os.path.join(app.config['STORAGE_PATH'], 'projects')
|
||||
project_dirs = [d for d in os.listdir(projects_dir) if 'TESTEDIT' in d]
|
||||
projects_dir = os.path.join(app.config["STORAGE_PATH"], "projects")
|
||||
project_dirs = [d for d in os.listdir(projects_dir) if "TESTEDIT" in d]
|
||||
assert len(project_dirs) > 0
|
||||
|
||||
|
||||
project_dir = project_dirs[0]
|
||||
project_id = project_dir.split('_')[0].replace('@', '')
|
||||
|
||||
project_id = project_dir.split("_")[0].replace("@", "")
|
||||
|
||||
# Edit the project
|
||||
response = logged_in_client.post(f'/projects/{project_id}/edit', data={
|
||||
'codigo': 'TESTEDIT',
|
||||
'descripcion': 'Proyecto editado',
|
||||
'cliente': 'Cliente Test Modificado',
|
||||
'esquema': 'TEST001',
|
||||
'destinacion': 'Pruebas Modificadas',
|
||||
'notas': 'Notas modificadas'
|
||||
}, follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
f"/projects/{project_id}/edit",
|
||||
data={
|
||||
"codigo": "TESTEDIT",
|
||||
"descripcion": "Proyecto editado",
|
||||
"cliente": "Cliente Test Modificado",
|
||||
"esquema": "TEST001",
|
||||
"destinacion": "Pruebas Modificadas",
|
||||
"notas": "Notas modificadas",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert b'Proyecto editado' in response.data
|
||||
assert b"Proyecto editado" in response.data
|
||||
|
|
|
@ -2,77 +2,97 @@ import pytest
|
|||
import json
|
||||
import os
|
||||
|
||||
|
||||
class TestSchemas:
|
||||
"""Test schema management functionality."""
|
||||
|
||||
|
||||
def test_list_schemas(self, logged_in_client):
|
||||
"""Test listing schemas."""
|
||||
response = logged_in_client.get('/schemas/')
|
||||
response = logged_in_client.get("/schemas/")
|
||||
assert response.status_code == 200
|
||||
assert b'Esquemas de Proyecto' in response.data
|
||||
|
||||
assert b"Esquemas de Proyecto" in response.data
|
||||
|
||||
def test_view_schema(self, logged_in_client):
|
||||
"""Test viewing a schema."""
|
||||
response = logged_in_client.get('/schemas/view/TEST001')
|
||||
response = logged_in_client.get("/schemas/view/TEST001")
|
||||
assert response.status_code == 200
|
||||
assert b'Esquema de prueba' in response.data
|
||||
|
||||
assert b"Esquema de prueba" in response.data
|
||||
|
||||
def test_create_schema(self, logged_in_client, app):
|
||||
"""Test creating a new schema."""
|
||||
response = logged_in_client.post('/schemas/create', data={
|
||||
'codigo': 'TEST002',
|
||||
'descripcion': 'Nuevo esquema de prueba',
|
||||
'documentos-0-tipo': 'pdf',
|
||||
'documentos-0-nombre': 'Manual de Usuario',
|
||||
'documentos-0-nivel_ver': 0,
|
||||
'documentos-0-nivel_editar': 5000,
|
||||
'documentos-1-tipo': 'txt',
|
||||
'documentos-1-nombre': 'Notas de Proyecto',
|
||||
'documentos-1-nivel_ver': 0,
|
||||
'documentos-1-nivel_editar': 1000
|
||||
}, follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
"/schemas/create",
|
||||
data={
|
||||
"codigo": "TEST002",
|
||||
"descripcion": "Nuevo esquema de prueba",
|
||||
"documentos-0-tipo": "pdf",
|
||||
"documentos-0-nombre": "Manual de Usuario",
|
||||
"documentos-0-nivel_ver": 0,
|
||||
"documentos-0-nivel_editar": 5000,
|
||||
"documentos-1-tipo": "txt",
|
||||
"documentos-1-nombre": "Notas de Proyecto",
|
||||
"documentos-1-nivel_ver": 0,
|
||||
"documentos-1-nivel_editar": 1000,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Check if schema was created
|
||||
with app.app_context():
|
||||
schemas_path = os.path.join(app.config['STORAGE_PATH'], 'schemas', 'schema.json')
|
||||
with open(schemas_path, 'r') as f:
|
||||
schemas_path = os.path.join(
|
||||
app.config["STORAGE_PATH"], "schemas", "schema.json"
|
||||
)
|
||||
with open(schemas_path, "r") as f:
|
||||
schemas = json.load(f)
|
||||
assert 'TEST002' in schemas
|
||||
assert schemas['TEST002']['descripcion'] == 'Nuevo esquema de prueba'
|
||||
assert len(schemas['TEST002']['documentos']) == 2
|
||||
|
||||
assert "TEST002" in schemas
|
||||
assert schemas["TEST002"]["descripcion"] == "Nuevo esquema de prueba"
|
||||
assert len(schemas["TEST002"]["documentos"]) == 2
|
||||
|
||||
def test_edit_schema(self, logged_in_client, app):
|
||||
"""Test editing a schema."""
|
||||
# First create a schema to edit
|
||||
logged_in_client.post('/schemas/create', data={
|
||||
'codigo': 'TESTEDIT',
|
||||
'descripcion': 'Esquema para editar',
|
||||
'documentos-0-tipo': 'pdf',
|
||||
'documentos-0-nombre': 'Documento Original',
|
||||
'documentos-0-nivel_ver': 0,
|
||||
'documentos-0-nivel_editar': 5000
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/schemas/create",
|
||||
data={
|
||||
"codigo": "TESTEDIT",
|
||||
"descripcion": "Esquema para editar",
|
||||
"documentos-0-tipo": "pdf",
|
||||
"documentos-0-nombre": "Documento Original",
|
||||
"documentos-0-nivel_ver": 0,
|
||||
"documentos-0-nivel_editar": 5000,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Now edit it
|
||||
response = logged_in_client.post('/schemas/edit/TESTEDIT', data={
|
||||
'codigo': 'TESTEDIT',
|
||||
'descripcion': 'Esquema editado',
|
||||
'documentos-0-tipo': 'pdf',
|
||||
'documentos-0-nombre': 'Documento Modificado',
|
||||
'documentos-0-nivel_ver': 500,
|
||||
'documentos-0-nivel_editar': 6000
|
||||
}, follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
"/schemas/edit/TESTEDIT",
|
||||
data={
|
||||
"codigo": "TESTEDIT",
|
||||
"descripcion": "Esquema editado",
|
||||
"documentos-0-tipo": "pdf",
|
||||
"documentos-0-nombre": "Documento Modificado",
|
||||
"documentos-0-nivel_ver": 500,
|
||||
"documentos-0-nivel_editar": 6000,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Verify changes
|
||||
with app.app_context():
|
||||
schemas_path = os.path.join(app.config['STORAGE_PATH'], 'schemas', 'schema.json')
|
||||
with open(schemas_path, 'r') as f:
|
||||
schemas_path = os.path.join(
|
||||
app.config["STORAGE_PATH"], "schemas", "schema.json"
|
||||
)
|
||||
with open(schemas_path, "r") as f:
|
||||
schemas = json.load(f)
|
||||
assert 'TESTEDIT' in schemas
|
||||
assert schemas['TESTEDIT']['descripcion'] == 'Esquema editado'
|
||||
assert schemas['TESTEDIT']['documentos'][0]['nombre'] == 'Documento Modificado'
|
||||
assert schemas['TESTEDIT']['documentos'][0]['nivel_ver'] == 500
|
||||
assert "TESTEDIT" in schemas
|
||||
assert schemas["TESTEDIT"]["descripcion"] == "Esquema editado"
|
||||
assert (
|
||||
schemas["TESTEDIT"]["documentos"][0]["nombre"]
|
||||
== "Documento Modificado"
|
||||
)
|
||||
assert schemas["TESTEDIT"]["documentos"][0]["nivel_ver"] == 500
|
||||
|
|
|
@ -2,127 +2,146 @@ import pytest
|
|||
import json
|
||||
import os
|
||||
|
||||
|
||||
class TestUserManagement:
|
||||
"""Test user management functionality."""
|
||||
|
||||
|
||||
def test_list_users(self, logged_in_client):
|
||||
"""Test listing users."""
|
||||
response = logged_in_client.get('/users/')
|
||||
response = logged_in_client.get("/users/")
|
||||
assert response.status_code == 200
|
||||
assert b'Usuarios del Sistema' in response.data
|
||||
assert b"Usuarios del Sistema" in response.data
|
||||
# Check for existing users
|
||||
assert b'admin' in response.data
|
||||
assert b'user1' in response.data
|
||||
|
||||
assert b"admin" in response.data
|
||||
assert b"user1" in response.data
|
||||
|
||||
def test_create_user(self, logged_in_client, app):
|
||||
"""Test creating a new user."""
|
||||
response = logged_in_client.post('/users/create', data={
|
||||
'nombre': 'Usuario de Prueba',
|
||||
'username': 'testuser',
|
||||
'email': 'test@example.com',
|
||||
'password': 'password123',
|
||||
'password_confirm': 'password123',
|
||||
'nivel': 1000,
|
||||
'idioma': 'es',
|
||||
'empresa': 'Empresa Test',
|
||||
'estado': 'activo',
|
||||
'fecha_caducidad': ''
|
||||
}, follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
"/users/create",
|
||||
data={
|
||||
"nombre": "Usuario de Prueba",
|
||||
"username": "testuser",
|
||||
"email": "test@example.com",
|
||||
"password": "password123",
|
||||
"password_confirm": "password123",
|
||||
"nivel": 1000,
|
||||
"idioma": "es",
|
||||
"empresa": "Empresa Test",
|
||||
"estado": "activo",
|
||||
"fecha_caducidad": "",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Check if user was created
|
||||
with app.app_context():
|
||||
users_path = os.path.join(app.config['STORAGE_PATH'], 'users', 'users.json')
|
||||
with open(users_path, 'r') as f:
|
||||
users_path = os.path.join(app.config["STORAGE_PATH"], "users", "users.json")
|
||||
with open(users_path, "r") as f:
|
||||
users = json.load(f)
|
||||
assert 'testuser' in users
|
||||
assert users['testuser']['nombre'] == 'Usuario de Prueba'
|
||||
assert users['testuser']['email'] == 'test@example.com'
|
||||
assert users['testuser']['nivel'] == 1000
|
||||
|
||||
assert "testuser" in users
|
||||
assert users["testuser"]["nombre"] == "Usuario de Prueba"
|
||||
assert users["testuser"]["email"] == "test@example.com"
|
||||
assert users["testuser"]["nivel"] == 1000
|
||||
|
||||
def test_edit_user(self, logged_in_client, app):
|
||||
"""Test editing an existing user."""
|
||||
# First create a user to edit
|
||||
logged_in_client.post('/users/create', data={
|
||||
'nombre': 'Usuario para Editar',
|
||||
'username': 'edit_user',
|
||||
'email': 'edit@example.com',
|
||||
'password': 'password123',
|
||||
'password_confirm': 'password123',
|
||||
'nivel': 1000,
|
||||
'idioma': 'es',
|
||||
'empresa': 'Empresa Original',
|
||||
'estado': 'activo',
|
||||
'fecha_caducidad': ''
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/users/create",
|
||||
data={
|
||||
"nombre": "Usuario para Editar",
|
||||
"username": "edit_user",
|
||||
"email": "edit@example.com",
|
||||
"password": "password123",
|
||||
"password_confirm": "password123",
|
||||
"nivel": 1000,
|
||||
"idioma": "es",
|
||||
"empresa": "Empresa Original",
|
||||
"estado": "activo",
|
||||
"fecha_caducidad": "",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Now edit the user
|
||||
response = logged_in_client.post('/users/edit/edit_user', data={
|
||||
'nombre': 'Usuario Editado',
|
||||
'email': 'edited@example.com',
|
||||
'password': '', # Empty password means no change
|
||||
'password_confirm': '',
|
||||
'nivel': 5000, # Changed level
|
||||
'idioma': 'en', # Changed language
|
||||
'empresa': 'Empresa Modificada',
|
||||
'estado': 'activo',
|
||||
'fecha_caducidad': ''
|
||||
}, follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
"/users/edit/edit_user",
|
||||
data={
|
||||
"nombre": "Usuario Editado",
|
||||
"email": "edited@example.com",
|
||||
"password": "", # Empty password means no change
|
||||
"password_confirm": "",
|
||||
"nivel": 5000, # Changed level
|
||||
"idioma": "en", # Changed language
|
||||
"empresa": "Empresa Modificada",
|
||||
"estado": "activo",
|
||||
"fecha_caducidad": "",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Verify changes
|
||||
with app.app_context():
|
||||
users_path = os.path.join(app.config['STORAGE_PATH'], 'users', 'users.json')
|
||||
with open(users_path, 'r') as f:
|
||||
users_path = os.path.join(app.config["STORAGE_PATH"], "users", "users.json")
|
||||
with open(users_path, "r") as f:
|
||||
users = json.load(f)
|
||||
assert 'edit_user' in users
|
||||
assert users['edit_user']['nombre'] == 'Usuario Editado'
|
||||
assert users['edit_user']['email'] == 'edited@example.com'
|
||||
assert users['edit_user']['nivel'] == 5000
|
||||
assert users['edit_user']['idioma'] == 'en'
|
||||
assert users['edit_user']['empresa'] == 'Empresa Modificada'
|
||||
|
||||
assert "edit_user" in users
|
||||
assert users["edit_user"]["nombre"] == "Usuario Editado"
|
||||
assert users["edit_user"]["email"] == "edited@example.com"
|
||||
assert users["edit_user"]["nivel"] == 5000
|
||||
assert users["edit_user"]["idioma"] == "en"
|
||||
assert users["edit_user"]["empresa"] == "Empresa Modificada"
|
||||
|
||||
def test_delete_user(self, logged_in_client, app):
|
||||
"""Test deleting a user."""
|
||||
# First create a user to delete
|
||||
logged_in_client.post('/users/create', data={
|
||||
'nombre': 'Usuario para Eliminar',
|
||||
'username': 'delete_user',
|
||||
'email': 'delete@example.com',
|
||||
'password': 'password123',
|
||||
'password_confirm': 'password123',
|
||||
'nivel': 1000,
|
||||
'idioma': 'es',
|
||||
'empresa': 'Empresa Test',
|
||||
'estado': 'activo',
|
||||
'fecha_caducidad': ''
|
||||
}, follow_redirects=True)
|
||||
|
||||
logged_in_client.post(
|
||||
"/users/create",
|
||||
data={
|
||||
"nombre": "Usuario para Eliminar",
|
||||
"username": "delete_user",
|
||||
"email": "delete@example.com",
|
||||
"password": "password123",
|
||||
"password_confirm": "password123",
|
||||
"nivel": 1000,
|
||||
"idioma": "es",
|
||||
"empresa": "Empresa Test",
|
||||
"estado": "activo",
|
||||
"fecha_caducidad": "",
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
# Verify user was created
|
||||
with app.app_context():
|
||||
users_path = os.path.join(app.config['STORAGE_PATH'], 'users', 'users.json')
|
||||
with open(users_path, 'r') as f:
|
||||
users_path = os.path.join(app.config["STORAGE_PATH"], "users", "users.json")
|
||||
with open(users_path, "r") as f:
|
||||
users = json.load(f)
|
||||
assert 'delete_user' in users
|
||||
|
||||
assert "delete_user" in users
|
||||
|
||||
# Now delete the user
|
||||
response = logged_in_client.post('/users/delete/delete_user', follow_redirects=True)
|
||||
|
||||
response = logged_in_client.post(
|
||||
"/users/delete/delete_user", follow_redirects=True
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Verify user was deleted
|
||||
with app.app_context():
|
||||
users_path = os.path.join(app.config['STORAGE_PATH'], 'users', 'users.json')
|
||||
with open(users_path, 'r') as f:
|
||||
users_path = os.path.join(app.config["STORAGE_PATH"], "users", "users.json")
|
||||
with open(users_path, "r") as f:
|
||||
users = json.load(f)
|
||||
assert 'delete_user' not in users
|
||||
|
||||
assert "delete_user" not in users
|
||||
|
||||
def test_cannot_delete_admin(self, logged_in_client):
|
||||
"""Test that admin user cannot be deleted."""
|
||||
response = logged_in_client.post('/users/delete/admin', follow_redirects=True)
|
||||
response = logged_in_client.post("/users/delete/admin", follow_redirects=True)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
# Should see an error message
|
||||
assert b'No se puede eliminar' in response.data or b'no puede' in response.data
|
||||
assert b"No se puede eliminar" in response.data or b"no puede" in response.data
|
||||
|
|
Loading…
Reference in New Issue