void rpctest_begin_cb (flux_t h, flux_msg_watcher_t *w, const flux_msg_t *msg, void *arg) { const char *json_str; flux_rpc_t *r; errno = 0; ok (!(r = flux_rpc (h, NULL, NULL, FLUX_NODEID_ANY, 0)) && errno == EINVAL, "flux_rpc with NULL topic fails with EINVAL"); /* working no-payload RPC */ ok ((r = flux_rpc (h, "rpctest.hello", NULL, FLUX_NODEID_ANY, 0)) != NULL, "flux_rpc with no payload when none is expected works"); 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"); flux_rpc_destroy (r); /* cause remote EPROTO (unexpected payload) - will be picked up in _get() */ ok ((r = flux_rpc (h, "rpctest.hello", "foo", FLUX_NODEID_ANY, 0)) != NULL, "flux_rpc with payload when none is expected 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); /* cause remote EPROTO (missing payload) - will be picked up in _get() */ errno = 0; ok ((r = flux_rpc (h, "rpctest.echo", NULL, FLUX_NODEID_ANY, 0)) != NULL, "flux_rpc with no payload when payload is expected 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); /* working with-payload RPC */ ok ((r = flux_rpc (h, "rpctest.echo", "foo", 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"); json_str = NULL; ok (flux_rpc_get (r, NULL, &json_str) == 0 && json_str && !strcmp (json_str, "foo"), "flux_rpc_get works and returned expected payload"); flux_rpc_destroy (r); flux_reactor_stop (h); }
static void then_cb (flux_rpc_t *r, void *arg) { flux_t h = arg; const char *json_str; ok (flux_rpc_check (r) == true, "flux_rpc_check says get won't block in then callback"); json_str = NULL; ok (flux_rpc_get (r, NULL, &json_str) == 0 && json_str && !strcmp (json_str, "xxx"), "flux_rpc_get works and returned expected payload in then callback"); flux_reactor_stop (h); }
int main (int argc, char *argv[]) { flux_msg_t *msg; flux_t h; plan (33); (void)setenv ("FLUX_CONNECTOR_PATH", CONNECTOR_PATH, 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 (flux_msg_watcher_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_start (h) == 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", "xxx", 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_start (h) == 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", "xxx", 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_start (h) < 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_start (h) == 0, "reactor completed normally"); flux_rpc_destroy (thenbug_r); flux_msg_watcher_delvec (h, htab); flux_close (h); done_testing(); return (0); }
void rpctest_thenbug_cb (flux_t h, flux_msg_watcher_t *w, const flux_msg_t *msg, void *arg) { (void)flux_rpc_check (thenbug_r); flux_reactor_stop (h); }
void rpctest_begin_cb (flux_t *h, flux_msg_handler_t *w, const flux_msg_t *msg, void *arg) { const char *json_str; flux_rpc_t *r; errno = 0; ok (!(r = flux_rpc (h, NULL, NULL, FLUX_NODEID_ANY, 0)) && errno == EINVAL, "flux_rpc with NULL topic fails with EINVAL"); /* working no-payload RPC */ ok ((r = flux_rpc (h, "rpctest.hello", NULL, FLUX_NODEID_ANY, 0)) != NULL, "flux_rpc with no payload when none is expected works"); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); ok (flux_rpc_get (r, NULL) == 0, "flux_rpc_get works"); flux_rpc_destroy (r); /* cause remote EPROTO (unexpected payload) - will be picked up in _get() */ ok ((r = flux_rpc (h, "rpctest.hello", "{}", FLUX_NODEID_ANY, 0)) != NULL, "flux_rpc with payload when none is expected works, at first"); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); errno = 0; ok (flux_rpc_get (r, NULL) < 0 && errno == EPROTO, "flux_rpc_get fails with EPROTO"); flux_rpc_destroy (r); /* cause remote EPROTO (missing payload) - will be picked up in _get() */ errno = 0; ok ((r = flux_rpc (h, "rpctest.echo", NULL, FLUX_NODEID_ANY, 0)) != NULL, "flux_rpc with no payload when payload is expected works, at first"); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); errno = 0; ok (flux_rpc_get (r, NULL) < 0 && errno == EPROTO, "flux_rpc_get fails with EPROTO"); flux_rpc_destroy (r); /* working with-payload RPC */ 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"); json_str = NULL; ok (flux_rpc_get (r, &json_str) == 0 && json_str && !strcmp (json_str, "{}"), "flux_rpc_get works and returned expected payload"); flux_rpc_destroy (r); /* working with-payload RPC (raw) */ char *d, data[] = "aaaaaaaaaaaaaaaaaaaa"; int l, len = strlen (data); ok ((r = flux_rpc_raw (h, "rpctest.rawecho", data, len, FLUX_NODEID_ANY, 0)) != NULL, "flux_rpc_raw with payload when payload is expected works"); ok (flux_rpc_check (r) == false, "flux_rpc_check says get would block"); json_str = NULL; ok (flux_rpc_get_raw (r, &d, &l) == 0 && d != NULL && l == len && memcmp (data, d, len) == 0, "flux_rpc_get_raw works and returned expected payload"); flux_rpc_destroy (r); /* use newish pack/unpack payload interfaces */ int i = 0; ok ((r = flux_rpcf (h, "rpctest.incr", FLUX_NODEID_ANY, 0, "{s:i}", "n", 107)) != NULL, "flux_rpcf works"); ok (flux_rpc_getf (r, "{s:i}", "n", &i) == 0, "flux_rpc_getf works"); ok (i == 108, "and service returned incremented value"); flux_rpc_destroy (r); flux_reactor_stop (flux_get_reactor (h)); }
void rpctest_thenbug_cb (flux_t *h, flux_msg_handler_t *w, const flux_msg_t *msg, void *arg) { (void)flux_rpc_check (thenbug_r); flux_reactor_stop (flux_get_reactor (h)); }
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; }