From 96bb98bef3083342edb3e334a1b18d199b40d421 Mon Sep 17 00:00:00 2001 From: Pablo Erhard Date: Mon, 6 Jul 2026 09:57:49 -0600 Subject: [PATCH 1/2] Use release-aware Node runtimes for dd-trace-js SSI tests --- tests/auto_inject/test_auto_inject_install.py | 7 +- tests/docker_ssi/test_docker_ssi.py | 13 ++- tests/docker_ssi/test_docker_ssi_appsec.py | 3 +- tests/docker_ssi/test_docker_ssi_crash.py | 6 +- tests/test_the_test/test_nodejs_runtime.py | 83 ++++++++++++++++ .../nodejs/provision_test-app-nodejs-22.yml | 45 +++++++++ ...provision_test-app-nodejs-container-22.yml | 19 ++++ .../provision_test-app-nodejs-esm-22.yml | 21 ++++ .../Dockerfile.template | 10 ++ .../test-app-nodejs-esm-22/Dockerfile.node | 12 +++ .../test-app-nodejs-esm-22/Dockerfile.node22 | 12 +++ .../Dockerfile.reverseproxy | 3 + .../test-app-nodejs-esm-22/docker-compose.yml | 33 +++++++ .../nodejs/test-app-nodejs-esm-22/nginx.conf | 47 +++++++++ utils/nodejs_runtime.py | 96 +++++++++++++++++++ utils/scripts/ci_orchestrators/aws_ssi.json | 39 +++++++- .../scripts/ci_orchestrators/workflow_data.py | 11 ++- 17 files changed, 445 insertions(+), 15 deletions(-) create mode 100644 tests/test_the_test/test_nodejs_runtime.py create mode 100644 utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-22.yml create mode 100644 utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-container-22.yml create mode 100644 utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-esm-22.yml create mode 100644 utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-container-22/Dockerfile.template create mode 100644 utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node create mode 100644 utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node22 create mode 100644 utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.reverseproxy create mode 100644 utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/docker-compose.yml create mode 100644 utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/nginx.conf create mode 100644 utils/nodejs_runtime.py diff --git a/tests/auto_inject/test_auto_inject_install.py b/tests/auto_inject/test_auto_inject_install.py index 76391c94bfb..0a5b162e66a 100644 --- a/tests/auto_inject/test_auto_inject_install.py +++ b/tests/auto_inject/test_auto_inject_install.py @@ -27,7 +27,8 @@ class TestSimpleInstallerAutoInjectManualProfiling(base.AutoInjectBaseTest): reason="PROF-10783", ) @irrelevant( - context.vm_name in ["Ubuntu_24_amd64", "Ubuntu_24_arm64"] and context.weblog_variant == "test-app-nodejs", + context.vm_name in ["Ubuntu_24_amd64", "Ubuntu_24_arm64"] + and context.weblog_variant in ["test-app-nodejs", "test-app-nodejs-22"], reason="PROF-11264", ) @irrelevant( @@ -48,7 +49,8 @@ class TestHostAutoInjectInstallScriptProfiling(base.AutoInjectBaseTest): reason="PROF-10783", ) @irrelevant( - context.vm_name in ["Ubuntu_24_amd64", "Ubuntu_24_arm64"] and context.weblog_variant == "test-app-nodejs", + context.vm_name in ["Ubuntu_24_amd64", "Ubuntu_24_arm64"] + and context.weblog_variant in ["test-app-nodejs", "test-app-nodejs-22"], reason="PROF-11264", ) @missing_feature(context.vm_os_branch == "windows", reason="Not implemented on Windows") @@ -128,6 +130,7 @@ class TestContainerAutoInjectInstallScriptCrashTracking_NoZombieProcess(base.Aut "test-app-ruby-container", "test-app-python-container", "test-app-nodejs-container", + "test-app-nodejs-container-22", ], reason="Zombies only appears in containers", ) diff --git a/tests/docker_ssi/test_docker_ssi.py b/tests/docker_ssi/test_docker_ssi.py index 93537e4c934..d3d526df21e 100644 --- a/tests/docker_ssi/test_docker_ssi.py +++ b/tests/docker_ssi/test_docker_ssi.py @@ -12,6 +12,7 @@ weblog, logger, ) +from utils.nodejs_runtime import is_supported_nodejs_runtime, is_unsupported_nodejs_runtime @scenarios.docker_ssi @@ -42,7 +43,7 @@ def setup_install_supported_runtime(self): @irrelevant(context.library == "python" and context.installed_language_runtime < "3.8.0") @irrelevant(context.library == "java" and context.installed_language_runtime < "1.8.0_0") @irrelevant(context.library == "php" and context.installed_language_runtime < "7.0") - @irrelevant(context.library == "nodejs" and context.installed_language_runtime < "17.0") + @irrelevant(is_unsupported_nodejs_runtime(context.library, context.installed_language_runtime)) @irrelevant(context.library >= "python@4.0.0rc1" and context.installed_language_runtime < "3.9.0") @irrelevant(context.library == "ruby" and context.installed_language_runtime < "2.6.0") def test_install_supported_runtime(self): @@ -77,7 +78,7 @@ def test_install_weblog_running(self): ) @irrelevant(context.library == "java" and context.installed_language_runtime < "1.8.0_0") @irrelevant(context.library == "php" and context.installed_language_runtime < "7.0") - @irrelevant(context.library == "nodejs" and context.installed_language_runtime < "17.0") + @irrelevant(is_unsupported_nodejs_runtime(context.library, context.installed_language_runtime)) @irrelevant(context.library >= "python@4.0.0rc1" and context.installed_language_runtime < "3.9.0") @irrelevant(context.library == "ruby" and context.installed_language_runtime < "2.6.0") def test_telemetry(self): @@ -106,7 +107,9 @@ def test_telemetry(self): @irrelevant(context.library == "php" and context.installed_language_runtime >= "7.0") @bug(context.library == "nodejs" and context.installed_language_runtime < "12.17.0", reason="INPLAT-252") @bug(context.library == "java" and context.installed_language_runtime == "1.7.0-201", reason="INPLAT-427") - @irrelevant(context.library == "nodejs" and context.installed_language_runtime >= "17.0") + @irrelevant( + context.library == "nodejs" and is_supported_nodejs_runtime(context.library, context.installed_language_runtime) + ) @irrelevant(context.library == "dotnet" and context.installed_language_runtime >= "6.0.0") @irrelevant(context.library == "ruby" and context.installed_language_runtime >= "2.6.0") def test_telemetry_abort(self): @@ -145,7 +148,7 @@ def setup_instrumentation_source_ssi(self): @irrelevant(context.library == "python" and context.installed_language_runtime < "3.9.0") @irrelevant(context.library == "java" and context.installed_language_runtime < "1.8.0_0") @irrelevant(context.library == "php" and context.installed_language_runtime < "7.1") - @irrelevant(context.library == "nodejs" and context.installed_language_runtime < "17.0") + @irrelevant(is_unsupported_nodejs_runtime(context.library, context.installed_language_runtime)) @irrelevant(context.library >= "python@4.0.0.dev" and context.installed_language_runtime < "3.9.0") @irrelevant(context.library < "python@4.0.0.dev" and context.installed_language_runtime < "3.8.0") @irrelevant(context.library == "ruby" and context.installed_language_runtime < "2.6.0") @@ -168,7 +171,7 @@ def setup_injection_metadata(self): @irrelevant(context.library == "python" and context.installed_language_runtime < "3.8.0") @irrelevant(context.library == "java" and context.installed_language_runtime < "1.8.0_0") @irrelevant(context.library == "php" and context.installed_language_runtime < "7.1") - @irrelevant(context.library == "nodejs" and context.installed_language_runtime < "17.0") + @irrelevant(is_unsupported_nodejs_runtime(context.library, context.installed_language_runtime)) @irrelevant(context.library >= "python@4.0.0rc1" and context.installed_language_runtime < "3.9.0") def test_injection_metadata(self): logger.info("Testing injection result variables") diff --git a/tests/docker_ssi/test_docker_ssi_appsec.py b/tests/docker_ssi/test_docker_ssi_appsec.py index 18597c58f81..313067db94e 100644 --- a/tests/docker_ssi/test_docker_ssi_appsec.py +++ b/tests/docker_ssi/test_docker_ssi_appsec.py @@ -2,6 +2,7 @@ from tests.parametric.test_telemetry import _mapped_telemetry_name from utils import scenarios, interfaces, weblog, features, irrelevant, context +from utils.nodejs_runtime import is_unsupported_nodejs_runtime @features.appsec_service_activation_origin_metric @@ -17,7 +18,7 @@ def setup_telemetry_source_ssi(self): @irrelevant(context.library == "java" and context.installed_language_runtime < "1.8.0_0") @irrelevant(context.library == "php" and context.installed_language_runtime < "7.1") - @irrelevant(context.library == "nodejs" and context.installed_language_runtime < "17.0") + @irrelevant(is_unsupported_nodejs_runtime(context.library, context.installed_language_runtime)) @irrelevant(context.library >= "python@4.0.0.dev" and context.installed_language_runtime < "3.9.0") @irrelevant(context.library < "python@4.0.0.dev" and context.installed_language_runtime < "3.8.0") @irrelevant(context.library == "ruby" and context.installed_language_runtime < "2.6.0", reason="Ruby 2.6+ required") diff --git a/tests/docker_ssi/test_docker_ssi_crash.py b/tests/docker_ssi/test_docker_ssi_crash.py index 2c9a6a9df32..f521a0bc21e 100644 --- a/tests/docker_ssi/test_docker_ssi_crash.py +++ b/tests/docker_ssi/test_docker_ssi_crash.py @@ -8,6 +8,7 @@ interfaces, ) from utils import weblog, logger +from utils.nodejs_runtime import is_unsupported_nodejs_runtime @scenarios.docker_ssi_crashtracking @@ -36,13 +37,14 @@ def setup_crash(self): @features.ssi_crashtracking @irrelevant(context.library == "python" and context.installed_language_runtime < "3.7.0") - @irrelevant(context.library == "nodejs" and context.installed_language_runtime < "17.0") + @irrelevant(is_unsupported_nodejs_runtime(context.library, context.installed_language_runtime)) @irrelevant(context.library == "ruby" and context.installed_language_runtime < "2.6.0") def test_crash(self): """Validate that a crash report is generated when the application crashes""" logger.info(f"Testing Docker SSI crash tracking: {context.library.name}") + crash_url = scenarios.docker_ssi_crashtracking.weblog_url + "/crashme" assert self.r.status_code is None, ( - f"Response from request {scenarios.docker_ssi_crashtracking.weblog_url + '/crashme'} was supposed to fail: {self.r}" + f"Response from request {crash_url} was supposed to fail: {self.r}" ) # No traces should have been generated diff --git a/tests/test_the_test/test_nodejs_runtime.py b/tests/test_the_test/test_nodejs_runtime.py new file mode 100644 index 00000000000..21d3722eec1 --- /dev/null +++ b/tests/test_the_test/test_nodejs_runtime.py @@ -0,0 +1,83 @@ +from utils._context.component_version import ComponentVersion, Version +from utils.nodejs_runtime import ( + filter_nodejs_runtimes_for_ci, + infer_minimum_nodejs_runtime_for_ci, + is_supported_nodejs_runtime, + select_nodejs_aws_weblog_for_ci, +) + + +def _clear_nodejs_runtime_env(monkeypatch): + for env_name in [ + "SYSTEM_TESTS_NODEJS_MIN_RUNTIME", + "DD_NODEJS_RUNTIME_VERSION", + "DD_INSTALLER_LIBRARY_VERSION", + "DD_INSTALLER_LIBRARY_VERSION_NODEJS", + "CI_COMMIT_BRANCH", + "CI_COMMIT_REF_NAME", + "CI_MERGE_REQUEST_SOURCE_BRANCH_NAME", + "CI_COMMIT_TAG", + "GITHUB_REF_NAME", + "GITHUB_HEAD_REF", + ]: + monkeypatch.delenv(env_name, raising=False) + + +def test_nodejs_runtime_support_depends_on_library_major(): + assert is_supported_nodejs_runtime(ComponentVersion("nodejs", "5.0.0"), Version("18.20")) + assert is_supported_nodejs_runtime(ComponentVersion("nodejs", "5.0.0"), Version("20.18")) + assert not is_supported_nodejs_runtime(ComponentVersion("nodejs", "6.0.0-pre"), Version("20.18")) + assert is_supported_nodejs_runtime(ComponentVersion("nodejs", "6.0.0-pre"), Version("22.0")) + + +def test_infer_minimum_nodejs_runtime_for_ci_from_library_version(monkeypatch): + _clear_nodejs_runtime_env(monkeypatch) + + assert infer_minimum_nodejs_runtime_for_ci("5.0.0") == "18.0" + assert infer_minimum_nodejs_runtime_for_ci("6.0.0-pre") == "22.0" + + +def test_infer_minimum_nodejs_runtime_for_ci_from_ref(monkeypatch): + _clear_nodejs_runtime_env(monkeypatch) + + monkeypatch.setenv("CI_COMMIT_BRANCH", "master") + assert infer_minimum_nodejs_runtime_for_ci("pipeline-123") == "22.0" + + monkeypatch.setenv("CI_COMMIT_BRANCH", "v5.67.0-proposal") + assert infer_minimum_nodejs_runtime_for_ci("pipeline-123") == "18.0" + + monkeypatch.setenv("CI_COMMIT_BRANCH", "v6.0.0-proposal") + assert infer_minimum_nodejs_runtime_for_ci("pipeline-123") == "22.0" + + monkeypatch.delenv("CI_COMMIT_BRANCH") + monkeypatch.setenv("CI_COMMIT_REF_NAME", "refs/heads/v5.68.0") + assert infer_minimum_nodejs_runtime_for_ci("pipeline-123") == "18.0" + + +def test_filter_nodejs_runtimes_for_ci(monkeypatch): + _clear_nodejs_runtime_env(monkeypatch) + + monkeypatch.setenv("CI_COMMIT_BRANCH", "master") + runtimes = [ + {"version_id": "JS1820", "version": "18.20"}, + {"version_id": "JS2018", "version": "20.18"}, + {"version_id": "JS2200", "version": "22.0"}, + {"version_id": "JS2300", "version": "23.0"}, + ] + + assert filter_nodejs_runtimes_for_ci(runtimes) == [ + {"version_id": "JS2200", "version": "22.0"}, + {"version_id": "JS2300", "version": "23.0"}, + ] + + +def test_select_nodejs_aws_weblog_for_ci(monkeypatch): + _clear_nodejs_runtime_env(monkeypatch) + + monkeypatch.setenv("CI_COMMIT_BRANCH", "master") + assert select_nodejs_aws_weblog_for_ci("test-app-nodejs") == "test-app-nodejs-22" + assert select_nodejs_aws_weblog_for_ci("test-app-nodejs-container") == "test-app-nodejs-container-22" + assert select_nodejs_aws_weblog_for_ci("test-app-nodejs-esm") == "test-app-nodejs-esm-22" + assert select_nodejs_aws_weblog_for_ci("test-app-nodejs-unsupported-defaults") == ( + "test-app-nodejs-unsupported-defaults" + ) diff --git a/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-22.yml b/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-22.yml new file mode 100644 index 00000000000..554e79d37e6 --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-22.yml @@ -0,0 +1,45 @@ +lang_variant: + name: nodejs22 + version: 22 + cache: true + install: + - os_type: linux + os_distro: deb + remote-command: | + sudo apt-get update + sudo apt-get install -y ca-certificates curl gnupg + curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - + sudo apt-get install -y nodejs + + - os_type: linux + os_distro: rpm + remote-command: | + sudo yum install tar -y || sudo dnf install tar -y || true + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash + export NVM_DIR="$HOME/.nvm" + [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" + nvm install 22 + nvm use 22 + n=$(which node) + n=${n%/bin/node} + chmod -R 755 "$n/bin/"* + sudo cp -r "$n"/bin "$n"/lib "$n"/share /usr/local + +weblog: + name: test-app-nodejs-22 + install: + - os_type: linux + copy_files: + - name: copy-service + local_path: utils/build/virtual_machine/weblogs/common/test-app.service + + - name: copy-service-run-script + local_path: utils/build/virtual_machine/weblogs/common/create_and_run_app_service.sh + + - name: copy-run-weblog-script + local_path: utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs/test-app-nodejs_run.sh + + - name: copy-binary + local_path: lib-injection/build/docker/nodejs/sample-app/index.js + + remote-command: sh test-app-nodejs_run.sh diff --git a/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-container-22.yml b/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-container-22.yml new file mode 100644 index 00000000000..ad8a29e0c9b --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-container-22.yml @@ -0,0 +1,19 @@ +weblog: + name: test-app-nodejs-container-22 + runtime_version: 22 + install: + - os_type: linux + copy_files: + - name: copy-container-run-script + local_path: utils/build/virtual_machine/weblogs/common/create_and_run_app_container.sh + + - name: copy-docker-compose-file + local_path: utils/build/virtual_machine/weblogs/common/docker-compose.yml + + - name: copy-nodejs-app + local_path: lib-injection/build/docker/nodejs/sample-app + + - name: copy-nodejs-app-dockerfile + local_path: utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-container-22/Dockerfile.template + + remote-command: sh create_and_run_app_container.sh diff --git a/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-esm-22.yml b/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-esm-22.yml new file mode 100644 index 00000000000..7bac8096f0f --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/provision_test-app-nodejs-esm-22.yml @@ -0,0 +1,21 @@ +weblog: + name: test-app-nodejs-esm-22 + nginx_config: utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/nginx.conf + install: + - os_type: linux + copy_files: + - name: copy-multicontainer-run-script + local_path: utils/build/virtual_machine/weblogs/common/create_and_run_app_multicontainer.sh + - name: copy-docker-compose-file + local_path: utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/docker-compose.yml + - name: copy-nodejs-app + local_path: lib-injection/build/docker/nodejs/sample-app + - name: copy-node22-app-dockerfile + local_path: utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node22 + - name: copy-nodejs-app-dockerfile + local_path: utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node + - name: copy-reverseproxy-dockerfile + local_path: utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.reverseproxy + - name: copy-reverseproxy-conf + local_path: utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/nginx.conf + remote-command: sh create_and_run_app_multicontainer.sh diff --git a/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-container-22/Dockerfile.template b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-container-22/Dockerfile.template new file mode 100644 index 00000000000..66c16e00e3e --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-container-22/Dockerfile.template @@ -0,0 +1,10 @@ +FROM public.ecr.aws/docker/library/node:22 + +# Create app directory +WORKDIR /usr/src/app + +COPY . . +# Install dependencies with exact versions using npm ci +RUN npm ci --only=production --no-audit --no-fund +EXPOSE 18080 +CMD [ "node", "index.js" ] diff --git a/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node new file mode 100644 index 00000000000..ec68fe6d63a --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node @@ -0,0 +1,12 @@ +FROM public.ecr.aws/docker/library/node:22-slim + +# Create app directory +WORKDIR /usr/src/app + +COPY . . + +# https://datadoghq.atlassian.net/browse/INPLAT-441 +ENV DD_NODEJS_EXPERIMENTAL_ESM=true + +EXPOSE 18080 +CMD [ "node", "index.mjs" ] diff --git a/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node22 b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node22 new file mode 100644 index 00000000000..ec68fe6d63a --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.node22 @@ -0,0 +1,12 @@ +FROM public.ecr.aws/docker/library/node:22-slim + +# Create app directory +WORKDIR /usr/src/app + +COPY . . + +# https://datadoghq.atlassian.net/browse/INPLAT-441 +ENV DD_NODEJS_EXPERIMENTAL_ESM=true + +EXPOSE 18080 +CMD [ "node", "index.mjs" ] diff --git a/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.reverseproxy b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.reverseproxy new file mode 100644 index 00000000000..f131f6f168b --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/Dockerfile.reverseproxy @@ -0,0 +1,3 @@ +FROM public.ecr.aws/nginx/nginx:stable-perl + +COPY nginx.conf /etc/nginx/nginx.conf diff --git a/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/docker-compose.yml b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/docker-compose.yml new file mode 100644 index 00000000000..b6741f39980 --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/docker-compose.yml @@ -0,0 +1,33 @@ +version: '2' + +services: + reverseproxy: + image: reverseproxy:latest + ports: + - 5985:8080 + restart: always + build: + context: . + dockerfile: Dockerfile.reverseproxy + healthcheck: + test: "curl -f http://localhost:8080" + + node_22: + env_file: "scenario_app.env" + image: system-tests/node_22:latest + restart: always + build: + context: . + dockerfile: Dockerfile.node22 + healthcheck: + test: "node health" + + node: + env_file: "scenario_app.env" + image: system-tests/node:latest + restart: always + build: + context: . + dockerfile: Dockerfile.node + healthcheck: + test: "node health" diff --git a/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/nginx.conf b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/nginx.conf new file mode 100644 index 00000000000..0b3e5c184cb --- /dev/null +++ b/utils/build/virtual_machine/weblogs/nodejs/test-app-nodejs-esm-22/nginx.conf @@ -0,0 +1,47 @@ +worker_processes 1; + +events { worker_connections 1024; } + +http { + + log_format compression '$remote_addr - $remote_user [$time_local] ' + '"$request" $status $upstream_addr ' + '"$http_referer" "$http_user_agent" "$gzip_ratio"'; + + upstream node_22_app { + server node_22:18080; + } + upstream node_app { + server node:18080; + } + + server { + listen 8080; + access_log /var/log/nginx/access.log compression; + + location / { + default_type application/json; + return 200 "{ + 'app_type':'multicontainer', + 'apps':[{ + 'runtime':'22', + 'type':'container', + 'url':'/node_22/' + },{ + 'runtime':'latest', + 'type':'container', + 'url':'/node/' + }] + }"; + } + + location /node_22/ { + proxy_pass http://node_22_app/; + proxy_redirect off; + } + location /node/ { + proxy_pass http://node_app/; + proxy_redirect off; + } + } +} diff --git a/utils/nodejs_runtime.py b/utils/nodejs_runtime.py new file mode 100644 index 00000000000..f5e62a67988 --- /dev/null +++ b/utils/nodejs_runtime.py @@ -0,0 +1,96 @@ +import os +import re + +from utils._context.component_version import ComponentVersion, Version + + +NODEJS_V5_MIN_RUNTIME = Version("18.0") +NODEJS_V6_MIN_RUNTIME = Version("22.0") + +_RELEASE_REF_RE = re.compile(r"^v?(?P\d+)\.") +_NODEJS_AWS_V6_WEBLOGS = { + "test-app-nodejs": "test-app-nodejs-22", + "test-app-nodejs-container": "test-app-nodejs-container-22", + "test-app-nodejs-esm": "test-app-nodejs-esm-22", +} + + +def minimum_supported_nodejs_runtime(library: ComponentVersion) -> Version: + if library >= "nodejs@6.0.0-pre": + return NODEJS_V6_MIN_RUNTIME + + return NODEJS_V5_MIN_RUNTIME + + +def is_supported_nodejs_runtime(library: ComponentVersion, runtime: Version | str | None) -> bool: + if library != "nodejs": + return True + + if runtime is None or str(runtime) == "": + return False + + return Version(str(runtime)) >= minimum_supported_nodejs_runtime(library) + + +def is_unsupported_nodejs_runtime(library: ComponentVersion, runtime: Version | str | None) -> bool: + return library == "nodejs" and not is_supported_nodejs_runtime(library, runtime) + + +def infer_minimum_nodejs_runtime_for_ci(library_version: str | None = None) -> Version | None: + explicit_runtime = os.getenv("SYSTEM_TESTS_NODEJS_MIN_RUNTIME") or os.getenv("DD_NODEJS_RUNTIME_VERSION") + if explicit_runtime: + return Version(explicit_runtime) + + if library_version is None: + library_version = os.getenv("DD_INSTALLER_LIBRARY_VERSION") or os.getenv("DD_INSTALLER_LIBRARY_VERSION_NODEJS") + + if library_version: + try: + return minimum_supported_nodejs_runtime(ComponentVersion("nodejs", library_version)) + except ValueError: + pass + + refs = ( + os.getenv("CI_COMMIT_BRANCH"), + os.getenv("CI_COMMIT_REF_NAME"), + os.getenv("CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"), + os.getenv("CI_COMMIT_TAG"), + os.getenv("GITHUB_REF_NAME"), + os.getenv("GITHUB_HEAD_REF"), + ) + for ref in refs: + if not ref: + continue + ref = ref.removeprefix("refs/heads/").removeprefix("refs/tags/") + if ref == "master": + return NODEJS_V6_MIN_RUNTIME + + match = _RELEASE_REF_RE.match(ref) + if not match: + continue + + major = int(match.group("major")) + if major >= 6: + return NODEJS_V6_MIN_RUNTIME + if major == 5: + return NODEJS_V5_MIN_RUNTIME + + return None + + +def filter_nodejs_runtimes_for_ci( + runtimes: list[dict[str, str]], library_version: str | None = None +) -> list[dict[str, str]]: + minimum_runtime = infer_minimum_nodejs_runtime_for_ci(library_version) + if minimum_runtime is None: + return runtimes + + return [runtime for runtime in runtimes if Version(runtime["version"]) >= minimum_runtime] + + +def select_nodejs_aws_weblog_for_ci(weblog: str, library_version: str | None = None) -> str: + minimum_runtime = infer_minimum_nodejs_runtime_for_ci(library_version) + if minimum_runtime is not None and minimum_runtime >= NODEJS_V6_MIN_RUNTIME: + return _NODEJS_AWS_V6_WEBLOGS.get(weblog, weblog) + + return weblog diff --git a/utils/scripts/ci_orchestrators/aws_ssi.json b/utils/scripts/ci_orchestrators/aws_ssi.json index 89947950ad5..11521302a78 100644 --- a/utils/scripts/ci_orchestrators/aws_ssi.json +++ b/utils/scripts/ci_orchestrators/aws_ssi.json @@ -298,6 +298,24 @@ "Debian_11_arm64" ] }, + { + "name": "test-app-nodejs-22", + "excluded_os_branches": [ + "ubuntu22_amd64", + "ubuntu22_arm64", + "ubuntu21", + "ubuntu20_arm64", + "ubuntu20_amd64", + "centos_7_amd64", + "rhel_7_amd64", + "amazon_linux2", + "windows" + ], + "excluded_os_names": [ + "Debian_11_amd64", + "Debian_11_arm64" + ] + }, { "name": "test-app-nodejs-unsupported-defaults", "exact_os_branches": [ @@ -344,6 +362,16 @@ "Ubuntu_24_10_arm64" ] }, + { + "name": "test-app-nodejs-esm-22", + "exact_os_branches": [ + "ubuntu24" + ], + "excluded_os_names": [ + "Ubuntu_24_10_amd64", + "Ubuntu_24_10_arm64" + ] + }, { "name": "test-app-nodejs-container", "excluded_os_branches": [ @@ -353,6 +381,15 @@ "Ubuntu_24_10_arm64" ] }, + { + "name": "test-app-nodejs-container-22", + "excluded_os_branches": [ + "windows" + ], + "excluded_os_names": [ + "Ubuntu_24_10_arm64" + ] + }, { "name": "test-app-nodejs-alpine", "excluded_os_branches": [ @@ -705,4 +742,4 @@ } ] } -} \ No newline at end of file +} diff --git a/utils/scripts/ci_orchestrators/workflow_data.py b/utils/scripts/ci_orchestrators/workflow_data.py index 4cdc6100b4e..bde9fd475a1 100644 --- a/utils/scripts/ci_orchestrators/workflow_data.py +++ b/utils/scripts/ci_orchestrators/workflow_data.py @@ -2,6 +2,7 @@ import json from utils._context._scenarios import go_proxies from utils._context.weblog_metadata import WeblogMetaData as Weblog, BuildMode +from utils.nodejs_runtime import filter_nodejs_runtimes_for_ci, select_nodejs_aws_weblog_for_ci def _load_json(file_path: str) -> dict: @@ -96,6 +97,8 @@ def get_aws_matrix(virtual_machines_file: str, aws_ssi_file: str, scenarios: lis for weblog_entry in weblogs: if language in weblog_entry: for weblog in weblog_entry[language]: + if language == "nodejs": + weblog = select_nodejs_aws_weblog_for_ci(weblog) weblog_spec = _get_weblog_spec(weblogs_spec, weblog) excluded = set(weblog_spec.get("excluded_os_branches", [])) exact = set(weblog_spec.get("exact_os_branches", [])) @@ -160,10 +163,10 @@ def get_docker_ssi_matrix( if not allowed_versions: allowed_runtimes.append("") elif "*" in allowed_versions: - allowed_runtimes.extend( - runtime["version"] - for runtime in runtimes["docker_ssi_runtimes"].get(language, []) - ) + language_runtimes = runtimes["docker_ssi_runtimes"].get(language, []) + if language == "nodejs": + language_runtimes = filter_nodejs_runtimes_for_ci(language_runtimes) + allowed_runtimes.extend(runtime["version"] for runtime in language_runtimes) else: runtime_map = { rt["version_id"]: rt["version"] From 261a290df04c6a480c572b6a578ce73748891e57 Mon Sep 17 00:00:00 2001 From: Pablo Erhard Date: Mon, 6 Jul 2026 10:09:42 -0600 Subject: [PATCH 2/2] fix lint issues --- tests/docker_ssi/test_docker_ssi_crash.py | 4 +--- tests/test_the_test/test_nodejs_runtime.py | 12 +++++++----- utils/nodejs_runtime.py | 12 +++++++----- utils/scripts/ci_orchestrators/workflow_data.py | 7 ++++--- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/tests/docker_ssi/test_docker_ssi_crash.py b/tests/docker_ssi/test_docker_ssi_crash.py index f521a0bc21e..effe2ac3d96 100644 --- a/tests/docker_ssi/test_docker_ssi_crash.py +++ b/tests/docker_ssi/test_docker_ssi_crash.py @@ -43,9 +43,7 @@ def test_crash(self): """Validate that a crash report is generated when the application crashes""" logger.info(f"Testing Docker SSI crash tracking: {context.library.name}") crash_url = scenarios.docker_ssi_crashtracking.weblog_url + "/crashme" - assert self.r.status_code is None, ( - f"Response from request {crash_url} was supposed to fail: {self.r}" - ) + assert self.r.status_code is None, f"Response from request {crash_url} was supposed to fail: {self.r}" # No traces should have been generated assert not interfaces.test_agent.get_traces(self.r), ( diff --git a/tests/test_the_test/test_nodejs_runtime.py b/tests/test_the_test/test_nodejs_runtime.py index 21d3722eec1..e36e9949ca1 100644 --- a/tests/test_the_test/test_nodejs_runtime.py +++ b/tests/test_the_test/test_nodejs_runtime.py @@ -1,3 +1,5 @@ +import pytest + from utils._context.component_version import ComponentVersion, Version from utils.nodejs_runtime import ( filter_nodejs_runtimes_for_ci, @@ -7,7 +9,7 @@ ) -def _clear_nodejs_runtime_env(monkeypatch): +def _clear_nodejs_runtime_env(monkeypatch: pytest.MonkeyPatch): for env_name in [ "SYSTEM_TESTS_NODEJS_MIN_RUNTIME", "DD_NODEJS_RUNTIME_VERSION", @@ -30,14 +32,14 @@ def test_nodejs_runtime_support_depends_on_library_major(): assert is_supported_nodejs_runtime(ComponentVersion("nodejs", "6.0.0-pre"), Version("22.0")) -def test_infer_minimum_nodejs_runtime_for_ci_from_library_version(monkeypatch): +def test_infer_minimum_nodejs_runtime_for_ci_from_library_version(monkeypatch: pytest.MonkeyPatch): _clear_nodejs_runtime_env(monkeypatch) assert infer_minimum_nodejs_runtime_for_ci("5.0.0") == "18.0" assert infer_minimum_nodejs_runtime_for_ci("6.0.0-pre") == "22.0" -def test_infer_minimum_nodejs_runtime_for_ci_from_ref(monkeypatch): +def test_infer_minimum_nodejs_runtime_for_ci_from_ref(monkeypatch: pytest.MonkeyPatch): _clear_nodejs_runtime_env(monkeypatch) monkeypatch.setenv("CI_COMMIT_BRANCH", "master") @@ -54,7 +56,7 @@ def test_infer_minimum_nodejs_runtime_for_ci_from_ref(monkeypatch): assert infer_minimum_nodejs_runtime_for_ci("pipeline-123") == "18.0" -def test_filter_nodejs_runtimes_for_ci(monkeypatch): +def test_filter_nodejs_runtimes_for_ci(monkeypatch: pytest.MonkeyPatch): _clear_nodejs_runtime_env(monkeypatch) monkeypatch.setenv("CI_COMMIT_BRANCH", "master") @@ -71,7 +73,7 @@ def test_filter_nodejs_runtimes_for_ci(monkeypatch): ] -def test_select_nodejs_aws_weblog_for_ci(monkeypatch): +def test_select_nodejs_aws_weblog_for_ci(monkeypatch: pytest.MonkeyPatch): _clear_nodejs_runtime_env(monkeypatch) monkeypatch.setenv("CI_COMMIT_BRANCH", "master") diff --git a/utils/nodejs_runtime.py b/utils/nodejs_runtime.py index f5e62a67988..a78b9ef9e24 100644 --- a/utils/nodejs_runtime.py +++ b/utils/nodejs_runtime.py @@ -6,6 +6,8 @@ NODEJS_V5_MIN_RUNTIME = Version("18.0") NODEJS_V6_MIN_RUNTIME = Version("22.0") +NODEJS_V5_MAJOR = 5 +NODEJS_V6_MAJOR = 6 _RELEASE_REF_RE = re.compile(r"^v?(?P\d+)\.") _NODEJS_AWS_V6_WEBLOGS = { @@ -61,18 +63,18 @@ def infer_minimum_nodejs_runtime_for_ci(library_version: str | None = None) -> V for ref in refs: if not ref: continue - ref = ref.removeprefix("refs/heads/").removeprefix("refs/tags/") - if ref == "master": + normalized_ref = ref.removeprefix("refs/heads/").removeprefix("refs/tags/") + if normalized_ref == "master": return NODEJS_V6_MIN_RUNTIME - match = _RELEASE_REF_RE.match(ref) + match = _RELEASE_REF_RE.match(normalized_ref) if not match: continue major = int(match.group("major")) - if major >= 6: + if major >= NODEJS_V6_MAJOR: return NODEJS_V6_MIN_RUNTIME - if major == 5: + if major == NODEJS_V5_MAJOR: return NODEJS_V5_MIN_RUNTIME return None diff --git a/utils/scripts/ci_orchestrators/workflow_data.py b/utils/scripts/ci_orchestrators/workflow_data.py index bde9fd475a1..89072160afd 100644 --- a/utils/scripts/ci_orchestrators/workflow_data.py +++ b/utils/scripts/ci_orchestrators/workflow_data.py @@ -97,9 +97,10 @@ def get_aws_matrix(virtual_machines_file: str, aws_ssi_file: str, scenarios: lis for weblog_entry in weblogs: if language in weblog_entry: for weblog in weblog_entry[language]: + selected_weblog = weblog if language == "nodejs": - weblog = select_nodejs_aws_weblog_for_ci(weblog) - weblog_spec = _get_weblog_spec(weblogs_spec, weblog) + selected_weblog = select_nodejs_aws_weblog_for_ci(weblog) + weblog_spec = _get_weblog_spec(weblogs_spec, selected_weblog) excluded = set(weblog_spec.get("excluded_os_branches", [])) exact = set(weblog_spec.get("exact_os_branches", [])) excluded_names = set(weblog_spec.get("excluded_os_names", [])) @@ -124,7 +125,7 @@ def get_aws_matrix(virtual_machines_file: str, aws_ssi_file: str, scenarios: lis if os_type in excludes_types: should_add_vm = False if should_add_vm: - results[scenario][weblog].append(vm["name"]) + results[scenario][selected_weblog].append(vm["name"]) return results