fix(xce-test-cli-ux): route diagnostic/warning messages to stderr uniformly

Audit every printf() call site in test.c not already covered by the
flagspec-rejection or perror() paths; convert 33 genuine error/warning
messages (expect-jobs, expect-job, wait-primary, help's not-found path,
jobrun/jobsub/jobstart/jobfinish/jobfail validation, resupdate, set) from
stdout to stderr, so a command's successful result data and its
diagnostics never share a stream.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019jaMf9QEwpugH2W9KAuc7f
This commit is contained in:
Rongsong Shen 2026-09-10 00:59:38 +00:00
parent 96746af3eb
commit a98fad24da
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
3 changed files with 305 additions and 55 deletions

View file

@ -997,7 +997,7 @@ static char* get_setting(char* key)
return active_ctx->settings[i].defval;
}
printf("Key `%s' is not in settings\n", key);
fprintf(stderr, "Key `%s' is not in settings\n", key);
return NULL;
}
@ -1467,8 +1467,15 @@ int preprocess_and_run(char* line)
int cmd_help(int argc, char* argv[])
{
int i;
int rc = 0;
int i;
int rc = 0;
/* xce-test-cli-ux task 3.6, Requirement 3.1/3.2: the command-list loop
* below is shared by two callers -- bare `help` (success, Req 3.2 result
* data) and the not-found fallback just above it (Req 3.1 diagnostic,
* "here's what IS available"). Route BOTH the not-found headline and
* that shared list to `out`, selected by which case we're in, rather
* than duplicating the loop. */
FILE* out = stdout;
if (argc > 1) {
char* cmd = argv[1];
@ -1521,13 +1528,14 @@ int cmd_help(int argc, char* argv[])
/* bug-1711 / Requirement 11.2: grammar fix only ("match", not
* "matchs") -- does NOT add the cross-context lookup Requirement
* 8.7 explicitly excludes. */
printf("No commands match `%s'. Possibilities are:\n", cmd);
out = stderr; /* Req 3.1: not-found is a diagnostic, not result data */
fprintf(out, "No commands match `%s'. Possibilities are:\n", cmd);
rc = -1;
}
for (i = 0; active_ctx->commands[i].name != NULL; i++) {
printf("\t%-12s\t%s\n", active_ctx->commands[i].name,
active_ctx->commands[i].doc);
fprintf(out, "\t%-12s\t%s\n", active_ctx->commands[i].name,
active_ctx->commands[i].doc);
}
return rc;
@ -2709,7 +2717,7 @@ int cmd_expect_jobs(int argc, char* argv[])
int count;
if (argc != 2) {
printf("expect-jobs <N>\n");
fprintf(stderr, "expect-jobs <N>\n");
return -EINVAL;
}
@ -2717,9 +2725,10 @@ int cmd_expect_jobs(int argc, char* argv[])
expected = strtol(argv[1], &end, 10);
if ((errno != 0) || (end == argv[1]) || (*end != '\0') || (expected < 0)) {
printf("expect-jobs: invalid count '%s' (expected a non-negative "
"integer)\n",
argv[1]);
fprintf(stderr,
"expect-jobs: invalid count '%s' (expected a non-negative "
"integer)\n",
argv[1]);
return -EINVAL;
}
@ -2729,13 +2738,15 @@ int cmd_expect_jobs(int argc, char* argv[])
count = joblist_query(NULL, NULL, 0, /*quiet=*/0, /*json_mode=*/0);
if (count < 0) {
printf("expect-jobs: could not determine job count (joblist query "
"failed)\n");
fprintf(stderr,
"expect-jobs: could not determine job count (joblist query "
"failed)\n");
return count;
}
if (count != (int)expected) {
printf("expect-jobs: expected %ld, actual %d\n", expected, count);
fprintf(stderr, "expect-jobs: expected %ld, actual %d\n", expected,
count);
return -EINVAL;
}
@ -2767,7 +2778,7 @@ int cmd_expect_job(int argc, char* argv[])
int rc;
if (argc != 2) {
printf("expect-job <jobid>\n");
fprintf(stderr, "expect-job <jobid>\n");
return -EINVAL;
}
@ -2777,14 +2788,15 @@ int cmd_expect_job(int argc, char* argv[])
rc = joblist_query(argv[1], &contains, 0, /*quiet=*/0, /*json_mode=*/0);
if (rc < 0) {
printf("expect-job: could not determine membership of '%s' (joblist "
"query failed)\n",
argv[1]);
fprintf(stderr,
"expect-job: could not determine membership of '%s' (joblist "
"query failed)\n",
argv[1]);
return rc;
}
if (!contains) {
printf("expect-job: job %s not found\n", argv[1]);
fprintf(stderr, "expect-job: job %s not found\n", argv[1]);
return -ENOENT;
}
@ -2858,7 +2870,7 @@ int cmd_wait_primary(int argc, char* argv[])
long start_ms, elapsed_ms;
if (argc > 2) {
printf("wait-primary [timeout_ms]\n");
fprintf(stderr, "wait-primary [timeout_ms]\n");
return -EINVAL;
}
@ -2870,9 +2882,10 @@ int cmd_wait_primary(int argc, char* argv[])
if ((errno != 0) || (end == argv[1]) || (*end != '\0')
|| (timeout_ms < 0)) {
printf("wait-primary: invalid timeout '%s' (expected a "
"non-negative integer in ms)\n",
argv[1]);
fprintf(stderr,
"wait-primary: invalid timeout '%s' (expected a "
"non-negative integer in ms)\n",
argv[1]);
return -EINVAL;
}
}
@ -2909,11 +2922,13 @@ int cmd_wait_primary(int argc, char* argv[])
* 1.1) rather than retrying -- ownership of `call` has passed
* to the still-running worker thread (interruptcall.h). */
mylog_setlevel(g_active_loglevel);
/* Same printf-based reporting style as this command's own
* success/timeout messages just below, rather than a one-off
* perror() this loop otherwise never uses. */
printf("wait-primary: interrupted after %ld ms\n",
monotonic_ms() - start_ms);
/* xce-test-cli-ux task 3.6, Requirement 3.1: an interrupted wait
* is a genuine command failure (rc == -EINTR here, same
* convention cmd_resval's EINTR path documents), so this goes
* to stderr like this command's other failure paths -- not
* grouped with its success message below anymore. */
fprintf(stderr, "wait-primary: interrupted after %ld ms\n",
monotonic_ms() - start_ms);
return rc;
}
@ -2945,9 +2960,10 @@ int cmd_wait_primary(int argc, char* argv[])
if (elapsed_ms >= timeout_ms) {
mylog_setlevel(g_active_loglevel);
printf("wait-primary: no primary served within %ld ms (waited "
"%ld ms)\n",
timeout_ms, elapsed_ms);
fprintf(stderr,
"wait-primary: no primary served within %ld ms (waited "
"%ld ms)\n",
timeout_ms, elapsed_ms);
return -ETIMEDOUT;
}
@ -3022,7 +3038,7 @@ int cmd_ctrlstatus(int argc, char* argv[])
(void)argv;
if (argc != 1) {
printf("ctrlstatus\n");
fprintf(stderr, "ctrlstatus\n");
return -EINVAL;
}
@ -3406,7 +3422,7 @@ int cmd_jobrun(int argc, char* argv[])
case 'j':
parse_jobid(&jobid, optarg);
if (jobid == 0) {
printf("you need to specify a positive jobid with -j");
fprintf(stderr, "you need to specify a positive jobid with -j");
return -1;
}
break;
@ -3418,7 +3434,7 @@ int cmd_jobrun(int argc, char* argv[])
}
if (jobid == 0) {
printf("no jobid specified");
fprintf(stderr, "no jobid specified");
return -1;
}
@ -3579,8 +3595,9 @@ int cmd_jobsub(int argc, char* argv[])
min = atoi(buf);
if (max == 0) {
printf("Incorrect setting of max tasks count, set to same "
"as min task value\n");
fprintf(stderr,
"Incorrect setting of max tasks count, set to "
"same as min task value\n");
max = min;
}
} else {
@ -3604,24 +3621,25 @@ int cmd_jobsub(int argc, char* argv[])
}
if (min == 0) {
printf("Incorrect setting of min task count, set to 1 as default\n");
fprintf(stderr,
"Incorrect setting of min task count, set to 1 as default\n");
min = 1;
}
if (NULLSTR(submit.user)) {
printf("you need to specify job user with -u\n");
fprintf(stderr, "you need to specify job user with -u\n");
rc = -EINVAL;
goto cleanup;
}
if (NULLSTR(submit.queue)) {
printf("you need to specify job queue with -q\n");
fprintf(stderr, "you need to specify job queue with -q\n");
rc = -EINVAL;
goto cleanup;
}
if (NULLSTR(submit.start_info->cmdline)) {
printf("you need to specify job command with -c\n");
fprintf(stderr, "you need to specify job command with -c\n");
rc = -EINVAL;
goto cleanup;
}
@ -5183,7 +5201,7 @@ int cmd_jobstart(int argc, char* argv[])
}
if (jobid == 0) {
printf(" you need specify a positive jobid\n");
fprintf(stderr, " you need specify a positive jobid\n");
return -EINVAL;
}
@ -5293,7 +5311,7 @@ int cmd_jobfinish(int argc, char* argv[])
}
if (jobid == 0) {
printf(" you need specify a positive jobid\n");
fprintf(stderr, " you need specify a positive jobid\n");
return -EINVAL;
}
@ -5401,7 +5419,7 @@ int cmd_jobfail(int argc, char* argv[])
}
if (jobid == 0) {
printf(" you need specify a positive jobid\n");
fprintf(stderr, " you need specify a positive jobid\n");
return -EINVAL;
}
@ -5650,10 +5668,19 @@ static int resupdate_report_one(char* name, char* host, xce_val_t* sent)
}
}
/* xce-test-cli-ux task 3.6, Requirement 3.1: unlike the "accepted" line
* above (legitimate per-resource outcome data on the success path), a
* "rejected" verdict reports that this specific update did NOT take
* effect -- a problem the operator/script needs to notice -- so it goes
* to stderr. This does NOT change cmd_resupdate()'s own return value:
* the caller still returns 0 overall even when one or more resources are
* reported rejected here (see this task's CONCERNS for why that return-
* value question is left as a follow-up, out of this stream-routing
* task's scope). */
if (ever_found) {
printf("%s: rejected: value mismatch\n", name);
fprintf(stderr, "%s: rejected: value mismatch\n", name);
} else {
printf("%s: rejected: unknown resource\n", name);
fprintf(stderr, "%s: rejected: unknown resource\n", name);
}
return 0;
@ -5725,7 +5752,8 @@ int cmd_resupdate(int argc, char* argv[])
case 'n':
if (resname != NULL) {
if (resval_str == NULL) {
printf(
fprintf(
stderr,
"res `%s' has no value specified, default will be used\n",
resname);
}
@ -5750,7 +5778,9 @@ int cmd_resupdate(int argc, char* argv[])
if (resname != NULL && resval_str == NULL) {
resval_str = optarg;
} else {
printf("ignore res value `%s' as no res name found\n", optarg);
fprintf(stderr,
"ignore res value `%s' as no res name found\n",
optarg);
}
break;
case 't':
@ -5760,13 +5790,15 @@ int cmd_resupdate(int argc, char* argv[])
} else if (strcasecmp(optarg, "string") == 0) {
type_override = Value_u_svalue;
} else {
printf(
fprintf(
stderr,
"ignoring unrecognized -t value `%s' (expected "
"`numeric' or `string')\n",
optarg);
}
} else {
printf("ignore -t `%s' as no res name found\n", optarg);
fprintf(stderr, "ignore -t `%s' as no res name found\n",
optarg);
}
break;
case '?':
@ -6075,7 +6107,7 @@ int cmd_set(int argc, char* argv[])
}
if (argc != 3) {
printf("set <key> <value>\n");
fprintf(stderr, "set <key> <value>\n");
return -EINVAL;
}
@ -6090,7 +6122,7 @@ int cmd_set(int argc, char* argv[])
}
}
printf("Can not find setting key: %s\n", argv[1]);
fprintf(stderr, "Can not find setting key: %s\n", argv[1]);
return -EINVAL;
}