Skip to content

Commit

Permalink
test(injector): add options to run subsets of tests & more test cases
Browse files Browse the repository at this point in the history
Add tests for the app.kubernetes.io/* and resource.opentelemetry.io/*
labels.
  • Loading branch information
basti1302 committed Feb 17, 2025
1 parent 9074c96 commit b429f9e
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 43 deletions.
16 changes: 16 additions & 0 deletions images/instrumentation/injector/test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,19 @@ This directory contains isolated tests for the injector code.
The difference to images/instrumentation/test is that the latter tests the whole instrumentation image.
Also, the tests in this folder do not use multi-platform images, an injector binary is build (in a container) per CPU
architecture, and then used for testing.

The test cases are listed in `run-tests-within-container.sh`.

Usage
-----

* `scripts/test-all.sh` to run all tests.
* `ARCHITECTURES=arm64,x86_64 scripts/test-all.sh` to run tests for a subset of CPU architectures.
* `LIBC_FLAVORS=glibc,musl scripts/test-all.sh` to run tests for a subset of libc flavors. Can be combined with
`ARCHITECTURES`.
* `TEST_CASES=twice,mapped scripts/test-all.sh` to only run tests cases whose names contain one of the
provided strings.
The test cases are listed in `run-tests-within-container.sh`.
Can be combined with `ARCHITECTURES` and `LIBC_FLAVORS`.
* `INSTRUMENTATION_IMAGE scripts/test-all.sh` use an existing local or remote instrumentation image.

40 changes: 20 additions & 20 deletions images/instrumentation/injector/test/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,34 @@ function echoEnvVar(envVarName) {
}
}

function main () {
const testCase = process.argv[2];
if (!testCase) {
console.error("error: not enough arguments, the name of the test case needs to be specifed");
process.exit(1)
function main() {
const command = process.argv[2];
if (!command) {
console.error('error: not enough arguments, the command for the app under test needs to be specifed');
process.exit(1);
}

switch (testCase) {
case "non-existing":
echoEnvVar("DOES_NOT_EXIST");
switch (command) {
case 'non-existing':
echoEnvVar('DOES_NOT_EXIST');
break;
case "existing":
echoEnvVar("TEST_VAR");
case 'existing':
echoEnvVar('TEST_VAR');
break;
case "node_options":
echoEnvVar("NODE_OPTIONS");
case 'node_options':
echoEnvVar('NODE_OPTIONS');
break;
case "node_options_twice":
echoEnvVar("NODE_OPTIONS");
process.stdout.write("; ")
echoEnvVar("NODE_OPTIONS");
case 'node_options_twice':
echoEnvVar('NODE_OPTIONS');
process.stdout.write('; ');
echoEnvVar('NODE_OPTIONS');
break;
case "otel_resource_attributes":
echoEnvVar("OTEL_RESOURCE_ATTRIBUTES");
case 'otel_resource_attributes':
echoEnvVar('OTEL_RESOURCE_ATTRIBUTES');
break;
default:
console.error(`unknown test case: ${testCase}`);
process.exit(1)
console.error(`unknown test app command: ${command}`);
process.exit(1);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ docker build \
docker run \
--platform "$docker_platform" \
--env EXPECTED_CPU_ARCHITECTURE="$expected_cpu_architecture" \
--env TEST_CASES="$TEST_CASES" \
--name "$container_name" \
"$image_name" \
$docker_run_extra_arguments
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# SPDX-FileCopyrightText: Copyright 2024 Dash0 Inc.
# SPDX-License-Identifier: Apache-2.0

set -eu
set -euo noglob

RED='\033[0;31m'
GREEN='\033[0;32m'
Expand Down Expand Up @@ -37,20 +37,47 @@ if [ ! -f $injector_binary ]; then
exit 1
fi

# Runs one test case. Usage:
#
# run_test_case $test_case_label $test_app_command $expected_output $env_vars
#
# - test_case_label: a human readable phrase describing the test case
# - test_app_command: will be passed on to app/index.js as a command line argument and determines the app's behavior
# - expected_output: The app's output will be compared to this string, the test case is deemed successful if the exit
# code is zero and the app's output matches this string
# - env_vars (optional): Set additional environment variables like NODE_OPTIONS or OTEL_RESOURCE_ATTRIBUTES when running
# the test
run_test_case() {
test_case_label=$1
test_case_id=$2
test_app_command=$2
expected=$3
existing_node_options_value=${4:-}
existing_otel_resource_attributes=${5:-}
full_command="LD_PRELOAD=""$injector_binary"" TEST_VAR=value DASH0_NAMESPACE_NAME=my-namespace DASH0_POD_NAME=my-pod DASH0_POD_UID=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff DASH0_CONTAINER_NAME=test-app"
if [ "$existing_node_options_value" != "" ]; then
full_command=" $full_command NODE_OPTIONS=$existing_node_options_value"
env_vars=${4:-}

if [ -n "${TEST_CASES:-}" ]; then
IFS=,
# shellcheck disable=SC2086
set -- $TEST_CASES""

run_this_test_case="false"
for selected_test_case in "$@"; do
set +e
match=$(expr "$test_case_label" : ".*$selected_test_case.*")
set -e
if [ "$match" -gt 0 ]; then
run_this_test_case="true"
fi
done
if [ "$run_this_test_case" != "true" ]; then
echo "- skipping test case \"$test_case_label\""
return
fi
fi
if [ "$existing_otel_resource_attributes" != "" ]; then
full_command=" $full_command OTEL_RESOURCE_ATTRIBUTES=$existing_otel_resource_attributes"

full_command="LD_PRELOAD=""$injector_binary"" TEST_VAR=value DASH0_NAMESPACE_NAME=my-namespace DASH0_POD_NAME=my-pod DASH0_POD_UID=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff DASH0_CONTAINER_NAME=test-app"
if [ "$env_vars" != "" ]; then
full_command=" $full_command $env_vars"
fi
full_command=" $full_command node index.js $test_case_id"
full_command=" $full_command node index.js $test_app_command"
echo "Running test command: $full_command"
set +e
test_output=$(eval "$full_command")
Expand Down Expand Up @@ -79,10 +106,13 @@ run_test_case "getenv: returns undefined for non-existing environment variable"
run_test_case "getenv: returns environment variable unchanged" existing "TEST_VAR: value"
run_test_case "getenv: overrides NODE_OPTIONS if it is not present" node_options "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry"
run_test_case "getenv: ask for NODE_OPTIONS (unset) twice" node_options_twice "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry; NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry"
run_test_case "getenv: prepends to NODE_OPTIONS if it is present" node_options "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation" "--no-deprecation"
run_test_case "getenv: ask for NODE_OPTIONS (set) twice" node_options_twice "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation; NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation" "--no-deprecation"
run_test_case "getenv: sets k8s.pod.uid and k8s.container.name via OTEL_RESOURCE_ATTRIBUTES" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app" ""
run_test_case "getenv: sets k8s.pod.uid and k8s.container.name via OTEL_RESOURCE_ATTRIBUTES with pre-existing value" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app,foo=bar" "" "foo=bar"
run_test_case "getenv: prepends to NODE_OPTIONS if it is present" node_options "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation" "NODE_OPTIONS=--no-deprecation"
run_test_case "getenv: ask for NODE_OPTIONS (set) twice" node_options_twice "NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation; NODE_OPTIONS: --require /__dash0__/instrumentation/node.js/node_modules/@dash0hq/opentelemetry --no-deprecation" "NODE_OPTIONS=--no-deprecation"
run_test_case "getenv: sets k8s.pod.uid and k8s.container.name via OTEL_RESOURCE_ATTRIBUTES" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app"
run_test_case "getenv: sets k8s.pod.uid and k8s.container.name via OTEL_RESOURCE_ATTRIBUTES with pre-existing value" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app,foo=bar" "OTEL_RESOURCE_ATTRIBUTES=foo=bar"
run_test_case "getenv: use mapped app.kubernetes.io labels for service.name and friends" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app,service.name=service-name,service.version=service-version,service.namespace=service-namespace" "DASH0_SERVICE_NAME=service-name DASH0_SERVICE_VERSION=service-version DASH0_SERVICE_NAMESPACE=service-namespace"
run_test_case "getenv: use mapped resource.opentelemetry.io labels as additional resource attributes" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app,aaa=bbb,ccc=ddd" "DASH0_RESOURCE_ATTRIBUTES=aaa=bbb,ccc=ddd"
run_test_case "getenv: combine mapped app.kubernetes.io and resource.opentelemetry.io labels" otel_resource_attributes "OTEL_RESOURCE_ATTRIBUTES: k8s.namespace.name=my-namespace,k8s.pod.name=my-pod,k8s.pod.uid=275ecb36-5aa8-4c2a-9c47-d8bb681b9aff,k8s.container.name=test-app,service.name=service-name,service.version=service-version,service.namespace=service-namespace,aaa=bbb,ccc=ddd" "DASH0_SERVICE_NAME=service-name DASH0_SERVICE_VERSION=service-version DASH0_SERVICE_NAMESPACE=service-namespace DASH0_RESOURCE_ATTRIBUTES=aaa=bbb,ccc=ddd"

exit $exit_code

90 changes: 81 additions & 9 deletions images/instrumentation/injector/test/scripts/test-all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,29 @@ source injector/test/scripts/util
# remove all outdated injector binaries
rm -rf injector/test/bin/*

architectures=""
if [[ -n "${ARCHITECTURES:-}" ]]; then
architectures=("${ARCHITECTURES//,/ }")
echo Only testing a subset of architectures: "${architectures[@]}"
fi
libc_flavors=""
if [[ -n "${LIBC_FLAVORS:-}" ]]; then
libc_flavors=("${LIBC_FLAVORS//,/ }")
echo Only testing a subset of libc flavors: "${libc_flavors[@]}"
fi
if [[ -n "${TEST_CASES:-}" ]]; then
echo Only running a subset of test cases : "$TEST_CASES"
else
TEST_CASES=""
fi

exit_code=0
summary=""
run_tests_for_architecture_and_libc_flavor() {
arch=$1
libc=$2
set +e
ARCH=$arch LIBC=$libc injector/test/scripts/run-tests-for-container.sh
ARCH="$arch" LIBC="$libc" TEST_CASES="$TEST_CASES" injector/test/scripts/run-tests-for-container.sh
test_exit_code=$?
set -e
echo
Expand Down Expand Up @@ -70,14 +86,33 @@ if [[ ! -e "$dockerfile_injector_build" ]]; then
exit 1
fi

declare -a all_architectures=(
"arm64"
"x86_64"
)
declare -a all_libc_flavors=(
"glibc"
"musl"
)

instrumentation_image=${INSTRUMENTATION_IMAGE:-}
if [[ -z "$instrumentation_image" ]]; then
# build injector binary for both architectures
echo ----------------------------------------
echo building the injector binary locally from source
echo ----------------------------------------
ARCH=arm64 injector/test/scripts/build-in-container.sh
ARCH=x86_64 injector/test/scripts/build-in-container.sh
for arch in "${all_architectures[@]}"; do
if [[ -n "${architectures[0]}" ]]; then
if [[ $(echo "${architectures[@]}" | grep -o "$arch" | wc -w) -eq 0 ]]; then
echo ----------------------------------------
echo "skipping build for CPU architecture $arch"
echo ----------------------------------------
continue
fi
fi

ARCH="$arch" injector/test/scripts/build-in-container.sh
done
else
if is_remote_image "$instrumentation_image"; then
echo ----------------------------------------
Expand All @@ -91,16 +126,53 @@ else
echo ----------------------------------------
printf "using injector binary from existing local image:\n$instrumentation_image\n"
echo ----------------------------------------
copy_injector_binary_from_container_image "$instrumentation_image" arm64 linux/arm64
copy_injector_binary_from_container_image "$instrumentation_image" x86_64 linux/amd64
for arch in "${all_architectures[@]}"; do
if [[ -n "${architectures[0]}" ]]; then
if [[ $(echo "${architectures[@]}" | grep -o "$arch" | wc -w) -eq 0 ]]; then
echo ----------------------------------------
echo "skipping copying injector binary from container for CPU architecture $arch"
echo ----------------------------------------
continue
fi
fi

if [[ "$arch" = "arm64" ]]; then
docker_platform="linux/arm64"
elif [[ "$arch" = "x86_64" ]]; then
docker_platform="linux/amd64"
else
echo "The architecture $arch is not supported."
exit 1
fi
copy_injector_binary_from_container_image "$instrumentation_image" "$arch" "$docker_platform"
done
fi
fi
echo

run_tests_for_architecture_and_libc_flavor arm64 glibc
run_tests_for_architecture_and_libc_flavor x86_64 glibc
run_tests_for_architecture_and_libc_flavor arm64 musl
run_tests_for_architecture_and_libc_flavor x86_64 musl
for arch in "${all_architectures[@]}"; do
if [[ -n "${architectures[0]}" ]]; then
if [[ $(echo "${architectures[@]}" | grep -o "$arch" | wc -w) -eq 0 ]]; then
echo ----------------------------------------
echo "skipping tests on CPU architecture $arch"
echo ----------------------------------------
continue
fi
fi

for libc_flavor in "${all_libc_flavors[@]}"; do
if [[ -n "${libc_flavors[0]}" ]]; then
if [[ $(echo "${libc_flavors[@]}" | grep -o "$libc_flavor" | wc -w) -eq 0 ]]; then
echo ----------------------------------------
echo "skipping tests for libc flavor $libc_flavor"
echo ----------------------------------------
continue
fi
fi

run_tests_for_architecture_and_libc_flavor "$arch" "$libc_flavor"
done
done

printf "$summary\n\n"
exit $exit_code

0 comments on commit b429f9e

Please sign in to comment.