diff --git a/.bazelrc b/.bazelrc index 72016ad8..b89ee6c1 100644 --- a/.bazelrc +++ b/.bazelrc @@ -14,7 +14,9 @@ build:x86_64-linux --define=config=x86_64-linux build:build_qnx8 --platforms=@score_bazel_platforms//:arm64-qnx8_0 build:build_qnx8 --extra_toolchains=@toolchains_qnx_qcc//:qcc_aarch64 +build:build_qnx8 --extra_toolchains=@toolchains_qnx_ifs//:ifs_aarch64 build:build_qnx8 --extra_toolchains=@score_toolchains_rust//toolchains/aarch64-unknown-qnx8_0:toolchain_aarch64_qnx8_0 +build:build_qnx8 --extra_toolchains=@rules_python//python/runtime_env_toolchains:all # needed to override python toolchain to use host build:build_qnx8 --define=config=build_qnx8 # TODO: Enable when rust toolchain for x86_64-qnx becomes available diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 539b6e06..0fdf39a2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -29,7 +29,7 @@ ], // Add your personal customizations "onCreateCommand": { - "update certificates & install dependencies": "sudo apt update && sudo apt install -y --no-install-recommends ca-certificates-java openjdk-17-jre-headless libacl1-dev tmux && sudo update-ca-certificates", + "update certificates & install dependencies": "sudo apt update && sudo apt install -y --no-install-recommends ca-certificates-java openjdk-17-jre-headless libacl1-dev tmux fakechroot && sudo update-ca-certificates", "bazel use system trust store": "echo 'startup --host_jvm_args=-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts --host_jvm_args=-Djavax.net.ssl.trustStorePassword=changeit' | sudo tee --append /etc/bazel.bazelrc" }, diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index eb1459ba..5a4f81a8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,10 +19,13 @@ on: types: [checks_requested] jobs: test: - name: "Run tests" - uses: eclipse-score/cicd-workflows/.github/workflows/tests.yml@main - permissions: - contents: read - pull-requests: read - with: - bazel-target: 'test //src/...' + steps: + - name: Install fakechroot + run: sudo apt install -y fakechroot + - name: Run tests + uses: eclipse-score/cicd-workflows/.github/workflows/tests.yml@main + permissions: + contents: read + pull-requests: read + with: + bazel-target: 'test //src/... //tests/integration/...' diff --git a/MODULE.bazel b/MODULE.bazel index e928db55..4eb906d5 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -99,6 +99,14 @@ python.toolchain( ) use_repo(python) +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip", dev_dependency = True) +pip.parse( + hub_name = "pip_score_venv_test", + python_version = PYTHON_VERSION, + requirements_lock = "//tests/utils:requirements.lock", +) +use_repo(pip, "pip_score_venv_test") + use_repo(toolchains_qnx, "toolchains_qnx_sdp") use_repo(toolchains_qnx, "toolchains_qnx_qcc") use_repo(toolchains_qnx, "toolchains_qnx_ifs") @@ -116,3 +124,10 @@ git_override( # Replace the commit hash (above) with the latest (https://github.com/hedronvision/bazel-compile-commands-extractor/commits/main). # Even better, set up Renovate and let it do the work for you (see "Suggestion: Updates" in the README). ) + + +bazel_dep(name = "score_itf", version = "0.1.0") +git_override( + module_name = "score_itf", + commit = "7b99c23ccccd9a75113ab4c1ef5c22dee98316f8", + remote = "https://github.com/etas-contrib/score_itf.git") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index ecb84986..87f4df57 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -22,8 +22,10 @@ "https://bcr.bazel.build/modules/apple_support/1.17.1/MODULE.bazel": "655c922ab1209978a94ef6ca7d9d43e940cd97d9c172fb55f94d91ac53f8610b", "https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442", "https://bcr.bazel.build/modules/apple_support/1.23.1/source.json": "d888b44312eb0ad2c21a91d026753f330caa48a25c9b2102fae75eb2b0dcfdd2", + "https://bcr.bazel.build/modules/aspect_bazel_lib/1.28.0/MODULE.bazel": "d793416e81c34d137d75ef84fe622df6c550826772a7f06e3b98a0d1c347fe1c", "https://bcr.bazel.build/modules/aspect_bazel_lib/1.31.2/MODULE.bazel": "7bee702b4862612f29333590f4b658a5832d433d6f8e4395f090e8f4e85d442f", "https://bcr.bazel.build/modules/aspect_bazel_lib/1.38.0/MODULE.bazel": "6307fec451ba9962c1c969eb516ebfe1e46528f7fa92e1c9ac8646bef4cdaa3f", + "https://bcr.bazel.build/modules/aspect_bazel_lib/1.42.1/MODULE.bazel": "b7aca918a7c7f4cb9ea223e7e2cba294760659ec7364cc551df156067e4a3621", "https://bcr.bazel.build/modules/aspect_bazel_lib/1.42.2/MODULE.bazel": "2e0d8ab25c57a14f56ace1c8e881b69050417ff91b2fb7718dc00d201f3c3478", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.0.0/MODULE.bazel": "e118477db5c49419a88d78ebc7a2c2cea9d49600fe0f490c1903324a2c16ecd9", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/MODULE.bazel": "cb1ba9f9999ed0bc08600c221f532c1ddd8d217686b32ba7d45b0713b5131452", @@ -43,6 +45,7 @@ "https://bcr.bazel.build/modules/aspect_rules_js/2.3.8/MODULE.bazel": "74bf20a7a6bd5f2be09607fdb4196cfd6f203422ea271752ec2b1afe95426101", "https://bcr.bazel.build/modules/aspect_rules_js/2.3.8/source.json": "411ec9d79d6f5fe8a083359588c21d01a5b48d88a2cbd334a4c90365015b7836", "https://bcr.bazel.build/modules/aspect_rules_lint/0.12.0/MODULE.bazel": "e767c5dbfeb254ec03275a7701b5cfde2c4d2873676804bc7cb27ddff3728fed", + "https://bcr.bazel.build/modules/aspect_rules_lint/1.0.0-rc9/MODULE.bazel": "7c0d5173bf7c3430fb99213c2664fb7fd0a4530e37de9a7c6006275e73036001", "https://bcr.bazel.build/modules/aspect_rules_lint/1.0.3/MODULE.bazel": "ed0fe929647ba21d2041e14ea3d757133ca306b72d4998e8a3d0d2f515196765", "https://bcr.bazel.build/modules/aspect_rules_lint/1.3.1/MODULE.bazel": "06ce330900a7d6403bc8d88e5dfad6aeeb8ae40179f66bb89e69c8bf6f6b1a0b", "https://bcr.bazel.build/modules/aspect_rules_lint/1.4.2/MODULE.bazel": "78d025facf6fa675fd6f0b62fd6a9a2bec7ef5ae1e288e5b53f4383b98017105", @@ -147,6 +150,8 @@ "https://bcr.bazel.build/modules/cel-spec/0.15.0/source.json": "ab7dccdf21ea2261c0f809b5a5221a4d7f8b580309f285fdf1444baaca75d44a", "https://bcr.bazel.build/modules/civetweb/1.16/MODULE.bazel": "46a38f9daeb57392e3827fce7d40926be0c802bd23cdd6bfd3a96c804de42fae", "https://bcr.bazel.build/modules/civetweb/1.16/source.json": "ba8b9585adb8355cb51b999d57172fd05e7a762c56b8d4bac6db42c99de3beb7", + "https://bcr.bazel.build/modules/container_structure_test/1.16.0/MODULE.bazel": "5bf2659d7724e232c10435e7ef3d5b3d3bc4bfc7825060e408b4a5e7d165ddf7", + "https://bcr.bazel.build/modules/container_structure_test/1.16.0/source.json": "c28ee996e071609f1c28fffce4297b0f2cb7f73387a6db56509310910641b188", "https://bcr.bazel.build/modules/curl/8.4.0/MODULE.bazel": "0bc250aa1cb69590049383df7a9537c809591fcf876c620f5f097c58fdc9bc10", "https://bcr.bazel.build/modules/curl/8.7.1/MODULE.bazel": "088221c35a2939c555e6e47cb31a81c15f8b59f4daa8009b1e9271a502d33485", "https://bcr.bazel.build/modules/curl/8.7.1/source.json": "bf9890e809717445b10a3ddc323b6d25c46631589c693a232df8310a25964484", @@ -348,6 +353,8 @@ "https://bcr.bazel.build/modules/rules_nodejs/6.3.0/MODULE.bazel": "45345e4aba35dd6e4701c1eebf5a4e67af4ed708def9ebcdc6027585b34ee52d", "https://bcr.bazel.build/modules/rules_nodejs/6.3.3/MODULE.bazel": "b66eadebd10f1f1b25f52f95ab5213a57e82c37c3f656fcd9a57ad04d2264ce7", "https://bcr.bazel.build/modules/rules_nodejs/6.3.3/source.json": "45bd343155bdfed2543f0e39b80ff3f6840efc31975da4b5795797f4c94147ad", + "https://bcr.bazel.build/modules/rules_oci/1.8.0/MODULE.bazel": "a4d656f6a0e7c7c1a73b9e394e37c8f9bbc237143ce9e19deba7a532fe189552", + "https://bcr.bazel.build/modules/rules_oci/1.8.0/source.json": "c14770a5dfba2980d8f1ebeaac0bfa4848ffb7febfca84ac2a7fd7e8f4d9e1e3", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", "https://bcr.bazel.build/modules/rules_pkg/1.1.0/MODULE.bazel": "9db8031e71b6ef32d1846106e10dd0ee2deac042bd9a2de22b4761b0c3036453", @@ -385,7 +392,8 @@ "https://bcr.bazel.build/modules/rules_shell/0.4.0/MODULE.bazel": "0f8f11bb3cd11755f0b48c1de0bbcf62b4b34421023aa41a2fc74ef68d9584f0", "https://bcr.bazel.build/modules/rules_shell/0.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592", "https://bcr.bazel.build/modules/rules_shell/0.5.0/MODULE.bazel": "8c8447370594d45539f66858b602b0bb2cb2d3401a4ebb9ad25830c59c0f366d", - "https://bcr.bazel.build/modules/rules_shell/0.5.0/source.json": "3038276f07cbbdd1c432d1f80a2767e34143ffbb03cfa043f017e66adbba324c", + "https://bcr.bazel.build/modules/rules_shell/0.6.0/MODULE.bazel": "c65e3ab217f64c3960e3ab55a53b430babcac6f0870fe79192812ae68a596a81", + "https://bcr.bazel.build/modules/rules_shell/0.6.0/source.json": "9431501bbc2114effd3b625b30555c5de51b7d291c1aee48b6f4d09d82126b3e", "https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca", "https://bcr.bazel.build/modules/rules_swift/1.18.0/MODULE.bazel": "a6aba73625d0dc64c7b4a1e831549b6e375fbddb9d2dde9d80c9de6ec45b24c9", "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046", @@ -443,8 +451,10 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/apple_support/1.15.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/apple_support/1.17.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/apple_support/1.23.1/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/1.28.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/1.31.2/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/1.38.0/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/1.42.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/1.42.2/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.0.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_bazel_lib/2.11.0/MODULE.bazel": "not found", @@ -461,6 +471,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_rules_js/2.0.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_rules_js/2.3.8/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_rules_lint/0.12.0/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_rules_lint/1.0.0-rc9/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_rules_lint/1.0.3/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_rules_lint/1.3.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/aspect_rules_lint/1.4.2/MODULE.bazel": "not found", @@ -534,6 +545,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/c-ares/1.15.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/cel-spec/0.15.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/civetweb/1.16/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/container_structure_test/1.16.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/curl/8.4.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/curl/8.7.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/cython/3.0.11-1/MODULE.bazel": "not found", @@ -691,6 +703,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_nodejs/6.2.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_nodejs/6.3.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_nodejs/6.3.3/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_oci/1.8.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/0.7.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/1.0.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_pkg/1.1.0/MODULE.bazel": "not found", @@ -724,6 +737,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_shell/0.4.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_shell/0.4.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_shell/0.5.0/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_shell/0.6.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/1.16.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/1.18.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/2.1.1/MODULE.bazel": "not found", @@ -1137,6 +1151,67 @@ ] } }, + "@@container_structure_test+//:repositories.bzl%extension": { + "general": { + "bzlTransitiveDigest": "/vl5vOyGN/nxHtUF3SxoDZnTDgDklt4HUpLQD5LE8+k=", + "usagesDigest": "WCu9SjsdaiOEDLolhYakkmsrItBrznRxVbmS81zCREg=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "structure_test_st_darwin_amd64": { + "repoRuleId": "@@container_structure_test+//:repositories.bzl%structure_test_repositories", + "attributes": { + "platform": "darwin_amd64" + } + }, + "structure_test_st_darwin_arm64": { + "repoRuleId": "@@container_structure_test+//:repositories.bzl%structure_test_repositories", + "attributes": { + "platform": "darwin_arm64" + } + }, + "structure_test_st_linux_arm64": { + "repoRuleId": "@@container_structure_test+//:repositories.bzl%structure_test_repositories", + "attributes": { + "platform": "linux_arm64" + } + }, + "structure_test_st_linux_i386": { + "repoRuleId": "@@container_structure_test+//:repositories.bzl%structure_test_repositories", + "attributes": { + "platform": "linux_i386" + } + }, + "structure_test_st_linux_s390x": { + "repoRuleId": "@@container_structure_test+//:repositories.bzl%structure_test_repositories", + "attributes": { + "platform": "linux_s390x" + } + }, + "structure_test_st_linux_amd64": { + "repoRuleId": "@@container_structure_test+//:repositories.bzl%structure_test_repositories", + "attributes": { + "platform": "linux_amd64" + } + }, + "structure_test_st_windows_amd64": { + "repoRuleId": "@@container_structure_test+//:repositories.bzl%structure_test_repositories", + "attributes": { + "platform": "windows_amd64" + } + }, + "structure_test_toolchains": { + "repoRuleId": "@@container_structure_test+//bazel:toolchains_repo.bzl%toolchains_repo", + "attributes": { + "toolchain_type": "@container_structure_test//bazel:structure_test_toolchain_type", + "toolchain": "@structure_test_st_{platform}//:structure_test_toolchain" + } + } + }, + "recordedRepoMappingEntries": [] + } + }, "@@rules_buf+//buf:extensions.bzl%ext": { "general": { "bzlTransitiveDigest": "SDu9W4CQUvGE9A6LTAEbu5g75w34Inmz0/AX9wecDv4=", @@ -1346,6 +1421,350 @@ "recordedRepoMappingEntries": [] } }, + "@@rules_oci+//oci:extensions.bzl%oci": { + "general": { + "bzlTransitiveDigest": "xyxpDiqqK3BxMIxpWRj4IyPVN2fvnWjVcwuaR1Mn/x8=", + "usagesDigest": "OFu2+tc1yHp/7HWI1JJ5ZWRDumcGKQIjZP+jFRwOAfk=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "ubuntu_24_04_linux_amd64": { + "repoRuleId": "@@rules_oci+//oci/private:pull.bzl%oci_pull", + "attributes": { + "scheme": "https", + "registry": "index.docker.io", + "repository": "library/ubuntu", + "identifier": "sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30", + "platform": "linux/amd64", + "target_name": "ubuntu_24_04_linux_amd64", + "bazel_tags": [] + } + }, + "ubuntu_24_04": { + "repoRuleId": "@@rules_oci+//oci/private:pull.bzl%oci_alias", + "attributes": { + "target_name": "ubuntu_24_04", + "scheme": "https", + "registry": "index.docker.io", + "repository": "library/ubuntu", + "identifier": "sha256:2e863c44b718727c860746568e1d54afd13b2fa71b160f5cd9058fc436217b30", + "platforms": { + "@@platforms//cpu:x86_64": "@ubuntu_24_04_linux_amd64" + }, + "bzlmod_repository": "ubuntu_24_04", + "reproducible": true + } + }, + "yq_darwin_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo", + "attributes": { + "platform": "darwin_amd64", + "version": "4.45.1" + } + }, + "yq_darwin_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo", + "attributes": { + "platform": "darwin_arm64", + "version": "4.45.1" + } + }, + "yq_linux_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo", + "attributes": { + "platform": "linux_amd64", + "version": "4.45.1" + } + }, + "yq_linux_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo", + "attributes": { + "platform": "linux_arm64", + "version": "4.45.1" + } + }, + "yq_linux_s390x": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo", + "attributes": { + "platform": "linux_s390x", + "version": "4.45.1" + } + }, + "yq_linux_riscv64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo", + "attributes": { + "platform": "linux_riscv64", + "version": "4.45.1" + } + }, + "yq_linux_ppc64le": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo", + "attributes": { + "platform": "linux_ppc64le", + "version": "4.45.1" + } + }, + "yq_windows_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_platform_repo", + "attributes": { + "platform": "windows_amd64", + "version": "4.45.1" + } + }, + "yq": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_host_alias_repo", + "attributes": {} + }, + "yq_toolchains": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:yq_toolchain.bzl%yq_toolchains_repo", + "attributes": { + "user_repository_name": "yq" + } + }, + "jq_darwin_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo", + "attributes": { + "platform": "darwin_amd64", + "version": "1.7" + } + }, + "jq_darwin_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo", + "attributes": { + "platform": "darwin_arm64", + "version": "1.7" + } + }, + "jq_linux_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo", + "attributes": { + "platform": "linux_amd64", + "version": "1.7" + } + }, + "jq_linux_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo", + "attributes": { + "platform": "linux_arm64", + "version": "1.7" + } + }, + "jq_windows_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_platform_repo", + "attributes": { + "platform": "windows_amd64", + "version": "1.7" + } + }, + "jq": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_host_alias_repo", + "attributes": {} + }, + "jq_toolchains": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:jq_toolchain.bzl%jq_toolchains_repo", + "attributes": { + "user_repository_name": "jq" + } + }, + "coreutils_darwin_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo", + "attributes": { + "platform": "darwin_amd64", + "version": "0.0.27" + } + }, + "coreutils_darwin_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo", + "attributes": { + "platform": "darwin_arm64", + "version": "0.0.27" + } + }, + "coreutils_linux_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo", + "attributes": { + "platform": "linux_amd64", + "version": "0.0.27" + } + }, + "coreutils_linux_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo", + "attributes": { + "platform": "linux_arm64", + "version": "0.0.27" + } + }, + "coreutils_windows_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_platform_repo", + "attributes": { + "platform": "windows_amd64", + "version": "0.0.27" + } + }, + "coreutils_toolchains": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:coreutils_toolchain.bzl%coreutils_toolchains_repo", + "attributes": { + "user_repository_name": "coreutils" + } + }, + "copy_to_directory_darwin_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo", + "attributes": { + "platform": "darwin_amd64" + } + }, + "copy_to_directory_darwin_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo", + "attributes": { + "platform": "darwin_arm64" + } + }, + "copy_to_directory_freebsd_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo", + "attributes": { + "platform": "freebsd_amd64" + } + }, + "copy_to_directory_linux_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo", + "attributes": { + "platform": "linux_amd64" + } + }, + "copy_to_directory_linux_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo", + "attributes": { + "platform": "linux_arm64" + } + }, + "copy_to_directory_linux_s390x": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo", + "attributes": { + "platform": "linux_s390x" + } + }, + "copy_to_directory_windows_amd64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo", + "attributes": { + "platform": "windows_amd64" + } + }, + "copy_to_directory_windows_arm64": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_platform_repo", + "attributes": { + "platform": "windows_arm64" + } + }, + "copy_to_directory_toolchains": { + "repoRuleId": "@@aspect_bazel_lib+//lib/private:copy_to_directory_toolchain.bzl%copy_to_directory_toolchains_repo", + "attributes": { + "user_repository_name": "copy_to_directory" + } + }, + "oci_crane_darwin_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "darwin_amd64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_darwin_arm64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "darwin_arm64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_arm64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_arm64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_armv6": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_armv6", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_i386": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_i386", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_s390x": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_s390x", + "crane_version": "v0.18.0" + } + }, + "oci_crane_linux_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "linux_amd64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_windows_armv6": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "windows_armv6", + "crane_version": "v0.18.0" + } + }, + "oci_crane_windows_amd64": { + "repoRuleId": "@@rules_oci+//oci:repositories.bzl%crane_repositories", + "attributes": { + "platform": "windows_amd64", + "crane_version": "v0.18.0" + } + }, + "oci_crane_toolchains": { + "repoRuleId": "@@rules_oci+//oci/private:toolchains_repo.bzl%toolchains_repo", + "attributes": { + "toolchain_type": "@rules_oci//oci:crane_toolchain_type", + "toolchain": "@oci_crane_{platform}//:crane_toolchain" + } + }, + "oci_crane_registry_toolchains": { + "repoRuleId": "@@rules_oci+//oci/private:toolchains_repo.bzl%toolchains_repo", + "attributes": { + "toolchain_type": "@rules_oci//oci:registry_toolchain_type", + "toolchain": "@oci_crane_{platform}//:registry_toolchain" + } + } + }, + "moduleExtensionMetadata": { + "explicitRootModuleDirectDeps": [], + "explicitRootModuleDirectDevDeps": [], + "useAllRepos": "NO", + "reproducible": false + }, + "recordedRepoMappingEntries": [ + [ + "aspect_bazel_lib+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_oci+", + "aspect_bazel_lib", + "aspect_bazel_lib+" + ], + [ + "rules_oci+", + "bazel_skylib", + "bazel_skylib+" + ] + ] + } + }, "@@rules_python+//python/uv:uv.bzl%uv": { "general": { "bzlTransitiveDigest": "Xpqjnjzy6zZ90Es9Wa888ZLHhn7IsNGbph/e6qoxzw8=", diff --git a/config/flatbuffers_rules.bzl b/config/flatbuffers_rules.bzl new file mode 100644 index 00000000..366d96ef --- /dev/null +++ b/config/flatbuffers_rules.bzl @@ -0,0 +1,77 @@ +def _flatbuffer_json_to_bin_impl(ctx): + flatc = ctx.executable.flatc + json = ctx.file.json + schema = ctx.file.schema + + # flatc will name the file the same as the json (can't be changed) + out_name = json.basename[:-len(".json")] + ".bin" + out = ctx.actions.declare_file(out_name, sibling = json) + + # flatc args --------------------------------- + flatc_args = [ + "-b", + "-o", + out.dirname, + ] + + for inc in ctx.attr.includes: + flatc_args.extend(["-I", inc.path]) + + if ctx.attr.strict_json: + flatc_args.append("--strict-json") + + flatc_args.extend([schema.path, json.path]) + # -------------------------------------------- + + ctx.actions.run( + inputs = [json, schema] + list(ctx.files.includes), + outputs = [out], + executable = flatc, + arguments = flatc_args, + progress_message = "flatc generation {}".format(json.short_path), + mnemonic = "FlatcGeneration", + ) + + rf = ctx.runfiles( + files = [out], + root_symlinks = { + ("_main/" + ctx.attr.out_dir + "/" + out_name): out, + }, + ) + + return DefaultInfo(files = depset([out]), runfiles = rf) + +flatbuffer_json_to_bin = rule( + implementation = _flatbuffer_json_to_bin_impl, + attrs = { + "json": attr.label( + allow_single_file = [".json"], + mandatory = True, + doc = "Json file to convert. Note that the binary file will have the same name as the json (minus the suffix)", + ), + "schema": attr.label( + allow_single_file = [".fbs"], + mandatory = True, + doc = "FBS file to use", + ), + "out_dir": attr.string( + default = "etc", + doc = "Directory to copy the generated file to, sibling to 'src' and 'tests' dirs. Do not include a trailing '/'", + ), + "flatc": attr.label( + default = Label("@flatbuffers//:flatc"), + executable = True, + cfg = "exec", + doc = "Reference to the flatc binary", + ), + # flatc arguments + "includes": attr.label_list( + allow_files = True, + doc = "Flatc include paths", + ), + "strict_json": attr.bool( + default = False, + doc = "Require strict JSON (no trailing commas etc)", + ), + }, +) diff --git a/scripts/clean_vm_network.sh b/scripts/clean_vm_network.sh new file mode 100755 index 00000000..af5790fc --- /dev/null +++ b/scripts/clean_vm_network.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +set -e + +if [ "$(id -u)" -ne 0 ]; then + echo "Error: This script must be run as root (use sudo)" >&2 + exit 1 +fi + +BRIDGE_DEVICE="br0" +TAP_DEVICE="tap0" + +ip link set "$TAP_DEVICE" nomaster +ip link set "$TAP_DEVICE" down +ip link delete "$TAP_DEVICE" +ip link set "$BRIDGE_DEVICE" down +ip link delete "$BRIDGE_DEVICE" + +echo "Network cleaned up: bridge $BRIDGE_DEVICE with $TAP_DEVICE" diff --git a/scripts/setup_vm_network.sh b/scripts/setup_vm_network.sh new file mode 100755 index 00000000..a89c98a0 --- /dev/null +++ b/scripts/setup_vm_network.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +set -e + +if [ "$(id -u)" -ne 0 ]; then + echo "Error: This script must be run as root (use sudo)" >&2 + exit 1 +fi + +IP="192.168.100.1/24" +BRIDGE_DEVICE="br0" +TAP_DEVICE="tap0" + +ip link add name "$BRIDGE_DEVICE" type bridge +ip link set "$BRIDGE_DEVICE" up +ip addr add "$IP" dev "$BRIDGE_DEVICE" + +ip tuntap add dev "$TAP_DEVICE" mode tap +ip link set "$TAP_DEVICE" up +ip link set "$TAP_DEVICE" master "$BRIDGE_DEVICE" + +echo "Network setup complete: bridge $BRIDGE_DEVICE ($IP) with $TAP_DEVICE" diff --git a/src/launch_manager_daemon/BUILD b/src/launch_manager_daemon/BUILD index 1822430c..b3a9952d 100644 --- a/src/launch_manager_daemon/BUILD +++ b/src/launch_manager_daemon/BUILD @@ -14,6 +14,8 @@ load("//config:common_cc.bzl", "cc_binary_with_common_opts", "cc_library_with_co package(default_visibility = ["//tests:__subpackages__"]) +exports_files(["config/lm_flatcfg.fbs"]) + cc_library( name = "config", hdrs = ["config/lm_flatcfg_generated.h"], diff --git a/src/launch_manager_daemon/health_monitor_lib/BUILD b/src/launch_manager_daemon/health_monitor_lib/BUILD index 3f699d3c..5fe4095b 100644 --- a/src/launch_manager_daemon/health_monitor_lib/BUILD +++ b/src/launch_manager_daemon/health_monitor_lib/BUILD @@ -13,6 +13,8 @@ load("//config:common_cc.bzl", "cc_binary_with_common_opts", "cc_library_with_common_opts") # flatcfg configuration +exports_files(["config/hm_flatcfg.fbs"]) + cc_library( name = "config", hdrs = [ diff --git a/src/launch_manager_daemon/src/process_group_manager/health_monitor_thread.cpp b/src/launch_manager_daemon/src/process_group_manager/health_monitor_thread.cpp index fb4173fe..01b5b3b4 100644 --- a/src/launch_manager_daemon/src/process_group_manager/health_monitor_thread.cpp +++ b/src/launch_manager_daemon/src/process_group_manager/health_monitor_thread.cpp @@ -37,7 +37,7 @@ bool HealthMonitorThread::start() { waitForInitializationCompleted(init_status); - return (init_status == score::lcm::saf::daemon::EInitCode::kNoError); + return init_status == saf::daemon::EInitCode::kNoError; } void HealthMonitorThread::stop() { diff --git a/src/launch_manager_daemon/src/process_group_manager/processgroupmanager.cpp b/src/launch_manager_daemon/src/process_group_manager/processgroupmanager.cpp index 3d8e3d99..6510243f 100644 --- a/src/launch_manager_daemon/src/process_group_manager/processgroupmanager.cpp +++ b/src/launch_manager_daemon/src/process_group_manager/processgroupmanager.cpp @@ -65,8 +65,6 @@ void ProcessGroupManager::setLaunchManagerConfiguration(const OsProcess* launch_ } bool ProcessGroupManager::initialize() { - bool success = false; - // setup signal handler em_cancelled.store(false); // RULECHECKER_comment(1, 1, check_union_object, "Union type defined in external library is used.", true) @@ -86,22 +84,24 @@ bool ProcessGroupManager::initialize() { sigaction(SIGUSR2, &action, NULL); sigaction(SIGVTALRM, &action, NULL); - success = initializeControlClientHandler() && initializeProcessGroups(); + if (!initializeControlClientHandler() || !initializeProcessGroups()) { + return false; + } - if (success) { - LM_LOG_DEBUG() << "Process Group initialization done"; - createProcessComponentsObjects(); - initializeGraphNodes(); - //success = ucm_polling_thread_.startPolling(); - success = health_monitor_thread_->start(); + LM_LOG_DEBUG() << "Process Group initialization done"; + createProcessComponentsObjects(); + initializeGraphNodes(); + if (!health_monitor_thread_->start()) { + LM_LOG_ERROR() << "Health monitor thread failed to start"; + return false; } - if (success && launch_manager_config_ && + if (launch_manager_config_ && OsalReturnType::kFail == IProcess::setSchedulingAndSecurity(launch_manager_config_->startup_config_)) { - success = false; + return false; } - return success; + return true; } void ProcessGroupManager::deinitialize() { diff --git a/src/launch_manager_daemon/src/process_group_manager/processlauncher.cpp b/src/launch_manager_daemon/src/process_group_manager/processlauncher.cpp index 8f3c33d7..8a59c36b 100644 --- a/src/launch_manager_daemon/src/process_group_manager/processlauncher.cpp +++ b/src/launch_manager_daemon/src/process_group_manager/processlauncher.cpp @@ -334,7 +334,7 @@ OsalReturnType IProcess::setSchedulingAndSecurity(const OsalConfig& config) { size_t supplementary_gids_number = config.supplementary_gids_.size(); // Note: the type of the first parameter of setgroups() differs in Linux and QNX, so we use osal - if (-1 == osal::setgroups(supplementary_gids_number, config.supplementary_gids_.data())) { + if (supplementary_gids_number > 0 && -1 == osal::setgroups(supplementary_gids_number, config.supplementary_gids_.data())) { LM_LOG_ERROR() << "setgroups() failed:" << std::strerror(errno); retval = OsalReturnType::kFail; } @@ -354,6 +354,7 @@ inline void IProcess::handleChildProcess(ChildProcessConfig& param) { if (OsalReturnType::kSuccess != setSchedulingAndSecurity(*param.config)) { sysexit(EXIT_FAILURE); } + changeCurrentWorkingDirectory(*param.config); implementMemoryResourceLimits(*param.config); changeSecurityPolicy(*param.config); diff --git a/tests/integration/BUILD b/tests/integration/BUILD new file mode 100644 index 00000000..b2ba66a2 --- /dev/null +++ b/tests/integration/BUILD @@ -0,0 +1,63 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("@pip_score_venv_test//:requirements.bzl", "all_requirements") +load("@rules_python//python:pip.bzl", "compile_pip_requirements") +load("@score_tooling//python_basics:defs.bzl", "score_py_pytest", "score_virtualenv") + +# In order to update the requirements, change the `requirements.txt` file and run: +# `bazel run //tests/integration:requirements.update`. +# This will update the `requirements.lock` file. +# To upgrade all dependencies to their latest versions, run: +# `bazel run //tests/integration:requirements.update -- --upgrade`. +compile_pip_requirements( + name = "requirements", + srcs = [ + "requirements.txt", + "@score_tooling//python_basics:requirements.txt", + ], + extra_args = [ + "--no-annotate", + ], + requirements_txt = "requirements.lock", + tags = [ + "manual", + ], +) + +score_virtualenv( + name = "python_tc_venv", + reqs = all_requirements, + venv_name = ".python_tc_venv", +) + +cc_library( + name = "test_helper", + hdrs = ["test_helper.hpp"], + visibility = ["//tests:__subpackages__"], + deps = [ + "@googletest//:gtest_main", + ], +) + +py_library( + name = "control_interface", + srcs = ["control_interface.py"], + visibility = ["//tests:__subpackages__"], +) + +py_library( + name = "testing_utils", + srcs = ["testing_utils.py"], + visibility = ["//tests:__subpackages__"], + deps = [":control_interface"], +) diff --git a/tests/integration/itf_smoke/BUILD b/tests/integration/itf_smoke/BUILD new file mode 100644 index 00000000..70f4b272 --- /dev/null +++ b/tests/integration/itf_smoke/BUILD @@ -0,0 +1,27 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("@score_tooling//:defs.bzl", "score_py_pytest") +load("//tests/utils:bazel/integration.bzl", "integration_test") + +integration_test( + name = "smoke", + srcs = [ + "smoke.py", + ], + deps = [ + "//tests/utils/fixtures", + ], + args = [ "--image-path=$(location //tests/utils/environments:test_environment)" ], + data = ["//tests/utils/environments:test_environment"], + tags = ["local"] +) diff --git a/tests/integration/itf_smoke/smoke.py b/tests/integration/itf_smoke/smoke.py new file mode 100644 index 00000000..98840737 --- /dev/null +++ b/tests/integration/itf_smoke/smoke.py @@ -0,0 +1,23 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +from tests.utils.fixtures.target import target +# from tests.utils.fixtures.ssh import ssh +from tests.utils.fixtures import control_interface + +import logging +logger = logging.getLogger(__name__) + +def test_one(control_interface): + ret, stdout, stderr = control_interface.exec_command_blocking("ls") + logger.error(stdout) diff --git a/tests/integration/readme.md b/tests/integration/readme.md new file mode 100644 index 00000000..5180abfd --- /dev/null +++ b/tests/integration/readme.md @@ -0,0 +1,12 @@ +# Local integration testing + +## Prerequisites +- fakechroot must be installed to run these tests + - `sudo apt install fakechroot` + +## Running the tests + +To run all tests, simply run `bazel test //tests/integration/...` + +## Running a single test +You can run a single integration test locally using `bazel test //tests/integration/` \ No newline at end of file diff --git a/tests/integration/smoke/BUILD b/tests/integration/smoke/BUILD new file mode 100644 index 00000000..1deb9a9f --- /dev/null +++ b/tests/integration/smoke/BUILD @@ -0,0 +1,73 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("@pip_score_venv_test//:requirements.bzl", "all_requirements") +load("@score_tooling//:defs.bzl", "score_py_pytest") +load("//config:flatbuffers_rules.bzl", "flatbuffer_json_to_bin") + +flatbuffer_json_to_bin( + name = "test_lm_cfg", + json = "lm_demo.json", + schema = "//src/launch_manager_daemon:config/lm_flatcfg.fbs", +) + +flatbuffer_json_to_bin( + name = "test_hm_cfg", + json = "hm_demo.json", + schema = "//src/launch_manager_daemon/health_monitor_lib:config/hm_flatcfg.fbs", +) + +cc_binary( + name = "control_daemon_mock", + srcs = ["control_daemon_mock.cpp"], + data = [ + ":test_hm_cfg", + ":test_lm_cfg", + ], + deps = [ + "//src/control_client_lib", + "//src/launch_manager_daemon/lifecycle_client_lib:lifecycle_client", + "//tests/integration:test_helper", + "@googletest//:gtest_main", + ], +) + +cc_binary( + name = "gtest_process", + srcs = ["gtest_process.cpp"], + deps = [ + "//src/control_client_lib", + "//src/launch_manager_daemon/lifecycle_client_lib:lifecycle_client", + "//tests/integration:test_helper", + "@googletest//:gtest_main", + ], +) + +score_py_pytest( + name = "smoke", + srcs = [ + "smoke.py", + ], + args = [ + ], + data = [ + ":control_daemon_mock", + ":gtest_process", + "//src/launch_manager_daemon:launch_manager", + ], + tags = [ + "integration", + ], + deps = all_requirements + [ + "//tests/integration:testing_utils", + ], +) diff --git a/tests/integration/smoke/control_daemon_mock.cpp b/tests/integration/smoke/control_daemon_mock.cpp new file mode 100644 index 00000000..aeea0ae4 --- /dev/null +++ b/tests/integration/smoke/control_daemon_mock.cpp @@ -0,0 +1,59 @@ +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#include +#include +#include +#include + +#include +#include +#include +#include "tests/integration/test_helper.hpp" + +score::lcm::ControlClient client([](const score::lcm::ExecutionErrorEvent& event) { + std::cerr << "Undefined state callback invoked for process group id: " << event.processGroup.data() << std::endl; +}); + +// create DefaultPG +const score::lcm::IdentifierHash defaultpg {"DefaultPG"}; +const score::lcm::IdentifierHash defaultpgOn {"DefaultPG/On"}; +const score::lcm::IdentifierHash defaultpgOff {"DefaultPG/Off"}; +// MainPG +const score::lcm::IdentifierHash mainpg {"MainPG"}; +const score::lcm::IdentifierHash mainpgOff {"MainPG/Off"}; + +TEST(Smoke, Daemon) { + TEST_STEP("Control daemon report kRunning") { + // report kRunning + auto result = score::lcm::LifecycleClient{}.ReportExecutionState(score::lcm::ExecutionState::kRunning); + + ASSERT_TRUE(result.has_value()) << "client.ReportExecutionState() failed"; + } + TEST_STEP("Turn default PG on") { + score::cpp::stop_token stop_token; + auto result = client.SetState(defaultpg, defaultpgOn).Get(stop_token); + EXPECT_TRUE(result.has_value()); + } + TEST_STEP("Turn default PG off") { + score::cpp::stop_token stop_token; + auto result = client.SetState(defaultpg, defaultpgOff).Get(stop_token); + EXPECT_TRUE(result.has_value()); + } + TEST_STEP("Turn main PG off") { + client.SetState(mainpg, mainpgOff); + } +} + +int main(int argc, char** argv) { + return TestRunner(__FILE__, true).RunTests(); +} diff --git a/tests/integration/smoke/gtest_process.cpp b/tests/integration/smoke/gtest_process.cpp new file mode 100644 index 00000000..702e51b9 --- /dev/null +++ b/tests/integration/smoke/gtest_process.cpp @@ -0,0 +1,31 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include +#include +#include +#include + +#include +#include "tests/integration/test_helper.hpp" + +TEST(Smoke, Process) { + // report kRunning + auto result = score::lcm::LifecycleClient{}.ReportExecutionState(score::lcm::ExecutionState::kRunning); + + ASSERT_TRUE(result.has_value()) << "client.ReportExecutionState() failed"; +} + +int main() { + return TestRunner(__FILE__).RunTests(); +} diff --git a/tests/integration/smoke/hm_demo.json b/tests/integration/smoke/hm_demo.json new file mode 100644 index 00000000..8e559853 --- /dev/null +++ b/tests/integration/smoke/hm_demo.json @@ -0,0 +1,13 @@ +{ + "versionMajor": 8, + "versionMinor": 0, + "process": [], + "hmMonitorInterface": [], + "hmSupervisionCheckpoint": [], + "hmAliveSupervision": [], + "hmDeadlineSupervision": [], + "hmLogicalSupervision": [], + "hmLocalSupervision": [], + "hmGlobalSupervision": [], + "hmRecoveryNotification": [] +} \ No newline at end of file diff --git a/tests/integration/smoke/lm_demo.json b/tests/integration/smoke/lm_demo.json new file mode 100644 index 00000000..10185fc8 --- /dev/null +++ b/tests/integration/smoke/lm_demo.json @@ -0,0 +1,123 @@ +{ + "versionMajor": 7, + "versionMinor": 0, + "Process": [ + { + "identifier": "control_daemon", + "uid": 0, + "gid": 0, + "path": "/tests/integration/smoke/control_daemon_mock", + "functionClusterAffiliation": "STATE_MANAGEMENT", + "numberOfRestartAttempts": 0, + "executable_reportingBehavior": "ReportsExecutionState", + "sgids": [], + "startupConfig": [ + { + "executionError": "1", + "schedulingPolicy": "SCHED_OTHER", + "schedulingPriority": "0", + "identifier": "control_daemon_startup_config", + "enterTimeoutValue": 1000, + "exitTimeoutValue": 1000, + "terminationBehavior": "ProcessIsNotSelfTerminating", + "executionDependency": [], + "processGroupStateDependency": [ + { + "stateMachine_name": "MainPG", + "stateName": "MainPG/Startup" + }, + { + "stateMachine_name": "MainPG", + "stateName": "MainPG/Recovery" + } + ], + "environmentVariable": [ + { + "key": "LD_LIBRARY_PATH", + "value": "/opt/lib" + }, + { + "key": "PROCESSIDENTIFIER", + "value": "control_daemon" + } + ], + "processArgument": [] + } + ] + }, + { + "identifier": "demo_app0_DefaultPG", + "uid": 0, + "gid": 0, + "path": "/tests/integration/smoke/gtest_process", + "numberOfRestartAttempts": 0, + "executable_reportingBehavior": "ReportsExecutionState", + "sgids": [], + "startupConfig": [ + { + "executionError": "1", + "schedulingPolicy": "SCHED_OTHER", + "schedulingPriority": "0", + "identifier": "demo_app_startup_config_0", + "enterTimeoutValue": 2000, + "exitTimeoutValue": 2000, + "terminationBehavior": "ProcessIsNotSelfTerminating", + "processGroupStateDependency": [ + { + "stateMachine_name": "DefaultPG", + "stateName": "DefaultPG/On" + } + ], + "environmentVariable": [ + { + "key": "LD_LIBRARY_PATH", + "value": "/opt/lib" + }, + { + "key": "PROCESSIDENTIFIER", + "value": "DefaultPG_app0" + }, + { + "key": "CONFIG_PATH", + "value": "/opt/supervision_demo/etc/health_monitor_process_cfg_0_MainPG.bin" + } + ] + } + ] + } + ], + "ModeGroup": [ + { + "identifier": "MainPG", + "initialMode_name": "Off", + "recoveryMode_name": "MainPG/Recovery", + "modeDeclaration": [ + { + "identifier": "MainPG/Off" + }, + { + "identifier": "MainPG/Startup" + }, + { + "identifier": "MainPG/Recovery" + } + ] + }, + { + "identifier": "DefaultPG", + "initialMode_name": "Off", + "recoveryMode_name": "DefaultPG/Recovery", + "modeDeclaration": [ + { + "identifier": "DefaultPG/Off" + }, + { + "identifier": "DefaultPG/On" + }, + { + "identifier": "DefaultPG/Recovery" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/integration/smoke/smoke.py b/tests/integration/smoke/smoke.py new file mode 100644 index 00000000..75fd6e5b --- /dev/null +++ b/tests/integration/smoke/smoke.py @@ -0,0 +1,29 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +from tests.integration.testing_utils import ( + get_common_interface, + check_for_failures, + format_logs, +) +from pathlib import Path + + +def test_smoke(): + code, stdout, stderr = get_common_interface().run_until_file_deployed( + "src/launch_manager_daemon/launch_manager" + ) + + print(format_logs(code, stdout, stderr)) + + check_for_failures(Path("tests/integration/smoke"), 2) + assert code == 0 diff --git a/tests/utils/BUILD b/tests/utils/BUILD new file mode 100644 index 00000000..bf569cad --- /dev/null +++ b/tests/utils/BUILD @@ -0,0 +1,50 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("@pip_score_venv_test//:requirements.bzl", "all_requirements") +load("@rules_python//python:pip.bzl", "compile_pip_requirements") +load("@score_tooling//python_basics:defs.bzl", "score_py_pytest", "score_virtualenv") + +# In order to update the requirements, change the `requirements.txt` file and run: +# `bazel run //tests/integration:requirements.update`. +# This will update the `requirements.lock` file. +# To upgrade all dependencies to their latest versions, run: +# `bazel run //tests/integration:requirements.update -- --upgrade`. +compile_pip_requirements( + name = "requirements", + srcs = [ + "requirements.txt", + "@score_tooling//python_basics:requirements.txt", + ], + extra_args = [ + "--no-annotate", + ], + requirements_txt = "requirements.lock", + tags = [ + "manual", + ], +) + +score_virtualenv( + name = "python_tc_venv", + reqs = all_requirements, + venv_name = ".python_tc_venv", +) + +cc_library( + name = "test_helper", + hdrs = ["test_helper.hpp"], + visibility = ["//tests:__subpackages__"], + deps = [ + "@googletest//:gtest_main", + ], +) diff --git a/tests/utils/bazel/integration.bzl b/tests/utils/bazel/integration.bzl new file mode 100644 index 00000000..a76f480c --- /dev/null +++ b/tests/utils/bazel/integration.bzl @@ -0,0 +1,23 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +load("@score_tooling//:defs.bzl", "score_py_pytest") + + +def integration_test(name, **kwargs): + srcs = kwargs.pop("srcs", []) + ["//tests/utils/fixtures:conf"] + + score_py_pytest( + name = name, + srcs = srcs, + **kwargs + ) diff --git a/tests/utils/environments/BUILD b/tests/utils/environments/BUILD new file mode 100644 index 00000000..6569ddd4 --- /dev/null +++ b/tests/utils/environments/BUILD @@ -0,0 +1,38 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +filegroup( + name = "target_config", + srcs = ["target_config.json"], + visibility = ["//tests/it:__subpackages__"], +) + +# Empty target for native builds +filegroup( + name = "empty_target", + srcs = [], + visibility = [ + "//tests:__subpackages__", + ], +) + +alias( + name = "test_environment", + actual = select({ + "@platforms//os:qnx": "//tests/utils/environments/qnx8_qemu:init_build", + "//conditions:default": ":empty_target", + }), + visibility = [ + "//tests:__subpackages__", + ], +) diff --git a/tests/utils/environments/qnx8_qemu/BUILD b/tests/utils/environments/qnx8_qemu/BUILD new file mode 100644 index 00000000..a3a2bf14 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/BUILD @@ -0,0 +1,27 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@score_toolchains_qnx//rules/fs:ifs.bzl", "qnx_ifs") + +qnx_ifs( + name = "init_build", + srcs = [ + "system.build", + "//tests/utils/environments/qnx8_qemu/configs", + ], + build_file = "init.build", + tags = ["manual"], # Excluded from wildcard builds + visibility = [ + "//tests:__subpackages__", + ], +) diff --git a/tests/utils/environments/qnx8_qemu/README.md b/tests/utils/environments/qnx8_qemu/README.md new file mode 100644 index 00000000..030c68ab --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/README.md @@ -0,0 +1,26 @@ +# QNX8 Image + +The qnx image is built in this repository. Most of the configs and settings are +copied from the qnx8 [reference_integration](https://github.com/eclipse-score/reference_integration/tree/v0.5.0-beta/qnx_qemu/build). + + +## Bazel + +`qnx_ifs` is bazel rule that wraps the qnx +[mkifs](https://www.qnx.com/developers/docs/8.0/com.qnx.doc.neutrino.utilities/topic/m/mkifs.html) +utility, and generates the image. + + +## Image + +### Networking + +The VM is configured with a static IP in the `network_setup.sh` script. + + +### Test Binaries + +The `reference_integration` builds the test binaries into the image however +here the test binaries shall be copied over network to lesten the time it takes +to run tests. + diff --git a/tests/utils/environments/qnx8_qemu/configs/BUILD b/tests/utils/environments/qnx8_qemu/configs/BUILD new file mode 100644 index 00000000..517f77d5 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/BUILD @@ -0,0 +1,32 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +filegroup( + name = "configs", + srcs = [ + "dhcpcd.conf", + "group", + "hostname", + "network_setup.sh", + "passwd", + "pci_hw.cfg", + "pci_server.cfg", + "profile", + "qcrypto.conf", + "ssh_host_rsa_key", + "ssh_host_rsa_key.pub", + "sshd_config", + "startup.sh", + ], + visibility = ["//tests:__subpackages__"], +) diff --git a/tests/utils/environments/qnx8_qemu/configs/dhcpcd.conf b/tests/utils/environments/qnx8_qemu/configs/dhcpcd.conf new file mode 100755 index 00000000..8a2ce0b8 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/dhcpcd.conf @@ -0,0 +1,42 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +# ******************************************************************************* +# Minimal DHCP Client Configuration for QNX QEMU System +# ******************************************************************************* +# This is a minimal dhcpcd.conf file for basic DHCP functionality + +# Allow all interfaces starting with vtnet +allowinterfaces vtnet0 + +# Use the hardware address of the interface for the Client ID +duid + +# Request essential network configuration +option routers +option domain_name_servers +option subnet_mask +option broadcast_address + +# Set timeout for DHCP requests (30 seconds) +timeout 30 + +# Disable IPv6 to simplify configuration +noipv6 + +# Don't send hostname for privacy +nohook hostname + +# Background after getting lease +background diff --git a/tests/utils/environments/qnx8_qemu/configs/group b/tests/utils/environments/qnx8_qemu/configs/group new file mode 100644 index 00000000..925ba062 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/group @@ -0,0 +1,16 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +root::0:root +qnxuser::1000:qnxuser +sshd::6:sshd diff --git a/tests/utils/environments/qnx8_qemu/configs/hostname b/tests/utils/environments/qnx8_qemu/configs/hostname new file mode 100644 index 00000000..c98f8c67 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/hostname @@ -0,0 +1 @@ +Qnx_S-core diff --git a/tests/utils/environments/qnx8_qemu/configs/network_setup.sh b/tests/utils/environments/qnx8_qemu/configs/network_setup.sh new file mode 100644 index 00000000..80d436c4 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/network_setup.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +# ******************************************************************************* +# Network Configuration Script +# Configures networking interfaces and settings for QNX system +# ******************************************************************************* + +echo "---> Starting Networking" +io-sock -m phy -m pci -d vtnet_pci # Start network stack with PHY and PCI modules, load VirtIO network driver +waitfor /dev/socket # Wait for socket device to become available before proceeding + +echo "---> Configuring network interface" +# Bring up the interface and configure with bridge-accessible IP for direct ping +if_up -p vtnet0 # Bring up the vtnet0 network interface in promiscuous mode +ifconfig vtnet0 192.168.100.10 netmask 255.255.255.0 # Configure IP address and subnet mask for vtnet0 + +# Configure system network settings +sysctl -w net.inet.icmp.bmcastecho=1 > /dev/null # Enable ICMP broadcast echo (responds to broadcast pings) +sysctl -w qnx.sec.droproot=33:33 > /dev/null # Set user/group ID (33:33) for dropping root privileges diff --git a/tests/utils/environments/qnx8_qemu/configs/passwd b/tests/utils/environments/qnx8_qemu/configs/passwd new file mode 100644 index 00000000..bcd2c608 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/passwd @@ -0,0 +1,17 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +root::0:0:Superuser:/:/bin/sh +qnxuser::1000:1000:QNX User:/:/bin/sh +sshd::15:6:sshd:/:/bin/false diff --git a/tests/utils/environments/qnx8_qemu/configs/pci_hw.cfg b/tests/utils/environments/qnx8_qemu/configs/pci_hw.cfg new file mode 100644 index 00000000..4a619d5e --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/pci_hw.cfg @@ -0,0 +1,9 @@ +[interrupts] +B0:D17:F0 A 18 +B0:D17:F0 B 19 +B0:D17:F0 C 16 +B0:D17:F0 D 17 +B3:D0:F0 A 18 +B3:D0:F0 B 19 +B3:D0:F0 C 16 +B3:D0:F0 D 17 diff --git a/tests/utils/environments/qnx8_qemu/configs/pci_server.cfg b/tests/utils/environments/qnx8_qemu/configs/pci_server.cfg new file mode 100644 index 00000000..899a56ba --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/pci_server.cfg @@ -0,0 +1,7 @@ +[buscfg] +DO_BUS_CONFIG=no + +[envars] +PCI_DEBUG_MODULE=pci_debug2.so +PCI_HW_MODULE=pci_hw-Intel_x86.so +PCI_HW_CONFIG_FILE=/proc/boot/pci_hw.cfg diff --git a/tests/utils/environments/qnx8_qemu/configs/profile b/tests/utils/environments/qnx8_qemu/configs/profile new file mode 100644 index 00000000..97e7e7ef --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/profile @@ -0,0 +1,18 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +export TERM=qansi +export PATH=/proc/boot +export LD_LIBRARY_PATH=/proc/boot +export MAGIC=/system/etc/magic diff --git a/tests/utils/environments/qnx8_qemu/configs/qcrypto.conf b/tests/utils/environments/qnx8_qemu/configs/qcrypto.conf new file mode 100644 index 00000000..b65b4c4a --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/qcrypto.conf @@ -0,0 +1 @@ +openssl-3 tags=* diff --git a/tests/utils/environments/qnx8_qemu/configs/ssh_host_rsa_key b/tests/utils/environments/qnx8_qemu/configs/ssh_host_rsa_key new file mode 100644 index 00000000..aff51a24 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/ssh_host_rsa_key @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn +NhAAAAAwEAAQAAAYEArR4LKpPGS2mqmnj+d4Y/0DLdYUVQ7hBaR/aYnNbZFUvO3nOFixa4 +u8pjRQbNFsERvY8o3Q1+SEg/xq+WC4vxhS9bjfMOxO29ncicvcDZR9kVOc/dNCLv6amdOy +9V/wN8rb7vy5KhPKF/uubj/HmcwRYZAYV3spR7C4OpN1tSZFBu/rcOYYYC7VxKcshEj8Yt +8QX7Bil+MIJHPLu7HTktgxDSp4Y3NUORoV9In1qM+rTJsxDHr3gfCOaN4OnQElwS7RfXx2 +BFcvA3d4JreynHocpLWUO6rrs1qjCsQZFPqQwBC7SDn8eiKy0XH+yPpioUaJ6L+YFqrk3c +KxijWKP5/aDuCQrw230mLtWatspHpNUXQSN1FQby6kqLUSV8gXX7lS91AMjdb3sqJ9ebxJ +xGARbp8ow1yRtTfqk6H04q2QgVQZ/Idso3TzQokt0K/feEdj7SwH3LsaAeMWPyo0WLUOk1 +8j46LUEayluF4UcIm8dnjoTywW9A/MS1C+2p4eTbAAAFeAU74GcFO+BnAAAAB3NzaC1yc2 +EAAAGBAK0eCyqTxktpqpp4/neGP9Ay3WFFUO4QWkf2mJzW2RVLzt5zhYsWuLvKY0UGzRbB +Eb2PKN0NfkhIP8avlguL8YUvW43zDsTtvZ3InL3A2UfZFTnP3TQi7+mpnTsvVf8DfK2+78 +uSoTyhf7rm4/x5nMEWGQGFd7KUewuDqTdbUmRQbv63DmGGAu1cSnLIRI/GLfEF+wYpfjCC +Rzy7ux05LYMQ0qeGNzVDkaFfSJ9ajPq0ybMQx694HwjmjeDp0BJcEu0X18dgRXLwN3eCa3 +spx6HKS1lDuq67NaowrEGRT6kMAQu0g5/HoistFx/sj6YqFGiei/mBaq5N3CsYo1ij+f2g +7gkK8Nt9Ji7VmrbKR6TVF0EjdRUG8upKi1ElfIF1+5UvdQDI3W97KifXm8ScRgEW6fKMNc +kbU36pOh9OKtkIFUGfyHbKN080KJLdCv33hHY+0sB9y7GgHjFj8qNFi1DpNfI+Oi1BGspb +heFHCJvHZ46E8sFvQPzEtQvtqeHk2wAAAAMBAAEAAAGAQMkziJWQ6fv7Wp/ZK0XUb8f5TU +Oxi8YW40OHzXoh93RNULaOzYSNUcnl6Jko+1D5oKUIt+Eq10Yih+qCDoQquJsGelLxvgTy +py/CaMjZB6hX5zDBKZfBjQJq0xFd73eQmz0PZHHVYWlW8c0imQOyBBiO9yDJsM0cVyzIkO +zeIqhvQWekPB74zXdybQ5BikSyQLbqQF4a2XCH1FS1K7SQMbKEAymZU5eb0nZkKS6r/87U +hOzMrgAYLS6K/hbCRXyrAlz61x2hMKTngb/ERWWilqJSGlF8Q4p2LmIxyUnll/C2cq2dvU +gMARPvZ3DL/QFl4fhLa20vTg83CQNaw6zuEAhTP8lmvDP+4DhtqUPno1T7161OpEHD/ZRb +oiwXmkwg+0yiR8a9OFiolAhwiqPhqC1W39+coEutjpbXQ1uJVoC0kWHMY9biBa7cb9Cxrq +boYLOs31sLhTWTrHgIgpsf/FSWYLF5hknZKpVhWQsfowyCtjn6uvVh+bcfUwOMCDthAAAA +wQDSHJTmW6o6uK53KE6t4c7x+G/qO2Y6FSRQuAbojL1o7gG0SYDFRR3k5fMQ/zqQ1pWrqR +5Im+InsfO5KG9489z/SCIXwPq6zev8WJjZV2P3A8qTBPzEeYmicZtJGH/sBuk8Oj/CdOKV ++GBzkqJdxruiNzLEIGS1gjserT6YJxmA5Q/j1Hiz+bSf66cHhGzmQ092tQ+gGvWPtbFn+D +YQVbp1GW8E6lbAOBew7IDcWp7LVDZuShBrDvFWtsaupZ7wYxoAAADBAOXzYeYNyrKsFCju +Qh1Bj0uVOf8lVvygGOzFA/OdqWuRr/h2aPsNYJFbdIiP61mvVd1umJ8BQDiXNlm/YpXOXu +jOm9a8BVKpMTtoohEkUbqBtv9vx+XHnhLCFYYL4GHJ9Dhj50L3djf++/HkahtZJlTkpSbt +/ukoZKI1m8MgpyC3xk2UDu1yWNizT2l1L7RnE+ZO4b5U9cONANiYBD8jcnZAvh4ld3ojo0 +iNXEVEGAKIodMUsgASxGwmoxuX3ugJIwAAAMEAwLp7eVBjg27eflRNYuW8akfDyq9zB1rp +YGo3GbPytb14WVJuyNL1tJ/B/rdFBg0IXf1FQJEL99kKJP5yDxjOx9kyXBhIWjm8arz39h +uw0wrsuRl2rrCfMABGS51GohtYmKETZ6x7/2n3l6iz/5mhRN8hW0JluJhKtj6ogO6GZERr +PTYwQs+9Q7QI1cPx7G5cEPhWhEd+OmKZuXRjhMQQ+ADj/lnUAhhGQatM9/bohJOdObWCRl +Fu+/MLbJQuA1zpAAAAAAEC +-----END OPENSSH PRIVATE KEY----- diff --git a/tests/utils/environments/qnx8_qemu/configs/ssh_host_rsa_key.pub b/tests/utils/environments/qnx8_qemu/configs/ssh_host_rsa_key.pub new file mode 100644 index 00000000..eee47d4f --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/ssh_host_rsa_key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCtHgsqk8ZLaaqaeP53hj/QMt1hRVDuEFpH9pic1tkVS87ec4WLFri7ymNFBs0WwRG9jyjdDX5ISD/Gr5YLi/GFL1uN8w7E7b2dyJy9wNlH2RU5z900Iu/pqZ07L1X/A3ytvu/LkqE8oX+65uP8eZzBFhkBhXeylHsLg6k3W1JkUG7+tw5hhgLtXEpyyESPxi3xBfsGKX4wgkc8u7sdOS2DENKnhjc1Q5GhX0ifWoz6tMmzEMeveB8I5o3g6dASXBLtF9fHYEVy8Dd3gmt7KcehyktZQ7quuzWqMKxBkU+pDAELtIOfx6IrLRcf7I+mKhRonov5gWquTdwrGKNYo/n9oO4JCvDbfSYu1Zq2ykek1RdBI3UVBvLqSotRJXyBdfuVL3UAyN1veyon15vEnEYBFunyjDXJG1N+qTofTirZCBVBn8h2yjdPNCiS3Qr994R2PtLAfcuxoB4xY/KjRYtQ6TXyPjotQRrKW4XhRwibx2eOhPLBb0D8xLUL7anh5Ns= diff --git a/tests/utils/environments/qnx8_qemu/configs/sshd_config b/tests/utils/environments/qnx8_qemu/configs/sshd_config new file mode 100644 index 00000000..4be18c46 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/sshd_config @@ -0,0 +1,64 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +# Port number for SSH +Port 22 + +# Protocol version +Protocol 2 + +# Host key location +HostKey /var/ssh/ssh_host_rsa_key + +# Enable port forwarding +AllowTcpForwarding yes + +# Enable SCP/SFTP +Subsystem sftp /usr/lib/ssh/sftp-server + +# AUTHENTICATION SETTINGS - Simple passwordless authentication +# Enable password authentication to check for empty passwords +PasswordAuthentication yes + +# Allow empty passwords (no password required) +PermitEmptyPasswords yes + +# Disable all other authentication methods completely +PubkeyAuthentication no +ChallengeResponseAuthentication no +HostbasedAuthentication no + +# Allow root login without authentication +PermitRootLogin yes + +# Allow user environment variables +PermitUserEnvironment yes + +# Don't create PID file +PidFile none + +# Log level for debugging +LogLevel DEBUG + +# Disable strict modes for easier setup +StrictModes no + +# Disable DNS lookups for faster connection +UseDNS no + +# Maximum authentication attempts +MaxAuthTries 3 + +# Disable login grace time +LoginGraceTime 30 diff --git a/tests/utils/environments/qnx8_qemu/configs/startup.sh b/tests/utils/environments/qnx8_qemu/configs/startup.sh new file mode 100644 index 00000000..14e4b553 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/configs/startup.sh @@ -0,0 +1,79 @@ +#!/bin/sh + +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +# ******************************************************************************* +# System Startup Script +# Executed during system initialization to start essential services +# ******************************************************************************* +echo "---> Starting slogger2" +slogger2 -s 4096 # Start system logger with 4KB buffer size for log messages +waitfor /dev/slog # Wait for system log device to become available + +echo "---> Starting PCI Services" +pci-server --config=/proc/boot/pci_server.cfg # Start PCI server with configuration file +waitfor /dev/pci # Wait for PCI device manager to initialize + +echo "---> Starting Pipe" +pipe # Start named pipe resource manager for IPC +waitfor /dev/pipe # Wait for pipe device to become available + +echo "---> Starting Random" +random # Start random number generator device +waitfor /dev/random # Wait for random device to become available + +echo "---> Starting fsevmgr" +fsevmgr # Start file system event manager for file notifications +waitfor /dev/fsnotify # Wait for filesystem notification device + +echo "---> Starting devb-ram" +devb-ram ram capacity=1 blk ramdisk=10m,cache=512k,vnode=256 2>/dev/null # Create 10MB RAM disk with 512KB cache +waitfor /dev/ram0 # Wait for RAM disk device to be ready + +echo "---> mounting ram disk" +mkqnx6fs -q /dev/ram0 # Create QNX6 filesystem on RAM disk (quiet mode) +waitfor /dev/ram0 # Wait for filesystem creation to complete +mount -t qnx6 /dev/ram0 /tmp_ram # Mount RAM disk as QNX6 filesystem at /tmp_ram + +echo "---> Starting mqueue" +mqueue # Start POSIX message queue resource manager +waitfor /dev/mqueue # Wait for message queue device to be available + +echo "---> Starting devc-pty" +devc-pty -n 32 # Start pseudo-terminal driver with 32 PTY pairs + +echo "---> Starting devb-eide" +devb-eide cam user=20:20 blk cache=64M,auto=partition,vnode=2000,ncache=2000,commit=low # Start IDE/SATA block driver +waitfor /dev/hd0 # Wait for first hard disk to be detected + +echo "---> Configuring network" +/etc/network_setup.sh # fixed IP setup --> commented out as dhcp is now in use + +echo "---> Setting hostname" +if [ -f /etc/hostname ]; then # Check if hostname file exists + HOSTNAME=$(cat /etc/hostname) # Read hostname from file + hostname "$HOSTNAME" # Set system hostname + echo "Hostname set to: $HOSTNAME" +else + hostname qnx-score # Set default hostname if no file exists + echo "Qnx_S-core" > /tmp/hostname # Create temporary hostname file + echo "Default hostname set to: Qnx_S-core" +fi + +echo "---> adding /tmp_discovery folder" +mkdir -p /tmp_ram/tmp_discovery +ln -sP /tmp_ram/tmp_discovery /tmp_discovery + +/proc/boot/sshd -f /var/ssh/sshd_config -E /tmp/sshd.log # Start SSH daemon with specified configuration file diff --git a/tests/utils/environments/qnx8_qemu/init.build b/tests/utils/environments/qnx8_qemu/init.build new file mode 100644 index 00000000..a7547556 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/init.build @@ -0,0 +1,98 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +############################################################################### +# +# Example image built based on minimal configuration from QNX +# +############################################################################### + +[-optional] + +[image=0x3600000] # Set image size to 56MB (0x3600000 bytes) +[virtual=x86_64,multiboot] boot = { # Configure for x86_64 architecture with multiboot support + # Use startup-x86 by default + startup-x86 -v -D8250..115200 -zz # Start x86 kernel with verbose output, serial console at 115200 baud + PATH=/proc/boot # Set executable search path to boot directory + LD_LIBRARY_PATH=/proc/boot # Set library search path to boot directory + [+keeplinked] procnto-smp-instr # Keep process manager linked and instrumented for SMP +} + +[+script] startup-script = { # Define startup script that runs during boot + procmgr_symlink /dev/shmem /tmp # Create symbolic link from shared memory to /tmp + # /tmp will be mounted later as a proper RAM disk + + display_msg Welcome to QNX OS 8.0 on x86_64 tweaked for S-CORE! # Display welcome message + + # These env variables get inherited by all programs which follow + SYSNAME=nto # Set system name to "nto" (Neutrino) + TERM=qansi # Set terminal type to QNX ANSI + + devc-ser8250 & # Start serial driver in background + waitfor /dev/ser1 # Wait for serial device to be available + reopen /dev/ser1 # Reopen serial device for console I/O + + display_msg Placeholder for startup script # Display startup message + etc/startup.sh # Execute main startup script + + [+session] /bin/sh & # Start shell session in background +} + +# Essential utilities - core system commands needed for basic operation +# These binaries provide fundamental system functionality and process management + +# Process and system management utilities +on # Command execution utility - runs commands with specific options +[type=link] waitfor=on # Create symbolic link: waitfor -> on (waits for resources to become available) +[type=link] ability=on # Create symbolic link: ability -> on (manages process abilities/privileges) + +# Shell and command interpreter +ksh # Korn shell - provides command-line interface and scripting +pidin # Process information display - shows running processes (like 'ps' on Linux) +[type=link] /bin/sh=/proc/boot/ksh # Create symbolic link: sh -> ksh (standard shell link) + +# File system utilities +mount # File system mount utility - mounts/unmounts file systems +getconf # System configuration query utility - retrieves system parameters +[type=link] setconf=getconf # Create symbolic link: setconf -> getconf (sets configuration parameters) + +# Device drivers for hardware access +devc-ser8250 # Serial port driver for 8250/16550 UART controllers (console access) + +# System logging utilities +slog2info # System log viewer - displays logged messages +slogger2 # System logging daemon - collects and manages log messages + +# Essential libraries - core runtime libraries required for system operation +# These libraries provide fundamental services like C runtime, networking, and logging + +# Standard C library - provides basic C runtime functions +libc.so.6 # Main C library (malloc, printf, file I/O, etc.) + +# Dynamic linker/loader - handles dynamic library loading at runtime +/usr/lib/ldqnx-64.so.2=ldqnx-64.so.2 # 64-bit QNX dynamic linker (loads shared libraries) + +# Networking library - provides socket and network communication functions +libsocket.so.4 # Socket library (TCP/IP, UDP, network I/O functions) +[type=link] libsocket.so=libsocket.so.4 # Create version-neutral symbolic link + +# System logging library - provides logging services for applications +libslog2.so.1 # System logging library (slog2_* functions) +[type=link] libslog2.so=libslog2.so.1 # Create version-neutral symbolic link + +# Storage driver - provides access to IDE/SATA block devices +devb-eide # Block device driver for IDE/SATA hard drives and SSDs + # Required for mounting QNX6 file systems from disk partitions + +[+include] tests/utils/environments/qnx8_qemu/system.build diff --git a/tests/utils/environments/qnx8_qemu/system.build b/tests/utils/environments/qnx8_qemu/system.build new file mode 100644 index 00000000..369ff5c1 --- /dev/null +++ b/tests/utils/environments/qnx8_qemu/system.build @@ -0,0 +1,275 @@ +# ******************************************************************************* +# Copyright (c) 2025 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + + +# ============================================================================ +# QNX System Build File - Defines system partition contents +# ============================================================================ +# This file defines the contents of the QNX system partition, including +# essential utilities, libraries, configuration files, and system services +# needed for a minimal QNX QEMU environment. + +############################################# +### SHARED LIBRARIES ### +############################################# +# Essential shared libraries for system operation + +libfsnotify.so.1 # File system notification library +cam-cdrom.so # CAM (Common Access Method) CD-ROM driver +cam-disk.so # CAM disk driver for storage devices +fs-dos.so # DOS file system support +fs-qnx6.so # QNX6 file system support +io-blk.so # Block I/O manager +libbz2.so.1 # BZip2 compression library +libc++.so.2 # C++ standard library +libc.so # C standard library (essential) +libcam.so.2 # CAM library for device access +libcatalog.so.1 # Message catalog support +libcrypto.so.3 # OpenSSL crypto library (disabled) +libfscrypto.so.1 # File system encryption support +libgcc_s.so.1 # GCC runtime support library +libiconv.so.1 # Character encoding conversion +liblzma.so.5 # LZMA compression library +libm.so # Math library +libpci.so.3.0 # PCI library v3.0 for hardware access +libqcrypto.so.1.0 # QNX cryptographic library +libqh.so # QNX helper library +libregex.so.1 # Regular expression library +libsecpol.so.1 # Security policy library +libslog2parse.so.1 # System log parsing library +libssl.so.3 # OpenSSL SSL/TLS library (disabled) +libtracelog.so.1 # Trace logging library +libxml2.so.2 # XML parsing library +libz.so # Zlib compression library +libexpat.so.2 # Expat XML parser library +libjail.so.1 # QNX jail library for process containment +qcrypto-openssl-3.so # QNX cryptographic library with OpenSSL 3 support +libpam.so.2 # Pluggable Authentication Modules library + + +############################################# +### FILE MANIPULATION UTILITIES ### +############################################# +# Core file system utilities - most are provided by toybox (minimal Unix utilities) + +[type=link] /bin/ls=/proc/boot/ls # Link ls to IFS version for compatibility +# Note: /bin/sh symlink already defined in init.build as /proc/boot/ksh +toybox # Minimal Unix utilities collection (replaces many GNU tools) +[type=link] cp=toybox # Copy files and directories +[type=link] ls=toybox # List directory contents +[type=link] cat=toybox # Display file contents +[type=link] chmod=toybox # Change file permissions +[type=link] rm=toybox # Remove files and directories +[type=link] dd=toybox # Convert and copy files with specified I/O block size +[type=link] echo=toybox # Display text +[type=link] grep=toybox # Search text patterns in files +[type=link] mkdir=toybox # Create directories +[type=link] ascii=toybox # Display ASCII character set +[type=link] base64=toybox # Base64 encoding/decoding utility +[type=link] basename=toybox # Extract filename from path +[type=link] bc=toybox # Basic calculator +[type=link] bunzip2=toybox # Decompress bzip2 files +[type=link] bzcat=toybox # Display contents of bzip2 files +[type=link] cal=toybox # Display calendar +[type=link] chgrp=toybox # Change group ownership +[type=link] chown=toybox # Change file ownership +[type=link] cksum=toybox # Calculate checksums +[type=link] clear=toybox # Clear terminal screen +[type=link] cmp=toybox # Compare files byte by byte +[type=link] comm=toybox # Compare sorted files line by line +[type=link] cpio=toybox # Copy files to/from archives +[type=link] crc32=toybox # Calculate CRC32 checksums +[type=link] cut=toybox # Extract columns from files +[type=link] date=toybox # Display or set system date +[type=link] diff=toybox # Compare files line by line +[type=link] dirname=toybox # Extract directory from path +[type=link] dos2unix=toybox # Convert DOS line endings to Unix +[type=link] du=toybox # Display disk usage +[type=link] egrep=toybox # Extended grep with regular expressions +[type=link] env=toybox # Display or set environment variables +[type=link] expand=toybox # Convert tabs to spaces +[type=link] expr=toybox # Evaluate expressions +[type=link] false=toybox # Return false status +[type=link] fgrep=toybox # Fast grep for fixed strings +[type=link] file=toybox # Determine file type +[type=link] find=toybox # Search for files and directories +[type=link] fmt=toybox # Format text paragraphs +[type=link] groups=toybox # Display user group membership +[type=link] gunzip=toybox # Decompress gzip files +[type=link] gzip=toybox # Compress files with gzip +[type=link] hd=toybox # Hexadecimal dump (alias for hexdump) +[type=link] head=toybox # Display first lines of files +[type=link] hexdump=toybox # Display files in hexadecimal format +[type=link] id=toybox # Display user and group IDs +[type=link] install=toybox # Copy files and set attributes +[type=link] link=toybox # Create hard links +[type=link] logname=toybox # Display login name +[type=link] md5sum=toybox # Calculate MD5 checksums +[type=link] mkfifo=toybox # Create named pipes (FIFOs) +[type=link] mktemp=toybox # Create temporary files/directories +[type=link] more=toybox # Display files page by page +[type=link] mv=toybox # Move/rename files and directories +[type=link] nl=toybox # Number lines in files +[type=link] nohup=toybox # Run commands immune to hangups +[type=link] od=toybox # Dump files in octal format +[type=link] paste=toybox # Merge lines from files +[type=link] patch=toybox # Apply patches to files +[type=link] printenv=toybox # Print environment variables +[type=link] printf=toybox # Format and print data +[type=link] pwd=toybox # Print working directory +[type=link] readlink=toybox # Display target of symbolic links +[type=link] realpath=toybox # Display absolute path +[type=link] rmdir=toybox # Remove empty directories +[type=link] sed=toybox # Stream editor for filtering/transforming text +[type=link] seq=toybox # Generate sequences of numbers +[type=link] sha1sum=toybox # Calculate SHA1 checksums +[type=link] sleep=toybox # Suspend execution for specified time +[type=link] sort=toybox # Sort lines in text files +[type=link] split=toybox # Split files into pieces +[type=link] stat=toybox # Display file/filesystem status +[type=link] strings=toybox # Extract printable strings from files +[type=link] tail=toybox # Display last lines of files +[type=link] tee=toybox # Copy input to files and stdout +[type=link] test=toybox # Evaluate conditional expressions +[type=link] time=toybox # Time command execution +[type=link] timeout=toybox # Run command with time limit +[type=link] touch=toybox # Update file timestamps +[type=link] tr=toybox # Translate or delete characters +[type=link] true=toybox # Return true status +[type=link] truncate=toybox # Truncate files to specified size +[type=link] tty=toybox # Display terminal name +[type=link] uname=toybox # Display system information +[type=link] uniq=toybox # Remove duplicate lines +[type=link] unix2dos=toybox # Convert Unix line endings to DOS +[type=link] unlink=toybox # Remove files (system call interface) +[type=link] uudecode=toybox # Decode uuencoded files +[type=link] uuencode=toybox # Encode files using uuencoding +[type=link] uuidgen=toybox # Generate UUIDs +[type=link] wc=toybox # Count lines, words, and characters +[type=link] which=toybox # Locate commands in PATH +[type=link] whoami=toybox # Display current username +[type=link] xargs=toybox # Execute commands from standard input +[type=link] xxd=toybox # Make hexdump or reverse +[type=link] yes=toybox # Output string repeatedly +[type=link] zcat=toybox # Display contents of compressed files +[type=link] nc=toybox # Netcat for network connections and packet streaming +[type=link] netcat=toybox # Netcat alias for network connections + + +############################################# +### Tools ### +############################################# +awk # Text processing and pattern scanning +devb-ram # RAM disk block device manager +devc-pty # Pseudo-terminal device manager +fsencrypt # File system encryption utility +fsevmgr # File system event manager +if_up # Network interface configuration +ifconfig # Network interface configuration tool +ln # Create file links +mkqnx6fs # Create QNX6 file systems +mount_ifs # Mount Image File System (IFS) +mqueue # POSIX message queue manager +openssl # SSL/TLS cryptographic toolkit +pci-server # PCI bus server +pdebug # Process debugger +pfctl # Packet filter control utility +pipe # Named pipe manager +random # Random number generator service +shutdown # System shutdown utility +sync # Synchronize file system buffers to disk +tar # Archive utility for creating/extracting tar files +umount # Unmount file systems +sysctl # Configure kernel parameters at runtime +sshd # SSH daemon for remote access +ssh # SSH client for remote connections +ssh-keygen # SSH key generation utility +hostname # Set or display system hostname +route +dhcpcd # DHCP client daemon for automatic network configuration +tcpdump # Network packet capture tool for Wireshark analysis +/usr/lib/ssh/sftp-server=${QNX_TARGET}/${PROCESSOR}/usr/libexec/sftp-server # File transfer server to enable scp + +############################################# +### NETWORKING COMPONENTS ### +############################################# +io-sock # Network socket manager +mods-pci.so # PCI module support for network hardware +mods-phy.so # Physical layer module for network interfaces +mods-usb.so # USB module support +libfdt.so.1 # Flattened Device Tree library +libusbdci.so.2 # USB device controller interface library +devs-vtnet_pci.so # VirtIO network device driver for QEMU/KVM +librpc.so.2 # For TCP dump + + +############################################# +### PCI COMPONENTS ### +############################################# +# PCI-related shared libraries and modules +pci/pci_hw-Intel_x86.so # Intel x86 PCI hardware support +pci/pci_slog2.so # PCI system logging support +pci/pci_cap-0x05.so # PCI capability handler for MSI +pci/pci_cap-0x10.so # PCI Express capability handler +pci/pci_cap-0x11.so # MSI-X capability handler +pci/pci_strings.so # PCI device string database +pci/pci_bkwd_compat.so # Backward compatibility support +pci/pci_debug2.so # Enhanced PCI debugging support + + +############################################# +### SYSTEM DIRECTORIES ### +############################################# +# Create SSH and system directories with appropriate permissions +[gid=0 uid=0 dperms=755 type=dir] /var/chroot/sshd # SSH chroot directory for privilege separation +[gid=0 uid=0 dperms=700 type=dir] /var/ssh # SSH configuration and key storage directory + + +############################################# +### SCRIPTS ### +############################################# +# System startup and initialization scripts +[perms=700] /etc/startup.sh = tests/utils/environments/qnx8_qemu/configs/startup.sh # Main system startup script +[perms=700] /etc/network_setup.sh = tests/utils/environments/qnx8_qemu/configs/network_setup.sh # Network configuration script + + +############################################# +### CONFIGURATION FILES ### +############################################# +# This section defines critical configuration files that control system +# behavior, hardware access, security policies, and user environment setup. + +[perms=0444] pci_server.cfg = tests/utils/environments/qnx8_qemu/configs/pci_server.cfg # PCI server configuration +[perms=0444] pci_hw.cfg = tests/utils/environments/qnx8_qemu/configs/pci_hw.cfg # PCI hardware configuration +[perms=0444] qcrypto.conf = tests/utils/environments/qnx8_qemu/configs/qcrypto.conf # QNX cryptographic library configuration + +# System hostname configuration +/etc/hostname = tests/utils/environments/qnx8_qemu/configs/hostname # System hostname definition file +/etc/profile = tests/utils/environments/qnx8_qemu/configs/profile + +# System user and group databases +/etc/passwd = tests/utils/environments/qnx8_qemu/configs/passwd # User account database with login information +/etc/group = tests/utils/environments/qnx8_qemu/configs/group # Group membership database + + +############################################# +### SSH CONFIGURATION ### +############################################# +# SSH server configuration (no static host keys - generated at runtime) +[perms=444] /var/ssh/sshd_config = tests/utils/environments/qnx8_qemu/configs/sshd_config # SSH daemon configuration file + +[uid=0 gid=0 perms=400] /var/ssh/ssh_host_rsa_key = tests/utils/environments/qnx8_qemu/configs/ssh_host_rsa_key # SSH server private key +[uid=0 gid=0 perms=400] /var/ssh/ssh_host_rsa_key.pub = tests/utils/environments/qnx8_qemu/configs/ssh_host_rsa_key.pub # SSH server public key + +# DHCP client configuration +[perms=644] /etc/dhcpcd.conf = tests/utils/environments/qnx8_qemu/configs/dhcpcd.conf # DHCP client configuration file diff --git a/tests/utils/environments/target_config.json b/tests/utils/environments/target_config.json new file mode 100644 index 00000000..0921d515 --- /dev/null +++ b/tests/utils/environments/target_config.json @@ -0,0 +1,29 @@ +{ + "S_CORE_ECU_QEMU": { + "performance_processor": { + "name": "S_CORE_ECU_QEMU_PP", + "ip_address": "192.168.100.10", + "ext_ip_address": "192.168.100.10", + "host_ip": "192.168.100.1", + "ssh_port": 22, + "diagnostic_ip_address": "0.0.0.0", + "diagnostic_address": "0x90", + "serial_device": "", + "network_interfaces": [], + "ecu_name": "s_core_ecu_qemu_pp", + "data_router_config": {}, + "qemu_num_cores": 2, + "qemu_ram_size": "1G" + }, + "safety_processor": { + "name": "S_CORE_ECU_QEMU_SC", + "ip_address": "192.168.115.20", + "diagnostic_ip_address": "0.0.0.0", + "diagnostic_address": "0x90", + "serial_device": "", + "use_doip": true + }, + "other_processors": {} + } +} + diff --git a/tests/utils/fixtures/BUILD b/tests/utils/fixtures/BUILD new file mode 100644 index 00000000..bdc626f7 --- /dev/null +++ b/tests/utils/fixtures/BUILD @@ -0,0 +1,32 @@ +load("@pip_score_venv_test//:requirements.bzl", "requirement") +load("@rules_python//python:defs.bzl", "py_library") + +py_library( + name = "fixtures", + srcs = [ + "target.py", + "ssh.py", + "control_interface.py", + "linux_interface.py", + "__init__.py", + ], + visibility = ["//tests:__subpackages__"], + deps = [ + requirement("pytest"), + "@score_itf//itf/core/qemu", + "@score_itf//itf/core/com:ssh", + "@score_itf//itf/core/utils/process", + ":conf" + ], + tags = [ + "local", + "integration" + ] +) + + +py_library( + name="conf", + srcs = [ "conftest.py" ], + visibility = ["//tests:__subpackages__"], +) diff --git a/tests/utils/fixtures/README.md b/tests/utils/fixtures/README.md new file mode 100644 index 00000000..e69de29b diff --git a/tests/utils/fixtures/__init__.py b/tests/utils/fixtures/__init__.py new file mode 100644 index 00000000..7e21ac02 --- /dev/null +++ b/tests/utils/fixtures/__init__.py @@ -0,0 +1,16 @@ +from .control_interface import ControlInterface +from .linux_interface import LinuxControl +from .ssh import SshInterface +from itf.core.com.ssh import Ssh +import pytest + +@pytest.fixture +def control_interface(target, request) -> ControlInterface: + + # if no image provided then run natively + if not request.config.getoption("--image-path"): + yield LinuxInterface + else: + with Ssh("192.168.100.10") as ssh: + yield SshInterface(ssh) + diff --git a/tests/utils/fixtures/conftest.py b/tests/utils/fixtures/conftest.py new file mode 100644 index 00000000..9da44a47 --- /dev/null +++ b/tests/utils/fixtures/conftest.py @@ -0,0 +1,18 @@ +import pytest + +def pytest_addoption(parser): + parser.addoption( + "--image-path", + action="store", + required=False, + help="Path to the image file for the target", + ) +# +# def pytest_addoption(parser): +# parser.addoption( +# "--lcm-path", +# action="store", +# required=False, +# help="Path to the lcm executable", +# ) +# diff --git a/tests/utils/fixtures/control_interface.py b/tests/utils/fixtures/control_interface.py new file mode 100644 index 00000000..668ae76b --- /dev/null +++ b/tests/utils/fixtures/control_interface.py @@ -0,0 +1,58 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +from typing import Tuple +from pathlib import Path +from abc import ABC, abstractmethod + + +class ControlInterface(ABC): + """Platform independent interface to execute commands on the target""" + + @abstractmethod + def exec_command_blocking( + *args: str, timeout=1, **env: str + ) -> Tuple[int, str, str]: + """Execute a command on the target + + Args: + *args (str): Command to run with arguments + timeout (int): Time in seconds to exit after, returning status -1 + **env (str): Environment vars to set + + Returns: + (int, str, str): exit_status, stdout, stderr + """ + raise NotImplementedError() + + @abstractmethod + def run_until_file_deployed( + *args, + timeout=1, + file_path=Path("tests/integration/test_end"), + poll_interval=0.05, + **env, + ) -> Tuple[int, str, str]: + """Launch a process and terminate it once a given file has been deployed + + Args: + + *args (str): Command to run with arguments + timeout (int): Time in seconds to exit after, returning status -1 + file_path (Path): File to wait for + poll_interval (float): How often, in seconds, to check if we should terminate the process + **env (str): Environment vars to set + + Returns: + (int, str, str): exit_status, stdout, stderr + """ + raise NotImplementedError() diff --git a/tests/utils/fixtures/linux_interface.py b/tests/utils/fixtures/linux_interface.py new file mode 100644 index 00000000..c1199d1c --- /dev/null +++ b/tests/utils/fixtures/linux_interface.py @@ -0,0 +1,189 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +import signal +import subprocess +import shutil +import threading +import time +from typing import List, Optional, Tuple, Literal +from pathlib import Path +import os +from .control_interface import ControlInterface + +_TIMEOUT_CODE = -1 + + +class LinuxControl(ControlInterface): + def exec_command_blocking(*args, timeout=1, **env) -> Tuple[int, str, str]: + try: + res = subprocess.run( + args, env=env, capture_output=True, text=True, timeout=timeout + ) + return res.returncode, "".join(res.stdout), "".join(res.stderr) + except subprocess.TimeoutExpired as ex: + return _TIMEOUT_CODE, ex.output.decode("utf-8"), ex.stderr + + def _reader(stream, sink: List[str]): + """Read text lines from a stream until EOF and append to sink.""" + try: + for line in iter(stream.readline, ""): + if not line: + break + sink.append(line) + finally: + try: + stream.close() + except Exception: + pass + + def _terminate_process_group( + proc: subprocess.Popen, sigterm_timeout_seconds: float + ): + """Terminate all processes in a processgroup. Graceful termination is + attempted before SIGKILL is sent""" + if proc.poll() is not None: + return # already exited + + try: + os.killpg(proc.pid, signal.SIGTERM) + except Exception: + proc.terminate() + + deadline = time.time() + sigterm_timeout_seconds + while time.time() < deadline: + if proc.poll() is not None: + return + time.sleep(0.05) + + # Force kill + try: + os.killpg(proc.pid, signal.SIGKILL) + except Exception: + proc.kill() + + def run_until_file_deployed( + *args, + timeout=1, + file_path=Path("tests/integration/test_end"), + poll_interval=0.05, + **env, + ) -> Tuple[int, str, str]: + proc = subprocess.Popen( + ("/usr/bin/fakeroot", "/usr/bin/fakechroot", "-s", "chroot", ".", *args), + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + bufsize=1, + text=True, + preexec_fn=os.setsid, # start the process in its own process group so we can signal the whole group + ) + + # Start reader threads to capture stdout/stderr without blocking + stdout_lines: List[str] = [] + stderr_lines: List[str] = [] + t_out = threading.Thread( + target=LinuxControl._reader, args=(proc.stdout, stdout_lines), daemon=True + ) + t_err = threading.Thread( + target=LinuxControl._reader, args=(proc.stderr, stderr_lines), daemon=True + ) + t_out.start() + t_err.start() + + start = time.time() + deadline = start + timeout + + exit_code: Optional[int] = None + + try: + while True: + rc = proc.poll() + if rc is not None: # Exited already + exit_code = rc + break + + now = time.time() + + if file_path.exists(): + exit_code = 0 + LinuxControl._terminate_process_group(proc, timeout) + os.remove(file_path) + break + + if now >= deadline: + exit_code = _TIMEOUT_CODE + LinuxControl._terminate_process_group(proc, timeout) + break + + time.sleep(poll_interval) + except KeyboardInterrupt: + LinuxControl._terminate_process_group(proc, timeout) + + # Ensure readers finish + t_out.join(timeout=2.0) + t_err.join(timeout=2.0) + + return exit_code, "".join(stdout_lines), "".join(stderr_lines) + + +def get_common_interface() -> ControlInterface: + """Get a platform independent façade to execute commands on the target""" + match get_platform(): + case "linux": + return LinuxControl + case "qemu": + raise NotImplementedError("QEMU façade is not yet implemented") + case _: + raise KeyError("Platform not recognised") + + +def get_platform() -> Literal["linux", "qemu"]: + return "linux" + + +def get_bazel_out_dir() -> Path: + """Files written to this location are accessible from `bazel-out` when + `--remote_download_outputs=all` + """ + return Path(os.environ.get("TEST_UNDECLARED_OUTPUTS_DIR")) + + +def check_for_failures(path: Path, expected_count: int): + """Check expected_count xml files for failures, raising an exception if + a failure is found or a different number of xml files are found. + """ + failing_files = [] + checked_files = [] + for file in path.iterdir(): + if file.suffix == ".xml": + gtest_xml = open(file).read() + query = 'failures="' + failure_number = gtest_xml[gtest_xml.find(query) + len(query)] + if failure_number != "0": + failing_files.append(file.name) + checked_files.append(file.name) + shutil.copy(file, get_bazel_out_dir()) + if len(failing_files) > 0: + raise RuntimeError( + f"Failures found in the following files:\n {'\n'.join(failing_files)}" + ) + if len(checked_files) != expected_count: + raise RuntimeError( + f"Expected to find {expected_count} xml files, instead found {len(checked_files)}:\n{'\n'.join(checked_files)}" + ) + + +def format_logs(exit_code: int, stdout: str, stderr: str) -> str: + """Human-readable format for exit code, stdout and stderr""" + extra_info = " (timeout)" if exit_code == _TIMEOUT_CODE else "" + return f"stdout:\n{stdout}\n\nstderr:\n{stderr}\n\nExit status = {exit_code}{extra_info}" diff --git a/tests/utils/fixtures/ssh.py b/tests/utils/fixtures/ssh.py new file mode 100644 index 00000000..eebaf880 --- /dev/null +++ b/tests/utils/fixtures/ssh.py @@ -0,0 +1,48 @@ +from tests.utils.fixtures.target import target +from tests.utils.fixtures.control_interface import ControlInterface +from itf.core.com.ssh import execute_command, Ssh +from typing import Tuple +from pathlib import Path +import pytest +import logging + + +logger = logging.getLogger(__name__) + +class SshInterface(ControlInterface): + """ + """ + + def __init__(self, ssh: Ssh): + self.__ssh = ssh + + def exec_command_blocking(self, + *args: str, timeout=1, **env: str + ) -> Tuple[int, str, str]: + stdin, stdout, stderr = self.__ssh.exec_command(' '.join(args)) + + ret_code = stdout.channel.recv_exit_status() + + return ret_code, stdout.read().decode('utf-8'), stderr.read().decode('utf-8') + + + def run_until_file_deployed(self, + *args, + timeout=1, + file_path=Path("tests/integration/test_end"), + poll_interval=0.05, + **env, + ) -> Tuple[int, str, str]: + pass + +@pytest.fixture +def ssh(target) -> SshInterface: + + logger.info("Starting SSH Connection") + with Ssh("192.168.100.10") as ssh: + + yield SshInterface(ssh) + + logger.info("Closing SSH Connection") + + diff --git a/tests/utils/fixtures/target.py b/tests/utils/fixtures/target.py new file mode 100644 index 00000000..f220f8b6 --- /dev/null +++ b/tests/utils/fixtures/target.py @@ -0,0 +1,41 @@ +import pytest +from typing import Optional +import logging +from time import sleep +from subprocess import Popen, PIPE, STDOUT +from pathlib import Path + +from itf.core.qemu.qemu import Qemu +from itf.core.com.ssh import Ssh +from itf.core.utils.process.console import PipeConsole + +logger = logging.getLogger(__name__) + +@pytest.fixture +def target(request) -> Optional[Popen]: + """Returns the target instance + """ + + logger.info("Starting Target") + subprocess_params = { + "stdin": PIPE, + "stdout": PIPE, + "stderr": STDOUT, + } + + # if no image provided then run natively + if not request.config.getoption("--image-path"): + yield None + + image_location = Path(request.config.getoption("--image-path")) + if not image_location.is_file(): + raise RuntimeError("No image") + qemu = Qemu(str(image_location), + host_first_network_device_ip_address="192.168.100.1") + + proc = qemu.start(subprocess_params) + # console = PipeConsole("QEMU", proc) + sleep(2) + yield qemu + logger.info("Closing Target") + qemu.stop() diff --git a/tests/utils/requirements.lock b/tests/utils/requirements.lock new file mode 100644 index 00000000..22a31765 --- /dev/null +++ b/tests/utils/requirements.lock @@ -0,0 +1,31 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# bazel run //tests/integration:requirements.update +# +basedpyright==1.29.2 \ + --hash=sha256:12c49186003b9f69a028615da883ef97035ea2119a9e3f93a00091b3a27088a6 \ + --hash=sha256:f389e2997de33d038c5065fd85bff351fbdc62fa6d6371c7b947fc3bce8d437d +iniconfig==2.1.0 \ + --hash=sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7 \ + --hash=sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760 +nodejs-wheel-binaries==22.16.0 \ + --hash=sha256:2728972d336d436d39ee45988978d8b5d963509e06f063e80fe41b203ee80b28 \ + --hash=sha256:2fffb4bf1066fb5f660da20819d754f1b424bca1b234ba0f4fa901c52e3975fb \ + --hash=sha256:447ad796850eb52ca20356ad39b2d296ed8fef3f214921f84a1ccdad49f2eba1 \ + --hash=sha256:4ae3cf22138891cb44c3ee952862a257ce082b098b29024d7175684a9a77b0c0 \ + --hash=sha256:71f2de4dc0b64ae43e146897ce811f80ac4f9acfbae6ccf814226282bf4ef174 \ + --hash=sha256:7f526ca6a132b0caf633566a2a78c6985fe92857e7bfdb37380f76205a10b808 \ + --hash=sha256:986b715a96ed703f8ce0c15712f76fc42895cf09067d72b6ef29e8b334eccf64 \ + --hash=sha256:d695832f026df3a0cf9a089d222225939de9d1b67f8f0a353b79f015aabbe7e2 \ + --hash=sha256:dbfccbcd558d2f142ccf66d8c3a098022bf4436db9525b5b8d32169ce185d99e +packaging==25.0 \ + --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \ + --hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f +pluggy==1.6.0 \ + --hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \ + --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746 +pytest==8.3.5 \ + --hash=sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820 \ + --hash=sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845 diff --git a/tests/utils/requirements.txt b/tests/utils/requirements.txt new file mode 100644 index 00000000..55b033e9 --- /dev/null +++ b/tests/utils/requirements.txt @@ -0,0 +1 @@ +pytest \ No newline at end of file diff --git a/tests/utils/test_helper.hpp b/tests/utils/test_helper.hpp new file mode 100644 index 00000000..b9fdf76f --- /dev/null +++ b/tests/utils/test_helper.hpp @@ -0,0 +1,86 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#include +#include +#include +#include + +/// @return File path to an xml adjacent to the input file path +std::string xmlPath(const std::string_view file) { + return std::filesystem::path{file}.filename().stem().string() + ".xml"; +} + +/// @brief Creates an empty file. +/// @return AssertionSuccess if the file is correctly created. +inline testing::AssertionResult touch_file(const std::string_view file_path) { + auto openRes = fopen(file_path.data(), "w+"); + if (!openRes) + return testing::AssertionFailure() + << "Could not touch file " << file_path << " errno: " << errno << " message: " << strerror(errno); + + if (fclose(openRes) != 0) + return testing::AssertionFailure() + << "Couldn't close opened file " << file_path << " errno: " << errno << " message: " << strerror(errno); + return testing::AssertionSuccess(); +} + +#define TEST_STEP(message) \ + for (bool once = \ + (std::cout << "[ STEP ] " << (message) << std::endl, \ + true); \ + once; \ + (std::cout << "[ END STEP ] " << (message) << std::endl), \ + once = false) + + +/// @brief Helper class to setup, run, and clean up GTEST tests +class TestRunner { + inline static std::atomic exitRequested = false; + + static void signalHandler(int) { + exitRequested = true; + } + + bool signal_completion; + +public: + /// @brief TestRunner constructor + /// @param[in] test_path location to write the GTEST xml file (usually __FILE__) + /// @param[in] do_signal_completion whether this test should deploy a file signaling the test has completed + /// Usually the control daemon should deploy this file. + TestRunner(std::string test_path, bool do_signal_completion=false) { + ::testing::GTEST_FLAG(output) = "xml:" + xmlPath(test_path); + testing::InitGoogleTest(); + + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); + signal_completion = do_signal_completion; + } + + ~TestRunner() { + if (!exitRequested) { + pause(); + } + + if (signal_completion) { + static_cast(touch_file("../test_end")); + } + } + + /// @brief Use this function in main() to run all tests. It returns 0 if all tests are successful, or 1 otherwise. + int RunTests() { + auto res = RUN_ALL_TESTS(); + + return res; + } +}; \ No newline at end of file