feat(job-array-one-based-index): XCE_JOBINDEX is the element number (task 3.2)
The worker sets XCE_JOBINDEX to the element number for jobs carrying the array marking (a one-element array's element gets 1) and to 0 otherwise. A submission-supplied XCE_JOBINDEX is not applied and a WARN names the job and the ignored variable; XCE_JOBID handling is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c60946c097
commit
7aa00f0d9d
4 changed files with 269 additions and 4 deletions
|
|
@ -416,8 +416,11 @@ void apply_env_vars(env_var_t** env_vars, uint64_t jobid)
|
|||
jobid_str);
|
||||
}
|
||||
|
||||
char jobindex_str[8];
|
||||
snprintf(jobindex_str, sizeof(jobindex_str), "%d", 0);
|
||||
/* Element number of an array element (6.1, 7.8); 0 otherwise (6.2). */
|
||||
uint64_t jobindex = is_array_tag(jobid) ? array_idx(jobid) : 0;
|
||||
char jobindex_str[8];
|
||||
snprintf(jobindex_str, sizeof(jobindex_str), "%lu",
|
||||
(unsigned long)jobindex);
|
||||
if (setenv("XCE_JOBINDEX", jobindex_str, 1) != 0) {
|
||||
XCECD_WORKER_LOG(XCE_LOG_ERROR,
|
||||
"Error setting environment variable: %s",
|
||||
|
|
@ -431,7 +434,16 @@ void apply_env_vars(env_var_t** env_vars, uint64_t jobid)
|
|||
while (current != NULL) {
|
||||
next_node = current->next;
|
||||
|
||||
if (current->key && current->value) {
|
||||
if (current->key && current->value
|
||||
&& strcmp(current->key, "XCE_JOBINDEX") == 0) {
|
||||
/* The system value cannot be overridden (6.3, 6.4). */
|
||||
char idstr[64];
|
||||
fmt_jobid(idstr, sizeof(idstr), jobid);
|
||||
XCECD_WORKER_LOG(XCE_LOG_WARN,
|
||||
"Job %s: ignoring submitted environment "
|
||||
"variable XCE_JOBINDEX (set by XCE)",
|
||||
idstr);
|
||||
} else if (current->key && current->value) {
|
||||
// Set environment variable (overwrite if exists)
|
||||
if (setenv(current->key, current->value, 1) != 0) {
|
||||
XCECD_WORKER_LOG(XCE_LOG_ERROR,
|
||||
|
|
|
|||
|
|
@ -219,3 +219,16 @@ test('worker diskstats test', diskstats_test,
|
|||
suite: 'worker',
|
||||
timeout: 60,
|
||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||
|
||||
# job-array-one-based-index task 3.2 (Requirements 6.1-6.5, 7.8): XCE_JOBINDEX
|
||||
# in a running job's environment -- white-box #include of xcecd_exdata.c.
|
||||
exdata_jobindex_test = executable('exdata_jobindex_test',
|
||||
'test_exdata_jobindex.c',
|
||||
include_directories: [worker_test_incdir],
|
||||
dependencies: worker_test_deps,
|
||||
install: false)
|
||||
|
||||
test('worker exdata_jobindex test', exdata_jobindex_test,
|
||||
suite: 'worker',
|
||||
timeout: 60,
|
||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||
|
|
|
|||
240
src/worker/testsuite/test_exdata_jobindex.c
Normal file
240
src/worker/testsuite/test_exdata_jobindex.c
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* test_exdata_jobindex.c -- XCE_JOBINDEX in a running job's environment
|
||||
* (job-array-one-based-index, task 3.2; Requirements 6.1-6.5, 7.8).
|
||||
*
|
||||
* apply_env_vars() (xcecd_exdata.c) sets XCE_JOBID and XCE_JOBINDEX and then
|
||||
* the submission's own variables. XCE_JOBINDEX must be the element number of
|
||||
* an array-tagged job ID (a one-element array included) and 0 for an
|
||||
* ordinary job; a submission-supplied XCE_JOBINDEX is ignored with a WARN
|
||||
* naming the job and the variable; XCE_JOBID handling is unchanged.
|
||||
*
|
||||
* White-box #include of ../src/xcecd_exdata.c (same convention as the other
|
||||
* tests in this suite). XCECD_WORKER_LOG is redefined to a capture hook
|
||||
* before the include: xcelog.h is include-guarded, so the production file's
|
||||
* own #include "xcelog.h" does not restore the original macro.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unity/unity.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "xcelog.h"
|
||||
|
||||
#define CAPTURE_MAX 32
|
||||
|
||||
static int captured_level[CAPTURE_MAX];
|
||||
static char captured_msg[CAPTURE_MAX][512];
|
||||
static int captured_count;
|
||||
|
||||
static void capture_log(int level, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (captured_count >= CAPTURE_MAX) {
|
||||
return;
|
||||
}
|
||||
captured_level[captured_count] = level;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(captured_msg[captured_count],
|
||||
sizeof(captured_msg[captured_count]), fmt, ap);
|
||||
va_end(ap);
|
||||
captured_count++;
|
||||
}
|
||||
|
||||
#undef XCECD_WORKER_LOG
|
||||
#define XCECD_WORKER_LOG(level, format, ...) \
|
||||
capture_log((int)(level), format __VA_OPT__(, ) __VA_ARGS__)
|
||||
|
||||
#include "../src/xcecd_exdata.c"
|
||||
|
||||
/* cluster 1, apiserver 2, timestamp 3, sequence block 1 (seq 1 << 15) */
|
||||
#define TEST_SEQ_BLOCK ((uint64_t)1 << N_ARRAY_IDX_BITS)
|
||||
#define ARRAY_ELEMENT(k) \
|
||||
MAKE_JOBID(1, 2, 3, TAG_JOB_ARRAY, TEST_SEQ_BLOCK | (uint64_t)(k))
|
||||
#define ORDINARY_JOB MAKE_JOBID(1, 2, 3, 0, 77)
|
||||
|
||||
static env_var_t* push_var(env_var_t* head, const char* key, const char* value)
|
||||
{
|
||||
env_var_t* node = calloc(1, sizeof(*node));
|
||||
|
||||
TEST_ASSERT_NOT_NULL(node);
|
||||
node->key = strdup(key);
|
||||
node->value = strdup(value);
|
||||
node->next = head;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Index of the first captured WARN containing every needle, or -1. */
|
||||
static int find_warn(const char* needle1, const char* needle2)
|
||||
{
|
||||
for (int i = 0; i < captured_count; i++) {
|
||||
if (captured_level[i] == XCE_LOG_WARN
|
||||
&& strstr(captured_msg[i], needle1) != NULL
|
||||
&& strstr(captured_msg[i], needle2) != NULL) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int count_warns(void)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < captured_count; i++) {
|
||||
if (captured_level[i] == XCE_LOG_WARN) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void expect_env(const char* name, const char* value)
|
||||
{
|
||||
const char* got = getenv(name);
|
||||
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(got, name);
|
||||
TEST_ASSERT_EQUAL_STRING_MESSAGE(value, got, name);
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
captured_count = 0;
|
||||
unsetenv("XCE_JOBID");
|
||||
unsetenv("XCE_JOBINDEX");
|
||||
unsetenv("XCE_TEST_USERVAR");
|
||||
}
|
||||
|
||||
void tearDown(void) { return; }
|
||||
|
||||
/* 6.1: an array element sees its own element number. */
|
||||
static void test_array_element_gets_its_number(void)
|
||||
{
|
||||
env_var_t* vars = NULL;
|
||||
|
||||
apply_env_vars(&vars, ARRAY_ELEMENT(3));
|
||||
expect_env("XCE_JOBINDEX", "3");
|
||||
|
||||
apply_env_vars(&vars, ARRAY_ELEMENT(32767));
|
||||
expect_env("XCE_JOBINDEX", "32767");
|
||||
}
|
||||
|
||||
/* 7.8: a one-element array's element behaves like any element: number 1. */
|
||||
static void test_one_element_array_gets_one(void)
|
||||
{
|
||||
env_var_t* vars = NULL;
|
||||
|
||||
apply_env_vars(&vars, ARRAY_ELEMENT(1));
|
||||
expect_env("XCE_JOBINDEX", "1");
|
||||
}
|
||||
|
||||
/* 6.2: an ordinary job gets 0 even if its low bits are non-zero. */
|
||||
static void test_ordinary_job_gets_zero(void)
|
||||
{
|
||||
env_var_t* vars = NULL;
|
||||
|
||||
apply_env_vars(&vars, ORDINARY_JOB);
|
||||
expect_env("XCE_JOBINDEX", "0");
|
||||
}
|
||||
|
||||
/* A pre-upgrade element 0 (tagged, index 0) is still reported as 0. */
|
||||
static void test_preupgrade_element_zero_gets_zero(void)
|
||||
{
|
||||
env_var_t* vars = NULL;
|
||||
|
||||
apply_env_vars(&vars, ARRAY_ELEMENT(0));
|
||||
expect_env("XCE_JOBINDEX", "0");
|
||||
}
|
||||
|
||||
/* 6.3, 6.4: a submission's XCE_JOBINDEX is ignored with a WARN naming the
|
||||
* job and the variable; other user variables are still applied. */
|
||||
static void test_user_jobindex_ignored_with_warn(void)
|
||||
{
|
||||
env_var_t* vars = NULL;
|
||||
char idstr[64];
|
||||
|
||||
vars = push_var(vars, "XCE_TEST_USERVAR", "kept");
|
||||
vars = push_var(vars, "XCE_JOBINDEX", "99");
|
||||
|
||||
apply_env_vars(&vars, ARRAY_ELEMENT(5));
|
||||
|
||||
TEST_ASSERT_NULL(vars);
|
||||
expect_env("XCE_JOBINDEX", "5");
|
||||
expect_env("XCE_TEST_USERVAR", "kept");
|
||||
|
||||
fmt_jobid(idstr, sizeof(idstr), ARRAY_ELEMENT(5));
|
||||
TEST_ASSERT_TRUE_MESSAGE(find_warn(idstr, "XCE_JOBINDEX") >= 0,
|
||||
"no WARN naming the job and XCE_JOBINDEX");
|
||||
TEST_ASSERT_EQUAL_INT(1, count_warns());
|
||||
}
|
||||
|
||||
/* 6.3: an ordinary job's user XCE_JOBINDEX is ignored too (stays 0). */
|
||||
static void test_user_jobindex_ignored_for_ordinary_job(void)
|
||||
{
|
||||
env_var_t* vars = NULL;
|
||||
char idstr[64];
|
||||
|
||||
vars = push_var(vars, "XCE_JOBINDEX", "");
|
||||
apply_env_vars(&vars, ORDINARY_JOB);
|
||||
|
||||
expect_env("XCE_JOBINDEX", "0");
|
||||
fmt_jobid(idstr, sizeof(idstr), ORDINARY_JOB);
|
||||
TEST_ASSERT_TRUE(find_warn(idstr, "XCE_JOBINDEX") >= 0);
|
||||
}
|
||||
|
||||
/* Only the exact name is ignored. */
|
||||
static void test_similar_names_still_applied(void)
|
||||
{
|
||||
env_var_t* vars = NULL;
|
||||
|
||||
vars = push_var(vars, "XCE_JOBINDEX_X", "a");
|
||||
vars = push_var(vars, "xce_jobindex", "b");
|
||||
apply_env_vars(&vars, ARRAY_ELEMENT(2));
|
||||
|
||||
expect_env("XCE_JOBINDEX", "2");
|
||||
expect_env("XCE_JOBINDEX_X", "a");
|
||||
expect_env("xce_jobindex", "b");
|
||||
TEST_ASSERT_EQUAL_INT(0, count_warns());
|
||||
unsetenv("XCE_JOBINDEX_X");
|
||||
unsetenv("xce_jobindex");
|
||||
}
|
||||
|
||||
/* 6.5: XCE_JOBID is the decimal job ID; a submission's own XCE_JOBID still
|
||||
* overrides it, as before, with no WARN. */
|
||||
static void test_jobid_unchanged(void)
|
||||
{
|
||||
env_var_t* vars = NULL;
|
||||
char dec[32];
|
||||
|
||||
snprintf(dec, sizeof(dec), "%lu", (unsigned long)ARRAY_ELEMENT(4));
|
||||
apply_env_vars(&vars, ARRAY_ELEMENT(4));
|
||||
expect_env("XCE_JOBID", dec);
|
||||
|
||||
snprintf(dec, sizeof(dec), "%lu", (unsigned long)ORDINARY_JOB);
|
||||
apply_env_vars(&vars, ORDINARY_JOB);
|
||||
expect_env("XCE_JOBID", dec);
|
||||
|
||||
captured_count = 0;
|
||||
vars = push_var(vars, "XCE_JOBID", "user-value");
|
||||
apply_env_vars(&vars, ORDINARY_JOB);
|
||||
expect_env("XCE_JOBID", "user-value");
|
||||
TEST_ASSERT_EQUAL_INT(0, count_warns());
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
RUN_TEST(test_array_element_gets_its_number);
|
||||
RUN_TEST(test_one_element_array_gets_one);
|
||||
RUN_TEST(test_ordinary_job_gets_zero);
|
||||
RUN_TEST(test_preupgrade_element_zero_gets_zero);
|
||||
RUN_TEST(test_user_jobindex_ignored_with_warn);
|
||||
RUN_TEST(test_user_jobindex_ignored_for_ordinary_job);
|
||||
RUN_TEST(test_similar_names_still_applied);
|
||||
RUN_TEST(test_jobid_unchanged);
|
||||
return UNITY_END();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue