Creado Tests

This commit is contained in:
Miguel 2025-03-04 10:38:19 +01:00
parent 79194e0f61
commit b48058e495
20 changed files with 1190 additions and 605 deletions

48
generate_test_report.py Normal file
View File

@ -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())

View File

@ -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

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,4 @@
{
"max_project_id": 0,
"max_document_id": 0
}

View File

@ -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
}
]
}
}

View File

@ -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"
}
}

View File

@ -0,0 +1,2 @@
# This file makes the tests directory a Python package
# allowing the json_reporter module to be imported

View File

@ -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)

15
tests/helpers.py Normal file
View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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()
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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