Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from advanced_omi_backend.client_manager import get_user_clients_all
from advanced_omi_backend.database import chunks_col, db, users_col
from advanced_omi_backend.memory import get_memory_service
from advanced_omi_backend.users import User, UserCreate
from advanced_omi_backend.users import User, UserCreate, UserUpdate

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -78,8 +78,9 @@ async def create_user(user_data: UserCreate):
)


async def update_user(user_id: str, user_data: UserCreate):
async def update_user(user_id: str, user_data: UserUpdate):
"""Update an existing user."""
print("DEBUG: New update_user function is being called!")
try:
# Validate ObjectId format
try:
Expand All @@ -106,23 +107,9 @@ async def update_user(user_id: str, user_data: UserCreate):

# Convert to User object for the manager
user_obj = User(**existing_user)

# Prepare update data - only include non-None fields
update_data = {}
if user_data.email:
update_data["email"] = user_data.email
if user_data.display_name is not None:
update_data["display_name"] = user_data.display_name
if hasattr(user_data, 'is_superuser'):
update_data["is_superuser"] = user_data.is_superuser
if hasattr(user_data, 'is_active'):
update_data["is_active"] = user_data.is_active
if user_data.password:
# Hash the password if provided
update_data["hashed_password"] = user_manager.password_helper.hash(user_data.password)

# Update the user
updated_user = await user_manager.update(user_obj, update_data)

# Update the user using the fastapi-users manager (now with fix for missing method)
updated_user = await user_manager.update(user_obj, user_data)

return JSONResponse(
status_code=200,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from advanced_omi_backend.auth import current_superuser
from advanced_omi_backend.controllers import user_controller
from advanced_omi_backend.users import User, UserCreate
from advanced_omi_backend.users import User, UserCreate, UserUpdate

logger = logging.getLogger(__name__)

Expand All @@ -30,7 +30,7 @@ async def create_user(user_data: UserCreate, current_user: User = Depends(curren


@router.put("/{user_id}")
async def update_user(user_id: str, user_data: UserCreate, current_user: User = Depends(current_superuser)):
async def update_user(user_id: str, user_data: UserUpdate, current_user: User = Depends(current_superuser)):
"""Update a user. Admin only."""
return await user_controller.update_user(user_id, user_data)

Expand Down
21 changes: 20 additions & 1 deletion backends/advanced/src/advanced_omi_backend/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class UserCreate(BaseUserCreate):
"""Schema for creating new users."""

display_name: Optional[str] = None
is_superuser: Optional[bool] = False


class UserRead(BaseUser[PydanticObjectId]):
Expand All @@ -28,8 +29,26 @@ class UserRead(BaseUser[PydanticObjectId]):

class UserUpdate(BaseUserUpdate):
"""Schema for updating user data."""

display_name: Optional[str] = None
is_superuser: Optional[bool] = None

def create_update_dict_superuser(self):
"""Create update dictionary for superuser operations."""
update_dict = {}
if self.email is not None:
update_dict["email"] = self.email
if self.password is not None:
update_dict["password"] = self.password
if self.is_active is not None:
update_dict["is_active"] = self.is_active
if self.is_verified is not None:
update_dict["is_verified"] = self.is_verified
if self.is_superuser is not None:
update_dict["is_superuser"] = self.is_superuser
if self.display_name is not None:
update_dict["display_name"] = self.display_name
return update_dict
Comment on lines +36 to +51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Override create_update_dict so updates actually persist.

UserManager.update calls user_update.create_update_dict(). Because this class doesn’t override that method, the manager still uses the default implementation, which omits display_name and any other custom fields. In practice, requests attempting to change display_name (or even is_superuser, which you’re trying to fix) will silently no-op. Please override create_update_dict() (or replace the manager call with your new helper) instead of introducing an unused create_update_dict_superuser. Right now the update endpoint can’t apply the fields this PR intends to support.

🤖 Prompt for AI Agents
In backends/advanced/src/advanced_omi_backend/users.py around lines 36 to 51,
you added create_update_dict_superuser but did not override create_update_dict,
so UserManager.update still uses the base method and ignores display_name and
other custom fields; replace or rename this helper by overriding
create_update_dict to build and return the update_dict (including email,
password, is_active, is_verified, is_superuser, display_name) so the manager
picks up and persists those fields, and ensure any call sites use the overridden
method rather than the old helper.



class User(BeanieBaseUser, Document):
Expand Down
230 changes: 230 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
# Friend-Lite API Tests

Comprehensive Robot Framework test suite for the Friend-Lite advanced backend API endpoints.

## Test Structure

### Test Files
- **`auth_tests.robot`** - Authentication and user management tests
- **`memory_tests.robot`** - Memory management and search tests
- **`conversation_tests.robot`** - Conversation management and versioning tests
- **`health_tests.robot`** - Health check and status endpoint tests
- **`chat_tests.robot`** - Chat service and session management tests
- **`client_queue_tests.robot`** - Client management and queue monitoring tests
- **`system_admin_tests.robot`** - System administration and configuration tests
- **`all_api_tests.robot`** - Master test suite runner

### Resource Files
- **`resources/auth_keywords.robot`** - Authentication helper keywords
- **`resources/memory_keywords.robot`** - Memory management keywords
- **`resources/conversation_keywords.robot`** - Conversation management keywords
- **`resources/chat_keywords.robot`** - Chat service keywords
- **`resources/setup_resources.robot`** - Basic setup and health check keywords
- **`resources/login_resources.robot`** - Login-specific utilities

### Configuration
- **`test_env.py`** - Environment configuration and test data
- **`.env`** - Environment variables (create from template)

## Running Tests

### Prerequisites
1. Friend-Lite backend running at `http://localhost:8001` (or set `API_URL` in `.env`)
2. Admin user credentials configured in `.env`
3. Robot Framework and RequestsLibrary installed

### Environment Setup
```bash
# Copy environment template
cp .env.template .env

# Edit .env with your configuration
API_URL=http://localhost:8001
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=your-secure-admin-password
```

### Running Individual Test Suites
```bash
# Authentication and user tests
robot auth_tests.robot

# Memory management tests
robot memory_tests.robot

# Conversation management tests
robot conversation_tests.robot

# Health and status tests
robot health_tests.robot

# Chat service tests
robot chat_tests.robot

# Client and queue tests
robot client_queue_tests.robot

# System administration tests
robot system_admin_tests.robot
```

### Running All Tests
```bash
# Run complete test suite
robot *.robot

# Run with specific tags
robot --include auth *.robot
robot --include positive *.robot
robot --include admin *.robot
```

### Test Output
```bash
# Custom output directory
robot --outputdir results *.robot

# Verbose logging
robot --loglevel DEBUG *.robot

# Parallel execution
pabot --processes 4 *.robot
```

## Test Coverage

### Authentication & Users (`/api/users`, `/auth`)
- ✅ Login with valid/invalid credentials
- ✅ Get current user information
- ✅ Create/update/delete users (admin only)
- ✅ User authorization and access control
- ✅ Admin privilege enforcement

### Memory Management (`/api/memories`)
- ✅ Get user memories with pagination
- ✅ Search memories with similarity thresholds
- ✅ Get memories with transcripts
- ✅ Delete specific memories
- ✅ Admin memory access across users
- ✅ Unfiltered memory access for debugging

### Conversation Management (`/api/conversations`)
- ✅ List and retrieve conversations
- ✅ Conversation version history
- ✅ Transcript reprocessing
- ✅ Memory reprocessing with version selection
- ✅ Version activation (transcript/memory)
- ✅ Conversation deletion and cleanup
- ✅ User data isolation

### Health & Status (`/health`, `/readiness`)
- ✅ Main health check with service details
- ✅ Readiness check for orchestration
- ✅ Authentication service health
- ✅ Queue system health status
- ✅ Chat service health check
- ✅ System metrics (admin only)

### Chat Service (`/api/chat`)
- ✅ Session creation and management
- ✅ Session title updates
- ✅ Message retrieval
- ✅ Chat statistics
- ✅ Memory extraction from sessions
- ✅ Session deletion and cleanup

### Client & Queue Management
- ✅ Active client monitoring
- ✅ Queue job listing with pagination
- ✅ Queue statistics and health
- ✅ User job isolation
- ✅ Processing task monitoring (admin only)

### System Administration
- ✅ Authentication configuration
- ✅ Diarization settings management
- ✅ Speaker configuration
- ✅ Memory configuration (YAML)
- ✅ Configuration validation and reload
- ✅ Bulk memory deletion

## Test Categories

### By Access Level
- **Public**: Health checks, auth config
- **User**: Memories, conversations, chat sessions
- **Admin**: User management, system config, metrics

### By Test Type
- **Positive**: Valid operations and expected responses
- **Negative**: Invalid inputs, unauthorized access
- **Security**: Authentication, authorization, data isolation
- **Integration**: Cross-service functionality

### By Component
- **Auth**: Authentication and authorization
- **Memory**: Memory storage and retrieval
- **Conversation**: Audio processing and transcription
- **Chat**: Interactive chat functionality
- **System**: Configuration and administration

## Key Features Tested

### Security
- JWT token authentication
- Role-based access control (admin vs user)
- Data isolation between users
- Unauthorized access prevention

### Data Management
- CRUD operations for all entities
- Pagination and filtering
- Search functionality with thresholds
- Versioning and history tracking

### System Integration
- Service health monitoring
- Configuration management
- Queue system monitoring
- Cross-service communication

### Error Handling
- Invalid input validation
- Non-existent resource handling
- Permission denied scenarios
- Service unavailability graceful degradation

## Maintenance

### Adding New Tests
1. Create test file or add to existing suite
2. Use appropriate resource keywords
3. Follow naming conventions (`Test Name Test`)
4. Include proper tags and documentation
5. Add cleanup in teardown if needed

### Updating Keywords
1. Modify resource files for reusable functionality
2. Keep keywords focused and single-purpose
3. Use proper argument handling
4. Include documentation strings

### Environment Variables
Update `test_env.py` when adding new configuration options or test data.

## Troubleshooting

### Common Issues
- **401 Unauthorized**: Check admin credentials in `.env`
- **Connection Refused**: Ensure backend is running
- **Test Failures**: Check service health endpoints first
- **Timeout Errors**: Increase timeouts in test configuration

### Debug Mode
```bash
# Run with detailed logging
robot --loglevel TRACE auth_tests.robot

# Stop on first failure
robot --exitonfailure *.robot
```
58 changes: 58 additions & 0 deletions tests/all_api_tests.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
*** Settings ***
Documentation Master Test Suite for All Friend-Lite API Endpoints
Suite Setup Master Suite Setup
Suite Teardown Master Suite Teardown

*** Test Cases ***

Run Auth Tests
[Documentation] Execute authentication and user management tests
[Tags] auth users suite
Run Tests auth_tests.robot

Run Memory Tests
[Documentation] Execute memory management tests
[Tags] memory suite
Run Tests memory_tests.robot

Run Conversation Tests
[Documentation] Execute conversation management tests
[Tags] conversation suite
Run Tests conversation_tests.robot

Run Health Tests
[Documentation] Execute health and status tests
[Tags] health status suite
Run Tests health_tests.robot

Run Chat Tests
[Documentation] Execute chat service tests
[Tags] chat suite
Run Tests chat_tests.robot

Run Client Queue Tests
[Documentation] Execute client and queue management tests
[Tags] client queue suite
Run Tests client_queue_tests.robot

Run System Admin Tests
[Documentation] Execute system and admin tests
[Tags] system admin suite
Run Tests system_admin_tests.robot

Comment on lines +8 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Master suite never triggers the underlying suites

Every test case in this file just calls Run Tests, but that keyword only logs a message and returns. When you execute all_api_tests.robot, none of the underlying suite files actually run, so failures in auth_tests.robot, memory_tests.robot, etc. go completely unnoticed. This defeats the whole point of the orchestrator. Please make Run Tests invoke the suite (for example via Run Process robot ${test_file} and assert the return code) or restructure the suite so that the real test files are imported/executed directly. Without that fix the master suite will always pass even if the API tests break.

Apply this diff (add the Process library and execute each suite):

*** Settings ***
 Documentation    Master Test Suite for All Friend-Lite API Endpoints
 Suite Setup      Master Suite Setup
 Suite Teardown   Master Suite Teardown
+Library          Process

*** Keywords ***
 Run Tests
     [Documentation]    Run a specific test file
     [Arguments]    ${test_file}
-    Log    Executing: ${test_file}
-    # Note: This is a placeholder - actual test execution handled by robot command
+    ${result}=    Run Process    robot    ${test_file}    stdout=STDOUT    stderr=STDOUT
+    Should Be Equal As Integers    ${result.rc}    0    Execution of ${test_file} failed

Also applies to: 45-58

🤖 Prompt for AI Agents
In tests/all_api_tests.robot around lines 8-42 (and also 45-58), the suite only
calls the custom Run Tests keyword which merely logs and does not execute the
underlying suites; import the Robot Process library at the top and replace each
Run Tests call with a Run Process invocation of the robot runner for that file,
capturing the returned result object and asserting the process return code is
zero (e.g. ${result}=  Run Process  robot  <suite_file>; Should Be Equal As
Integers  ${result.rc}  0) so each underlying suite actually runs and failures
fail the master suite.

*** Keywords ***

Master Suite Setup
[Documentation] Setup for the entire test suite
Log Starting Friend-Lite API Test Suite
Log Testing against: ${API_URL}

Master Suite Teardown
[Documentation] Cleanup for the entire test suite
Log Friend-Lite API Test Suite completed

Run Tests
[Documentation] Run a specific test file
[Arguments] ${test_file}
Log Executing: ${test_file}
# Note: This is a placeholder - actual test execution handled by robot command
Loading
Loading