diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:27:27 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:27:27 +0300 |
| commit | 294b9fe361076c6c740bc182dc7605e745ed2ea3 (patch) | |
| tree | 75eec75937af0579c7e5e0c8e8a02260d0df83d0 /corebinutils/nproc/tests | |
| parent | 5086370dd0d4e581d1f5e4b8a085cd421eb23235 (diff) | |
| parent | b02e14aacf37412ca3632719075c9c42967e23b6 (diff) | |
| download | Project-Tick-294b9fe361076c6c740bc182dc7605e745ed2ea3.tar.gz Project-Tick-294b9fe361076c6c740bc182dc7605e745ed2ea3.zip | |
Add 'corebinutils/nproc/' from commit 'b02e14aacf37412ca3632719075c9c42967e23b6'
git-subtree-dir: corebinutils/nproc
git-subtree-mainline: 5086370dd0d4e581d1f5e4b8a085cd421eb23235
git-subtree-split: b02e14aacf37412ca3632719075c9c42967e23b6
Diffstat (limited to 'corebinutils/nproc/tests')
| -rw-r--r-- | corebinutils/nproc/tests/test.sh | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/corebinutils/nproc/tests/test.sh b/corebinutils/nproc/tests/test.sh new file mode 100644 index 0000000000..6349577600 --- /dev/null +++ b/corebinutils/nproc/tests/test.sh @@ -0,0 +1,368 @@ +#!/bin/sh +set -eu + +ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +NPROC_BIN=${NPROC_BIN:-"$ROOT/out/nproc"} +CC=${CC:-cc} +TMPDIR=${TMPDIR:-/tmp} +WORKDIR=$(mktemp -d "$TMPDIR/nproc-test.XXXXXX") +HELPER_C="$WORKDIR/affinity-helper.c" +HELPER_BIN="$WORKDIR/affinity-helper" +STDOUT_FILE="$WORKDIR/stdout" +STDERR_FILE="$WORKDIR/stderr" +trap 'rm -rf "$WORKDIR"' EXIT INT TERM + +export LC_ALL=C + +fail() { + printf '%s\n' "FAIL: $1" >&2 + exit 1 +} + +assert_eq() { + name=$1 + expected=$2 + actual=$3 + if [ "$expected" != "$actual" ]; then + printf '%s\n' "FAIL: $name" >&2 + printf '%s\n' "--- expected ---" >&2 + printf '%s' "$expected" >&2 + printf '\n%s\n' "--- actual ---" >&2 + printf '%s' "$actual" >&2 + printf '\n' >&2 + exit 1 + fi +} + +assert_match() { + name=$1 + text=$2 + pattern=$3 + printf '%s\n' "$text" | grep -Eq "$pattern" || fail "$name" +} + +assert_status() { + name=$1 + expected=$2 + actual=$3 + if [ "$expected" -ne "$actual" ]; then + printf '%s\n' "FAIL: $name" >&2 + printf '%s\n' "expected status: $expected" >&2 + printf '%s\n' "actual status: $actual" >&2 + exit 1 + fi +} + +assert_empty() { + name=$1 + text=$2 + if [ -n "$text" ]; then + printf '%s\n' "FAIL: $name" >&2 + printf '%s\n' "--- expected empty ---" >&2 + printf '%s\n' "--- actual ---" >&2 + printf '%s' "$text" >&2 + printf '\n' >&2 + exit 1 + fi +} + +run_capture() { + if "$@" >"$STDOUT_FILE" 2>"$STDERR_FILE"; then + LAST_STATUS=0 + else + LAST_STATUS=$? + fi + + LAST_STDOUT=$(cat "$STDOUT_FILE") + LAST_STDERR=$(cat "$STDERR_FILE") +} + +build_helper() { + cat >"$HELPER_C" <<'EOF' +#define _GNU_SOURCE 1 + +#include <errno.h> +#include <limits.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static cpu_set_t * +read_affinity(size_t *setsize, int *cpu_count) +{ + cpu_set_t *mask; + long configured; + + configured = sysconf(_SC_NPROCESSORS_CONF); + if (configured < 1 || configured > INT_MAX / 2) + *cpu_count = 128; + else + *cpu_count = (int)configured; + + if (*cpu_count < 1) + *cpu_count = 1; + + for (;;) { + int saved_errno; + + mask = CPU_ALLOC((size_t)*cpu_count); + if (mask == NULL) { + perror("CPU_ALLOC"); + exit(1); + } + *setsize = CPU_ALLOC_SIZE((size_t)*cpu_count); + CPU_ZERO_S(*setsize, mask); + + if (sched_getaffinity(0, *setsize, mask) == 0) + return (mask); + + saved_errno = errno; + CPU_FREE(mask); + if (saved_errno != EINVAL) { + errno = saved_errno; + perror("sched_getaffinity"); + exit(1); + } + if (*cpu_count > INT_MAX / 2) { + fprintf(stderr, "affinity mask too large\n"); + exit(1); + } + *cpu_count *= 2; + } +} + +static int +online_processors(void) +{ + long value; + + value = sysconf(_SC_NPROCESSORS_ONLN); + if (value < 1) { + fprintf(stderr, "invalid online cpu count\n"); + exit(1); + } + return ((int)value); +} + +static int +subset_size_for_mask(const cpu_set_t *mask, size_t setsize) +{ + int available; + + available = CPU_COUNT_S(setsize, mask); + if (available <= 1) + return (0); + return (available - 1); +} + +static void +fill_subset(cpu_set_t *subset, size_t setsize, const cpu_set_t *mask, int subset_size, + int cpu_count) +{ + int cpu; + int chosen; + + CPU_ZERO_S(setsize, subset); + chosen = 0; + for (cpu = 0; cpu < cpu_count && chosen < subset_size; cpu++) { + if (!CPU_ISSET_S(cpu, setsize, mask)) + continue; + CPU_SET_S(cpu, setsize, subset); + chosen++; + } + if (chosen != subset_size) { + fprintf(stderr, "failed to build subset mask\n"); + exit(1); + } +} + +int +main(int argc, char **argv) +{ + cpu_set_t *mask; + cpu_set_t *subset; + size_t setsize; + int cpu_count; + int subset_size; + + mask = read_affinity(&setsize, &cpu_count); + subset_size = subset_size_for_mask(mask, setsize); + + if (argc == 2 && strcmp(argv[1], "counts") == 0) { + printf("available=%d\n", CPU_COUNT_S(setsize, mask)); + printf("online=%d\n", online_processors()); + printf("subset=%d\n", subset_size); + CPU_FREE(mask); + return (0); + } + + if (argc >= 2 && strcmp(argv[1], "run-subset") == 0) { + if (argc < 3) { + fprintf(stderr, "run-subset requires a command\n"); + CPU_FREE(mask); + return (1); + } + if (subset_size == 0) { + CPU_FREE(mask); + return (2); + } + + subset = CPU_ALLOC((size_t)cpu_count); + if (subset == NULL) { + perror("CPU_ALLOC"); + CPU_FREE(mask); + return (1); + } + fill_subset(subset, setsize, mask, subset_size, cpu_count); + if (sched_setaffinity(0, setsize, subset) != 0) { + perror("sched_setaffinity"); + CPU_FREE(subset); + CPU_FREE(mask); + return (1); + } + CPU_FREE(subset); + CPU_FREE(mask); + execvp(argv[2], &argv[2]); + perror("execvp"); + return (1); + } + + fprintf(stderr, "usage: affinity-helper counts | run-subset command [args ...]\n"); + CPU_FREE(mask); + return (1); +} +EOF + + "$CC" -D_GNU_SOURCE=1 -O2 -std=c17 -Wall -Wextra -Werror \ + "$HELPER_C" -o "$HELPER_BIN" || fail "failed to build helper with $CC" +} + +extract_value() { + name=$1 + text=$2 + value=$(printf '%s\n' "$text" | sed -n "s/^$name=//p") + [ -n "$value" ] || fail "missing helper value: $name" + printf '%s' "$value" +} + +[ -x "$NPROC_BIN" ] || fail "missing binary: $NPROC_BIN" +build_helper + +counts_output=$("$HELPER_BIN" counts) +available_count=$(extract_value available "$counts_output") +online_count=$(extract_value online "$counts_output") +subset_count=$(extract_value subset "$counts_output") + +run_capture "$NPROC_BIN" +assert_status "default status" 0 "$LAST_STATUS" +assert_eq "default stdout" "$available_count" "$LAST_STDOUT" +assert_empty "default stderr" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --all +assert_status "all status" 0 "$LAST_STATUS" +assert_eq "all stdout" "$online_count" "$LAST_STDOUT" +assert_empty "all stderr" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --ignore=0 +assert_status "ignore zero status" 0 "$LAST_STATUS" +assert_eq "ignore zero stdout" "$available_count" "$LAST_STDOUT" +assert_empty "ignore zero stderr" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --ignore 0 +assert_status "ignore split status" 0 "$LAST_STATUS" +assert_eq "ignore split stdout" "$available_count" "$LAST_STDOUT" +assert_empty "ignore split stderr" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --ignore="$available_count" +assert_status "ignore saturates status" 0 "$LAST_STATUS" +assert_eq "ignore saturates stdout" "1" "$LAST_STDOUT" +assert_empty "ignore saturates stderr" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --all --ignore="$online_count" +assert_status "all ignore saturates status" 0 "$LAST_STATUS" +assert_eq "all ignore saturates stdout" "1" "$LAST_STDOUT" +assert_empty "all ignore saturates stderr" "$LAST_STDERR" + +run_capture "$NPROC_BIN" -- +assert_status "double dash status" 0 "$LAST_STATUS" +assert_eq "double dash stdout" "$available_count" "$LAST_STDOUT" +assert_empty "double dash stderr" "$LAST_STDERR" + +if [ "$subset_count" -gt 0 ]; then + run_capture "$HELPER_BIN" run-subset "$NPROC_BIN" + assert_status "subset affinity status" 0 "$LAST_STATUS" + assert_eq "subset affinity stdout" "$subset_count" "$LAST_STDOUT" + assert_empty "subset affinity stderr" "$LAST_STDERR" +fi + +help_text="usage: nproc [--all] [--ignore=count] + nproc --help + nproc --version" + +run_capture "$NPROC_BIN" --help +assert_status "help status" 0 "$LAST_STATUS" +assert_empty "help stdout" "$LAST_STDOUT" +assert_eq "help stderr" "$help_text" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --version +assert_status "version status" 0 "$LAST_STATUS" +assert_match "version stdout" "$LAST_STDOUT" '^nproc \(neither_GNU nor_coreutils\) 8\.32$' +assert_empty "version stderr" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --ignore=abc +assert_status "invalid ignore alpha status" 1 "$LAST_STATUS" +assert_empty "invalid ignore alpha stdout" "$LAST_STDOUT" +assert_eq "invalid ignore alpha stderr" \ + "nproc: invalid ignore count: abc" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --ignore=-1 +assert_status "invalid ignore negative status" 1 "$LAST_STATUS" +assert_empty "invalid ignore negative stdout" "$LAST_STDOUT" +assert_eq "invalid ignore negative stderr" \ + "nproc: invalid ignore count: -1" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --ignore= +assert_status "invalid ignore empty status" 1 "$LAST_STATUS" +assert_empty "invalid ignore empty stdout" "$LAST_STDOUT" +assert_eq "invalid ignore empty stderr" \ + "nproc: invalid ignore count: " "$LAST_STDERR" + +run_capture "$NPROC_BIN" --ignore +assert_status "missing ignore status" 1 "$LAST_STATUS" +assert_empty "missing ignore stdout" "$LAST_STDOUT" +assert_eq "missing ignore stderr" \ + "nproc: option requires an argument: --ignore +usage: nproc [--all] [--ignore=count] + nproc --help + nproc --version" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --bogus +assert_status "unknown option status" 1 "$LAST_STATUS" +assert_empty "unknown option stdout" "$LAST_STDOUT" +assert_eq "unknown option stderr" \ + "nproc: unknown option: --bogus +usage: nproc [--all] [--ignore=count] + nproc --help + nproc --version" "$LAST_STDERR" + +run_capture "$NPROC_BIN" extra +assert_status "unexpected operand status" 1 "$LAST_STATUS" +assert_empty "unexpected operand stdout" "$LAST_STDOUT" +assert_eq "unexpected operand stderr" \ + "nproc: unexpected operand: extra +usage: nproc [--all] [--ignore=count] + nproc --help + nproc --version" "$LAST_STDERR" + +run_capture "$NPROC_BIN" --help --all +assert_status "help exclusive status" 1 "$LAST_STATUS" +assert_empty "help exclusive stdout" "$LAST_STDOUT" +assert_eq "help exclusive stderr" \ + "nproc: option --help must be used alone +usage: nproc [--all] [--ignore=count] + nproc --help + nproc --version" "$LAST_STDERR" + +printf '%s\n' "PASS" |
