diff --git a/test/rpc_client/Makefile b/test/rpc_client/Makefile index 50e976a27..58e2c9ffa 100644 --- a/test/rpc_client/Makefile +++ b/test/rpc_client/Makefile @@ -40,7 +40,7 @@ APP = rpc_client_test C_SRCS := rpc_client_test.c -SPDK_LIB_LIST = jsonrpc json log util +SPDK_LIB_LIST = jsonrpc json rpc log util LIBS += $(SPDK_LIB_LINKER_ARGS) $(ENV_LINKER_ARGS) diff --git a/test/rpc_client/rpc_client.sh b/test/rpc_client/rpc_client.sh index 296a6fff5..b85fa2db2 100755 --- a/test/rpc_client/rpc_client.sh +++ b/test/rpc_client/rpc_client.sh @@ -7,30 +7,8 @@ set -e source $rootdir/test/common/autotest_common.sh -function rpc_client_test() { - if [ $(uname -s) = Linux ]; then - local conf=$rootdir/test/bdev/bdev.conf.in - - if [ ! -e $conf ]; then - return 1 - fi - - $rootdir/test/app/bdev_svc/bdev_svc -i 0 -c ${conf} & - svc_pid=$! - echo "Process bdev_svc pid: $svc_pid" - waitforlisten $svc_pid - trap "killprocess $svc_pid" SIGINT SIGTERM EXIT - - $rootdir/test/rpc_client/rpc_client_test - - killprocess $svc_pid - fi - - return 0 -} - timing_enter rpc_client -rpc_client_test +$rootdir/test/rpc_client/rpc_client_test timing_exit rpc_client trap - SIGINT SIGTERM EXIT diff --git a/test/rpc_client/rpc_client_test.c b/test/rpc_client/rpc_client_test.c index 5e9514ad0..1814e7854 100644 --- a/test/rpc_client/rpc_client_test.c +++ b/test/rpc_client/rpc_client_test.c @@ -34,8 +34,12 @@ #include "spdk/stdinc.h" #include "spdk/event.h" #include "spdk/jsonrpc.h" +#include "spdk/util.h" +#include "spdk/rpc.h" + #define RPC_MAX_METHODS 200 +#define JOIN_TIMEOUT_S 1 static const char *g_rpcsock_addr = SPDK_DEFAULT_RPC_ADDR; static int g_addr_family = AF_UNIX; @@ -73,13 +77,17 @@ spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *m spdk_jsonrpc_end_request(request, w); spdk_jsonrpc_client_send_request(client, request); - rc = spdk_jsonrpc_client_recv_response(client); - if (rc) { + do { + rc = spdk_jsonrpc_client_recv_response(client); + } while (rc == -EAGAIN || rc == -ENOTCONN); + + if (rc != 0) { goto out; } json_resp = spdk_jsonrpc_client_get_response(client); if (json_resp == NULL) { + SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n"); rc = -errno; goto out; @@ -87,6 +95,7 @@ spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *m /* Check for error response */ if (json_resp->error != NULL) { + SPDK_ERRLOG("Unexpected error response\n"); rc = -1; goto out; } @@ -95,6 +104,7 @@ spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *m rc = get_jsonrpc_method_json_parser(&resp, json_resp->result); if (rc) { + SPDK_ERRLOG("get_jsonrpc_method_json_parser() failed\n"); goto out; } @@ -106,6 +116,7 @@ spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *m } rc = -1; + SPDK_ERRLOG("Method '%s' not found in response\n", method_name); out: for (i = 0; i < (int)resp.method_num; i++) { @@ -117,20 +128,166 @@ out: return rc; } -int main(int argc, char **argv) +static void +rpc_test_method_startup(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) +{ + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "rpc_test_method_startup(): Method body not implemented"); +} +SPDK_RPC_REGISTER("test_method_startup", rpc_test_method_startup, SPDK_RPC_STARTUP) + +static void +rpc_test_method_runtime(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) +{ + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "rpc_test_method_runtime(): Method body not implemented"); +} +SPDK_RPC_REGISTER("test_method_runtime", rpc_test_method_runtime, SPDK_RPC_RUNTIME) + +/* Helper function */ +static int +_sem_timedwait(sem_t *sem, __time_t sec) +{ + struct timespec timeout; + + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += sec; + + return sem_timedwait(sem, &timeout); +} + +volatile int g_rpc_server_th_stop; +static sem_t g_rpc_server_th_listening; +static sem_t g_rpc_server_th_done; + +static void * +rpc_server_th(void *arg) { - struct spdk_jsonrpc_client *client; int rc; + + rc = spdk_rpc_listen(g_rpcsock_addr); + if (rc) { + fprintf(stderr, "spdk_rpc_listen() failed: %d\n", rc); + goto out; + } + + sem_post(&g_rpc_server_th_listening); + + while (!g_rpc_server_th_stop) { + spdk_rpc_accept(); + usleep(50); + } + + spdk_rpc_close(); +out: + sem_post(&g_rpc_server_th_done); + + return (void *)(intptr_t)rc; +} + +static sem_t g_rpc_client_th_done; + +static void * +rpc_client_th(void *arg) +{ + struct spdk_jsonrpc_client *client = NULL; char *method_name = "get_rpc_methods"; + int rc; + + + rc = _sem_timedwait(&g_rpc_server_th_listening, 2); + if (rc == -1) { + fprintf(stderr, "Timeout waiting for server thread to start listening: %d\n", errno); + goto out; + } client = spdk_jsonrpc_client_connect(g_rpcsock_addr, g_addr_family); if (!client) { - return EXIT_FAILURE; + fprintf(stderr, "spdk_jsonrpc_client_connect() failed: %d\n", errno); + rc = -1; + goto out; } rc = spdk_jsonrpc_client_check_rpc_method(client, method_name); + if (rc) { + fprintf(stderr, "spdk_jsonrpc_client_check_rpc_method() failed: %d\n", errno); + goto out; + } - spdk_jsonrpc_client_close(client); +out: + if (client) { + spdk_jsonrpc_client_close(client); + } - return rc ? EXIT_FAILURE : 0; + sem_post(&g_rpc_client_th_done); + return (void *)(intptr_t)rc; +} + +int main(int argc, char **argv) +{ + pthread_t srv_tid, client_tid; + int srv_tid_valid; + int client_tid_valid = -1; + int th_rc = INT_MIN; + int rc = 0, err_cnt = 0; + + sem_init(&g_rpc_server_th_listening, 0, 0); + sem_init(&g_rpc_server_th_done, 0, 0); + sem_init(&g_rpc_client_th_done, 0, 0); + + srv_tid_valid = pthread_create(&srv_tid, NULL, rpc_server_th, NULL); + if (srv_tid_valid != 0) { + fprintf(stderr, "pthread_create() failed to create server thread: %d\n", srv_tid_valid); + goto out; + } + + client_tid_valid = pthread_create(&client_tid, NULL, rpc_client_th, NULL); + if (client_tid_valid != 0) { + fprintf(stderr, "pthread_create(): failed to create client thread: %d\n", client_tid_valid); + goto out; + } + +out: + if (client_tid_valid == 0) { + rc = _sem_timedwait(&g_rpc_client_th_done, JOIN_TIMEOUT_S); + if (rc) { + fprintf(stderr, "failed to join client thread (rc: %d)\n", rc); + err_cnt++; + } + + rc = pthread_join(client_tid, (void **)&th_rc); + if (rc) { + fprintf(stderr, "pthread_join() on cliennt thread failed (rc: %d)\n", rc); + err_cnt++; + } else if (th_rc) { + fprintf(stderr, "cliennt thread failed reported failure(thread rc: %d)\n", th_rc); + err_cnt++; + } + } + + g_rpc_server_th_stop = 1; + + if (srv_tid_valid == 0) { + rc = _sem_timedwait(&g_rpc_server_th_done, JOIN_TIMEOUT_S); + if (rc) { + fprintf(stderr, "server thread failed to exit in %d sec: (rc: %d)\n", JOIN_TIMEOUT_S, rc); + err_cnt++; + } + + rc = pthread_join(srv_tid, (void **)&th_rc); + if (rc) { + fprintf(stderr, "pthread_join() on cliennt thread failed (rc: %d)\n", rc); + err_cnt++; + } else if (th_rc) { + fprintf(stderr, "cliennt thread failed reported failure(thread rc: %d)\n", th_rc); + err_cnt++; + } + } + + sem_destroy(&g_rpc_server_th_listening); + sem_destroy(&g_rpc_server_th_done); + sem_destroy(&g_rpc_client_th_done); + + fprintf(stderr, "%s\n", err_cnt == 0 ? "OK" : "FAILED"); + return err_cnt ? EXIT_FAILURE : 0; }