diff --git a/.github/tools/qnx_credential_helper.py b/.github/tools/qnx_credential_helper.py new file mode 100755 index 0000000000..06ae795160 --- /dev/null +++ b/.github/tools/qnx_credential_helper.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +# ******************************************************************************* +# 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 +# ******************************************************************************* + +import http.cookiejar +import json +import netrc +import os +import sys +import urllib.parse +import urllib.request + + +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + + +if __name__ == "__main__": + data = json.load(sys.stdin) + + if "qnx.com" not in data["uri"]: + eprint("Unsupported domain") + sys.exit(1) + + if "SCORE_QNX_USER" in os.environ and "SCORE_QNX_PASSWORD" in os.environ: + login = os.environ["SCORE_QNX_USER"] + password = os.environ["SCORE_QNX_PASSWORD"] + else: + try: + nrc = netrc.netrc() + auth = nrc.authenticators("qnx.com") + if auth: + login, _, password = auth + else: + raise Exception("No credential found for QNX") + except Exception as excp: + eprint(excp) + eprint("Failed getting credentials from .netrc") + sys.exit(1) + + data = urllib.parse.urlencode( + {"userlogin": login, "password": password, "UseCookie": "1"} + ) + data = data.encode("ascii") + + cookie_jar = http.cookiejar.CookieJar() + cookie_processor = urllib.request.HTTPCookieProcessor(cookie_jar) + opener = urllib.request.build_opener(cookie_processor) + urllib.request.install_opener(opener) + + r = urllib.request.urlopen("https://www.qnx.com/account/login.html", data) + if r.status != 200: + eprint("Failed to login to QNX") + sys.exit(1) + + cookies = {c.name: c.value for c in list(cookie_jar)} + if not "myQNX" in cookies: + eprint("Failed to get myQNX cookie from login page") + sys.exit(1) + + myQNX = cookies["myQNX"] + print( + json.dumps( + { + "headers": { + "Cookie": [f"myQNX={myQNX}"], + } + } + ) + ) diff --git a/.github/workflows/build_and_test_on_every_pr.yml b/.github/workflows/build_and_test_on_every_pr.yml new file mode 100644 index 0000000000..5e68aec34e --- /dev/null +++ b/.github/workflows/build_and_test_on_every_pr.yml @@ -0,0 +1,56 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* + +name: Test reference integration +on: + pull_request: + types: [opened, reopened, synchronize] + merge_group: + types: [checks_requested] + +permissions: + contents: write + +jobs: + test_reference_integration: + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.2 + - name: Setup Bazel + uses: bazel-contrib/setup-bazel@0.9.1 + - name: Setup QNX License + env: + SCORE_QNX_LICENSE: ${{ secrets.SCORE_QNX_LICENSE }} + run: | + mkdir -p /opt/score_qnx/license + echo "${SCORE_QNX_LICENSE}" | base64 --decode > /opt/score_qnx/license/licenses + - name: Install qemu + run: | + sudo apt-get update + sudo apt-get install -y qemu-system + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + - name: Bazel execute itf qnx_qemu tests + env: + SCORE_QNX_USER: ${{ secrets.SCORE_QNX_USER }} + SCORE_QNX_PASSWORD: ${{ secrets.SCORE_QNX_PASSWORD }} + run: | + cd qnx_qemu + bazel test --config=qemu-integration --test_output=streamed --credential_helper=*.qnx.com=${{ github.workspace }}/.github/tools/qnx_credential_helper.py -- \ + //:test_ssh_qemu \ + //:test_scrample_qemu \ + diff --git a/.github/workflows/release_verification.yml b/.github/workflows/release_verification.yml new file mode 100644 index 0000000000..013e06a426 --- /dev/null +++ b/.github/workflows/release_verification.yml @@ -0,0 +1,68 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* + +# Workflow configuration for S-CORE CI - Release Check +# This workflow runs Bazel build and test when triggered by tag creation. + +name: Test reference integration +on: + push: + tags: + - 'v*' # Triggers on version tags like v1.0.0 + - 'release-*' # Triggers on release tags like release-1.0.0 + +permissions: + contents: write + +jobs: + test_target: + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.2 + - name: Setup Bazel + uses: bazel-contrib/setup-bazel@0.9.1 + - name: Setup QNX License + env: + SCORE_QNX_LICENSE: ${{ secrets.SCORE_QNX_LICENSE }} + run: | + mkdir -p /opt/score_qnx/license + echo "${SCORE_QNX_LICENSE}" | base64 --decode > /opt/score_qnx/license/licenses + - name: Install qemu + run: | + sudo apt-get update + sudo apt-get install -y qemu-system + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + - name: Bazel execute itf qnx_qemu tests + env: + SCORE_QNX_USER: ${{ secrets.SCORE_QNX_USER }} + SCORE_QNX_PASSWORD: ${{ secrets.SCORE_QNX_PASSWORD }} + run: | + cd qnx_qemu + bazel test --config=qemu-integration --test_output=streamed --credential_helper=*.qnx.com=${{ github.workspace }}/.github/tools/qnx_credential_helper.py -- \ + //:test_ssh_qemu \ + //:test_scrample_qemu \ + release_verification: + runs-on: ubuntu-latest + needs: [test_target] + if: always() && (needs.test_target.result == 'failure') + steps: + - name: Remove release and tag (if exists) + uses: nikhilbadyal/ghaction-rm-releases@v0.7.0 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_PATTERN: ${{ github.ref_name }} diff --git a/qnx_qemu/BUILD b/qnx_qemu/BUILD index 8397709945..030893978d 100644 --- a/qnx_qemu/BUILD +++ b/qnx_qemu/BUILD @@ -95,3 +95,22 @@ py_itf_test( "target_config.json", ], ) + +py_itf_test( + name = "test_scrample_qemu", + srcs = [ + "test/itf/test_scrample.py", + ], + args = [ + "--target_config=$(location target_config.json)", + "--ecu=s_core_ecu_qemu", + "--qemu_image=$(location //build:init)", + ], + plugins = [ + "itf.plugins.base.base_plugin", + ], + data = [ + "//build:init", + "target_config.json", + ], +) diff --git a/qnx_qemu/MODULE.bazel b/qnx_qemu/MODULE.bazel index bc48df30cf..6f8af0ea7d 100644 --- a/qnx_qemu/MODULE.bazel +++ b/qnx_qemu/MODULE.bazel @@ -11,32 +11,11 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* module( - name = "score_toolchains_qnx_tests", + name = "score_ri_qnx_qemu", version = "0.0.1", compatibility_level = 0, ) -bazel_dep(name = "score_toolchains_qnx", version = "0.0.2") -git_override( - module_name = "score_toolchains_qnx", - commit = "faa88ee7b26c82b23127b4493f140c15df4c7b8d", - remote = "https://github.com/eclipse-score/toolchains_qnx.git", -) - - -toolchains_qnx = use_extension("@score_toolchains_qnx//:extensions.bzl", "toolchains_qnx") -toolchains_qnx.sdp( - sha256 = "f2e0cb21c6baddbcb65f6a70610ce498e7685de8ea2e0f1648f01b327f6bac63", - strip_prefix = "installation", - url = "https://www.qnx.com/download/download/79858/installation.tgz", -) -use_repo(toolchains_qnx, "toolchains_qnx_sdp") -use_repo(toolchains_qnx, "toolchains_qnx_qcc") -use_repo(toolchains_qnx, "toolchains_qnx_ifs") - -register_toolchains("@toolchains_qnx_qcc//:qcc_x86_64") -register_toolchains("@toolchains_qnx_ifs//:ifs_x86_64") - ############################################################################### # # Shell dependency @@ -63,35 +42,53 @@ use_repo(python) ############################################################################### # -# LLVM Toolchains +# GCC Toolchains # ############################################################################### -bazel_dep(name = "toolchains_llvm", version = "1.2.0") +# Configure the host toolchain. +bazel_dep(name = "score_toolchains_gcc", version = "0.5", dev_dependency=True) +gcc = use_extension("@score_toolchains_gcc//extentions:gcc.bzl", "gcc", dev_dependency=True) +gcc.toolchain( + url = "https://github.com/eclipse-score/toolchains_gcc_packages/releases/download/0.0.1/x86_64-unknown-linux-gnu_gcc12.tar.gz", + sha256 = "457f5f20f57528033cb840d708b507050d711ae93e009388847e113b11bf3600", + strip_prefix = "x86_64-unknown-linux-gnu", +) +gcc.extra_features( + features = [ + "minimal_warnings", + "treat_warnings_as_errors", + ], +) +gcc.warning_flags( + minimal_warnings = ["-Wall", "-Wno-error=deprecated-declarations", "-Wno-error=narrowing"], + strict_warnings = ["-Wextra", "-Wpedantic"], +) +use_repo(gcc, "gcc_toolchain", "gcc_toolchain_gcc") -llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm") -llvm.toolchain( - cxx_standard = {"": "c++17"}, - llvm_version = "19.1.0", +register_toolchains("@gcc_toolchain//:all") + +# Configure target toolchain for QNX build. +bazel_dep(name = "score_toolchains_qnx", version = "0.0.3") +toolchains_qnx = use_extension("@score_toolchains_qnx//:extensions.bzl", "toolchains_qnx") +toolchains_qnx.sdp( + sha256 = "f2e0cb21c6baddbcb65f6a70610ce498e7685de8ea2e0f1648f01b327f6bac63", + strip_prefix = "installation", + url = "https://www.qnx.com/download/download/79858/installation.tgz", ) -use_repo(llvm, "llvm_toolchain") -use_repo(llvm, "llvm_toolchain_llvm") +use_repo(toolchains_qnx, "toolchains_qnx_sdp") +use_repo(toolchains_qnx, "toolchains_qnx_qcc") +use_repo(toolchains_qnx, "toolchains_qnx_ifs") -register_toolchains("@llvm_toolchain//:all") +register_toolchains("@toolchains_qnx_qcc//:qcc_x86_64") +register_toolchains("@toolchains_qnx_ifs//:ifs_x86_64") ############################################################################### # -# C++ rules +# Other dependencies # ############################################################################### bazel_dep(name = "rules_cc", version = "0.1.1") - -############################################################################### -# -# ITF dependency -# -############################################################################### bazel_dep(name = "score_itf", version = "0.1.0") - bazel_dep(name = "score_baselibs", version = "0.1.3") bazel_dep(name = "score_communication", version = "0.0.1") @@ -100,7 +97,6 @@ git_override( commit = "2d0d067b064a6e27d115f382bc938a30d44f08e7", remote = "https://github.com/eclipse-score/communication.git", ) - bazel_dep(name = "scrample", version = "0.0.1") git_override( module_name = "scrample", @@ -108,8 +104,6 @@ git_override( remote = "https://github.com/eclipse-score/scrample.git", ) - - bazel_dep(name = "rules_boost", repo_name = "com_github_nelhage_rules_boost") archive_override( module_name = "rules_boost", diff --git a/qnx_qemu/configs/network_setup_dhcp.sh b/qnx_qemu/configs/network_setup_dhcp.sh index 7aa1547782..1b88acf568 100644 --- a/qnx_qemu/configs/network_setup_dhcp.sh +++ b/qnx_qemu/configs/network_setup_dhcp.sh @@ -41,13 +41,7 @@ MAX_RETRIES=10 # 10 retries * 3 seconds = 30 seconds tot while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do # Get current IP address for vtnet0 - - # It can happen that dhcpcd at the beggining assigns an APIPA address (169.254.x.x) - # Wait for the correct IP assignment - IP_ADDR_TO_CHECK=$(ifconfig vtnet0 | grep 'inet ' | awk '{print $2}') - if ! echo "$IP_ADDR_TO_CHECK" | grep -q "^169\.254"; then - IP_ADDR=$IP_ADDR_TO_CHECK - fi + IP_ADDR=$(ifconfig vtnet0 | grep 'inet ' | awk '{print $2}') if [ -n "$IP_ADDR" ] && [ "$IP_ADDR" != "0.0.0.0" ]; then echo "---> DHCP successful! Acquired IP" @@ -95,4 +89,4 @@ fi # Configure system network settings sysctl -w net.inet.icmp.bmcastecho=1 > /dev/null # Enable ICMP broadcast echo (responds to broadcast pings) -echo "---> Network configuration completed" +echo "---> Network configuration completed" \ No newline at end of file diff --git a/qnx_qemu/test/itf/test_scrample.py b/qnx_qemu/test/itf/test_scrample.py new file mode 100644 index 0000000000..e9533f6645 --- /dev/null +++ b/qnx_qemu/test/itf/test_scrample.py @@ -0,0 +1,39 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* +from itf.plugins.com.ping import ping +from itf.plugins.com.ssh import execute_command_output +import logging + +logger = logging.getLogger(__name__) + + +def test_scrample_app_is_deployed(target_fixture): + with target_fixture.sut.ssh() as ssh: + exit_code, stdout, stderr = execute_command_output( + ssh, "test -f scrample" + ) + assert exit_code == 0, "SSH command failed" + + +def test_scrample_app_is_running(target_fixture): + with target_fixture.sut.ssh() as ssh: + exit_code, stdout, stderr = execute_command_output( + ssh, "./scrample -n 10 -t 100 -m send & ./scrample -n 5 -t 100 -m recv", + timeout = 30, max_exec_time = 180, + logger_in = logger, verbose = True, + ) + + logger.info (stdout) + logger.info (stderr) + + assert exit_code == 0, "SSH command failed"