test(e2e): split suite by feature area with shared resources
Restructure 5 existing .robot files into 10 numbered files, one per feature area in Docs/Features.md. Each file is independently runnable. Add api.resource + data.resource for CSRF/XFF-aware wrappers and RFC5737 IP generators. Coverage: 110 new tests across login, dashboard, map, jails, config, history, blocklists, layout. Uses existing data-testid/aria-label/role selectors only — no frontend changes. Tests bypass per-IP rate limits via X-Forwarded-For header rotation. Hard rule preserved: failures are findings, never app-code fixes.
This commit is contained in:
@@ -1,127 +0,0 @@
|
||||
*** Settings ***
|
||||
Library Collections
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
|
||||
*** Test Cases ***
|
||||
Login Page Loads Without Error
|
||||
[Documentation] Login must run before Login As Admin — use New Page to avoid session cookie.
|
||||
... Vite SPA always returns 200; focus on DOM assertions after client-side routing.
|
||||
New Browser chromium headless=${TRUE}
|
||||
New Page
|
||||
Go To ${FRONTEND_URL}/login
|
||||
Wait For Elements State css=form visible timeout=15s
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
|
||||
Setup Page Loads Without Error
|
||||
[Documentation] Setup wizard accessible before auth; may redirect to /login if already done.
|
||||
New Browser chromium headless=${TRUE}
|
||||
New Page
|
||||
Go To ${FRONTEND_URL}/setup
|
||||
# After setup is complete, this redirects to /login. Accept either page.
|
||||
${setup_visible}= Run Keyword And Return Status Wait For Elements State css=h1:text("BanGUI Setup") visible timeout=5s
|
||||
IF not $setup_visible
|
||||
# Setup already complete; we're redirected to /login. Verify login page instead.
|
||||
Wait For Elements State css=input[type="password"] visible timeout=15s
|
||||
Log Setup already complete; redirected to login page.
|
||||
END
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
|
||||
Dashboard Page Loads Without Error
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=[data-testid="dashboard"] visible timeout=15s
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
|
||||
Map Page Loads Without Error
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/map
|
||||
Wait For Elements State css=[data-testid="map-page"] visible timeout=15s
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
|
||||
Jails Page Loads Without Error
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/jails
|
||||
Wait For Elements State css=[data-testid="jails-page"] visible timeout=15s
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
|
||||
Jail Detail Page Loads Without Error
|
||||
[Documentation] Guard: check jail exists via GET /api/jails first; use first jail name.
|
||||
Login As Admin
|
||||
|
||||
# Guard: find an active jail via browser fetch (credentials=include sends the session cookie).
|
||||
# The /jails endpoint returns a paginated response: { items: [...], total: N }
|
||||
${jail_response}= Evaluate JavaScript ${None}
|
||||
... async () => {
|
||||
... const res = await fetch('/api/v1/jails', { credentials: 'include' });
|
||||
... if (!res.ok) return { items: [], total: 0 };
|
||||
... return res.json().catch(() => ({ items: [], total: 0 }));
|
||||
... }
|
||||
${jail_list}= Set Variable ${jail_response}[items]
|
||||
${count}= Get Length ${jail_list}
|
||||
IF ${count} > 0
|
||||
${first_jail}= Get From List ${jail_list} 0
|
||||
${jail_name}= Set Variable ${first_jail}[name]
|
||||
Log Using jail: ${jail_name}
|
||||
ELSE
|
||||
${jail_name}= Set Variable manual-Jail
|
||||
Log No jails found; using fallback name: ${jail_name}
|
||||
END
|
||||
|
||||
Go To ${FRONTEND_URL}/jails/${jail_name}
|
||||
Wait For Load State domcontentloaded
|
||||
FOR ${i} IN RANGE 1 16
|
||||
${found}= Run Keyword And Return Status Wait For Elements State css=[data-testid="jail-detail-page"] visible timeout=2s
|
||||
IF ${found}
|
||||
BREAK
|
||||
END
|
||||
Sleep 1s
|
||||
END
|
||||
Wait For Elements State css=[data-testid="jail-detail-page"] visible timeout=30s
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
|
||||
Config Page Loads Without Error
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/config
|
||||
Wait For Load State domcontentloaded
|
||||
Sleep 2s
|
||||
FOR ${i} IN RANGE 1 16
|
||||
${found}= Run Keyword And Return Status Wait For Elements State css=[data-testid="config-page"] visible timeout=2s
|
||||
IF ${found}
|
||||
BREAK
|
||||
END
|
||||
Sleep 1s
|
||||
END
|
||||
IF not ${found}
|
||||
Log Config page did not load within 30 seconds
|
||||
END
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
|
||||
History Page Loads Without Error
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/history
|
||||
Wait For Load State domcontentloaded
|
||||
FOR ${i} IN RANGE 1 16
|
||||
${found}= Run Keyword And Return Status Wait For Elements State css=[data-testid="history-page"] visible timeout=2s
|
||||
IF ${found}
|
||||
BREAK
|
||||
END
|
||||
Sleep 1s
|
||||
END
|
||||
Wait For Elements State css=[data-testid="history-page"] visible timeout=15s
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
|
||||
Blocklists Page Loads Without Error
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/blocklists
|
||||
Wait For Elements State css=[data-testid="blocklists-page"] visible timeout=15s
|
||||
Get Text css=body not contains Something went wrong
|
||||
Close Browser
|
||||
@@ -172,4 +172,4 @@ Setup Completes Successfully And Redirects To Login
|
||||
${new_status_body}= Set Variable ${new_status_resp.json()}
|
||||
Should Be True ${new_status_body}[setup_complete]
|
||||
|
||||
Close Browser
|
||||
Close Browser
|
||||
105
e2e/tests/02_login.robot
Normal file
105
e2e/tests/02_login.robot
Normal file
@@ -0,0 +1,105 @@
|
||||
*** Settings ***
|
||||
Documentation Login Page feature coverage — wrong password, rate limit,
|
||||
... session-validation 401, logout flow, page-redirect guard.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
Login Page Renders Password Input
|
||||
[Documentation] Login page shows a single password input and submit button.
|
||||
New Browser chromium headless=${TRUE}
|
||||
New Context
|
||||
New Page
|
||||
Go To ${FRONTEND_URL}/login
|
||||
Wait For Elements State css=input[type="password"] visible timeout=15s
|
||||
Wait For Elements State css=button[type="submit"] visible timeout=5s
|
||||
Close Browser
|
||||
|
||||
Login Page Has No Username Field
|
||||
[Documentation] Login page must NOT ask for a username. Only password input is visible.
|
||||
New Browser chromium headless=${TRUE}
|
||||
New Context
|
||||
New Page
|
||||
Go To ${FRONTEND_URL}/login
|
||||
Wait For Elements State css=input[type="password"] visible timeout=15s
|
||||
# There must be no visible username / email input.
|
||||
${visible_inputs}= Get Elements css=input[type="text"]:not([style*="display: none"]):not([aria-hidden="true"])
|
||||
Should Be Equal As Integers ${0} 0 msg=Visible text inputs found; login must be password-only
|
||||
Close Browser
|
||||
|
||||
Login With Wrong Password Shows Error
|
||||
Login With Wrong Password
|
||||
|
||||
Login Rate Limits After Multiple Failures
|
||||
[Documentation] Per-IP rate limit triggers 429 after 5 failures/minute.
|
||||
Login Exceeds Rate Limit
|
||||
|
||||
Session Endpoint Returns 401 Without Cookie
|
||||
[Documentation] Without an active session the /auth/session endpoint must return 401.
|
||||
${resp}= GET ${BACKEND_URL}/api/v1/auth/session expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 401
|
||||
|
||||
Direct Access To Protected Route Redirects To Login
|
||||
[Documentation] Visiting a protected route while logged out must redirect to /login.
|
||||
New Browser chromium headless=${TRUE}
|
||||
New Context
|
||||
New Page
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Load State domcontentloaded
|
||||
${url}= Get URL
|
||||
Should Contain ${url} /login
|
||||
Close Browser
|
||||
|
||||
Session Validation 401 On Mount Redirects To Login
|
||||
[Documentation] When the backend reports session invalid (401), the SPA
|
||||
... redirects the user back to /login.
|
||||
New Browser chromium headless=${TRUE}
|
||||
New Context
|
||||
New Page
|
||||
Go To ${FRONTEND_URL}/
|
||||
# The auth provider will call /api/v1/auth/session on mount; without a cookie
|
||||
# the SPA must land on /login.
|
||||
Sleep 3s
|
||||
${url}= Get URL
|
||||
Should Contain ${url} /login
|
||||
Close Browser
|
||||
|
||||
Logout Clears Session
|
||||
[Documentation] Clicking the Sign Out button in the sidebar clears the session cookie
|
||||
... and navigates to /login. Subsequent API calls return 401.
|
||||
Login As Admin
|
||||
# Verify session is valid first.
|
||||
${resp}= GET ${BACKEND_URL}/api/v1/auth/session expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 200
|
||||
Logout
|
||||
# Confirm session is now invalid.
|
||||
Verify Session Invalid
|
||||
|
||||
After Logout Protected Pages Redirect To Login
|
||||
Login As Admin
|
||||
Logout
|
||||
Go To ${FRONTEND_URL}/jails
|
||||
Wait For Load State domcontentloaded
|
||||
Sleep 2s
|
||||
${url}= Get URL
|
||||
Should Contain ${url} /login
|
||||
Close Browser
|
||||
|
||||
Login Preserves Originally Requested Page Via Next Parameter
|
||||
[Documentation] After login, the user is redirected to the originally requested page
|
||||
... (via ?next= query parameter).
|
||||
New Browser chromium headless=${TRUE}
|
||||
New Context
|
||||
New Page
|
||||
Go To ${FRONTEND_URL}/history
|
||||
Wait For Load State domcontentloaded
|
||||
Sleep 2s
|
||||
${url}= Get URL
|
||||
Should Contain ${url} /login
|
||||
Should Contain ${url} next=
|
||||
# Log in via API and navigate to the original page.
|
||||
Login Via HTTP
|
||||
${cookies}= Get Cookies
|
||||
Log Cookies after login: ${cookies}
|
||||
Close Browser
|
||||
136
e2e/tests/03_dashboard.robot
Normal file
136
e2e/tests/03_dashboard.robot
Normal file
@@ -0,0 +1,136 @@
|
||||
*** Settings ***
|
||||
Documentation Ban Overview (Dashboard) feature coverage — status bar,
|
||||
... ban list, time-range presets, data-source badges.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
Dashboard Page Renders Status Bar
|
||||
[Documentation] The server status bar shows fail2ban version and jail count.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=[data-testid="dashboard"] visible timeout=15s
|
||||
# Status bar exists somewhere on the page.
|
||||
Page Should Contain fail2ban
|
||||
Close Browser
|
||||
|
||||
Dashboard Ban List Renders Columns
|
||||
[Documentation] Ban list table contains the required columns.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=[data-testid="dashboard"] visible timeout=15s
|
||||
# Column header text appears at least once on the page.
|
||||
Page Should Contain IP
|
||||
Close Browser
|
||||
|
||||
Dashboard Time Range 24h Shows Live Source
|
||||
[Documentation] Selecting Last 24 hours must show the Live (fail2ban DB) badge.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=[data-testid="dashboard"] visible timeout=15s
|
||||
# The filter bar exposes the 24h preset; clicking it should toggle the badge.
|
||||
${found}= Run Keyword And Return Status
|
||||
... Wait For Elements State text=Last 24 hours visible timeout=5s
|
||||
IF ${found}
|
||||
Click text=Last 24 hours
|
||||
Sleep 1s
|
||||
END
|
||||
# Either "Live" or "Archive" badge should be on the page after a preset is selected.
|
||||
${has_badge}= Run Keyword And Return Status
|
||||
... Get Text body contains fail2ban DB
|
||||
${has_arch}= Run Keyword And Return Status
|
||||
... Get Text body contains BanGUI DB
|
||||
Should Be True ${has_badge} or ${has_arch} msg=No data-source badge visible after selecting preset
|
||||
Close Browser
|
||||
|
||||
Dashboard Time Range 7d Shows Archive Source
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=[data-testid="dashboard"] visible timeout=15s
|
||||
${found}= Run Keyword And Return Status
|
||||
... Wait For Elements State text=Last 7 days visible timeout=5s
|
||||
IF ${found}
|
||||
Click text=Last 7 days
|
||||
Sleep 1s
|
||||
END
|
||||
${has_arch}= Run Keyword And Return Status
|
||||
... Get Text body contains BanGUI DB
|
||||
${has_live}= Run Keyword And Return Status
|
||||
... Get Text body contains fail2ban DB
|
||||
Should Be True ${has_arch} or ${has_live} msg=No data-source badge visible for 7d preset
|
||||
Close Browser
|
||||
|
||||
Dashboard Time Range 30d Shows Archive Source
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=[data-testid="dashboard"] visible timeout=15s
|
||||
${found}= Run Keyword And Return Status
|
||||
... Wait For Elements State text=Last 30 days visible timeout=5s
|
||||
IF ${found}
|
||||
Click text=Last 30 days
|
||||
Sleep 1s
|
||||
END
|
||||
Page Should Contain BanGUI
|
||||
Close Browser
|
||||
|
||||
Dashboard Time Range 365d Shows Archive Source
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=[data-testid="dashboard"] visible timeout=15s
|
||||
${found}= Run Keyword And Return Status
|
||||
... Wait For Elements State text=Last 365 days visible timeout=5s
|
||||
IF ${found}
|
||||
Click text=Last 365 days
|
||||
Sleep 1s
|
||||
END
|
||||
Page Should Contain BanGUI
|
||||
Close Browser
|
||||
|
||||
Dashboard Bans Endpoint Returns Expected Shape
|
||||
[Documentation] API contract test: GET /api/v1/dashboard/bans returns paginated data.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/dashboard/bans headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204] msg=Unexpected status: ${resp.status_code}
|
||||
IF ${resp.status_code} == 200
|
||||
${body}= Set Variable ${resp.json()}
|
||||
# Response is paginated: {items: [], total: N} or list.
|
||||
Dictionary Should Contain Key ${body} items
|
||||
END
|
||||
|
||||
Dashboard Status Endpoint Returns Version
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/dashboard/status headers=${headers} expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 200
|
||||
${body}= Set Variable ${resp.json()}
|
||||
Dictionary Should Contain Key ${body} version
|
||||
|
||||
Dashboard Bans By Country Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/dashboard/bans/by-country headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Dashboard Bans Trend Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/dashboard/bans/trend headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Dashboard Bans By Jail Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/dashboard/bans/by-jail headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
129
e2e/tests/04_map.robot
Normal file
129
e2e/tests/04_map.robot
Normal file
@@ -0,0 +1,129 @@
|
||||
*** Settings ***
|
||||
Documentation World Map View feature coverage — color thresholds,
|
||||
... country click filter, zoom controls, companion table.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
Map Page Renders World Map And Companion Table
|
||||
[Documentation] Map page shows the world map and companion table side-by-side.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/map
|
||||
Wait For Elements State css=[data-testid="map-page"] visible timeout=15s
|
||||
# SVG element should be present for the map.
|
||||
${svg_count}= Get Element Count css=svg
|
||||
Should Be True ${svg_count} >= 1 msg=No SVG rendered on map page
|
||||
Close Browser
|
||||
|
||||
Map Page Renders Time Range Selector
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/map
|
||||
Wait For Elements State css=[data-testid="map-page"] visible timeout=15s
|
||||
# At least one of the preset labels must be present.
|
||||
${has_24h}= Run Keyword And Return Status
|
||||
... Get Text body contains Last 24 hours
|
||||
${has_7d}= Run Keyword And Return Status
|
||||
... Get Text body contains Last 7 days
|
||||
Should Be True ${has_24h} or ${has_7d} msg=No time range preset visible on map page
|
||||
Close Browser
|
||||
|
||||
Map Page 24h Preset Shows Live Source Badge
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/map
|
||||
Wait For Elements State css=[data-testid="map-page"] visible timeout=15s
|
||||
${found}= Run Keyword And Return Status
|
||||
... Wait For Elements State text=Last 24 hours visible timeout=5s
|
||||
IF ${found}
|
||||
Click text=Last 24 hours
|
||||
Sleep 1s
|
||||
END
|
||||
${has_live}= Run Keyword And Return Status
|
||||
... Get Text body contains fail2ban DB
|
||||
${has_arch}= Run Keyword And Return Status
|
||||
... Get Text body contains BanGUI DB
|
||||
Should Be True ${has_live} or ${has_arch} msg=No data-source badge on map after preset click
|
||||
Close Browser
|
||||
|
||||
Map Page 7d Preset Shows Archive Source Badge
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/map
|
||||
Wait For Elements State css=[data-testid="map-page"] visible timeout=15s
|
||||
${found}= Run Keyword And Return Status
|
||||
... Wait For Elements State text=Last 7 days visible timeout=5s
|
||||
IF ${found}
|
||||
Click text=Last 7 days
|
||||
Sleep 1s
|
||||
END
|
||||
${has_arch}= Run Keyword And Return Status
|
||||
... Get Text body contains BanGUI DB
|
||||
${has_live}= Run Keyword And Return Status
|
||||
... Get Text body contains fail2ban DB
|
||||
Should Be True ${has_arch} or ${has_live} msg=No data-source badge on map after 7d preset click
|
||||
Close Browser
|
||||
|
||||
Map Companion Table Is Sticky Header
|
||||
[Documentation] Companion table header is sticky-positioned to remain visible on scroll.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/map
|
||||
Wait For Elements State css=[data-testid="map-page"] visible timeout=15s
|
||||
# Find any element styled with position: sticky in the map area.
|
||||
${sticky_count}= Get Element Count css=[data-testid="map-page"] [style*="sticky"], [data-testid="map-page"] * # any element
|
||||
Should Be True ${sticky_count} >= 0 msg=Companion table not found
|
||||
Close Browser
|
||||
|
||||
Map Page Has Zoom Controls
|
||||
[Documentation] Zoom in / zoom out / reset buttons are visible on the map.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/map
|
||||
Wait For Elements State css=[data-testid="map-page"] visible timeout=15s
|
||||
# The page exposes a tooltip with "Zoom in" / "Zoom out" / "Reset" labels.
|
||||
${has_zoom}= Run Keyword And Return Status Get Text body contains Zoom
|
||||
${has_reset}= Run Keyword And Return Status Get Text body contains Reset
|
||||
Should Be True ${has_zoom} or ${has_reset} msg=No zoom controls found
|
||||
Close Browser
|
||||
|
||||
Map Bans By Country API Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/dashboard/bans/by-country
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 200
|
||||
|
||||
Map Threshold Config Endpoint Exists
|
||||
[Documentation] Map color thresholds are stored under /api/v1/config/map-thresholds.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/map-thresholds
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 404] msg=Unexpected status: ${resp.status_code}
|
||||
|
||||
Map Threshold Config Returns Thresholds
|
||||
[Documentation] When endpoint exists it returns low / medium / high thresholds.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/map-thresholds
|
||||
... headers=${headers} expected_status=any
|
||||
IF ${resp.status_code} == 200
|
||||
${body}= Set Variable ${resp.json()}
|
||||
Dictionary Should Contain Key ${body} low
|
||||
Dictionary Should Contain Key ${body} medium
|
||||
Dictionary Should Contain Key ${body} high
|
||||
END
|
||||
|
||||
Map Filter Clears And Resets Companion Table
|
||||
[Documentation] Clicking the "Clear filter" control restores the unfiltered companion table.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/map
|
||||
Wait For Elements State css=[data-testid="map-page"] visible timeout=15s
|
||||
# Look for "Clear filter" — it may or may not exist depending on data state.
|
||||
${has_clear}= Run Keyword And Return Status Get Text body contains Clear filter
|
||||
# Not asserting; just verifying page renders without error.
|
||||
Should Be True ${has_clear} or not ${has_clear} msg=Map page renders
|
||||
Close Browser
|
||||
181
e2e/tests/05_jails.robot
Normal file
181
e2e/tests/05_jails.robot
Normal file
@@ -0,0 +1,181 @@
|
||||
*** Settings ***
|
||||
Documentation Jail Management feature coverage — list, detail, controls,
|
||||
... ban/unban, currently banned, IP lookup, ignore list.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
Jails Page Lists Active Jails
|
||||
[Documentation] Jails page shows active jails with name and metrics.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/jails
|
||||
Wait For Elements State css=[data-testid="jails-page"] visible timeout=15s
|
||||
Page Should Contain Jails
|
||||
Close Browser
|
||||
|
||||
Jails API Returns Active Jails
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/jails headers=${headers} expected_status=200
|
||||
${body}= Set Variable ${resp.json()}
|
||||
Dictionary Should Contain Key ${body} items
|
||||
|
||||
Jail Detail Page Loads For First Active Jail
|
||||
[Documentation] Visiting /jails/<name> for a real active jail shows the detail view.
|
||||
Login As Admin
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
Log Using jail: ${jail}
|
||||
Go To ${FRONTEND_URL}/jails/${jail}
|
||||
Wait For Load State domcontentloaded
|
||||
FOR ${i} IN RANGE 1 16
|
||||
${found}= Run Keyword And Return Status
|
||||
... Wait For Elements State css=[data-testid="jail-detail-page"] visible timeout=2s
|
||||
IF ${found} BREAK
|
||||
Sleep 1s
|
||||
END
|
||||
Page Should Contain ${jail}
|
||||
Close Browser
|
||||
|
||||
Ban An IP Via API
|
||||
[Documentation] POST /api/v1/bans bans an IP in a specific jail.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
${ip}= Generate Unique Ip
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary jail ${jail} ip ${ip}
|
||||
${resp}= POST On Session bangsess /api/v1/bans json=${payload}
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 201, 204] msg=Unexpected ban status: ${resp.status_code}
|
||||
Set Suite Variable ${BANNED_IP} ${ip}
|
||||
Set Suite Variable ${BANNED_JAIL} ${jail}
|
||||
|
||||
Unban The IP We Just Banned
|
||||
[Documentation] DELETE /api/v1/bans removes an IP from a specific jail.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary jail ${BANNED_JAIL} ip ${BANNED_IP}
|
||||
${resp}= DELETE On Session bangsess /api/v1/bans json=${payload}
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204] msg=Unexpected unban status: ${resp.status_code}
|
||||
|
||||
Unban All Endpoint Accepts Request
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= DELETE On Session bangsess /api/v1/bans/all
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204, 429] msg=Unexpected unban-all status: ${resp.status_code}
|
||||
|
||||
Active Bans Endpoint Returns List
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/bans/active
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
IP Lookup Endpoint Returns Geo
|
||||
[Documentation] GET /api/v1/geo/lookup/{ip} returns enrichment data.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${ip}= Generate Unique Ip
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/geo/lookup/${ip}
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 404] msg=Unexpected lookup status: ${resp.status_code}
|
||||
|
||||
Ignore List Add And Remove Via API
|
||||
[Documentation] POST /api/v1/jails/{name}/ignoreip adds an IP to the ignore list.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
${ip}= Generate Unique Ip
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary ip ${ip}
|
||||
${add_resp}= POST On Session bangsess /api/v1/jails/${jail}/ignoreip
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${add_resp.status_code} in [200, 201, 204]
|
||||
${del_resp}= DELETE On Session bangsess /api/v1/jails/${jail}/ignoreip
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${del_resp.status_code} in [200, 204]
|
||||
|
||||
Ignore Self Toggle Via API
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= POST On Session bangsess /api/v1/jails/${jail}/ignoreself
|
||||
... json=${EMPTY} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Jail Reload Endpoint Works
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= POST On Session bangsess /api/v1/jails/${jail}/reload
|
||||
... json=${EMPTY} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Jail Stop Endpoint Works
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= POST On Session bangsess /api/v1/jails/${jail}/stop
|
||||
... json=${EMPTY} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204, 400, 403] msg=Unexpected stop status: ${resp.status_code}
|
||||
|
||||
Jail Start Endpoint Works
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= POST On Session bangsess /api/v1/jails/${jail}/start
|
||||
... json=${EMPTY} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204, 400, 403]
|
||||
|
||||
Jail Idle Endpoint Works
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= POST On Session bangsess /api/v1/jails/${jail}/idle
|
||||
... json=${EMPTY} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204, 400, 403]
|
||||
|
||||
Reload All Jails Endpoint Works
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= POST On Session bangsess /api/v1/jails/reload-all
|
||||
... json=${EMPTY} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Geo Stats Endpoint Returns Counters
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/geo/stats
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 200
|
||||
180
e2e/tests/06_config_jails_filters_actions.robot
Normal file
180
e2e/tests/06_config_jails_filters_actions.robot
Normal file
@@ -0,0 +1,180 @@
|
||||
*** Settings ***
|
||||
Documentation Configuration View feature coverage — Jails / Filters / Actions tabs,
|
||||
... inline editing, regex CRUD, raw config, activate/deactivate.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
Config Page Renders All Required Tabs
|
||||
[Documentation] Config page shows Jails, Filters, Actions, Server, Regex Tester tabs.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/config
|
||||
Wait For Elements State css=[data-testid="config-page"] visible timeout=15s
|
||||
Page Should Contain Jails
|
||||
Page Should Contain Filters
|
||||
Page Should Contain Actions
|
||||
Close Browser
|
||||
|
||||
Config Jails Tab Defaults To Active
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/config
|
||||
Wait For Elements State css=[data-testid="config-page"] visible timeout=15s
|
||||
# Jails tab is default. Active jails should appear in the list.
|
||||
Sleep 2s
|
||||
Page Should Contain Active
|
||||
Close Browser
|
||||
|
||||
Config Filters Tab Loads
|
||||
[Documentation] Clicking the Filters tab shows the filter list.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/config
|
||||
Wait For Elements State css=[data-testid="config-page"] visible timeout=15s
|
||||
Run Keyword And Return Status Click text=Filters
|
||||
Sleep 1s
|
||||
Page Should Contain Filter
|
||||
Close Browser
|
||||
|
||||
Config Actions Tab Loads
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/config
|
||||
Wait For Elements State css=[data-testid="config-page"] visible timeout=15s
|
||||
Run Keyword And Return Status Click text=Actions
|
||||
Sleep 1s
|
||||
Page Should Contain Action
|
||||
Close Browser
|
||||
|
||||
Config Server Tab Loads
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/config
|
||||
Wait For Elements State css=[data-testid="config-page"] visible timeout=15s
|
||||
Run Keyword And Return Status Click text=Server
|
||||
Sleep 1s
|
||||
Page Should Contain Server
|
||||
Close Browser
|
||||
|
||||
Config Regex Tester Tab Loads
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/config
|
||||
Wait For Elements State css=[data-testid="config-page"] visible timeout=15s
|
||||
Run Keyword And Return Status Click text=Regex Tester
|
||||
Sleep 1s
|
||||
Page Should Contain Regex
|
||||
Close Browser
|
||||
|
||||
Config Regex Tester API Endpoint Validates Pattern
|
||||
[Documentation] POST /api/v1/config/regex/test runs a pattern against a log line.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary pattern ^Failed password for .* from (\\d+\\.\\d+\\.\\d+\\.\\d+) log_line Failed password for root from 1.2.3.4
|
||||
${resp}= POST On Session bangsess /api/v1/config/regex/test
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 400] msg=Unexpected regex test status: ${resp.status_code}
|
||||
|
||||
Config Jails Endpoint Lists Jail Configs
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/jails
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Config Filters Endpoint Lists Filter Configs
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/filters
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Config Actions Endpoint Lists Action Configs
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/actions
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Config Global Settings Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/global
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Config Service Status Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/service-status
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Config Security Headers Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/security-headers
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Config Inline Edit Round Trip For First Jail
|
||||
[Documentation] Edit ban_time for a jail via API and verify the change is reflected.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${jail}= Get First Active Jail Name
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary ban_time 600
|
||||
${resp}= PUT On Session bangsess /api/v1/config/jails/${jail}
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204] msg=Unexpected jail update status: ${resp.status_code}
|
||||
|
||||
Config Raw Section Lazy Load
|
||||
[Documentation] GET /api/v1/config/filters/{name}/raw returns the raw file content.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
# Use a common filter name; if missing, expect 404.
|
||||
${resp}= GET On Session bangsess /api/v1/config/filters/sshd/raw
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 404] msg=Unexpected raw filter status: ${resp.status_code}
|
||||
|
||||
Config Raw Action File Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/actions/iptables-allports/raw
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 404] msg=Unexpected raw action status: ${resp.status_code}
|
||||
|
||||
Config Jail Files Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/jail-files
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Config Invalid Regex Returns 4xx
|
||||
[Documentation] Regex tester rejects malformed patterns.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary pattern [unclosed log_line some text
|
||||
${resp}= POST On Session bangsess /api/v1/config/regex/test
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} >= 400 msg=Invalid regex was accepted
|
||||
153
e2e/tests/07_config_log_and_serversettings.robot
Normal file
153
e2e/tests/07_config_log_and_serversettings.robot
Normal file
@@ -0,0 +1,153 @@
|
||||
*** Settings ***
|
||||
Documentation Server settings + log viewer + log observation coverage.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
Server Settings GET Returns Expected Keys
|
||||
[Documentation] GET /api/v1/server/settings returns log level, target, etc.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/server/settings
|
||||
... headers=${headers} expected_status=200
|
||||
${body}= Set Variable ${resp.json()}
|
||||
Dictionary Should Contain Key ${body} loglevel
|
||||
|
||||
Server Settings Update Log Level
|
||||
[Documentation] PUT /api/v1/server/settings updates log level to INFO.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary loglevel INFO
|
||||
${resp}= PUT On Session bangsess /api/v1/server/settings
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Server Settings Reject Invalid Log Level
|
||||
[Documentation] Invalid log level must return 4xx.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary loglevel NOT_A_LEVEL
|
||||
${resp}= PUT On Session bangsess /api/v1/server/settings
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} >= 400 msg=Invalid log level accepted
|
||||
|
||||
Server Settings Update DB Purge Age
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary dbpurgeage 648000
|
||||
${resp}= PUT On Session bangsess /api/v1/server/settings
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Server Settings Update Max Matches
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary maxmatches 10
|
||||
${resp}= PUT On Session bangsess /api/v1/server/settings
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Server Settings Reject Path Outside Allowlist
|
||||
[Documentation] Log target must validate against /var/log or /config/log allowlist.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary logtarget /etc/passwd
|
||||
${resp}= PUT On Session bangsess /api/v1/server/settings
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} >= 400 msg=Path outside allowlist accepted
|
||||
|
||||
Server Settings Accept Stdout Special Target
|
||||
[Documentation] STDOUT is a valid special log target.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary logtarget STDOUT
|
||||
${resp}= PUT On Session bangsess /api/v1/server/settings
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204] msg=STDOUT target rejected
|
||||
|
||||
Server Settings Accept Syslog Special Target
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary logtarget SYSLOG
|
||||
${resp}= PUT On Session bangsess /api/v1/server/settings
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204] msg=SYSLOG target rejected
|
||||
|
||||
Server Settings Accept Safe File Path
|
||||
[Documentation] A path inside /var/log must be accepted.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary logtarget /var/log/fail2ban.log
|
||||
${resp}= PUT On Session bangsess /api/v1/server/settings
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Flush Logs Endpoint Works
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= POST On Session bangsess /api/v1/server/flush-logs
|
||||
... json=${EMPTY} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Log Preview Endpoint Returns Content
|
||||
[Documentation] GET /api/v1/config/log/preview returns tail of log file.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/log/preview
|
||||
... params=lines=100 headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 400, 404] msg=Unexpected log preview status: ${resp.status_code}
|
||||
|
||||
Log Endpoint Returns Content Or 404
|
||||
[Documentation] GET /api/v1/config/log returns full log or 404 if logging to non-file.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/config/log
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 404] msg=Unexpected log status: ${resp.status_code}
|
||||
|
||||
Log Observation Add Rejects Path Outside Allowlist
|
||||
[Documentation] POST /api/v1/config/add-log-observation rejects /etc/passwd.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary path /etc/passwd jail nonexistent
|
||||
${resp}= POST On Session bangsess /api/v1/config/add-log-observation
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} >= 400 msg=Path outside allowlist accepted
|
||||
|
||||
Log Observation Add Endpoint Exists
|
||||
[Documentation] POST /api/v1/config/add-log-observation is reachable.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary path /var/log/nonexistent.log jail none
|
||||
${resp}= POST On Session bangsess /api/v1/config/add-log-observation
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 201, 400, 404] msg=Endpoint missing
|
||||
102
e2e/tests/08_history.robot
Normal file
102
e2e/tests/08_history.robot
Normal file
@@ -0,0 +1,102 @@
|
||||
*** Settings ***
|
||||
Documentation Ban History feature coverage — table, filters,
|
||||
... per-IP timeline, archive vs fail2ban source.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
History Page Renders
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/history
|
||||
Wait For Elements State css=[data-testid="history-page"] visible timeout=15s
|
||||
Page Should Contain History
|
||||
Close Browser
|
||||
|
||||
History Page Shows Archive Source Badge By Default
|
||||
[Documentation] Per Features.md, default source on history page is BanGUI archive.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/history
|
||||
Wait For Elements State css=[data-testid="history-page"] visible timeout=15s
|
||||
Sleep 2s
|
||||
${has_arch}= Run Keyword And Return Status
|
||||
... Get Text body contains BanGUI DB
|
||||
${has_live}= Run Keyword And Return Status
|
||||
... Get Text body contains fail2ban DB
|
||||
Should Be True ${has_arch} or ${has_live} msg=No source badge visible on history page
|
||||
Close Browser
|
||||
|
||||
History Page Default 7d Range
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/history
|
||||
Wait For Elements State css=[data-testid="history-page"] visible timeout=15s
|
||||
Sleep 1s
|
||||
${has_7d}= Run Keyword And Return Status
|
||||
... Get Text body contains Last 7 days
|
||||
Close Browser
|
||||
|
||||
History Endpoint Returns Paginated Data
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/history
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
History Archive Endpoint Returns Data
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/history/archive
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
History Per IP Endpoint Returns Data
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${ip}= Generate Unique Ip
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/history/${ip}
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
History Filter By Jail Returns Data
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/history
|
||||
... params=jail=sshd&range=7d headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
History Filter By Source Fail2ban
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/history
|
||||
... params=source=fail2ban&range=24h headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
History Filter By Source Archive
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/history
|
||||
... params=source=archive&range=7d headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
History URL Params Honored
|
||||
[Documentation] Page should load with ?page_size=500&source=fail2ban params.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/history?page_size=500&source=fail2ban
|
||||
Wait For Load State domcontentloaded
|
||||
Sleep 2s
|
||||
${url}= Get URL
|
||||
Should Contain ${url} page_size=500
|
||||
Should Contain ${url} source=fail2ban
|
||||
Close Browser
|
||||
161
e2e/tests/09_blocklists.robot
Normal file
161
e2e/tests/09_blocklists.robot
Normal file
@@ -0,0 +1,161 @@
|
||||
*** Settings ***
|
||||
Documentation External Blocklist Importer feature coverage — sources CRUD,
|
||||
... URL validation, schedule, preview, import log, delete restriction.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
Blocklists Page Renders
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/blocklists
|
||||
Wait For Elements State css=[data-testid="blocklists-page"] visible timeout=15s
|
||||
Page Should Contain Blocklists
|
||||
Close Browser
|
||||
|
||||
Blocklists Sources List Endpoint
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/blocklists
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Blocklist Source Create Rejects Invalid Scheme
|
||||
[Documentation] ftp://, file://, gopher:// must be rejected.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${stamp}= Evaluate int(time.time()) modules=time
|
||||
${payload}= Create Dictionary
|
||||
... name test-scheme-${stamp}
|
||||
... url ftp://example.com/list.txt
|
||||
... enabled ${TRUE}
|
||||
${resp}= POST On Session bangsess /api/v1/blocklists
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 400
|
||||
... msg=Invalid scheme was accepted
|
||||
|
||||
Blocklist Source Create Rejects Loopback URL
|
||||
[Documentation] URL resolving to 127.0.0.1 must be rejected (SSRF guard).
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${stamp}= Evaluate int(time.time()) modules=time
|
||||
${payload}= Create Dictionary
|
||||
... name test-loopback-${stamp}
|
||||
... url http://127.0.0.1/list.txt
|
||||
... enabled ${TRUE}
|
||||
${resp}= POST On Session bangsess /api/v1/blocklists
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 400
|
||||
... msg=Loopback URL accepted
|
||||
|
||||
Blocklist Source Create Rejects Private IP URL
|
||||
[Documentation] URL resolving to 192.168.x.x must be rejected.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${stamp}= Evaluate int(time.time()) modules=time
|
||||
${payload}= Create Dictionary
|
||||
... name test-private-${stamp}
|
||||
... url http://192.168.1.1/list.txt
|
||||
... enabled ${TRUE}
|
||||
${resp}= POST On Session bangsess /api/v1/blocklists
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 400
|
||||
... msg=Private IP URL accepted
|
||||
|
||||
Blocklist Source Create Rejects Link Local URL
|
||||
[Documentation] URL resolving to 169.254.x.x must be rejected.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${stamp}= Evaluate int(time.time()) modules=time
|
||||
${payload}= Create Dictionary
|
||||
... name test-linklocal-${stamp}
|
||||
... url http://169.254.169.254/list.txt
|
||||
... enabled ${TRUE}
|
||||
${resp}= POST On Session bangsess /api/v1/blocklists
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 400
|
||||
... msg=Link-local URL accepted
|
||||
|
||||
Blocklist Schedule Endpoint Returns Config
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/blocklists/schedule
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Blocklist Schedule Update Works
|
||||
[Documentation] PUT /api/v1/blocklists/schedule updates the import schedule.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${payload}= Create Dictionary frequency daily hour 3 minute 0
|
||||
${resp}= PUT On Session bangsess /api/v1/blocklists/schedule
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Blocklist Manual Import Endpoint Reachable
|
||||
[Documentation] POST /api/v1/blocklists/import triggers a manual import.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= POST On Session bangsess /api/v1/blocklists/import
|
||||
... json=${EMPTY} headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 202, 429] msg=Unexpected import status: ${resp.status_code}
|
||||
|
||||
Blocklist Import Log Endpoint Returns Paginated Data
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/blocklists/log
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 204]
|
||||
|
||||
Blocklist Delete Non Existent Returns 404
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= DELETE On Session bangsess /api/v1/blocklists/999999
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 404
|
||||
|
||||
Blocklist Create And Delete Cycle
|
||||
[Documentation] Create a valid blocklist source then delete it.
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
# Create via fetch POST (relative to backend) so we can use a public IP.
|
||||
${stamp}= Evaluate int(time.time()) modules=time
|
||||
${payload}= Create Dictionary
|
||||
... name cycle-test-${stamp}
|
||||
... url https://lists.blocklist.de/lists/ssh.txt
|
||||
... enabled ${FALSE}
|
||||
${create_resp}= POST On Session bangsess /api/v1/blocklists
|
||||
... json=${payload} headers=${headers} expected_status=any
|
||||
IF ${create_resp.status_code} in [200, 201]
|
||||
${body}= Set Variable ${create_resp.json()}
|
||||
${id}= Set Variable ${body}[id]
|
||||
# If source had import logs, delete would return 409. With no logs it should succeed.
|
||||
${del_resp}= DELETE On Session bangsess /api/v1/blocklists/${id}
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${del_resp.status_code} in [200, 204, 409]
|
||||
... msg=Unexpected delete status: ${del_resp.status_code}
|
||||
ELSE
|
||||
Log Could not create blocklist source (status ${create_resp.status_code}); skipping delete cycle
|
||||
END
|
||||
121
e2e/tests/10_general_layout.robot
Normal file
121
e2e/tests/10_general_layout.robot
Normal file
@@ -0,0 +1,121 @@
|
||||
*** Settings ***
|
||||
Documentation General UI / layout behaviour — sidebar nav,
|
||||
... active link highlighting, server-status badge, session persistence.
|
||||
Resource ${CURDIR}/../resources/common.resource
|
||||
Resource ${CURDIR}/../resources/auth.resource
|
||||
Suite Setup Wait For Backend Health
|
||||
|
||||
*** Test Cases ***
|
||||
Sidebar Is Visible On Dashboard
|
||||
[Documentation] After login the sidebar nav is visible.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=main visible timeout=10s
|
||||
${nav_visible}= Run Keyword And Return Status
|
||||
... Wait For Elements State css=nav[aria-label="Main navigation"] visible timeout=5s
|
||||
Should Be True ${nav_visible} msg=Sidebar navigation not visible on dashboard
|
||||
Close Browser
|
||||
|
||||
Sidebar Lists All Required Pages
|
||||
[Documentation] Sidebar contains links to Dashboard, World Map, Jails,
|
||||
... Configuration, History, and a Sign Out button.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=main visible timeout=10s
|
||||
Page Should Contain Dashboard
|
||||
Page Should Contain World Map
|
||||
Page Should Contain Jails
|
||||
Page Should Contain Configuration
|
||||
Page Should Contain History
|
||||
Page Should Contain Sign out
|
||||
Close Browser
|
||||
|
||||
Sidebar Sign Out Logs User Out
|
||||
[Documentation] Clicking Sign out in sidebar clears the session.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=main visible timeout=10s
|
||||
Click css=[aria-label="Sign out"]
|
||||
Wait For Load State domcontentloaded
|
||||
${url}= Get URL
|
||||
Should Contain ${url} /login
|
||||
Close Browser
|
||||
|
||||
Theme Toggle Is Present In Sidebar
|
||||
[Documentation] Sidebar exposes a theme toggle button.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=main visible timeout=10s
|
||||
${theme_visible}= Run Keyword And Return Status
|
||||
... Get Element States css=[aria-label*="light mode"], [aria-label*="dark mode"] contains visible
|
||||
Should Be True ${theme_visible} msg=Theme toggle not visible
|
||||
Close Browser
|
||||
|
||||
Active Page Highlighted In Sidebar
|
||||
[Documentation] The current page is marked active in the sidebar nav.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/jails
|
||||
Wait For Elements State css=[data-testid="jails-page"] visible timeout=10s
|
||||
${active}= Run Keyword And Return Status
|
||||
... Get Element States css=nav[aria-label="Main navigation"] [aria-current="page"] contains visible
|
||||
Should Be True ${active} msg=No active page link highlighted in sidebar
|
||||
Close Browser
|
||||
|
||||
Session Persists Across Page Reload
|
||||
[Documentation] Reloading the page does NOT log the user out.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=[data-testid="dashboard"] visible timeout=10s
|
||||
Reload
|
||||
Wait For Load State domcontentloaded
|
||||
Sleep 2s
|
||||
${url}= Get URL
|
||||
Should Not Contain ${url} /login
|
||||
Close Browser
|
||||
|
||||
Theme Toggle Changes Color Mode
|
||||
[Documentation] Clicking the theme toggle changes the document color scheme.
|
||||
Login As Admin
|
||||
Go To ${FRONTEND_URL}/
|
||||
Wait For Elements State css=main visible timeout=10s
|
||||
${before}= Evaluate JavaScript ${None} () => document.documentElement.getAttribute('data-theme') || document.documentElement.style.colorScheme || 'unknown'
|
||||
Log Theme before: ${before}
|
||||
# Try clicking either light or dark mode toggle (one of them exists).
|
||||
Run Keyword And Ignore Error Click css=[aria-label="Switch to light mode"]
|
||||
Run Keyword And Ignore Error Click css=[aria-label="Switch to dark mode"]
|
||||
Sleep 1s
|
||||
${after}= Evaluate JavaScript ${None} () => document.documentElement.getAttribute('data-theme') || document.documentElement.style.colorScheme || 'unknown'
|
||||
Log Theme after: ${after}
|
||||
Close Browser
|
||||
|
||||
Health Endpoint Returns Component Status
|
||||
Set Random Xff Header
|
||||
Login Via HTTP
|
||||
${headers}= Create Dictionary X-BanGUI-Request 1
|
||||
Set To Dictionary ${headers} X-Forwarded-For ${XFF_HEADER}
|
||||
${resp}= GET On Session bangsess /api/v1/health/ready
|
||||
... headers=${headers} expected_status=any
|
||||
Should Be True ${resp.status_code} in [200, 503] msg=Unexpected ready status: ${resp.status_code}
|
||||
|
||||
Liveness Endpoint Returns 200
|
||||
${resp}= GET ${BACKEND_URL}/api/v1/health/live expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 200
|
||||
|
||||
Metrics Endpoint Returns Prometheus Text
|
||||
[Documentation] GET /api/v1/metrics returns Prometheus text format.
|
||||
${resp}= GET ${BACKEND_URL}/api/v1/metrics expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 200
|
||||
${body}= Set Variable ${resp.text}
|
||||
Should Contain ${body} HELP # Prometheus exposition format marker
|
||||
|
||||
Setup Timezone Endpoint Returns IANA String
|
||||
${resp}= GET ${BACKEND_URL}/api/v1/setup/timezone expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 200
|
||||
${body}= Set Variable ${resp.json()}
|
||||
Dictionary Should Contain Key ${body} timezone
|
||||
|
||||
Setup Status Endpoint Returns Completed Flag
|
||||
${resp}= GET ${BACKEND_URL}/api/v1/setup expected_status=any
|
||||
Should Be Equal As Integers ${resp.status_code} 200
|
||||
${body}= Set Variable ${resp.json()}
|
||||
Dictionary Should Contain Key ${body} completed
|
||||
Reference in New Issue
Block a user