static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */ udb_query_t *q, udb_query_preparation_area_t *prep_area) { const char *statement; dbi_result res; size_t column_num; char **column_names; char **column_values; int status; size_t i; /* Macro that cleans up dynamically allocated memory and returns the * specified status. */ #define BAIL_OUT(status) \ if (column_names != NULL) { sfree (column_names[0]); sfree (column_names); } \ if (column_values != NULL) { sfree (column_values[0]); sfree (column_values); } \ if (res != NULL) { dbi_result_free (res); res = NULL; } \ return (status) column_names = NULL; column_values = NULL; statement = udb_query_get_statement (q); assert (statement != NULL); res = dbi_conn_query (db->connection, statement); if (res == NULL) { char errbuf[1024]; ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "dbi_conn_query failed: %s", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); BAIL_OUT (-1); } else /* Get the number of columns */ { unsigned int db_status; db_status = dbi_result_get_numfields (res); if (db_status == DBI_FIELD_ERROR) { char errbuf[1024]; ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "dbi_result_get_numfields failed: %s", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); BAIL_OUT (-1); } column_num = (size_t) db_status; DEBUG ("cdbi_read_database_query (%s, %s): There are %zu columns.", db->name, udb_query_get_name (q), column_num); } /* Allocate `column_names' and `column_values'. {{{ */ column_names = calloc (column_num, sizeof (*column_names)); if (column_names == NULL) { ERROR ("dbi plugin: calloc failed."); BAIL_OUT (-1); } column_names[0] = calloc (column_num, DATA_MAX_NAME_LEN); if (column_names[0] == NULL) { ERROR ("dbi plugin: calloc failed."); BAIL_OUT (-1); } for (i = 1; i < column_num; i++) column_names[i] = column_names[i - 1] + DATA_MAX_NAME_LEN; column_values = calloc (column_num, sizeof (*column_values)); if (column_values == NULL) { ERROR ("dbi plugin: calloc failed."); BAIL_OUT (-1); } column_values[0] = calloc (column_num, DATA_MAX_NAME_LEN); if (column_values[0] == NULL) { ERROR ("dbi plugin: calloc failed."); BAIL_OUT (-1); } for (i = 1; i < column_num; i++) column_values[i] = column_values[i - 1] + DATA_MAX_NAME_LEN; /* }}} */ /* Copy the field names to `column_names' */ for (i = 0; i < column_num; i++) /* {{{ */ { const char *column_name; column_name = dbi_result_get_field_name (res, (unsigned int) (i + 1)); if (column_name == NULL) { ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "Cannot retrieve name of field %zu.", db->name, udb_query_get_name (q), i + 1); BAIL_OUT (-1); } sstrncpy (column_names[i], column_name, DATA_MAX_NAME_LEN); } /* }}} for (i = 0; i < column_num; i++) */ udb_query_prepare_result (q, prep_area, (db->host ? db->host : hostname_g), /* plugin = */ "dbi", db->name, column_names, column_num, /* interval = */ (db->interval > 0) ? db->interval : 0); /* 0 = error; 1 = success; */ status = dbi_result_first_row (res); /* {{{ */ if (status != 1) { char errbuf[1024]; ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "dbi_result_first_row failed: %s. Maybe the statement didn't " "return any rows?", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); udb_query_finish_result (q, prep_area); BAIL_OUT (-1); } /* }}} */ /* Iterate over all rows and call `udb_query_handle_result' with each list of * values. */ while (42) /* {{{ */ { status = 0; /* Copy the value of the columns to `column_values' */ for (i = 0; i < column_num; i++) /* {{{ */ { status = cdbi_result_get_field (res, (unsigned int) (i + 1), column_values[i], DATA_MAX_NAME_LEN); if (status != 0) { ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "cdbi_result_get_field (%zu) failed.", db->name, udb_query_get_name (q), i + 1); status = -1; break; } } /* }}} for (i = 0; i < column_num; i++) */ /* If all values were copied successfully, call `udb_query_handle_result' * to dispatch the row to the daemon. */ if (status == 0) /* {{{ */ { status = udb_query_handle_result (q, prep_area, column_values); if (status != 0) { ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "udb_query_handle_result failed.", db->name, udb_query_get_name (q)); } } /* }}} */ /* Get the next row from the database. */ status = dbi_result_next_row (res); /* {{{ */ if (status != 1) { if (dbi_conn_error (db->connection, NULL) != 0) { char errbuf[1024]; WARNING ("dbi plugin: cdbi_read_database_query (%s, %s): " "dbi_result_next_row failed: %s.", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); } break; } /* }}} */ } /* }}} while (42) */ /* Tell the db query interface that we're done with this query. */ udb_query_finish_result (q, prep_area); /* Clean up and return `status = 0' (success) */ BAIL_OUT (0); #undef BAIL_OUT } /* }}} int cdbi_read_database_query */
int lcc_getval (lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */ size_t *ret_values_num, gauge_t **ret_values, char ***ret_values_names) { char ident_str[6 * LCC_NAME_LEN]; char ident_esc[12 * LCC_NAME_LEN]; char command[14 * LCC_NAME_LEN]; lcc_response_t res; size_t values_num; gauge_t *values = NULL; char **values_names = NULL; size_t i; int status; if (c == NULL) return (-1); if (ident == NULL) { lcc_set_errno (c, EINVAL); return (-1); } /* Build a commend with an escaped version of the identifier string. */ status = lcc_identifier_to_string (c, ident_str, sizeof (ident_str), ident); if (status != 0) return (status); snprintf (command, sizeof (command), "GETVAL %s", lcc_strescape (ident_esc, ident_str, sizeof (ident_esc))); command[sizeof (command) - 1] = 0; /* Send talk to the daemon.. */ status = lcc_sendreceive (c, command, &res); if (status != 0) return (status); if (res.status != 0) { LCC_SET_ERRSTR (c, "Server error: %s", res.message); lcc_response_free (&res); return (-1); } values_num = res.lines_num; #define BAIL_OUT(e) do { \ lcc_set_errno (c, (e)); \ free (values); \ if (values_names != NULL) { \ for (i = 0; i < values_num; i++) { \ free (values_names[i]); \ } \ } \ free (values_names); \ lcc_response_free (&res); \ return (-1); \ } while (0) /* If neither the values nor the names are requested, return here.. */ if ((ret_values == NULL) && (ret_values_names == NULL)) { if (ret_values_num != NULL) *ret_values_num = values_num; lcc_response_free (&res); return (0); } /* Allocate space for the values */ if (ret_values != NULL) { values = (gauge_t *) malloc (values_num * sizeof (*values)); if (values == NULL) BAIL_OUT (ENOMEM); } if (ret_values_names != NULL) { values_names = (char **) calloc (values_num, sizeof (*values_names)); if (values_names == NULL) BAIL_OUT (ENOMEM); } for (i = 0; i < res.lines_num; i++) { char *key; char *value; char *endptr; key = res.lines[i]; value = strchr (key, '='); if (value == NULL) BAIL_OUT (EILSEQ); *value = 0; value++; if (values != NULL) { endptr = NULL; errno = 0; values[i] = strtod (value, &endptr); if ((endptr == value) || (errno != 0)) BAIL_OUT (errno); } if (values_names != NULL) { values_names[i] = strdup (key); if (values_names[i] == NULL) BAIL_OUT (ENOMEM); } } /* for (i = 0; i < res.lines_num; i++) */ if (ret_values_num != NULL) *ret_values_num = values_num; if (ret_values != NULL) *ret_values = values; if (ret_values_names != NULL) *ret_values_names = values_names; lcc_response_free (&res); return (0); } /* }}} int lcc_getval */
void test_timed (flux_t *h) { flux_reduce_t *r; int i, errors; double timeout; clear_counts (); ok ((r = flux_reduce_create (h, reduce_ops, 0.1, NULL, FLUX_REDUCE_TIMEDFLUSH)) != NULL, "timed: flux_reduce_create works"); if (!r) BAIL_OUT(); ok (flux_reduce_opt_get (r, FLUX_REDUCE_OPT_TIMEOUT, &timeout, sizeof (timeout)) == 0 && timeout == 0.1, "timed: flux_reduce_opt_get TIMEOUT returned timeout"); /* Append 100 items in batch 0 before starting reactor. * Reduction occurs at each append. * Nothing should be sinked. */ errors = 0; for (i = 0; i < 100; i++) { if (flux_reduce_append (r, xstrdup ("hi"), 0) < 0) errors++; } ok (errors == 0, "timed.0: flux_reduce_append added 100 items"); cmp_ok (reduce_calls, "==", 99, "timed.0: op.reduce called 99 times"); cmp_ok (sink_calls, "==", 0, "timed.0: op.sink called 0 times"); /* Start reactor so timeout handler can run. * It should fire once and sink all items in one sink call. */ ok (flux_reactor_run (flux_get_reactor (h), 0) == 0, "timed.0: reactor completed normally"); cmp_ok (sink_calls, "==", 1, "timed.0: op.sink called 1 time"); cmp_ok (sink_items, "==", 100, "timed.0: op.sink processed 100 items"); clear_counts (); /* Now append one more item to batch 0. * It should be immediately flushed. */ ok (flux_reduce_append (r, xstrdup ("hi"), 0) == 0, "timed.0: flux_reduce_append added 1 more item"); cmp_ok (reduce_calls, "==", 0, "timed.0: op.reduce not called"); cmp_ok (sink_calls, "==", 1, "timed.0: op.sink called 1 time"); cmp_ok (sink_items, "==", 1, "timed.0: op.sink processed 1 items"); clear_counts (); /* Append 100 items to batch 1. * It should behave like the first batch. */ errors = 0; for (i = 0; i < 100; i++) { if (flux_reduce_append (r, xstrdup ("hi"), 1) < 0) errors++; } ok (errors == 0, "timed.1: flux_reduce_append added 100 items"); cmp_ok (reduce_calls, "==", 99, "timed.1: op.reduce called 99 times"); cmp_ok (sink_calls, "==", 0, "timed.1: op.sink called 0 times"); /* Start reactor so timeout handler can run. * It should fire once and sink all items in one sink call. */ ok (flux_reactor_run (flux_get_reactor (h), 0) == 0, "timed.1: reactor completed normally"); cmp_ok (sink_calls, "==", 1, "timed.1: op.sink called 1 time"); cmp_ok (sink_items, "==", 100, "timed.1: op.sink processed 100 items"); flux_reduce_destroy (r); }
static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */ udb_result_preparation_area_t *prep_area, char **column_names, size_t column_num) { size_t i; if ((r == NULL) || (prep_area == NULL)) return (-EINVAL); #define BAIL_OUT(status) \ prep_area->ds = NULL; \ sfree (prep_area->instances_pos); \ sfree (prep_area->values_pos); \ sfree (prep_area->metadata_pos); \ sfree (prep_area->instances_buffer); \ sfree (prep_area->values_buffer); \ sfree (prep_area->metadata_buffer); \ return (status) /* Make sure previous preparations are cleaned up. */ udb_result_finish_result (r, prep_area); prep_area->instances_pos = NULL; prep_area->values_pos = NULL; prep_area->metadata_pos = NULL; /* Read `ds' and check number of values {{{ */ prep_area->ds = plugin_get_ds (r->type); if (prep_area->ds == NULL) { ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not " "known by the daemon. See types.db(5) for details.", r->type); BAIL_OUT (-1); } if (prep_area->ds->ds_num != r->values_num) { ERROR ("db query utils: udb_result_prepare_result: The type `%s' " "requires exactly %zu value%s, but the configuration specifies %zu.", r->type, prep_area->ds->ds_num, (prep_area->ds->ds_num == 1) ? "" : "s", r->values_num); BAIL_OUT (-1); } /* }}} */ /* Allocate r->instances_pos, r->values_pos, r->metadata_post, * r->instances_buffer, r->values_buffer, and r->metadata_buffer {{{ */ if (r->instances_num > 0) { prep_area->instances_pos = (size_t *) calloc (r->instances_num, sizeof (size_t)); if (prep_area->instances_pos == NULL) { ERROR ("db query utils: udb_result_prepare_result: calloc failed."); BAIL_OUT (-ENOMEM); } prep_area->instances_buffer = (char **) calloc (r->instances_num, sizeof (char *)); if (prep_area->instances_buffer == NULL) { ERROR ("db query utils: udb_result_prepare_result: calloc failed."); BAIL_OUT (-ENOMEM); } } /* if (r->instances_num > 0) */ prep_area->values_pos = (size_t *) calloc (r->values_num, sizeof (size_t)); if (prep_area->values_pos == NULL) { ERROR ("db query utils: udb_result_prepare_result: calloc failed."); BAIL_OUT (-ENOMEM); } prep_area->values_buffer = (char **) calloc (r->values_num, sizeof (char *)); if (prep_area->values_buffer == NULL) { ERROR ("db query utils: udb_result_prepare_result: calloc failed."); BAIL_OUT (-ENOMEM); } prep_area->metadata_pos = (size_t *) calloc (r->metadata_num, sizeof (size_t)); if (prep_area->metadata_pos == NULL) { ERROR ("db query utils: udb_result_prepare_result: calloc failed."); BAIL_OUT (-ENOMEM); } prep_area->metadata_buffer = (char **) calloc (r->metadata_num, sizeof (char *)); if (prep_area->metadata_buffer == NULL) { ERROR ("db query utils: udb_result_prepare_result: calloc failed."); BAIL_OUT (-ENOMEM); } /* }}} */ /* Determine the position of the plugin instance column {{{ */ for (i = 0; i < r->instances_num; i++) { size_t j; for (j = 0; j < column_num; j++) { if (strcasecmp (r->instances[i], column_names[j]) == 0) { prep_area->instances_pos[i] = j; break; } } if (j >= column_num) { ERROR ("db query utils: udb_result_prepare_result: " "Column `%s' could not be found.", r->instances[i]); BAIL_OUT (-ENOENT); } } /* }}} for (i = 0; i < r->instances_num; i++) */ /* Determine the position of the value columns {{{ */ for (i = 0; i < r->values_num; i++) { size_t j; for (j = 0; j < column_num; j++) { if (strcasecmp (r->values[i], column_names[j]) == 0) { prep_area->values_pos[i] = j; break; } } if (j >= column_num) { ERROR ("db query utils: udb_result_prepare_result: " "Column `%s' could not be found.", r->values[i]); BAIL_OUT (-ENOENT); } } /* }}} for (i = 0; i < r->values_num; i++) */ /* Determine the position of the metadata columns {{{ */ for (i = 0; i < r->metadata_num; i++) { size_t j; for (j = 0; j < column_num; j++) { if (strcasecmp (r->metadata[i], column_names[j]) == 0) { prep_area->metadata_pos[i] = j; break; } } if (j >= column_num) { ERROR ("db query utils: udb_result_prepare_result: " "Metadata column `%s' could not be found.", r->values[i]); BAIL_OUT (-ENOENT); } } /* }}} for (i = 0; i < r->metadata_num; i++) */ #undef BAIL_OUT return (0); } /* }}} int udb_result_prepare_result */
int main (int argc, char *argv[]) { const int q_size = 16; struct queue *q; struct job *j; json_t *attrs; json_t *badattrs; json_t *o; json_t *el; json_t *id_o; flux_jobid_t id; plan (NO_PLAN); q = make_test_queue (q_size); if (!(attrs = json_pack ("[s]", "id"))) BAIL_OUT ("json_pack failed"); /* list_job_array */ o = list_job_array (q, 0, attrs); ok (o != NULL && json_is_array (o), "list_job_array returns array"); ok (json_array_size (o) == q_size, "array has expected size"); json_decref (o); o = list_job_array (q, 4, attrs); ok (o != NULL && json_is_array (o), "list_job_array max_entries=4 returns array"); ok (json_array_size (o) == 4, "array has expected size"); el = json_array_get (o, 1); ok (el != NULL && json_is_object (el), "array[1] is an object"); ok ((id_o = json_object_get (el, "id")) != NULL, "array[1] id is set"); id = json_integer_value (id_o); ok (id == 1, "array[1] id=1"); if (id != 1) diag ("id=%d", (int)id); ok (json_object_size (el) == 1, "array[1] size=1"); json_decref (o); errno = 0; ok (list_job_array (q, -1, attrs) == NULL && errno == EPROTO, "list_job_array max_entries < 0 fails with EPROTO"); errno = 0; ok (list_job_array (q, -1, NULL) == NULL && errno == EPROTO, "list_job_array attrs=NULL fails with EPROTO"); /* list_one_job */ if (!(j = queue_lookup_by_id (q, 0))) BAIL_OUT ("queue_lookup_by_id 0 failed"); if (!(badattrs = json_pack ("[s]", "foo"))) BAIL_OUT ("json_pack failed"); errno = 0; ok (list_one_job (j, badattrs) == NULL && errno == EINVAL, "list_one_job attrs=[\"foo\"] fails with EINVAL"); json_decref (badattrs); if (!(badattrs = json_pack ("[i]", 42))) BAIL_OUT ("json_pack failed"); errno = 0; ok (list_one_job (j, badattrs) == NULL && errno == EPROTO, "list_one_job attrs=[42] fails with EPROTO"); json_decref (badattrs); json_decref (attrs); queue_destroy (q); done_testing (); }
int main (int ac, char **av) { int rc; struct subprocess_manager *sm; struct subprocess *p, *q; const char *s; char *buf; char *args[] = { "hello", NULL }; char *args2[] = { "goodbye", NULL }; char *args3[] = { "/bin/true", NULL }; char *args4[] = { "/bin/sleep", "10", NULL }; int start_fdcount, end_fdcount; start_fdcount = fdcount (); diag ("initial fd count %d", start_fdcount); plan (NO_PLAN); if (!(sm = subprocess_manager_create ())) BAIL_OUT ("Failed to create subprocess manager"); ok (sm != NULL, "create subprocess manager"); diag ("subprocess accessors tests"); if (!(p = subprocess_create (sm))) BAIL_OUT ("Failed to create subprocess handle: %s", strerror (errno)); ok (p != NULL, "create subprocess handle"); rc = subprocess_set_args (p, 1, args); ok (rc >= 0, "subprocess_set_args: %s", strerror (errno)); ok (subprocess_get_argc (p) == 1, "subprocess argc is 1"); s = subprocess_get_arg (p, 0); is (s, "hello", "subprocess argv[0] is 'hello'"); rc = subprocess_argv_append (p, "foo"); ok (rc >= 0, "subprocess_arg_append"); ok (subprocess_get_argc (p) == 2, "subprocess argc is now 2"); s = subprocess_get_arg (p, 2); ok (s == NULL, "subprocess_get_arg() out of bounds returns NULL"); rc = subprocess_set_args (p, 1, args2); ok (rc >= 0, "set_args replaces existing"); s = subprocess_get_arg (p, 0); is (s, "goodbye", "subprocess argv[0] is 'goodbye'"); rc = subprocess_setenv (p, "FOO", "bar", 1); ok (rc >= 0, "subprocess_setenv"); s = subprocess_getenv (p, "FOO"); is (s, "bar", "subprocess_getenv works"); rc = subprocess_setenv (p, "FOO", "bar2", 0); ok (rc == -1, "subprocess_setenv without overwrite fails for existing var"); ok (errno == EEXIST, "and with appropriate errno"); s = subprocess_getenv (p, "FOO"); is (s, "bar", "subproces_getenv still shows correct variable"); subprocess_unsetenv (p, "FOO"); s = subprocess_getenv (p, "FOO"); ok (s == NULL, "subproces_getenv fails for unset variable"); rc = subprocess_setenvf (p, "FOO", 1, "%d", 42); ok (rc >= 0, "subprocess_setenvf"); s = subprocess_getenv (p, "FOO"); is (s, "42", "subprocess_getenv works after setenvf"); is (subprocess_state_string (p), "Pending", "Unstarted process has state 'Pending'"); subprocess_destroy (p); diag ("fd count after subproc create/destroy %d", fdcount ()); /* Test running an executable */ diag ("test subprocess_manager_run"); p = subprocess_manager_run (sm, 1, args3, NULL); ok (p != NULL, "subprocess_manager_run"); ok (subprocess_pid (p) != (pid_t) -1, "process has valid pid"); q = subprocess_manager_wait (sm); ok (p == q, "subprocess_manager_wait returns correct process"); ok (subprocess_exited (p), "subprocess has exited after wait returns"); is (subprocess_state_string (p), "Exited", "State is now 'Exited'"); ok (subprocess_exit_code (p) == 0, "With expected exit code"); subprocess_destroy (p); q = NULL; /* Test failing program */ diag ("test expected failure from subprocess_manager_run"); args3[0] = "/bin/false"; p = subprocess_manager_run (sm, 1, args3, NULL); if (p) { ok (p != NULL, "subprocess_manager_run"); ok (subprocess_pid (p) != (pid_t) -1, "process has valid pid"); q = subprocess_manager_wait (sm); ok (p == q, "subprocess_manager_wait returns correct process"); is (subprocess_state_string (p), "Exited", "State is now 'Exited'"); is (subprocess_exit_string (p), "Exited with non-zero status", "State is now 'Exited with non-zero status'"); ok (subprocess_exit_code (p) == 1, "Exit code is 1."); subprocess_destroy (p); q = NULL; } diag ("Test signaled program"); /* Test signaled program */ p = subprocess_manager_run (sm, 2, args4, NULL); ok (p != NULL, "subprocess_manager_run: %s", strerror (errno)); if (p) { ok (subprocess_pid (p) != (pid_t) -1, "process has valid pid"); ok (subprocess_kill (p, SIGKILL) >= 0, "subprocess_kill"); q = subprocess_manager_wait (sm); ok (p == q, "subprocess_manager_wait returns correct process"); is (subprocess_state_string (p), "Exited", "State is now 'Exited'"); is (subprocess_exit_string (p), "Killed", "Exit string is 'Killed'"); ok (subprocess_signaled (p) == 9, "Killed by signal 9."); ok (subprocess_exit_status (p) == 0x9, "Exit status is 0x9 (Killed)"); ok (subprocess_exit_code (p) == 137, "Exit code is 137 (128+9)"); subprocess_destroy (p); } q = NULL; diag ("Test fork/exec interface"); /* Test separate fork/exec interface */ p = subprocess_create (sm); ok (p != NULL, "subprocess_create works"); ok (subprocess_pid (p) == (pid_t) -1, "Initial pid value is -1"); ok (subprocess_fork (p) == -1, "fork on unitialized subprocess should fail"); ok (subprocess_kill (p, 1) == -1, "kill on unitialized subprocess should fail"); is (subprocess_state_string (p), "Pending", "initial subprocess state is 'Pending'"); ok (subprocess_argv_append (p, "true") >= 0, "set argv"); ok (subprocess_setenv (p, "PATH", getenv ("PATH"), 1) >= 0, "set dnv"); ok (subprocess_fork (p) == 0, "subprocess_fork"); is (subprocess_state_string (p), "Waiting", "subprocess is Waiting"); ok (subprocess_pid (p) > 0, "subprocess_pid() is valid"); ok (subprocess_exec (p) == 0, "subprocess_run"); is (subprocess_state_string (p), "Running", "subprocess is Running"); q = subprocess_manager_wait (sm); ok (q != NULL, "subprocess_manager_wait"); ok (q == p, "got correct child after wait"); ok (subprocess_exit_code (p) == 0, "Child exited normally"); subprocess_destroy (p); q = NULL; diag ("Test exec failure"); /* Test exec failure */ p = subprocess_create (sm); ok (p != NULL, "subprocess create"); ok (subprocess_argv_append (p, "/unlikely/program") >= 0, "set argv"); ok (subprocess_setenv (p, "PATH", getenv ("PATH"), 1) >= 0, "setnv"); ok (subprocess_fork (p) == 0, "subprocess_fork"); rc = subprocess_exec (p); ok (rc < 0, "subprocess_exec should fail"); ok (errno == ENOENT, "errno should be ENOENT"); is (subprocess_state_string (p), "Exec Failure", "State is Exec Failed"); is (subprocess_exit_string (p), "Exec Failure", "Exit state is Exec Failed"); subprocess_destroy (p); diag ("Test set working directory"); /* Test set working directory */ p = subprocess_create (sm); ok (p != NULL, "subprocess create"); ok (subprocess_get_cwd (p) == NULL, "CWD is not set"); ok (subprocess_set_cwd (p, "/tmp") >= 0, "Set CWD to /tmp"); is (subprocess_get_cwd (p), "/tmp", "CWD is now /tmp"); ok (subprocess_setenv (p, "PATH", getenv ("PATH"), 1) >= 0, "set PATH"); ok (subprocess_set_command (p, "test `pwd` = '/tmp'" ) >= 0, "Set args"); ok (subprocess_run (p) >= 0, "subprocess_run"); is (subprocess_state_string (p), "Running", "subprocess now running"); q = subprocess_manager_wait (sm); ok (q != NULL, "subprocess_manager_wait: %s", strerror (errno)); ok (q == p, "subprocess_manager_wait() got expected subprocess"); ok (subprocess_exited (p), "subprocess exited"); ok (!subprocess_signaled (p), "subprocess didn't die from signal"); ok (subprocess_exit_code (p) == 0, "subprocess successfully run in /tmp"); subprocess_destroy (p); diag ("Test subprocess_reap interface"); /* Test subprocess_reap */ p = subprocess_create (sm); q = subprocess_create (sm); ok (subprocess_argv_append (p, "/bin/true") >= 0, "set argv for first subprocess"); ok (subprocess_argv_append (q, "/bin/true") >= 0, "set argv for second subprocess"); ok (subprocess_run (p) >= 0, "run process 1"); ok (subprocess_run (q) >= 0, "run process 2"); ok (subprocess_reap (q) >= 0, "reap process 2"); ok (subprocess_exited (q), "process 2 is now exited"); ok (subprocess_exit_code (q) == 0, "process 2 exited with code 0"); ok (subprocess_reap (p) >= 0, "reap process 1"); ok (subprocess_exited (p), "process 1 is now exited"); ok (subprocess_exit_code (p) == 0, "process 1 exited with code 0"); subprocess_destroy (p); subprocess_destroy (q); diag ("Test subprocess I/O"); /* Test subprocess output */ p = subprocess_create (sm); ok (p != NULL, "subprocess_create"); ok (subprocess_argv_append (p, "/bin/echo") >= 0, "subprocess_argv_append"); ok (subprocess_argv_append (p, "Hello, 123") >= 0, "subprocess_argv_append"); buf = NULL; subprocess_set_context (p, "io", (void *) &buf); ok (subprocess_get_context (p, "io") == (void *) &buf, "able to set subprocess context"); ok (subprocess_set_io_callback (p, testio_cb) >= 0, "set io callback"); ok (subprocess_run (p) >= 0, "run process with IO"); ok (subprocess_reap (p) >= 0, "reap process"); ok (subprocess_flush_io (p) >=0, "flush io"); ok (subprocess_exited (p) >= 0, "process is now exited"); ok (subprocess_exit_code (p) == 0, "process exited normally"); ok (buf != NULL, "io buffer is allocated"); if (buf) { ok (strcmp (buf, "Hello, 123\n") == 0, "io buffer is correct"); free (buf); } subprocess_destroy (p); /* Test subprocess input */ diag ("test subprocess stdin"); p = subprocess_create (sm); ok (p != NULL, "subprocess_create"); ok (subprocess_argv_append (p, "/bin/cat") >= 0, "subprocess_argv_append"); buf = NULL; subprocess_set_context (p, "io", (void *) &buf); ok (subprocess_get_context (p, "io") == (void *) &buf, "able to set subprocess context"); ok (subprocess_set_io_callback (p, testio_cb) >= 0, "set io callback"); ok (subprocess_run (p) >= 0, "run process with IO"); ok (subprocess_write (p, "Hello\n", 7, true) >= 0, "write to subprocess"); ok (subprocess_reap (p) >= 0, "reap process"); ok (subprocess_flush_io (p) >= 0, "manually flush io"); ok (subprocess_io_complete (p) == 1, "io is now complete"); ok (subprocess_exited (p) >= 0, "process is now exited"); ok (subprocess_exit_code (p) == 0, "process exited normally"); ok (buf != NULL, "io buffer is allocated"); if (buf) { ok (strcmp (buf, "Hello\n") == 0, "io buffer is correct"); free (buf); } subprocess_destroy (p); subprocess_manager_destroy (sm); end_fdcount = fdcount (); diag ("final fd count %d", end_fdcount); ok (start_fdcount == end_fdcount, "no file descriptors were leaked"); done_testing (); }
int main(int argc, char** argv) { const char *tmp = getenv ("TMPDIR"); char file[PATH_MAX]; char dir[PATH_MAX]; char dir2[PATH_MAX]; struct stat sb; int fd, len; plan (NO_PLAN); /* Independent file and dir */ len = snprintf (file, sizeof (file), "%s/cleanup_test.XXXXXX", tmp ? tmp : "/tmp"); if ((len < 0) || (len >= sizeof (file))) BAIL_OUT ("snprintf failed creating tmp file path"); if (!(fd = mkstemp (file))) BAIL_OUT ("could not create tmp file"); close (fd); len = snprintf (dir, sizeof (dir), "%s/cleanup_test.XXXXXX", tmp ? tmp : "/tmp"); if ((len < 0) || (len >= sizeof (dir))) BAIL_OUT ("snprintf failed creating tmp directory"); if (!mkdtemp (dir)) BAIL_OUT ("could not create tmp directory"); cleanup_push_string (cleanup_file, file); cleanup_push_string (cleanup_directory, dir); cleanup_run (); ok (stat (file, &sb) < 0 && errno == ENOENT, "cleanup removed independent file"); ok (stat (dir, &sb) < 0 && errno == ENOENT, "cleanup removed independent dir"); /* This time put file inside directory */ len = snprintf (dir, sizeof (dir), "%s/cleanup_test.XXXXXX", tmp ? tmp : "/tmp"); if ((len < 0) || (len >= sizeof (dir))) BAIL_OUT ("snprintf failed creating tmp directory"); if (!mkdtemp (dir)) BAIL_OUT ("could not create tmp directory"); len = snprintf (file, sizeof (file), "%s/file", dir); if ((len < 0) || (len >= sizeof (file))) BAIL_OUT ("snprintf failed creating tmp file path"); if (!(fd = open (file, O_CREAT, 0644))) BAIL_OUT ("could not create tmp file"); close (fd); cleanup_push_string (cleanup_directory, dir); cleanup_push_string (cleanup_file, file); cleanup_run (); ok (stat (file, &sb) < 0 && errno == ENOENT, "cleanup removed file pushed second"); ok (stat (dir, &sb) < 0 && errno == ENOENT, "cleanup removed dir pushed first"); /* Same but reverse push order */ len = snprintf (dir, sizeof (dir), "%s/cleanup_test.XXXXXX", tmp ? tmp : "/tmp"); if ((len < 0) || (len >= sizeof (dir))) BAIL_OUT ("snprintf failed creating tmp directory"); if (!mkdtemp (dir)) BAIL_OUT ("could not create tmp directory"); len = snprintf (file, sizeof (file), "%s/file", dir); if ((len < 0) || (len >= sizeof (file))) BAIL_OUT ("snprintf failed creating tmp file path"); if (!(fd = open (file, O_CREAT, 0644))) BAIL_OUT ("could not create tmp file"); close (fd); cleanup_push_string (cleanup_file, file); cleanup_push_string (cleanup_directory, dir); cleanup_run (); ok (stat (dir, &sb) == 0, "cleanup failed to remove dir pushed first"); ok (stat (file, &sb) < 0 && errno == ENOENT, "cleanup removed file pushed second (1 deep)"); if (rmdir (dir) < 0) BAIL_OUT ("rmdir %s failed", dir); /* Same but recursive removal */ len = snprintf (dir, sizeof (dir), "%s/cleanup_test.XXXXXX", tmp ? tmp : "/tmp"); if ((len < 0) || (len >= sizeof (dir))) BAIL_OUT ("snprintf failed creating tmp directory"); if (!mkdtemp (dir)) BAIL_OUT ("could not create tmp directory"); len = snprintf (file, sizeof (file), "%s/file", dir); if ((len < 0) || (len >= sizeof (file))) BAIL_OUT ("snprintf failed creating tmp file path"); if (!(fd = open (file, O_CREAT, 0644))) BAIL_OUT ("could not create tmp file"); close (fd); cleanup_push_string (cleanup_directory_recursive, dir); cleanup_run (); ok (stat (file, &sb) < 0 && errno == ENOENT, "cleanup removed file not pushed (1 deep)"); ok (stat (dir, &sb) < 0 && errno == ENOENT, "cleanup removed pushed dir recursively"); /* Try couple levels deep */ len = snprintf (dir, sizeof (dir), "%s/cleanup_test.XXXXXX", tmp ? tmp : "/tmp"); if ((len < 0) || (len >= sizeof (dir))) BAIL_OUT ("snprintf failed creating tmp dir path"); if (!mkdtemp (dir)) BAIL_OUT ("could not create tmp directory"); len = snprintf (dir2, sizeof (dir2), "%s/dir", dir); if ((len < 0) || (len >= sizeof (dir2))) BAIL_OUT ("snprintf failed creating tmp dir path"); if (mkdir (dir2, 0755) < 0) BAIL_OUT ("mkdir failed"); len = snprintf (file, sizeof (file), "%s/file", dir2); if ((len < 0) || (len >= sizeof (file))) BAIL_OUT ("snprintf failed creating tmp file path"); if (!(fd = open (file, O_CREAT, 0644))) BAIL_OUT ("could not create tmp file"); close (fd); cleanup_push_string (cleanup_directory_recursive, dir); cleanup_run (); ok (stat (file, &sb) < 0 && errno == ENOENT, "cleanup removed file not pushed (2 deep)"); ok (stat (dir2, &sb) < 0 && errno == ENOENT, "cleanup removed dir not pushed (1 deep)"); ok (stat (dir, &sb) < 0 && errno == ENOENT, "cleanup removed pushed dir recursively"); done_testing(); }
int main (int argc, char *argv[]) { struct queue *q; struct job *job[3]; struct job *njob[2]; struct job *j, *j_prev; plan (NO_PLAN); q = queue_create (true); if (!q) BAIL_OUT ("could not create queue"); ok (queue_size (q) == 0, "queue_size returns 0"); /* insert 1,2,3 */ job[0] = job_create_test (1, FLUX_JOB_PRIORITY_DEFAULT); job[1] = job_create_test (2, FLUX_JOB_PRIORITY_DEFAULT); job[2] = job_create_test (3, FLUX_JOB_PRIORITY_DEFAULT); ok (queue_insert (q, job[0], &job[0]->queue_handle) == 0, "queue_insert 1 pri=def"); ok (queue_insert (q, job[1], &job[1]->queue_handle) == 0, "queue_insert 2 pri=def"); ok (queue_insert (q, job[2], &job[2]->queue_handle) == 0, "queue_insert 3 pri=def"); errno = 0; ok (queue_insert (q, job[2], &job[2]->queue_handle) < 0 && errno == EEXIST, "queue_insert 3 again fails with EEXIST"); /* queue size, refcounts */ ok (queue_size (q) == 3, "queue_size returns 3"); ok (job[0]->refcount == 2 && job[1]->refcount == 2 && job[2]->refcount == 2, "queue took reference on inserted jobs"); /* iterators */ ok (queue_first (q) == job[0] && queue_next (q) == job[1] && queue_next (q) == job[2] && queue_next (q) == NULL, "queue iterators return job 1,2,3,NULL"); /* lookup_by_id */ ok (queue_lookup_by_id (q, 1) == job[0] && queue_lookup_by_id (q, 2) == job[1] && queue_lookup_by_id (q, 3) == job[2], "queue_lookup_by_id works for all three jobs"); errno = 0; ok (queue_lookup_by_id (q, 42) == NULL && errno == ENOENT, "queue_lookupby_id 42 fails with ENOENT"); /* insert high priority */ njob[0] = job_create_test (100, FLUX_JOB_PRIORITY_MAX); ok (queue_insert (q, njob[0], &njob[0]->queue_handle) == 0, "queue_insert 100 pri=max"); ok (queue_first (q) == njob[0], "queue_first returns high priority job"); /* insert low priority */ njob[1] = job_create_test (101, FLUX_JOB_PRIORITY_MIN); ok (queue_insert (q, njob[1], &njob[1]->queue_handle) == 0, "queue_insert 101 pri=min"); j_prev = NULL; j = queue_first (q); while (j) { j_prev = j; j = queue_next (q); } ok (j_prev == njob[1], "iterators find low priority job last"); /* set high priority and reorder * review: queue contains 100,1,2,3,101 */ job[2]->priority = FLUX_JOB_PRIORITY_MAX; // job 3 queue_reorder (q, job[2], job[2]->queue_handle); ok (queue_first (q) == job[2], "reorder job 3 pri=max moves that job first"); /* queue_delete */ queue_delete (q, njob[0], njob[0]->queue_handle); queue_delete (q, njob[1], njob[1]->queue_handle); ok (njob[0]->refcount == 1 && njob[1]->refcount == 1, "queue_delete dropped reference on jobs"); errno = 0; ok (queue_lookup_by_id (q, 100) == NULL && errno == ENOENT, "queue_lookup_by_id on deleted job fails with ENOENT"); /* destroy */ queue_destroy (q); ok (job[0]->refcount == 1 && job[1]->refcount == 1 && job[2]->refcount == 1, "queue dropped reference on jobs at destruction"); job_decref (job[0]); job_decref (job[1]); job_decref (job[2]); job_decref (njob[0]); job_decref (njob[1]); done_testing (); }
static void fatal_err (const char *message, void *arg) { BAIL_OUT ("fatal error: %s", message); }
static void handle_core_signal(int signo) { BAIL_OUT("Signal %d thrown", signo); }
int main (int argc, char **argv) { flux_t h; heartbeat_t *hb; flux_msg_handler_t *w; plan (18); check_codec (); (void)setenv ("FLUX_CONNECTOR_PATH", flux_conf_get ("connector_path", CONF_FLAG_INTREE), 0); ok ((h = flux_open ("loop://", 0)) != NULL, "opened loop connector"); if (!h) BAIL_OUT ("can't continue without loop handle"); flux_fatal_set (h, fatal_err, NULL); ok ((hb = heartbeat_create ()) != NULL, "heartbeat_create works"); heartbeat_set_flux (hb, h); ok (heartbeat_get_rate (hb) == 2., "heartbeat_get_rate returns default of 2s"); errno = 0; ok (heartbeat_set_rate (hb, -1) < 1 && errno == EINVAL, "heartbeat_set_rate -1 fails with EINVAL"); errno = 0; ok (heartbeat_set_rate (hb, 1000000) < 1 && errno == EINVAL, "heartbeat_set_rate 1000000 fails with EINVAL"); ok (heartbeat_set_ratestr (hb, "250ms") == 0, "heartbeat_set_ratestr 250ms works"); ok (heartbeat_get_rate (hb) == 0.250, "heartbeat_get_rate returns what was set"); ok (heartbeat_set_rate (hb, 0.1) == 0, "heartbeat_set_rate 0.1 works"); ok (heartbeat_get_rate (hb) == 0.1, "heartbeat_get_rate returns what was set"); ok (heartbeat_get_epoch (hb) == 0, "heartbeat_get_epoch works, default is zero"); w = flux_msg_handler_create (h, FLUX_MATCH_EVENT, heartbeat_event_cb, hb); ok (w != NULL, "created event watcher"); flux_msg_handler_start (w); ok (heartbeat_start (hb) == 0, "heartbeat_start works"); ok (flux_reactor_run (flux_get_reactor (h), 0) == 0, "flux reactor exited normally"); heartbeat_destroy (hb); flux_msg_handler_destroy (w); flux_close (h); done_testing (); return 0; }
static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q) { PGresult *res; c_psql_user_data_t *data; const char *host; char **column_names; char **column_values; int column_num; int rows_num; int status; int row, col; /* The user data may hold parameter information, but may be NULL. */ data = udb_query_get_user_data (q); /* Versions up to `3' don't know how to handle parameters. */ if (3 <= db->proto_version) res = c_psql_exec_query_params (db, q, data); else if ((NULL == data) || (0 == data->params_num)) res = c_psql_exec_query_noparams (db, q); else { log_err ("Connection to database \"%s\" does not support parameters " "(protocol version %d) - cannot execute query \"%s\".", db->database, db->proto_version, udb_query_get_name (q)); return -1; } column_names = NULL; column_values = NULL; #define BAIL_OUT(status) \ sfree (column_names); \ sfree (column_values); \ PQclear (res); \ return status if (PGRES_TUPLES_OK != PQresultStatus (res)) { log_err ("Failed to execute SQL query: %s", PQerrorMessage (db->conn)); log_info ("SQL query was: %s", udb_query_get_statement (q)); BAIL_OUT (-1); } rows_num = PQntuples (res); if (1 > rows_num) { BAIL_OUT (0); } column_num = PQnfields (res); column_names = (char **) calloc (column_num, sizeof (char *)); if (NULL == column_names) { log_err ("calloc failed."); BAIL_OUT (-1); } column_values = (char **) calloc (column_num, sizeof (char *)); if (NULL == column_values) { log_err ("calloc failed."); BAIL_OUT (-1); } for (col = 0; col < column_num; ++col) { /* Pointers returned by `PQfname' are freed by `PQclear' via * `BAIL_OUT'. */ column_names[col] = PQfname (res, col); if (NULL == column_names[col]) { log_err ("Failed to resolv name of column %i.", col); BAIL_OUT (-1); } } if (C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host) || (0 == strcmp (db->host, "localhost"))) host = hostname_g; else host = db->host; status = udb_query_prepare_result (q, host, "postgresql", db->database, column_names, (size_t) column_num); if (0 != status) { log_err ("udb_query_prepare_result failed with status %i.", status); BAIL_OUT (-1); } for (row = 0; row < rows_num; ++row) { for (col = 0; col < column_num; ++col) { /* Pointers returned by `PQgetvalue' are freed by `PQclear' via * `BAIL_OUT'. */ column_values[col] = PQgetvalue (res, row, col); if (NULL == column_values[col]) { log_err ("Failed to get value at (row = %i, col = %i).", row, col); break; } } /* check for an error */ if (col < column_num) continue; status = udb_query_handle_result (q, column_values); if (status != 0) { log_err ("udb_query_handle_result failed with status %i.", status); } } /* for (row = 0; row < rows_num; ++row) */ BAIL_OUT (0); #undef BAIL_OUT } /* c_psql_exec_query */
/** * @brief Validate iterator * @details Uses the iterator to walk the JSON tree and validates that all items is visited in the right order * * @param jsmn_tokens [description] * @param jsmn_len [description] * * @return [description] */ int iterator_validate(jsmntok_t *jsmn_tokens, unsigned int jsmn_len) { jsmn_iterator_t stack[1024]; jsmntok_t *jsmn_value = NULL; jsmntok_t *jsmn_identifier = NULL; unsigned int jsmn_iterator_index = 1; unsigned int stack_index = 0; unsigned int iterator_hint = 0; int exit_line = 0; int ret_value; #define JSMN_INDEX(_item_) (unsigned int)(_item_ - jsmn_tokens) #define BAIL_OUT() do { exit_line = __LINE__; goto error_out; } while(0) /* Setup root item */ stack_index = 0; if ((ret_value = jsmn_iterator_init(&stack[stack_index], jsmn_tokens, jsmn_len, 0)) < 0) { BAIL_OUT(); } /* Set hint to first item */ iterator_hint = 1; /* Index for first item */ jsmn_iterator_index = 1; /* Iterate over all items, only abort on error. We don't pass iterator_hint which means that the iterator will fallback to internal function to determine where next object begins*/ while ((ret_value = jsmn_iterator_next(&stack[stack_index], &jsmn_identifier, &jsmn_value, 0)) >= 0) { /* No more items, need to pop stack if possible */ if (ret_value == 0) { /* Back at root item, so bail out */ if (stack_index == 0) break; /* parser_pos should point at the index after the current Array/Object, we use it to hint to the outer Array/Object where next item is */ iterator_hint = stack[stack_index].parser_pos; /* Pop the stack */ stack_index--; /* Continue using new stack pointer */ continue; } /* Validate that iterator hint is correct (need to compensate for Object) */ if (iterator_hint != JSMN_INDEX(jsmn_value) - (jsmn_identifier ? 1 : 0)) BAIL_OUT(); /* We have identifier so we are inside object, add this before the value */ if (jsmn_identifier) { if (jsmn_iterator_index != JSMN_INDEX(jsmn_identifier)) BAIL_OUT(); jsmn_iterator_index++; } if (jsmn_iterator_index != JSMN_INDEX(jsmn_value)) BAIL_OUT(); jsmn_iterator_index++; /* Always put iterator_hint to the next value, if end of Array/Object it will be updated when popping the stack */ iterator_hint = JSMN_INDEX(jsmn_value) + 1; /* Need to handle sublevels before next object */ if (jsmn_value->type == JSMN_OBJECT || jsmn_value->type == JSMN_ARRAY) { if (stack_index + 1 >= countof(stack)) BAIL_OUT(); /* Initiate new iterator on the stack */ if (jsmn_iterator_init(&stack[stack_index + 1], jsmn_tokens, jsmn_len, stack[stack_index].parser_pos) < 0) BAIL_OUT(); /* Update stack pointer */ stack_index++; } } /* Check for error abort of while loop */ if (ret_value != 0) BAIL_OUT(); /* Check so we have visited all items */ if (jsmn_iterator_index != jsmn_len) BAIL_OUT(); return 0; error_out: printf("exit_line: %d\r\n", exit_line); if (jsmn_iterator_index != jsmn_len) { return (int)jsmn_iterator_index; } return -100; }
int main (int ac, char *av[]) { struct idset *ids = NULL; struct rnode *n = NULL; plan (NO_PLAN); if (!(n = rnode_create (0, "0-3"))) BAIL_OUT ("could not create an rnode object"); ok (rnode_avail (n) == 4, "rnode_avail == 4"); ok (rnode_alloc (n, 5, &ids) < 0 && errno == ENOSPC, "rnode_alloc too many cores returns errno ENOSPC"); rnode_alloc_and_check (n, 1, "0"); ok (rnode_avail (n) == 3, "rnode_avail == 3"); rnode_avail_check (n, "1-3"); rnode_alloc_and_check (n, 1, "1"); ok (rnode_avail (n) == 2, "rnode_avail == 2"); rnode_avail_check (n, "2-3"); rnode_alloc_and_check (n, 2, "2-3"); ok (rnode_avail (n) == 0, "rnode_avail == 0"); rnode_avail_check (n, ""); ok (rnode_alloc (n, 1, &ids) < 0 && errno == ENOSPC && ids == NULL, "rnode_alloc on empty rnode fails with ENOSPC"); ok (rnode_free (n, "3-4") < 0 && errno == ENOENT, "rnode_free with invalid ids fails"); ok (rnode_avail (n) == 0, "rnode_avail still is 0"); rnode_avail_check (n, ""); ok (rnode_free (n, "0-1") == 0, "rnode_free (0-1) works"); ok (rnode_avail (n) == 2, "rnode_avail now is 2"); rnode_avail_check (n, "0-1"); ok (rnode_free (n, "0") < 0 && errno == EEXIST, "rnode_free of already available id fails"); ok (rnode_avail (n) == 2, "rnode_avail is still 2"); ok (rnode_free (n, "3") == 0, "rnode_free '3' works"); rnode_avail_check (n, "0-1,3"); rnode_alloc_and_check (n, 3, "0-1,3"); rnode_destroy (n); n = rnode_create_count (1, 8); if (n == NULL) BAIL_OUT ("rnode_create_count failed"); ok (n->rank == 1, "rnode rank set correctly"); ok (n != NULL, "rnode_create_count"); rnode_avail_check (n, "0-7"); rnode_destroy (n); struct idset *idset = idset_decode ("0-3"); n = rnode_create_idset (3, idset); idset_destroy (idset); if (n == NULL) BAIL_OUT ("rnode_create_idset failed"); ok (n != NULL, "rnode_create_idset"); ok (n->rank == 3, "rnode rank set correctly"); rnode_avail_check (n, "0-3"); struct idset *alloc = idset_decode ("1,3"); ok (rnode_alloc_idset (n, alloc) == 0, "rnode_alloc_idset (1,3)"); rnode_avail_check (n, "0,2"); ok (rnode_alloc_idset (n, alloc) < 0 && errno == EEXIST, "rnode_alloc_idset with idset already allocated returns EEXIST"); ok (rnode_free_idset (n, alloc) == 0, "rnode_free_idset (1,3)"); rnode_avail_check (n, "0-3"); ok (rnode_free_idset (n, alloc) < 0 && errno == EEXIST, "rnode_free_idset with idset already available returns EEXIST"); idset_destroy (alloc); alloc = idset_decode ("4-7"); ok (rnode_alloc_idset (n, alloc) < 0 && errno == ENOENT, "rnode_alloc_idset with invalid ids return ENOENT"); ok (rnode_free_idset (n, alloc) < 0 && errno == ENOENT, "rnode_free_idset with invalid ids return ENOENT"); idset_destroy (alloc); rnode_destroy (n); done_testing (); }
/* db->db_lock must be locked when calling this function */ static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q, udb_query_preparation_area_t *prep_area) { PGresult *res; c_psql_user_data_t *data; const char *host; char **column_names; char **column_values; int column_num; int rows_num; int status; int row, col; /* The user data may hold parameter information, but may be NULL. */ data = udb_query_get_user_data (q); /* Versions up to `3' don't know how to handle parameters. */ if (3 <= db->proto_version) res = c_psql_exec_query_params (db, q, data); else if ((NULL == data) || (0 == data->params_num)) res = c_psql_exec_query_noparams (db, q); else { log_err ("Connection to database \"%s\" (%s) does not support " "parameters (protocol version %d) - " "cannot execute query \"%s\".", db->database, db->instance, db->proto_version, udb_query_get_name (q)); return -1; } /* give c_psql_write() a chance to acquire the lock if called recursively * through dispatch_values(); this will happen if, both, queries and * writers are configured for a single connection */ pthread_mutex_unlock (&db->db_lock); column_names = NULL; column_values = NULL; if (PGRES_TUPLES_OK != PQresultStatus (res)) { pthread_mutex_lock (&db->db_lock); if ((CONNECTION_OK != PQstatus (db->conn)) && (0 == c_psql_check_connection (db))) { PQclear (res); return c_psql_exec_query (db, q, prep_area); } log_err ("Failed to execute SQL query: %s", PQerrorMessage (db->conn)); log_info ("SQL query was: %s", udb_query_get_statement (q)); PQclear (res); return -1; } #define BAIL_OUT(status) \ sfree (column_names); \ sfree (column_values); \ PQclear (res); \ pthread_mutex_lock (&db->db_lock); \ return status rows_num = PQntuples (res); if (1 > rows_num) { BAIL_OUT (0); } column_num = PQnfields (res); column_names = (char **) calloc (column_num, sizeof (char *)); if (NULL == column_names) { log_err ("calloc failed."); BAIL_OUT (-1); } column_values = (char **) calloc (column_num, sizeof (char *)); if (NULL == column_values) { log_err ("calloc failed."); BAIL_OUT (-1); } for (col = 0; col < column_num; ++col) { /* Pointers returned by `PQfname' are freed by `PQclear' via * `BAIL_OUT'. */ column_names[col] = PQfname (res, col); if (NULL == column_names[col]) { log_err ("Failed to resolve name of column %i.", col); BAIL_OUT (-1); } } if (C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host) || (0 == strcmp (db->host, "127.0.0.1")) || (0 == strcmp (db->host, "localhost"))) host = hostname_g; else host = db->host; status = udb_query_prepare_result (q, prep_area, host, "postgresql", db->instance, column_names, (size_t) column_num, db->interval); if (0 != status) { log_err ("udb_query_prepare_result failed with status %i.", status); BAIL_OUT (-1); } for (row = 0; row < rows_num; ++row) { for (col = 0; col < column_num; ++col) { /* Pointers returned by `PQgetvalue' are freed by `PQclear' via * `BAIL_OUT'. */ column_values[col] = PQgetvalue (res, row, col); if (NULL == column_values[col]) { log_err ("Failed to get value at (row = %i, col = %i).", row, col); break; } } /* check for an error */ if (col < column_num) continue; status = udb_query_handle_result (q, prep_area, column_values); if (status != 0) { log_err ("udb_query_handle_result failed with status %i.", status); } } /* for (row = 0; row < rows_num; ++row) */ udb_query_finish_result (q, prep_area); BAIL_OUT (0); #undef BAIL_OUT } /* c_psql_exec_query */
int main (int argc, char *argv[]) { flux_msg_t *msg; flux_t *h; flux_reactor_t *reactor; plan (NO_PLAN); (void)setenv ("FLUX_CONNECTOR_PATH", flux_conf_get ("connector_path", CONF_FLAG_INTREE), 0); ok ((h = flux_open ("loop://", FLUX_O_COPROC)) != NULL, "opened loop connector"); if (!h) BAIL_OUT ("can't continue without loop handle"); flux_fatal_set (h, fatal_err, NULL); ok ((reactor = flux_get_reactor(h)) != NULL, "obtained reactor"); if (!h) BAIL_OUT ("can't continue without reactor"); ok (flux_msg_handler_addvec (h, htab, NULL) == 0, "registered message handlers"); /* test continues in rpctest_begin_cb() so that rpc calls * can sleep while we answer them */ ok ((msg = flux_request_encode ("rpctest.begin", NULL)) != NULL, "encoded rpctest.begin request OK"); ok (flux_send (h, msg, 0) == 0, "sent rpctest.begin request"); ok (flux_reactor_run (reactor, 0) == 0, "reactor completed normally"); flux_msg_destroy (msg); /* test _then: Slightly tricky. * Send request. We're not in a coproc ctx here in main(), so there * will be no response, therefore, check will be false. Register * continuation, start reactor. Response will be received, continuation * will be invoked. Continuation stops the reactor. */ flux_rpc_t *r; ok ((r = flux_rpc (h, "rpctest.echo", "{}", FLUX_NODEID_ANY, 0)) != NULL, "flux_rpc with payload when payload is expected works"); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); /* reg/unreg _then a couple times for fun */ ok (flux_rpc_then (r, NULL, 0) == 0, "flux_rpc_then with NULL cb works"); ok (flux_rpc_then (r, then_cb, h) == 0, "flux_rpc_then works after NULL"); ok (flux_rpc_then (r, NULL, 0) == 0, "flux_rpc_then with NULL cb after non-NULL works"); ok (flux_rpc_then (r, then_cb, h) == 0, "flux_rpc_then works"); /* enough of that */ ok (flux_reactor_run (reactor, 0) == 0, "reactor completed normally"); flux_rpc_destroy (r); /* Test a _then corner case: * If _check() is called before _then(), a message may have been cached * in the flux_rpc_t. rpctest_thenbug_cb creates this condition. * Next, _then continuation is installed, but will reactor call it? * This will hang if rpc implementation doesn't return a cached message * back to the handle in _then(). Else, continuation will stop reactor. */ ok ((thenbug_r = flux_rpc (h, "rpctest.echo", "{}", FLUX_NODEID_ANY, 0)) != NULL, "thenbug: sent echo request"); do { if (!(msg = flux_request_encode ("rpctest.thenbug", NULL)) || flux_send (h, msg, 0) < 0 || flux_reactor_run (reactor, 0) < 0) { flux_msg_destroy (msg); break; } flux_msg_destroy (msg); } while (!flux_rpc_check (thenbug_r)); ok (true, "thenbug: check says message ready"); ok (flux_rpc_then (thenbug_r, then_cb, h) == 0, "thenbug: registered then - hangs on failure"); ok (flux_reactor_run (reactor, 0) == 0, "reactor completed normally"); flux_rpc_destroy (thenbug_r); flux_msg_handler_delvec (htab); flux_close (h); done_testing(); return (0); }
static int flush (lcc_connection_t *c, int argc, char **argv) { int timeout = -1; lcc_identifier_t *identifiers = NULL; int identifiers_num = 0; char **plugins = NULL; int plugins_num = 0; int status; int i; assert (strcasecmp (argv[0], "flush") == 0); #define BAIL_OUT(s) \ do { \ if (identifiers != NULL) \ free (identifiers); \ identifiers_num = 0; \ if (plugins != NULL) \ free (plugins); \ plugins_num = 0; \ return (s); \ } while (0) for (i = 1; i < argc; ++i) { char *key, *value; key = argv[i]; value = strchr (argv[i], (int)'='); if (! value) { fprintf (stderr, "ERROR: flush: Invalid option ``%s''.\n", argv[i]); BAIL_OUT (-1); } *value = '\0'; ++value; if (strcasecmp (key, "timeout") == 0) { char *endptr = NULL; timeout = (int) strtol (value, &endptr, 0); if (endptr == value) { fprintf (stderr, "ERROR: Failed to parse timeout as number: %s.\n", value); BAIL_OUT (-1); } else if ((endptr != NULL) && (*endptr != '\0')) { fprintf (stderr, "WARNING: Ignoring trailing garbage after timeout: " "%s.\n", endptr); } } else if (strcasecmp (key, "plugin") == 0) { status = array_grow ((void *)&plugins, &plugins_num, sizeof (*plugins)); if (status != 0) BAIL_OUT (status); plugins[plugins_num - 1] = value; } else if (strcasecmp (key, "identifier") == 0) { status = array_grow ((void *)&identifiers, &identifiers_num, sizeof (*identifiers)); if (status != 0) BAIL_OUT (status); memset (identifiers + (identifiers_num - 1), 0, sizeof (*identifiers)); status = parse_identifier (c, value, identifiers + (identifiers_num - 1)); if (status != 0) BAIL_OUT (status); } else { fprintf (stderr, "ERROR: flush: Unknown option `%s'.\n", key); BAIL_OUT (-1); } } if (plugins_num == 0) { status = array_grow ((void *)&plugins, &plugins_num, sizeof (*plugins)); if (status != 0) BAIL_OUT (status); assert (plugins_num == 1); plugins[0] = NULL; } for (i = 0; i < plugins_num; ++i) { if (identifiers_num == 0) { status = lcc_flush (c, plugins[i], NULL, timeout); if (status != 0) fprintf (stderr, "ERROR: Failed to flush plugin `%s': %s.\n", (plugins[i] == NULL) ? "(all)" : plugins[i], lcc_strerror (c)); } else { int j; for (j = 0; j < identifiers_num; ++j) { status = lcc_flush (c, plugins[i], identifiers + j, timeout); if (status != 0) { char id[1024]; lcc_identifier_to_string (c, id, sizeof (id), identifiers + j); fprintf (stderr, "ERROR: Failed to flush plugin `%s', " "identifier `%s': %s.\n", (plugins[i] == NULL) ? "(all)" : plugins[i], id, lcc_strerror (c)); } } } } BAIL_OUT (0); #undef BAIL_OUT } /* flush */
int rpctest_begin_cb (flux_t h, int type, zmsg_t **zmsg, void *arg) { uint32_t nodeid; int i, errors; int old_count; flux_rpc_t *r; const char *json_str; errno = 0; ok (!(r = flux_rpc_multi (h, NULL, "foo", "all", 0)) && errno == EINVAL, "flux_rpc_multi [0] with NULL topic fails with EINVAL"); errno = 0; ok (!(r = flux_rpc_multi (h, "bar", "foo", NULL, 0)) && errno == EINVAL, "flux_rpc_multi [0] with NULL nodeset fails with EINVAL"); errno = 0; ok (!(r = flux_rpc_multi (h, "bar", "foo", "xyz", 0)) && errno == EINVAL, "flux_rpc_multi [0] with bad nodeset fails with EINVAL"); /* working no-payload RPC */ old_count = hello_count; ok ((r = flux_rpc_multi (h, "rpctest.hello", NULL, "all", 0)) != NULL, "flux_rpc_multi [0] with no payload when none is expected works"); if (!r) BAIL_OUT ("can't continue without successful rpc call"); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); ok (flux_rpc_get (r, NULL, NULL) == 0, "flux_rpc_get works"); ok (hello_count == old_count + 1, "rpc was called once"); flux_rpc_destroy (r); /* cause remote EPROTO (unexpected payload) - picked up in _get() */ ok ((r = flux_rpc_multi (h, "rpctest.hello", "foo", "all", 0)) != NULL, "flux_rpc_multi [0] with unexpected payload works, at first"); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); errno = 0; ok (flux_rpc_get (r, NULL, NULL) < 0 && errno == EPROTO, "flux_rpc_get fails with EPROTO"); flux_rpc_destroy (r); /* fake that we have a larger session */ fake_size = 128; char s[16]; uint32_t size = 0; snprintf (s, sizeof (s), "%u", fake_size); flux_attr_fake (h, "size", s, FLUX_ATTRFLAG_IMMUTABLE); flux_get_size (h, &size); cmp_ok (size, "==", fake_size, "successfully faked flux_get_size() of %d", fake_size); /* repeat working no-payload RPC test (now with 128 nodes) */ old_count = hello_count; ok ((r = flux_rpc_multi (h, "rpctest.hello", NULL, "all", 0)) != NULL, "flux_rpc_multi [0-%d] with no payload when none is expected works", fake_size - 1); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); errors = 0; for (i = 0; i < fake_size; i++) if (flux_rpc_get (r, NULL, NULL) < 0) errors++; ok (errors == 0, "flux_rpc_get succeded %d times", fake_size); cmp_ok (hello_count - old_count, "==", fake_size, "rpc was called %d times", fake_size); flux_rpc_destroy (r); /* same with a subset */ old_count = hello_count; ok ((r = flux_rpc_multi (h, "rpctest.hello", NULL, "[0-63]", 0)) != NULL, "flux_rpc_multi [0-%d] with no payload when none is expected works", 64 - 1); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); errors = 0; for (i = 0; i < 64; i++) if (flux_rpc_get (r, &nodeid, NULL) < 0 || nodeid != i) errors++; ok (errors == 0, "flux_rpc_get succeded %d times, with correct nodeid map", 64); cmp_ok (hello_count - old_count, "==", 64, "rpc was called %d times", 64); flux_rpc_destroy (r); /* same with echo payload */ ok ((r = flux_rpc_multi (h, "rpctest.echo", "foo", "[0-63]", 0)) != NULL, "flux_rpc_multi [0-%d] ok", 64 - 1); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); errors = 0; for (i = 0; i < 64; i++) { if (flux_rpc_get (r, NULL, &json_str) < 0 || !json_str || strcmp (json_str, "foo") != 0) errors++; } ok (errors == 0, "flux_rpc_get succeded %d times, with correct return payload", 64); flux_rpc_destroy (r); /* detect partial failure without mresponse */ nodeid_fake_error = 20; ok ((r = flux_rpc_multi (h, "rpctest.nodeid", NULL, "[0-63]", 0)) != NULL, "flux_rpc_multi [0-%d] ok", 64 - 1); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); for (i = 0; i < 64; i++) { if (flux_rpc_get (r, &nodeid, &json_str) < 0) break; } ok (i == 20 && errno == EPERM, "flux_rpc_get correctly reports single error"); flux_rpc_destroy (r); /* test _then (still at fake session size of 128) */ ok ((then_r = flux_rpc_multi (h, "rpctest.hello", NULL, "[0-127]", 0)) != NULL, "flux_rpc_multi [0-127] ok"); ok (flux_rpc_then (then_r, then_cb, h) == 0, "flux_rpc_then works"); /* then_cb stops reactor; results reported, then_r destroyed in main() */ return 0; }