Repository navigation
packaging(ns8): wire up the robot suite #144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| name: Test module (robot) | ||
|
|
||
| # Robot Framework integration tests for the NS8 module. The suite in | ||
| # packaging/ns8/tests installs the module on a real NS8 cluster, configures it, | ||
| # checks the route, screenshots the UI and removes it again. | ||
| # | ||
| # WHY THIS DOES NOT USE THE STOCK NS8 WORKFLOW | ||
| # | ||
| # NethServer/ns8-github-actions provides test-module.yml@v1, the one-line | ||
| # entry point every NS8 module uses. It cannot be used here. It derives the | ||
| # image under test from the repository name: | ||
| # | ||
| # name = basename(repository), with any leading "ns8-" stripped | ||
| # owner = lowercased repo owner | ||
| # tag = head branch, with "main" forced to "latest" | ||
| # image = ghcr.io/<owner>/<name>:<tag> | ||
| # | ||
| # For this repository that yields ghcr.io/calnode/calnode:latest, which is two | ||
| # wrong answers at once: | ||
| # * the module image is ghcr.io/calnode/ns8-calnode, not ghcr.io/calnode/calnode | ||
| # (the latter is the Calnode application image, which has no NS8 module | ||
| # manifest, so add-module would fail); | ||
| # * this repo deliberately never publishes a :latest module tag. :latest stays | ||
| # pinned to releases, and main publishes :edge, exactly as docker-publish.yml | ||
| # does for the app image. | ||
| # | ||
| # So this workflow calls test-on-digitalocean-infra.yml@v1 directly, which is | ||
| # the reusable workflow test-module.yml delegates to anyway, and supplies the | ||
| # image URL itself via the `args` input. Everything else (DigitalOcean | ||
| # provisioning, NS8 install, create-cluster, the test runner, artifact upload, | ||
| # tmate debugging) is still theirs and unmodified. | ||
| # | ||
| # NOT RUNNING AUTOMATICALLY YET | ||
| # | ||
| # It needs a `do_token` repository secret (DigitalOcean API token) for the | ||
| # cluster provisioning, and this repo does not have one. Declaring the workflow | ||
| # with a workflow_run trigger now would just fail red on every publish, so it is | ||
| # manual-only until that is sorted out. | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| image: | ||
| description: 'Module image under test' | ||
| required: false | ||
| type: string | ||
| default: 'ghcr.io/calnode/ns8-calnode:edge' | ||
| run_ui_tests: | ||
| description: 'Run the [ui] tests (slower, needs the Playwright image)' | ||
| required: false | ||
| type: boolean | ||
| default: false | ||
| debug_shell: | ||
| description: 'Hand out a tmate debug shell on failure' | ||
| required: false | ||
| type: boolean | ||
| default: false | ||
| # To run this on every successful publish instead of by hand, add: | ||
| # workflow_run: | ||
| # workflows: ['NS8 module publish'] | ||
|
Comment on lines
+58
to
+59
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uncommenting this as written produces a red, billable run. Under Technical details# The documented `workflow_run` follow-up is not self-contained
## Affected sites
- `.github/workflows/test-module.yml:57-61` — the commented trigger block.
- `.github/workflows/test-module.yml:77` — `args: ${{ inputs.image }}`, empty under `workflow_run`.
- `.github/workflows/test-module.yml:81-82` — the two `type: boolean` inputs, empty under `workflow_run`.
- `packaging/ns8/tests/10__calnode.robot:10` — `add-module ${IMAGE_URL}`, undefined in core mode.
- Upstream `scripts/test-module.sh:20-28` — `if [ -n "${2:-}" ] && [[ $2 != -* ]]; then IMAGE_URL="$2"; mode="module"` … `else mode="core"`.
- Upstream `scripts/test-module.sh:137-139` — `-v "IMAGE_URL:${IMAGE_URL}"` is added only in module mode.
- Upstream `test-on-digitalocean-infra.yml:19-23,58-62` — `repo_ref` defaults to `${{ github.sha }}`; `run_ui_tests`/`debug_shell` are `type: boolean`.
- Upstream `test-module.yml:22,66` — the stock path guards with `if: github.event.workflow_run.conclusion == 'success'` and threads `repo_ref: ${{ needs.module.outputs.sha }}` (= `github.event.workflow_run.head_sha || github.sha`).
## Required outcome
- Whatever the trigger becomes, the run must (a) only fire on a successful publish, (b) derive the image URL and the tested ref from `github.event.workflow_run.*` rather than from `inputs`, since `inputs` does not exist for that event.
## Suggested approach
- Add the success guard: `if: github.event.workflow_run.conclusion == 'success'` on the `test` job.
- Give each `with:` value a fallback that works for both events, e.g. `args: ${{ inputs.image || format('ghcr.io/calnode/ns8-calnode:{0}', ...) }}` or, more simply, compute a local `env:` block that prefers `inputs.*` and falls back to the workflow_run ref.
- Set `repo_ref: ${{ github.event.workflow_run.head_sha || github.sha }}`.
- Note that `types: [completed]` also fires for the `pull_request` runs of "NS8 module publish", which build but push nothing — those would test the previous `edge` image against the PR's test files.
## Open questions for the human
- Is `workflow_run` the intended trigger at all, or should this become `workflow_call` so the `NS8 module publish` workflow calls it directly with an explicit image? That sidesteps every `inputs` problem above. |
||
| # types: [completed] | ||
| # ...after setting the do_token secret. | ||
|
|
||
| jobs: | ||
| test: | ||
| name: Run tests | ||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| statuses: write | ||
| uses: NethServer/ns8-github-actions/.github/workflows/test-on-digitalocean-infra.yml@v1 | ||
| with: | ||
| # packaging/ns8 holds both the module definition and tests/, so this is the | ||
| # module root for the purposes of the runner. | ||
| path: packaging/ns8 | ||
| # `args` is the second positional argument to run-ns8-tests, i.e. the | ||
| # IMAGE_URL that the suite passes to add-module. See the header note. | ||
| args: ${{ inputs.image }} | ||
| # One leader node. The default is "dn1 rl1" (two droplets); the suite is | ||
| # single-node, so a second one only doubles the cost. | ||
| leader_nodes: rl1 | ||
| run_ui_tests: ${{ inputs.run_ui_tests }} | ||
| debug_shell: ${{ inputs.debug_shell }} | ||
| secrets: | ||
| do_token: ${{ secrets.do_token }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| *** Settings *** | ||
| Library SSHLibrary | ||
|
|
||
| *** Variables *** | ||
| ${TEST_HOST} calnode.example.test | ||
| ${module_id} ${EMPTY} | ||
|
|
||
| *** Test Cases *** | ||
| Check if ns8-calnode is installed correctly | ||
| ${output} ${rc} = Execute Command add-module ${IMAGE_URL} 1 | ||
| ... return_rc=True | ||
| Should Be Equal As Integers ${rc} 0 | ||
| &{output} = Evaluate ${output} | ||
| Set Global Variable ${module_id} ${output.module_id} | ||
|
|
||
| Check if ns8-calnode can be configured | ||
| ${rc} = Execute Command api-cli run module/${module_id}/configure-module --data '{"host": "${TEST_HOST}", "lets_encrypt": false, "http2https": false}' | ||
| ... return_rc=True return_stdout=False | ||
| Should Be Equal As Integers ${rc} 0 | ||
|
|
||
| Check if ns8-calnode works as expected | ||
| # Host-based route: pass the hostname explicitly since it does not resolve here | ||
| ${rc} = Execute Command curl -f -H 'Host: ${TEST_HOST}' http://127.0.0.1/ | ||
| ... return_rc=True return_stdout=False | ||
| Should Be Equal As Integers ${rc} 0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| *** Settings *** | ||
| Documentation Settings-UI screenshots. Excluded automatically unless the runner | ||
| ... is started with RUN_UI_TESTS=true. | ||
|
|
||
| *** Variables *** | ||
| ${ADMIN_USER} admin | ||
| ${ADMIN_PASSWORD} Nethesis,1234 | ||
|
|
||
| *** Keywords *** | ||
| 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 *** | ||
| Take screenshots | ||
| [Tags] ui | ||
| # Imported here rather than in *** Settings *** on purpose: the runner uses a | ||
| # different image, without robotframework-browser, whenever RUN_UI_TESTS is | ||
| # unset. A suite-level import would fail the whole run before the [ui] | ||
| # exclusion could skip this one test. | ||
| Import Library Browser | ||
| New Browser chromium headless=True | ||
| 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/1._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/2._Settings.png | ||
| Close Browser |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| *** Settings *** | ||
| Library SSHLibrary | ||
|
|
||
| *** Test Cases *** | ||
| Check if ns8-calnode is removed correctly | ||
| ${rc} = Execute Command remove-module --no-preserve ${module_id} | ||
| ... return_rc=True return_stdout=False | ||
| Should Be Equal As Integers ${rc} 0 |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This claim is false, and the very next clause contradicts it:
ns8-module.yml:118-121publishes modulelateston avX.Y.Ztag (module_tags=${version} ${version%.*} latest), andpush-manifest.shpushes every entry inIMAGETAGS. Onlymainpublishesedge, which is whatREADME.md:149-151already says accurately. The conclusion survives — the stock workflow resolves the name tocalnode, notns8-calnode, which alone settles it — but this header exists so nobody re-derives the decision, and a header whose second reason expires at the first module release is the kind of thing that gets someone to "fix" the workflow back.Technical details