backup
This commit is contained in:
126
tests/robot/api/anime.robot
Normal file
126
tests/robot/api/anime.robot
Normal file
@@ -0,0 +1,126 @@
|
||||
*** Settings ***
|
||||
Documentation Anime library API tests for Aniworld.
|
||||
... Covers status, rescan, search, add, details, episodes, filters, and duplicates.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Run Keywords
|
||||
... Create Anonymous Session
|
||||
... AND Setup Master Password
|
||||
... AND Create Authenticated Session
|
||||
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# Library Status
|
||||
# ---------------------------------------------------------------------------
|
||||
Get Anime Library Status
|
||||
[Documentation] Retrieve the anime library status.
|
||||
${resp}= Get Anime Status
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} directory series_count
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rescan
|
||||
# ---------------------------------------------------------------------------
|
||||
Rescan Library
|
||||
[Documentation] Trigger a library rescan and verify acceptance.
|
||||
${resp}= Rescan Library
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Scan Status During Idle
|
||||
[Documentation] Get scan status when no scan is in progress.
|
||||
${resp}= Get Scan Status
|
||||
Response Should Have Status ${resp} 200
|
||||
${in_progress}= Get JSON Value ${resp} $.in_progress
|
||||
Should Be Equal As Strings ${in_progress} False
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Search
|
||||
# ---------------------------------------------------------------------------
|
||||
Search Anime
|
||||
[Documentation] Search for anime series via the provider.
|
||||
${resp}= Search Anime attack
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Series CRUD
|
||||
# ---------------------------------------------------------------------------
|
||||
Add New Series
|
||||
[Documentation] Add a new anime series to the library.
|
||||
${resp}= Add Series https://aniworld.to/anime/stream/attack-on-titan Attack on Titan 2013
|
||||
Response Should Have Status ${resp} 201
|
||||
${key}= Get JSON Value ${resp} $.key
|
||||
Should Not Be Empty ${key}
|
||||
Set Test Variable ${TEST_SERIES_KEY} ${key}
|
||||
|
||||
Get Series Details
|
||||
[Documentation] Retrieve details for a specific series.
|
||||
Add New Series
|
||||
${resp}= Get Series Details ${TEST_SERIES_KEY}
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} key name folder episodes
|
||||
|
||||
Update Series Settings
|
||||
[Documentation] Update settings for a specific series.
|
||||
Add New Series
|
||||
${payload}= Create Dictionary preferred_language=german
|
||||
${resp}= PUT API /api/anime/${TEST_SERIES_KEY}/settings ${payload}
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Get Series Episodes
|
||||
[Documentation] Retrieve the episode list for a series.
|
||||
Add New Series
|
||||
${resp}= Get Series Episodes ${TEST_SERIES_KEY}
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
Delete Series
|
||||
[Documentation] Remove a series from the library.
|
||||
Add New Series
|
||||
${resp}= Delete Series ${TEST_SERIES_KEY}
|
||||
Response Should Have Status ${resp} 200
|
||||
${get_resp}= Get Series Details ${TEST_SERIES_KEY}
|
||||
Response Should Have Status ${get_resp} 404
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Filters
|
||||
# ---------------------------------------------------------------------------
|
||||
List All Series
|
||||
[Documentation] List all series without filters.
|
||||
${resp}= GET API /api/anime/
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
List Missing Episodes Only
|
||||
[Documentation] Filter series to show only those with missing episodes.
|
||||
${resp}= GET API /api/anime/?filter=missing
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
List No Episodes
|
||||
[Documentation] Filter series to show only those with zero episodes.
|
||||
${resp}= GET API /api/anime/?filter=no_episodes
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Duplicates
|
||||
# ---------------------------------------------------------------------------
|
||||
Duplicate Folders Detection
|
||||
[Documentation] Check for duplicate folder groups in the library.
|
||||
${resp}= GET API /api/anime/duplicate-folders
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# NFO Regeneration
|
||||
# ---------------------------------------------------------------------------
|
||||
Regenerate NFO For Series
|
||||
[Documentation] Trigger NFO regeneration for a specific series.
|
||||
Add New Series
|
||||
${resp}= POST API /api/anime/${TEST_SERIES_KEY}/regenerate-nfo
|
||||
Response Should Have Status ${resp} 200
|
||||
118
tests/robot/api/auth.robot
Normal file
118
tests/robot/api/auth.robot
Normal file
@@ -0,0 +1,118 @@
|
||||
*** Settings ***
|
||||
Documentation Authentication API tests for Aniworld.
|
||||
... Covers setup, login, logout, status, rate limiting, and JWT validation.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Create Anonymous Session
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# Setup
|
||||
# ---------------------------------------------------------------------------
|
||||
Setup Master Password
|
||||
[Documentation] Configure the master password for the first time.
|
||||
${resp}= POST Auth Setup ${SETUP_PASSWORD} 201
|
||||
Response Should Have Status ${resp} 201
|
||||
${configured}= Is Auth Configured
|
||||
Should Be True ${configured}
|
||||
|
||||
Setup Rejects Weak Password
|
||||
[Documentation] Verify that weak passwords are rejected during setup.
|
||||
${resp}= POST Auth Setup weak 400
|
||||
Response Should Have Status ${resp} 400
|
||||
|
||||
Setup Rejects Duplicate
|
||||
[Documentation] Verify that setup cannot be performed twice.
|
||||
Setup Master Password
|
||||
${resp}= POST Auth Setup AnotherPass123! 400
|
||||
Response Should Have Status ${resp} 400
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Login
|
||||
# ---------------------------------------------------------------------------
|
||||
Login With Valid Password
|
||||
[Documentation] Log in with the correct master password and receive a JWT token.
|
||||
Setup Master Password
|
||||
${resp}= POST Auth Login ${SETUP_PASSWORD} 200
|
||||
Response Should Have Status ${resp} 200
|
||||
${token}= Get JSON Value ${resp} $.access_token
|
||||
Should Not Be Empty ${token}
|
||||
|
||||
Login With Invalid Password
|
||||
[Documentation] Log in with an incorrect password and receive 401.
|
||||
Setup Master Password
|
||||
${resp}= POST Auth Login WrongPass123! 401
|
||||
Response Should Have Status ${resp} 401
|
||||
|
||||
Login Rate Limiting
|
||||
[Documentation] Verify that repeated failed login attempts trigger rate limiting.
|
||||
Setup Master Password
|
||||
FOR ${i} IN RANGE 6
|
||||
${resp}= POST Auth Login WrongPass123! expected_status=ANY
|
||||
END
|
||||
${resp}= POST Auth Login WrongPass123! expected_status=ANY
|
||||
Should Be True ${resp.status_code} >= 429 or ${resp.status_code} == 401
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Auth Status
|
||||
# ---------------------------------------------------------------------------
|
||||
Auth Status Unconfigured
|
||||
[Documentation] Check auth status before any setup has occurred.
|
||||
${resp}= GET Auth Status 200
|
||||
Response Should Have Status ${resp} 200
|
||||
${configured}= Get JSON Value ${resp} $.configured
|
||||
Should Be Equal As Strings ${configured} False
|
||||
|
||||
Auth Status Configured Unauthenticated
|
||||
[Documentation] Check auth status after setup but without a token.
|
||||
Setup Master Password
|
||||
${resp}= GET Auth Status 200
|
||||
Response Should Have Status ${resp} 200
|
||||
${configured}= Get JSON Value ${resp} $.configured
|
||||
Should Be Equal As Strings ${configured} True
|
||||
${authenticated}= Get JSON Value ${resp} $.authenticated
|
||||
Should Be Equal As Strings ${authenticated} False
|
||||
|
||||
Auth Status Authenticated
|
||||
[Documentation] Check auth status with a valid Bearer token.
|
||||
Setup Master Password
|
||||
${token}= Login And Get Token
|
||||
${headers}= Create Dictionary Authorization=Bearer ${token}
|
||||
Create Session authed ${BASE_URL} headers=${headers}
|
||||
${resp}= GET On Session authed /api/auth/status expected_status=200
|
||||
Response Should Have Status ${resp} 200
|
||||
${authenticated}= Get JSON Value ${resp} $.authenticated
|
||||
Should Be Equal As Strings ${authenticated} True
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Logout
|
||||
# ---------------------------------------------------------------------------
|
||||
Logout
|
||||
[Documentation] Log out and verify the token is invalidated.
|
||||
Setup Master Password
|
||||
${token}= Login And Get Token
|
||||
${headers}= Create Dictionary Authorization=Bearer ${token}
|
||||
Create Session authed ${BASE_URL} headers=${headers}
|
||||
${resp}= POST On Session authed /api/auth/logout expected_status=200
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Protected Endpoints
|
||||
# ---------------------------------------------------------------------------
|
||||
Protected Endpoint Without Auth
|
||||
[Documentation] Verify that protected endpoints reject unauthenticated requests.
|
||||
Setup Master Password
|
||||
${resp}= GET On Session anon /api/anime/ expected_status=401
|
||||
Response Should Have Status ${resp} 401
|
||||
|
||||
Protected Endpoint With Auth
|
||||
[Documentation] Verify that protected endpoints accept authenticated requests.
|
||||
Setup Master Password
|
||||
${token}= Login And Get Token
|
||||
${headers}= Create Dictionary Authorization=Bearer ${token}
|
||||
Create Session authed ${BASE_URL} headers=${headers}
|
||||
${resp}= GET On Session authed /api/anime/ expected_status=200
|
||||
Response Should Have Status ${resp} 200
|
||||
138
tests/robot/api/config.robot
Normal file
138
tests/robot/api/config.robot
Normal file
@@ -0,0 +1,138 @@
|
||||
*** Settings ***
|
||||
Documentation Configuration API tests for Aniworld.
|
||||
... Covers get, update, validate, backup create/list/restore/delete, and export/import.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Run Keywords
|
||||
... Create Anonymous Session
|
||||
... AND Setup Master Password
|
||||
... AND Create Authenticated Session
|
||||
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# Get / Update Config
|
||||
# ---------------------------------------------------------------------------
|
||||
Get Default Config
|
||||
[Documentation] Retrieve the current configuration and verify its structure.
|
||||
${resp}= GET API /api/config
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} name data_dir scheduler logging backup nfo
|
||||
|
||||
Update Config
|
||||
[Documentation] Update configuration fields and verify they are persisted.
|
||||
${payload}= Create Dictionary
|
||||
... name=UpdatedAniworld
|
||||
... data_dir=data
|
||||
... scheduler={'enabled': False, 'schedule_time': '04:00', 'schedule_days': ['mon', 'tue']}
|
||||
... logging={'level': 'DEBUG', 'file': 'logs/test.log', 'max_bytes': 1048576, 'backup_count': 5}
|
||||
... backup={'enabled': False}
|
||||
... nfo={'tmdb_api_key': '', 'auto_create': False, 'download_poster': False, 'download_logo': False, 'download_fanart': False}
|
||||
... other={'anime_directory': '/tmp/aniworld_test_anime'}
|
||||
${resp}= Update Config ${payload}
|
||||
Response Should Have Status ${resp} 200
|
||||
${config}= Get Current Config
|
||||
Should Be Equal As Strings ${config}[name] UpdatedAniworld
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Config Validation
|
||||
# ---------------------------------------------------------------------------
|
||||
Validate Valid Config
|
||||
[Documentation] Validate a well-formed configuration.
|
||||
${payload}= Create Dictionary
|
||||
... name=Aniworld
|
||||
... data_dir=data
|
||||
... scheduler={'enabled': True, 'schedule_time': '03:00', 'schedule_days': ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']}
|
||||
... logging={'level': 'INFO', 'file': None, 'max_bytes': None, 'backup_count': 3}
|
||||
... backup={'enabled': False}
|
||||
... nfo={'tmdb_api_key': '', 'auto_create': True, 'download_poster': True, 'download_logo': True, 'download_fanart': True}
|
||||
... other={}
|
||||
${resp}= Validate Config ${payload} 200
|
||||
Response Should Have Status ${resp} 200
|
||||
${valid}= Get JSON Value ${resp} $.valid
|
||||
Should Be Equal As Strings ${valid} True
|
||||
|
||||
Validate Invalid Config Missing Name
|
||||
[Documentation] Validate a config missing the required 'name' field.
|
||||
${payload}= Create Dictionary
|
||||
... data_dir=data
|
||||
... scheduler={'enabled': True, 'schedule_time': '03:00', 'schedule_days': ['mon']}
|
||||
... logging={'level': 'INFO'}
|
||||
... backup={'enabled': False}
|
||||
... nfo={'auto_create': False}
|
||||
... other={}
|
||||
${resp}= Validate Config ${payload} 422
|
||||
Response Should Have Status ${resp} 422
|
||||
|
||||
Validate Invalid Schedule Time
|
||||
[Documentation] Validate a config with malformed schedule_time.
|
||||
${payload}= Create Dictionary
|
||||
... name=Aniworld
|
||||
... data_dir=data
|
||||
... scheduler={'enabled': True, 'schedule_time': '25:00', 'schedule_days': ['mon']}
|
||||
... logging={'level': 'INFO'}
|
||||
... backup={'enabled': False}
|
||||
... nfo={'auto_create': False}
|
||||
... other={}
|
||||
${resp}= Validate Config ${payload} 422
|
||||
Response Should Have Status ${resp} 422
|
||||
|
||||
Validate Invalid Log Level
|
||||
[Documentation] Validate a config with an invalid logging level.
|
||||
${payload}= Create Dictionary
|
||||
... name=Aniworld
|
||||
... data_dir=data
|
||||
... scheduler={'enabled': True, 'schedule_time': '03:00', 'schedule_days': ['mon']}
|
||||
... logging={'level': 'INVALID', 'file': None, 'max_bytes': None, 'backup_count': 3}
|
||||
... backup={'enabled': False}
|
||||
... nfo={'auto_create': False}
|
||||
... other={}
|
||||
${resp}= Validate Config ${payload} 422
|
||||
Response Should Have Status ${resp} 422
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Backup Management
|
||||
# ---------------------------------------------------------------------------
|
||||
Config Backup Create
|
||||
[Documentation] Create a configuration backup and verify it exists.
|
||||
${resp}= POST API /api/config/backups expected_status=201
|
||||
Response Should Have Status ${resp} 201
|
||||
|
||||
Config Backup List
|
||||
[Documentation] List configuration backups and verify the response structure.
|
||||
POST API /api/config/backups expected_status=201
|
||||
${resp}= GET API /api/config/backups
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Key ${resp} $.backups
|
||||
|
||||
Config Backup Restore
|
||||
[Documentation] Create a backup, change config, then restore and verify reversion.
|
||||
${resp}= POST API /api/config/backups expected_status=201
|
||||
${json}= Convert String To Json ${resp.text}
|
||||
${backup_name}= Get Value From Json ${json} $.backup_name
|
||||
${name_before}= Set Variable ${backup_name}[0]
|
||||
# Change config
|
||||
${payload}= Create Dictionary
|
||||
... name=BeforeRestore
|
||||
... data_dir=data
|
||||
... scheduler={'enabled': False, 'schedule_time': '03:00', 'schedule_days': ['mon']}
|
||||
... logging={'level': 'INFO', 'file': None, 'max_bytes': None, 'backup_count': 3}
|
||||
... backup={'enabled': False}
|
||||
... nfo={'auto_create': False}
|
||||
... other={}
|
||||
Update Config ${payload}
|
||||
# Restore
|
||||
${resp}= POST API /api/config/backups/${name_before}/restore
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Config Backup Delete
|
||||
[Documentation] Create a backup and then delete it.
|
||||
${resp}= POST API /api/config/backups expected_status=201
|
||||
${json}= Convert String To Json ${resp.text}
|
||||
${backup_name}= Get Value From Json ${json} $.backup_name
|
||||
${name}= Set Variable ${backup_name}[0]
|
||||
${del_resp}= DELETE API /api/config/backups/${name}
|
||||
Response Should Have Status ${del_resp} 200
|
||||
145
tests/robot/api/download.robot
Normal file
145
tests/robot/api/download.robot
Normal file
@@ -0,0 +1,145 @@
|
||||
*** Settings ***
|
||||
Documentation Download queue API tests for Aniworld.
|
||||
... Covers status, add, start/stop/pause/resume, clear, retry, and remove.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Run Keywords
|
||||
... Create Anonymous Session
|
||||
... AND Setup Master Password
|
||||
... AND Create Authenticated Session
|
||||
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# Queue Status
|
||||
# ---------------------------------------------------------------------------
|
||||
Get Empty Queue Status
|
||||
[Documentation] Retrieve queue status when the queue is empty.
|
||||
${resp}= Get Queue Status
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} status statistics
|
||||
${pending}= Get JSON Value ${resp} $.statistics.pending
|
||||
Should Be Equal As Integers ${pending} 0
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Add To Queue
|
||||
# ---------------------------------------------------------------------------
|
||||
Add Episodes To Queue
|
||||
[Documentation] Add episodes to the download queue.
|
||||
${episodes}= Create List
|
||||
... {'season': 1, 'episode': 1, 'title': 'Episode 1'}
|
||||
... {'season': 1, 'episode': 2, 'title': 'Episode 2'}
|
||||
${payload}= Create Dictionary
|
||||
... serie_id=test-series
|
||||
... serie_folder=Test Series
|
||||
... serie_name=Test Series
|
||||
... episodes=${episodes}
|
||||
... priority=NORMAL
|
||||
${resp}= Add To Queue ${payload}
|
||||
Response Should Have Status ${resp} 201
|
||||
${ids}= Get JSON Value ${resp} $.item_ids
|
||||
Should Not Be Empty ${ids}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Queue Controls
|
||||
# ---------------------------------------------------------------------------
|
||||
Start Queue
|
||||
[Documentation] Start processing the download queue.
|
||||
${resp}= Start Queue
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Stop Queue
|
||||
[Documentation] Stop processing the download queue.
|
||||
${resp}= Stop Queue
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Pause Queue
|
||||
[Documentation] Pause the download queue.
|
||||
${resp}= Pause Queue
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Resume Queue
|
||||
[Documentation] Resume the download queue.
|
||||
${resp}= Resume Queue
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Clear Operations
|
||||
# ---------------------------------------------------------------------------
|
||||
Clear Completed Downloads
|
||||
[Documentation] Clear all completed downloads from the queue.
|
||||
${resp}= Clear Completed
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Clear Failed Downloads
|
||||
[Documentation] Clear all failed downloads from the queue.
|
||||
${resp}= Clear Failed
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Clear Pending Downloads
|
||||
[Documentation] Clear all pending downloads from the queue.
|
||||
${resp}= Clear Pending
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Item Management
|
||||
# ---------------------------------------------------------------------------
|
||||
Remove Item From Queue
|
||||
[Documentation] Remove a specific item from the queue.
|
||||
${episodes}= Create List {'season': 1, 'episode': 1, 'title': 'Episode 1'}
|
||||
${payload}= Create Dictionary
|
||||
... serie_id=remove-test
|
||||
... serie_folder=Remove Test
|
||||
... serie_name=Remove Test
|
||||
... episodes=${episodes}
|
||||
... priority=NORMAL
|
||||
${add_resp}= Add To Queue ${payload}
|
||||
${json}= Convert String To Json ${add_resp.text}
|
||||
${ids}= Get Value From Json ${json} $.item_ids
|
||||
${item_id}= Set Variable ${ids}[0]
|
||||
${del_resp}= DELETE API /api/queue/item/${item_id}
|
||||
Response Should Have Status ${del_resp} 200
|
||||
|
||||
Retry Failed Item
|
||||
[Documentation] Retry a failed download item.
|
||||
${episodes}= Create List {'season': 1, 'episode': 1, 'title': 'Episode 1'}
|
||||
${payload}= Create Dictionary
|
||||
... serie_id=retry-test
|
||||
... serie_folder=Retry Test
|
||||
... serie_name=Retry Test
|
||||
... episodes=${episodes}
|
||||
... priority=NORMAL
|
||||
${add_resp}= Add To Queue ${payload}
|
||||
${json}= Convert String To Json ${add_resp.text}
|
||||
${ids}= Get Value From Json ${json} $.item_ids
|
||||
${item_id}= Set Variable ${ids}[0]
|
||||
${retry_resp}= POST API /api/queue/item/${item_id}/retry
|
||||
Response Should Have Status ${retry_resp} 200
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Queue Statistics Accuracy
|
||||
# ---------------------------------------------------------------------------
|
||||
Queue Statistics Accuracy
|
||||
[Documentation] Verify that queue statistics reflect the actual item counts.
|
||||
# Clear first
|
||||
Clear Pending
|
||||
# Add 2 items
|
||||
${episodes}= Create List
|
||||
... {'season': 1, 'episode': 1, 'title': 'Ep 1'}
|
||||
... {'season': 1, 'episode': 2, 'title': 'Ep 2'}
|
||||
${payload}= Create Dictionary
|
||||
... serie_id=stats-test
|
||||
... serie_folder=Stats Test
|
||||
... serie_name=Stats Test
|
||||
... episodes=${episodes}
|
||||
... priority=NORMAL
|
||||
Add To Queue ${payload}
|
||||
${resp}= Get Queue Status
|
||||
Response Should Have Status ${resp} 200
|
||||
${pending}= Get JSON Value ${resp} $.statistics.pending
|
||||
Should Be Equal As Integers ${pending} 2
|
||||
${total}= Get JSON Value ${resp} $.statistics.total
|
||||
Should Be Equal As Integers ${total} 2
|
||||
29
tests/robot/api/health.robot
Normal file
29
tests/robot/api/health.robot
Normal file
@@ -0,0 +1,29 @@
|
||||
*** Settings ***
|
||||
Documentation Health check API tests for Aniworld.
|
||||
... Covers basic and detailed health endpoints.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Create Anonymous Session
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# Basic Health
|
||||
# ---------------------------------------------------------------------------
|
||||
Basic Health Check
|
||||
[Documentation] Verify the basic health endpoint returns 200.
|
||||
${resp}= GET On Session anon /health expected_status=200
|
||||
Response Should Have Status ${resp} 200
|
||||
${status}= Get JSON Value ${resp} $.status
|
||||
Should Be Equal As Strings ${status} healthy
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Detailed Health
|
||||
# ---------------------------------------------------------------------------
|
||||
Detailed Health Check
|
||||
[Documentation] Verify the detailed health endpoint returns metrics.
|
||||
${resp}= GET On Session anon /health/detailed expected_status=200
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} status version uptime memory cpu
|
||||
56
tests/robot/api/logging.robot
Normal file
56
tests/robot/api/logging.robot
Normal file
@@ -0,0 +1,56 @@
|
||||
*** Settings ***
|
||||
Documentation Logging API tests for Aniworld.
|
||||
... Covers config, file listing, tail, download, test messages, and cleanup.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Run Keywords
|
||||
... Create Anonymous Session
|
||||
... AND Setup Master Password
|
||||
... AND Create Authenticated Session
|
||||
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# Logging Config
|
||||
# ---------------------------------------------------------------------------
|
||||
Get Logging Config
|
||||
[Documentation] Retrieve the current logging configuration.
|
||||
${resp}= Get Logging Config
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} level file max_bytes backup_count
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Log Files
|
||||
# ---------------------------------------------------------------------------
|
||||
List Log Files
|
||||
[Documentation] List available log files.
|
||||
${resp}= List Log Files
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
Tail Log File
|
||||
[Documentation] Tail the contents of a log file.
|
||||
${resp}= Tail Log File aniworld.log
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Download Log File
|
||||
[Documentation] Download a log file as binary.
|
||||
${resp}= Download Log File aniworld.log
|
||||
Response Should Have Status ${resp} 200
|
||||
Should Be Equal As Strings ${resp.headers['content-type']} application/octet-stream
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Log Management
|
||||
# ---------------------------------------------------------------------------
|
||||
Write Test Log Messages
|
||||
[Documentation] Write test log messages at various levels.
|
||||
${resp}= Write Test Logs
|
||||
Response Should Have Status ${resp} 200
|
||||
|
||||
Cleanup Old Logs
|
||||
[Documentation] Delete old log files.
|
||||
${resp}= Cleanup Logs
|
||||
Response Should Have Status ${resp} 200
|
||||
50
tests/robot/api/nfo.robot
Normal file
50
tests/robot/api/nfo.robot
Normal file
@@ -0,0 +1,50 @@
|
||||
*** Settings ***
|
||||
Documentation NFO metadata API tests for Aniworld.
|
||||
... Covers diagnostics, repair, needs-repair list, and scan.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Run Keywords
|
||||
... Create Anonymous Session
|
||||
... AND Setup Master Password
|
||||
... AND Create Authenticated Session
|
||||
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# NFO Diagnostics
|
||||
# ---------------------------------------------------------------------------
|
||||
Get NFO Diagnostics
|
||||
[Documentation] Retrieve NFO diagnostics for a series.
|
||||
${resp}= Get Nfo Diagnostics attack-on-titan
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# NFO Repair
|
||||
# ---------------------------------------------------------------------------
|
||||
Repair NFO For Series
|
||||
[Documentation] Trigger NFO repair for a specific series.
|
||||
${resp}= Repair Nfo attack-on-titan
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Needs Repair List
|
||||
# ---------------------------------------------------------------------------
|
||||
List Series Needing Repair
|
||||
[Documentation] List all series that need NFO repair.
|
||||
${resp}= Get Needs Repair
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} total series
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# NFO Scan
|
||||
# ---------------------------------------------------------------------------
|
||||
Run NFO Scan
|
||||
[Documentation] Run an NFO scan across all series.
|
||||
${resp}= Scan Nfo
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} total created updated errors_count duration_seconds
|
||||
92
tests/robot/api/scheduler.robot
Normal file
92
tests/robot/api/scheduler.robot
Normal file
@@ -0,0 +1,92 @@
|
||||
*** Settings ***
|
||||
Documentation Scheduler API tests for Aniworld.
|
||||
... Covers get config, update config, trigger rescan, and validation.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Run Keywords
|
||||
... Create Anonymous Session
|
||||
... AND Setup Master Password
|
||||
... AND Create Authenticated Session
|
||||
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# Get / Update Config
|
||||
# ---------------------------------------------------------------------------
|
||||
Get Scheduler Config
|
||||
[Documentation] Retrieve the current scheduler configuration and runtime status.
|
||||
${resp}= Get Scheduler Config
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Contain Keys ${resp} success config status
|
||||
${config_keys}= Create List enabled interval_minutes schedule_time schedule_days auto_download_after_rescan
|
||||
FOR ${key} IN @{config_keys}
|
||||
Response Should Contain Key ${resp} $.config.${key}
|
||||
END
|
||||
${status_keys}= Create List is_running next_run last_run scan_in_progress
|
||||
FOR ${key} IN @{status_keys}
|
||||
Response Should Contain Key ${resp} $.status.${key}
|
||||
END
|
||||
|
||||
Update Scheduler Config
|
||||
[Documentation] Update scheduler settings and verify they are persisted.
|
||||
${payload}= Create Dictionary
|
||||
... enabled=True
|
||||
... interval_minutes=120
|
||||
... schedule_time=04:30
|
||||
... schedule_days=['mon', 'wed', 'fri']
|
||||
... auto_download_after_rescan=True
|
||||
${resp}= Update Scheduler Config ${payload}
|
||||
Response Should Have Status ${resp} 200
|
||||
${saved_time}= Get JSON Value ${resp} $.config.schedule_time
|
||||
Should Be Equal As Strings ${saved_time} 04:30
|
||||
${saved_days}= Get JSON Value ${resp} $.config.schedule_days
|
||||
List Should Contain Value ${saved_days} mon
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Trigger Rescan
|
||||
# ---------------------------------------------------------------------------
|
||||
Trigger Manual Rescan
|
||||
[Documentation] Manually trigger a scheduled rescan.
|
||||
${resp}= Trigger Rescan
|
||||
Response Should Have Status ${resp} 200
|
||||
${success}= Get JSON Value ${resp} $.success
|
||||
Should Be Equal As Strings ${success} True
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Validation
|
||||
# ---------------------------------------------------------------------------
|
||||
Invalid Schedule Time
|
||||
[Documentation] Verify that malformed schedule_time is rejected.
|
||||
${payload}= Create Dictionary
|
||||
... enabled=True
|
||||
... interval_minutes=60
|
||||
... schedule_time=25:00
|
||||
... schedule_days=['mon']
|
||||
... auto_download_after_rescan=False
|
||||
${resp}= Update Scheduler Config ${payload}
|
||||
Response Should Have Status ${resp} 422
|
||||
|
||||
Invalid Schedule Days
|
||||
[Documentation] Verify that invalid day abbreviations are rejected.
|
||||
${payload}= Create Dictionary
|
||||
... enabled=True
|
||||
... interval_minutes=60
|
||||
... schedule_time=03:00
|
||||
... schedule_days=['monday', 'tuesday']
|
||||
... auto_download_after_rescan=False
|
||||
${resp}= Update Scheduler Config ${payload}
|
||||
Response Should Have Status ${resp} 422
|
||||
|
||||
Empty Schedule Days
|
||||
[Documentation] Verify that empty schedule_days is handled.
|
||||
${payload}= Create Dictionary
|
||||
... enabled=True
|
||||
... interval_minutes=60
|
||||
... schedule_time=03:00
|
||||
... schedule_days=[]
|
||||
... auto_download_after_rescan=False
|
||||
${resp}= Update Scheduler Config ${payload}
|
||||
Response Should Have Status ${resp} 200
|
||||
35
tests/robot/api/setup.robot
Normal file
35
tests/robot/api/setup.robot
Normal file
@@ -0,0 +1,35 @@
|
||||
*** Settings ***
|
||||
Documentation Setup (unresolved folders) API tests for Aniworld.
|
||||
... Covers listing unresolved folders, getting details, and resolving.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Run Keywords
|
||||
... Create Anonymous Session
|
||||
... AND Setup Master Password
|
||||
... AND Create Authenticated Session
|
||||
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# Unresolved Folders
|
||||
# ---------------------------------------------------------------------------
|
||||
List Unresolved Folders
|
||||
[Documentation] List all unresolved folders in the anime directory.
|
||||
${resp}= Get Unresolved Folders
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
Get Unresolved Folder Details
|
||||
[Documentation] Get details for a specific unresolved folder.
|
||||
${resp}= Get Unresolved Folder Details SomeFolder
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
|
||||
Resolve Folder With Provider Key
|
||||
[Documentation] Resolve an unresolved folder by mapping it to a provider key.
|
||||
${resp}= Resolve Folder SomeFolder attack-on-titan
|
||||
Response Should Have Status ${resp} 200
|
||||
Response Should Be Valid JSON ${resp}
|
||||
41
tests/robot/api/websocket.robot
Normal file
41
tests/robot/api/websocket.robot
Normal file
@@ -0,0 +1,41 @@
|
||||
*** Settings ***
|
||||
Documentation WebSocket API tests for Aniworld.
|
||||
... Covers connection, room subscription, ping/pong, and notifications.
|
||||
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/api_keywords.resource
|
||||
|
||||
Test Setup Run Keywords
|
||||
... Create Anonymous Session
|
||||
... AND Setup Master Password
|
||||
... AND Create Authenticated Session
|
||||
|
||||
Test Teardown Delete All Sessions
|
||||
|
||||
*** Test Cases ***
|
||||
# ---------------------------------------------------------------------------
|
||||
# WebSocket Connection
|
||||
# ---------------------------------------------------------------------------
|
||||
Connect To WebSocket
|
||||
[Documentation] Establish a WebSocket connection with a valid JWT token.
|
||||
${token}= Login And Get Token
|
||||
${ws_url}= Set Variable ws://${SERVER_HOST}:${SERVER_PORT}/ws/connect?token=${token}
|
||||
${result}= Evaluate __import__('asyncio').run(__import__('websockets').connect('${ws_url}'))
|
||||
# Note: Full WebSocket testing requires a custom Python keyword library
|
||||
# or using Browser library's Evaluate with inline JavaScript.
|
||||
Pass Execution WebSocket connection test requires custom keyword library
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Placeholder for WebSocket Room Subscription
|
||||
# ---------------------------------------------------------------------------
|
||||
Subscribe To Rooms
|
||||
[Documentation] Subscribe to WebSocket rooms (downloads, queue, scan, system).
|
||||
Pass Execution WebSocket room subscription requires custom keyword library
|
||||
|
||||
Receive Ping Pong
|
||||
[Documentation] Verify WebSocket heartbeat mechanism.
|
||||
Pass Execution WebSocket ping/pong requires custom keyword library
|
||||
|
||||
Receive System Notification
|
||||
[Documentation] Trigger an action that emits a system message and verify receipt.
|
||||
Pass Execution WebSocket notification requires custom keyword library
|
||||
Reference in New Issue
Block a user