From 6ba1f81d93d15bd2254a01abfc0bd82188319323 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 10:41:42 +0000 Subject: [PATCH 1/9] Initial plan From 4fa716d5126132603135370f4f59a8ae0b997fbb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 10:44:34 +0000 Subject: [PATCH 2/9] Add CI workflow for UI tests on Renovate PRs Co-authored-by: andre8244 <4612169+andre8244@users.noreply.github.com> --- .github/workflows/test-renovate-ui.yml | 48 ++++++++++++++++++++++++++ ui/test-ui.sh | 41 ++++++++++++++++++++++ ui/tests/pythonreq.txt | 3 ++ ui/tests/test_ui.robot | 39 +++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 .github/workflows/test-renovate-ui.yml create mode 100755 ui/test-ui.sh create mode 100644 ui/tests/pythonreq.txt create mode 100644 ui/tests/test_ui.robot diff --git a/.github/workflows/test-renovate-ui.yml b/.github/workflows/test-renovate-ui.yml new file mode 100644 index 0000000..ab774c0 --- /dev/null +++ b/.github/workflows/test-renovate-ui.yml @@ -0,0 +1,48 @@ +name: Test UI on Renovate PRs + +on: + pull_request: + branches: + - main + +jobs: + check-author: + runs-on: ubuntu-latest + permissions: {} + outputs: + is_renovate: ${{ steps.check.outputs.is_renovate }} + steps: + - id: check + run: | + if [[ "${{ github.actor }}" == "renovate[bot]" ]]; then + echo "is_renovate=true" >> "$GITHUB_OUTPUT" + else + echo "is_renovate=false" >> "$GITHUB_OUTPUT" + fi + + publish-images: + needs: check-author + if: needs.check-author.outputs.is_renovate == 'true' + uses: NethServer/ns8-github-actions/.github/workflows/publish-branch.yml@v1 + permissions: + packages: write + actions: read + contents: write + + module: + needs: publish-images + permissions: {} + uses: NethServer/ns8-github-actions/.github/workflows/module-info.yml@v1 + + run_tests: + needs: module + permissions: {} + uses: NethServer/ns8-github-actions/.github/workflows/test-on-digitalocean-infra.yml@v1 + with: + script: test-ui.sh + path: ui + args: "ghcr.io/${{needs.module.outputs.owner}}/${{needs.module.outputs.name}}:${{needs.module.outputs.tag}}" + repo_ref: ${{needs.module.outputs.sha}} + debug_shell: false + secrets: + do_token: ${{ secrets.do_token }} diff --git a/ui/test-ui.sh b/ui/test-ui.sh new file mode 100755 index 0000000..7a44986 --- /dev/null +++ b/ui/test-ui.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# +# Copyright (C) 2023 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-3.0-or-later +# + +set -e + +SSH_KEYFILE=${SSH_KEYFILE:-$HOME/.ssh/id_rsa} + +LEADER_NODE="${1:?missing LEADER_NODE argument}" +IMAGE_URL="${2:?missing IMAGE_URL argument}" + +ssh_key="$(< $SSH_KEYFILE)" + +cleanup() { + set +e + podman cp rf-core-runner:/home/pwuser/outputs tests/ + podman stop rf-core-runner + podman rm rf-core-runner +} + +trap cleanup EXIT + +podman run -i \ + --network=host \ + --volume=.:/home/pwuser/ns8-module:z \ + --name rf-core-runner ghcr.io/marketsquare/robotframework-browser/rfbrowser-stable:19.11.0 \ + bash -l -s < /home/pwuser/ns8-key +pip install -q -r /home/pwuser/ns8-module/tests/pythonreq.txt +mkdir ~/outputs +cd /home/pwuser/ns8-module +exec robot \ + -v NODE_ADDR:${LEADER_NODE} \ + -v IMAGE_URL:${IMAGE_URL} \ + -v SSH_KEYFILE:/home/pwuser/ns8-key \ + -d ~/outputs /home/pwuser/ns8-module/tests/test_ui.robot +EOF diff --git a/ui/tests/pythonreq.txt b/ui/tests/pythonreq.txt new file mode 100644 index 0000000..279c2b3 --- /dev/null +++ b/ui/tests/pythonreq.txt @@ -0,0 +1,3 @@ +robotframework +robotframework-sshlibrary +robotframework-browser diff --git a/ui/tests/test_ui.robot b/ui/tests/test_ui.robot new file mode 100644 index 0000000..b86f156 --- /dev/null +++ b/ui/tests/test_ui.robot @@ -0,0 +1,39 @@ +*** Settings *** +Library SSHLibrary +Library Browser +Suite Setup Connect to the node + +*** Variables *** +${SSH_KEYFILE} %{HOME}/.ssh/id_ecdsa + +*** Keywords *** +Connect to the node + Open Connection ${NODE_ADDR} + Login With Public Key root ${SSH_KEYFILE} + ${output} = Execute Command systemctl is-system-running --wait + Should Be True '${output}' == 'running' or '${output}' == 'degraded' + +*** Test Cases *** +Install nethsecurity-controller module + ${output} ${rc} = Execute Command add-module ${IMAGE_URL} 1 + ... return_rc=True + Should Be Equal As Integers ${rc} 0 + &{output} = Evaluate ${output} + Set Suite Variable ${module_id} ${output.module_id} + +Take screenshot of Status page + New Browser chromium headless=True + New Page https://${NODE_ADDR}/cluster-admin/#/apps/${module_id} + Take Screenshot filename=${OUTPUT DIR}/nethsecurity-controller-status.png + Close Browser + +Take screenshot of Settings page + New Browser chromium headless=True + New Page https://${NODE_ADDR}/cluster-admin/#/apps/${module_id}?page=settings + Take Screenshot filename=${OUTPUT DIR}/nethsecurity-controller-settings.png + Close Browser + +Remove nethsecurity-controller module + ${rc} = Execute Command remove-module --no-preserve ${module_id} + ... return_rc=True return_stdout=False + Should Be Equal As Integers ${rc} 0 From ce57756c2a0fde16edaf69468d8b7c86e880afa5 Mon Sep 17 00:00:00 2001 From: Andrea Leardini Date: Fri, 27 Feb 2026 17:25:24 +0100 Subject: [PATCH 3/9] ci: add UI test workflow for Renovate PRs (wip) --- .github/workflows/test-renovate-ui.yml | 13 ++++++++-- ui/.gitignore | 3 +++ ui/test-ui.sh | 2 +- ui/tests/test_ui.robot | 35 ++++++++++++++++++-------- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test-renovate-ui.yml b/.github/workflows/test-renovate-ui.yml index ab774c0..fc38404 100644 --- a/.github/workflows/test-renovate-ui.yml +++ b/.github/workflows/test-renovate-ui.yml @@ -1,9 +1,16 @@ name: Test UI on Renovate PRs on: + workflow_dispatch: pull_request: branches: - main + paths: + - "ui/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true jobs: check-author: @@ -13,8 +20,10 @@ jobs: is_renovate: ${{ steps.check.outputs.is_renovate }} steps: - id: check + env: + PR_AUTHOR: ${{ github.event.pull_request.user.login }} run: | - if [[ "${{ github.actor }}" == "renovate[bot]" ]]; then + if [[ -z "$PR_AUTHOR" || "$PR_AUTHOR" == "renovate[bot]" ]]; then echo "is_renovate=true" >> "$GITHUB_OUTPUT" else echo "is_renovate=false" >> "$GITHUB_OUTPUT" @@ -34,7 +43,7 @@ jobs: permissions: {} uses: NethServer/ns8-github-actions/.github/workflows/module-info.yml@v1 - run_tests: + run_ui_tests: needs: module permissions: {} uses: NethServer/ns8-github-actions/.github/workflows/test-on-digitalocean-infra.yml@v1 diff --git a/ui/.gitignore b/ui/.gitignore index 403adbc..a7f0426 100644 --- a/ui/.gitignore +++ b/ui/.gitignore @@ -21,3 +21,6 @@ pnpm-debug.log* *.njsproj *.sln *.sw? + +# tests outputs +tests/outputs diff --git a/ui/test-ui.sh b/ui/test-ui.sh index 7a44986..f98a071 100755 --- a/ui/test-ui.sh +++ b/ui/test-ui.sh @@ -1,7 +1,7 @@ #!/bin/bash # -# Copyright (C) 2023 Nethesis S.r.l. +# Copyright (C) 2026 Nethesis S.r.l. # SPDX-License-Identifier: GPL-3.0-or-later # diff --git a/ui/tests/test_ui.robot b/ui/tests/test_ui.robot index b86f156..07dc91c 100644 --- a/ui/tests/test_ui.robot +++ b/ui/tests/test_ui.robot @@ -5,6 +5,9 @@ Suite Setup Connect to the node *** Variables *** ${SSH_KEYFILE} %{HOME}/.ssh/id_ecdsa +${ADMIN_USER} admin +# //// change password to Nethesis,1234 +${ADMIN_PASSWORD} Nethesis,12345 *** Keywords *** Connect to the node @@ -13,27 +16,37 @@ Connect to the node ${output} = Execute Command systemctl is-system-running --wait Should Be True '${output}' == 'running' or '${output}' == 'degraded' +Login to cluster-admin + New Page https://${NODE_ADDR}/cluster-admin/ + Fill Text text="Username" ${ADMIN_USER} + Click button >> text="Continue" + Fill Text text="Password" ${ADMIN_PASSWORD} + Click button >> text="Log in" + Wait For Elements State css=#main-content visible timeout=10s + *** Test Cases *** -Install nethsecurity-controller module +Install module ${output} ${rc} = Execute Command add-module ${IMAGE_URL} 1 ... return_rc=True Should Be Equal As Integers ${rc} 0 &{output} = Evaluate ${output} Set Suite Variable ${module_id} ${output.module_id} -Take screenshot of Status page - New Browser chromium headless=True - New Page https://${NODE_ADDR}/cluster-admin/#/apps/${module_id} - Take Screenshot filename=${OUTPUT DIR}/nethsecurity-controller-status.png - Close Browser - -Take screenshot of Settings page +Take screenshots New Browser chromium headless=True - New Page https://${NODE_ADDR}/cluster-admin/#/apps/${module_id}?page=settings - Take Screenshot filename=${OUTPUT DIR}/nethsecurity-controller-settings.png + New Context ignoreHTTPSErrors=True + Login to cluster-admin + Go To https://${NODE_ADDR}/cluster-admin/#/apps/${module_id} + Wait For Elements State iframe >>> h2 >> text="Status" visible timeout=10s + Sleep 5s + Take Screenshot filename=${OUTPUT DIR}/browser/screenshot/status.png + Go To https://${NODE_ADDR}/cluster-admin/#/apps/${module_id}?page=settings + Wait For Elements State iframe >>> h2 >> text="Settings" visible timeout=10s + Sleep 5s + Take Screenshot filename=${OUTPUT DIR}/browser/screenshot/settings.png Close Browser -Remove nethsecurity-controller module +Remove module ${rc} = Execute Command remove-module --no-preserve ${module_id} ... return_rc=True return_stdout=False Should Be Equal As Integers ${rc} 0 From dc09b6f8020055ab6135e3ab9aad89f8dbb06b50 Mon Sep 17 00:00:00 2001 From: Andrea Leardini Date: Mon, 2 Mar 2026 09:54:12 +0100 Subject: [PATCH 4/9] fix login password --- ui/tests/test_ui.robot | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/tests/test_ui.robot b/ui/tests/test_ui.robot index 07dc91c..4710b70 100644 --- a/ui/tests/test_ui.robot +++ b/ui/tests/test_ui.robot @@ -6,8 +6,7 @@ Suite Setup Connect to the node *** Variables *** ${SSH_KEYFILE} %{HOME}/.ssh/id_ecdsa ${ADMIN_USER} admin -# //// change password to Nethesis,1234 -${ADMIN_PASSWORD} Nethesis,12345 +${ADMIN_PASSWORD} Nethesis,1234 *** Keywords *** Connect to the node From e955538cfc8f981cd7e3648deadc635d557700ae Mon Sep 17 00:00:00 2001 From: Andrea Leardini Date: Tue, 3 Mar 2026 10:53:39 +0100 Subject: [PATCH 5/9] Review by DavidePrincipi Co-authored-by: Davide Principi --- .github/workflows/test-renovate-ui.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-renovate-ui.yml b/.github/workflows/test-renovate-ui.yml index fc38404..663d169 100644 --- a/.github/workflows/test-renovate-ui.yml +++ b/.github/workflows/test-renovate-ui.yml @@ -7,6 +7,7 @@ on: - main paths: - "ui/**" + - "build-images.sh" concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} From e3391e905ad2706caed693ef5489e858413190bf Mon Sep 17 00:00:00 2001 From: Andrea Leardini Date: Tue, 3 Mar 2026 11:40:07 +0100 Subject: [PATCH 6/9] Add debug shell support --- .github/workflows/test-renovate-ui.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-renovate-ui.yml b/.github/workflows/test-renovate-ui.yml index 663d169..38d17b2 100644 --- a/.github/workflows/test-renovate-ui.yml +++ b/.github/workflows/test-renovate-ui.yml @@ -2,12 +2,17 @@ name: Test UI on Renovate PRs on: workflow_dispatch: + inputs: + debug_shell: + description: "Debug shell" + required: true + type: boolean pull_request: branches: - main paths: - "ui/**" - - "build-images.sh" + - "build-images.sh" concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} From 89840a1e983254b7b561cc7d314174f4e2055e3c Mon Sep 17 00:00:00 2001 From: Andrea Leardini Date: Tue, 3 Mar 2026 11:41:19 +0100 Subject: [PATCH 7/9] Review by DavidePrincipi Co-authored-by: Davide Principi --- ui/test-ui.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ui/test-ui.sh b/ui/test-ui.sh index f98a071..74b3e7a 100755 --- a/ui/test-ui.sh +++ b/ui/test-ui.sh @@ -31,11 +31,12 @@ podman run -i \ set -e echo "$ssh_key" > /home/pwuser/ns8-key pip install -q -r /home/pwuser/ns8-module/tests/pythonreq.txt -mkdir ~/outputs -cd /home/pwuser/ns8-module +cd /home/pwuser/ns8-module/ui +mkdir -vp tests/outputs exec robot \ -v NODE_ADDR:${LEADER_NODE} \ -v IMAGE_URL:${IMAGE_URL} \ -v SSH_KEYFILE:/home/pwuser/ns8-key \ - -d ~/outputs /home/pwuser/ns8-module/tests/test_ui.robot + --name ui-tests \ + -d tests/outputs tests/ EOF From 42b790091673d5aca42248504ac60eb39c5f634a Mon Sep 17 00:00:00 2001 From: Andrea Leardini Date: Tue, 3 Mar 2026 11:50:42 +0100 Subject: [PATCH 8/9] Use update test-module.yml as reference --- .github/workflows/test-renovate-ui.yml | 33 +++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-renovate-ui.yml b/.github/workflows/test-renovate-ui.yml index 38d17b2..37acc2f 100644 --- a/.github/workflows/test-renovate-ui.yml +++ b/.github/workflows/test-renovate-ui.yml @@ -49,15 +49,42 @@ jobs: permissions: {} uses: NethServer/ns8-github-actions/.github/workflows/module-info.yml@v1 + chooser: + runs-on: ubuntu-latest + outputs: + node_a: ${{ steps.pick.outputs.node_a }} + node_b: ${{ steps.pick.outputs.node_b }} + steps: + - id: pick + run: | + if (( $GITHUB_RUN_NUMBER % 2 )); then + echo "node_a=rl1" >> "$GITHUB_OUTPUT" + echo "node_b=dn1" >> "$GITHUB_OUTPUT" + else + echo "node_a=dn1" >> "$GITHUB_OUTPUT" + echo "node_b=rl1" >> "$GITHUB_OUTPUT" + fi + run_ui_tests: - needs: module + needs: [module, chooser] permissions: {} + strategy: + fail-fast: false + matrix: + scenario: [install, update] uses: NethServer/ns8-github-actions/.github/workflows/test-on-digitalocean-infra.yml@v1 with: script: test-ui.sh path: ui - args: "ghcr.io/${{needs.module.outputs.owner}}/${{needs.module.outputs.name}}:${{needs.module.outputs.tag}}" + coremodules: ${{ matrix.scenario == 'install' && format('ghcr.io/{0}/{1}:{2}', needs.module.outputs.owner, needs.module.outputs.name, needs.module.outputs.tag) || '' }} + leader_nodes: >- + ${{ + matrix.scenario == 'install' + && needs.chooser.outputs.node_a + || needs.chooser.outputs.node_b + }} + args: ${{ format('ghcr.io/{0}/{1}:{2} -v SCENARIO:{3}', needs.module.outputs.owner, needs.module.outputs.name, needs.module.outputs.tag, matrix.scenario) }} repo_ref: ${{needs.module.outputs.sha}} - debug_shell: false + debug_shell: ${{ github.event.inputs.debug_shell == 'true' || false }} secrets: do_token: ${{ secrets.do_token }} From bccb1d0e22b809c5693b640d803280aeeac9ae30 Mon Sep 17 00:00:00 2001 From: Andrea Leardini Date: Tue, 3 Mar 2026 13:04:52 +0100 Subject: [PATCH 9/9] Minor enhancements --- .github/workflows/test-renovate-ui.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test-renovate-ui.yml b/.github/workflows/test-renovate-ui.yml index 37acc2f..07a9a5f 100644 --- a/.github/workflows/test-renovate-ui.yml +++ b/.github/workflows/test-renovate-ui.yml @@ -29,6 +29,8 @@ jobs: env: PR_AUTHOR: ${{ github.event.pull_request.user.login }} run: | + # On workflow_dispatch, PR_AUTHOR is empty — allow the run. + # On pull_request, only allow renovate[bot]. if [[ -z "$PR_AUTHOR" || "$PR_AUTHOR" == "renovate[bot]" ]]; then echo "is_renovate=true" >> "$GITHUB_OUTPUT" else @@ -50,7 +52,10 @@ jobs: uses: NethServer/ns8-github-actions/.github/workflows/module-info.yml@v1 chooser: + needs: check-author + if: needs.check-author.outputs.is_renovate == 'true' runs-on: ubuntu-latest + permissions: {} outputs: node_a: ${{ steps.pick.outputs.node_a }} node_b: ${{ steps.pick.outputs.node_b }} @@ -68,6 +73,7 @@ jobs: run_ui_tests: needs: [module, chooser] permissions: {} + timeout-minutes: 30 strategy: fail-fast: false matrix: