LCOV - code coverage report
Current view: top level - spdk/test/rpc_client - rpc_client_test.c (source / functions) Hit Total Coverage
Test: Combined Lines: 144 222 64.9 %
Date: 2024-07-14 22:57:34 Functions: 15 17 88.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 68 172 39.5 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2018 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : #include "spdk/event.h"
       8                 :            : #include "spdk/jsonrpc.h"
       9                 :            : #include "spdk/util.h"
      10                 :            : #include "spdk/rpc.h"
      11                 :            : 
      12                 :            : 
      13                 :            : #define RPC_MAX_METHODS 200
      14                 :            : #define JOIN_TIMEOUT_S 1
      15                 :            : 
      16                 :            : static const char *g_rpcsock_addr = SPDK_DEFAULT_RPC_ADDR;
      17                 :            : static int g_addr_family = AF_UNIX;
      18                 :            : 
      19                 :            : #define RPC_MAX_METHODS 200
      20                 :            : 
      21                 :            : struct get_jsonrpc_methods_resp {
      22                 :            :         char *method_names[RPC_MAX_METHODS];
      23                 :            :         size_t method_num;
      24                 :            : };
      25                 :            : 
      26                 :            : static int
      27                 :       2468 : _rpc_client_wait_for_response(struct spdk_jsonrpc_client *client)
      28                 :            : {
      29                 :            :         int rc;
      30                 :            : 
      31                 :            :         do {
      32                 :      11314 :                 rc = spdk_jsonrpc_client_poll(client, 1);
      33   [ +  +  -  + ]:      11314 :         } while (rc == 0 || rc == -ENOTCONN);
      34                 :            : 
      35         [ -  + ]:         63 :         if (rc <= 0) {
      36                 :          0 :                 SPDK_ERRLOG("Failed to get response: %d\n", rc);
      37                 :            :         }
      38                 :            : 
      39                 :         63 :         return rc;
      40                 :            : }
      41                 :            : 
      42                 :            : static int
      43                 :         21 : get_jsonrpc_method_json_parser(struct get_jsonrpc_methods_resp *resp,
      44                 :            :                                const struct spdk_json_val *result)
      45                 :            : {
      46                 :         21 :         return spdk_json_decode_array(result, spdk_json_decode_string, resp->method_names,
      47                 :            :                                       RPC_MAX_METHODS, &resp->method_num, sizeof(char *));
      48                 :            : }
      49                 :            : 
      50                 :            : static int
      51                 :         21 : spdk_jsonrpc_client_check_rpc_method(struct spdk_jsonrpc_client *client, char *method_name)
      52                 :            : {
      53                 :            :         int rc, i;
      54                 :         21 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
      55                 :         21 :         struct get_jsonrpc_methods_resp resp = {};
      56                 :            :         struct spdk_json_write_ctx *w;
      57                 :            :         struct spdk_jsonrpc_client_request *request;
      58                 :            : 
      59                 :         21 :         request = spdk_jsonrpc_client_create_request();
      60         [ -  + ]:         21 :         if (request == NULL) {
      61                 :          0 :                 return -ENOMEM;
      62                 :            :         }
      63                 :            : 
      64                 :         21 :         w = spdk_jsonrpc_begin_request(request, 1, "rpc_get_methods");
      65                 :         21 :         spdk_jsonrpc_end_request(request, w);
      66                 :         21 :         spdk_jsonrpc_client_send_request(client, request);
      67                 :            : 
      68                 :         21 :         rc = _rpc_client_wait_for_response(client);
      69         [ -  + ]:         21 :         if (rc <= 0) {
      70                 :          0 :                 goto out;
      71                 :            :         }
      72                 :            : 
      73                 :         21 :         json_resp = spdk_jsonrpc_client_get_response(client);
      74         [ -  + ]:         21 :         if (json_resp == NULL) {
      75                 :          0 :                 SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
      76                 :          0 :                 rc = -1;
      77                 :          0 :                 goto out;
      78                 :            : 
      79                 :            :         }
      80                 :            : 
      81                 :            :         /* Check for error response */
      82         [ -  + ]:         21 :         if (json_resp->error != NULL) {
      83                 :          0 :                 SPDK_ERRLOG("Unexpected error response\n");
      84                 :          0 :                 rc = -1;
      85                 :          0 :                 goto out;
      86                 :            :         }
      87                 :            : 
      88         [ -  + ]:         21 :         assert(json_resp->result);
      89                 :            : 
      90                 :         21 :         rc = get_jsonrpc_method_json_parser(&resp, json_resp->result);
      91         [ -  + ]:         21 :         if (rc) {
      92                 :          0 :                 SPDK_ERRLOG("get_jsonrpc_method_json_parser() failed\n");
      93                 :          0 :                 goto out;
      94                 :            :         }
      95                 :            : 
      96         [ +  - ]:        110 :         for (i = 0; i < (int)resp.method_num; i++) {
      97   [ +  +  -  +  :        110 :                 if (strcmp(method_name, resp.method_names[i]) == 0) {
                   +  + ]
      98                 :         21 :                         rc = 0;
      99                 :         21 :                         goto out;
     100                 :            :                 }
     101                 :            :         }
     102                 :            : 
     103                 :          0 :         rc = -1;
     104                 :          0 :         SPDK_ERRLOG("Method '%s' not found in response\n", method_name);
     105                 :            : 
     106                 :         21 : out:
     107         [ +  + ]:        147 :         for (i = 0; i < (int)resp.method_num; i++) {
     108                 :        126 :                 SPDK_NOTICELOG("%s\n", resp.method_names[i]);
     109                 :        126 :                 free(resp.method_names[i]);
     110                 :            :         }
     111                 :            : 
     112                 :         21 :         spdk_jsonrpc_client_free_response(json_resp);
     113                 :         21 :         return rc;
     114                 :            : }
     115                 :            : 
     116                 :            : static int
     117                 :         21 : spdk_jsonrpc_client_check_null_params_method(struct spdk_jsonrpc_client *client)
     118                 :            : {
     119                 :            :         int rc;
     120                 :         21 :         bool res = false;
     121                 :         21 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
     122                 :            :         struct spdk_json_write_ctx *w;
     123                 :            :         struct spdk_jsonrpc_client_request *request;
     124                 :            : 
     125                 :         21 :         request = spdk_jsonrpc_client_create_request();
     126         [ -  + ]:         21 :         if (request == NULL) {
     127                 :          0 :                 return -ENOMEM;
     128                 :            :         }
     129                 :            : 
     130                 :         21 :         w = spdk_jsonrpc_begin_request(request, 1, "test_null_params");
     131                 :         21 :         spdk_json_write_name(w, "params");
     132                 :         21 :         spdk_json_write_null(w);
     133                 :         21 :         spdk_jsonrpc_end_request(request, w);
     134                 :         21 :         spdk_jsonrpc_client_send_request(client, request);
     135                 :            : 
     136                 :         21 :         rc = _rpc_client_wait_for_response(client);
     137         [ -  + ]:         21 :         if (rc <= 0) {
     138                 :          0 :                 goto out;
     139                 :            :         }
     140                 :            : 
     141                 :         21 :         json_resp = spdk_jsonrpc_client_get_response(client);
     142         [ -  + ]:         21 :         if (json_resp == NULL) {
     143                 :          0 :                 SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
     144                 :          0 :                 rc = -1;
     145                 :          0 :                 goto out;
     146                 :            : 
     147                 :            :         }
     148                 :            : 
     149                 :            :         /* Check for error response */
     150         [ -  + ]:         21 :         if (json_resp->error != NULL) {
     151                 :          0 :                 SPDK_ERRLOG("Unexpected error response\n");
     152                 :          0 :                 rc = -1;
     153                 :          0 :                 goto out;
     154                 :            :         }
     155                 :            : 
     156         [ -  + ]:         21 :         assert(json_resp->result);
     157                 :            : 
     158   [ +  -  -  +  :         21 :         if (spdk_json_decode_bool(json_resp->result, &res) != 0 || res != true) {
                   -  + ]
     159                 :          0 :                 SPDK_ERRLOG("Response is not a boolean or it is not 'true'\n");
     160                 :          0 :                 rc = -EINVAL;
     161                 :          0 :                 goto out;
     162                 :            :         } else {
     163                 :         21 :                 rc = 0;
     164                 :            :         }
     165                 :            : 
     166                 :         21 : out:
     167                 :         21 :         spdk_jsonrpc_client_free_response(json_resp);
     168                 :         21 :         return rc;
     169                 :            : }
     170                 :            : 
     171                 :            : static void
     172                 :          0 : rpc_test_method_startup(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
     173                 :            : {
     174                 :          0 :         spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     175                 :            :                                          "rpc_test_method_startup(): Method body not implemented");
     176                 :          0 : }
     177                 :         21 : SPDK_RPC_REGISTER("test_method_startup", rpc_test_method_startup, SPDK_RPC_STARTUP)
     178                 :            : 
     179                 :            : static void
     180                 :          0 : rpc_test_method_runtime(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
     181                 :            : {
     182                 :          0 :         spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     183                 :            :                                          "rpc_test_method_runtime(): Method body not implemented");
     184                 :          0 : }
     185                 :         21 : SPDK_RPC_REGISTER("test_method_runtime", rpc_test_method_runtime, SPDK_RPC_RUNTIME)
     186                 :            : 
     187                 :            : static void
     188                 :         21 : rpc_test_method_null_params(struct spdk_jsonrpc_request *request,
     189                 :            :                             const struct spdk_json_val *params)
     190                 :            : {
     191         [ -  + ]:         21 :         if (params != NULL) {
     192                 :          0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     193                 :            :                                                  "rpc_test_method_null_params(): Parameters are not NULL");
     194                 :          0 :                 return;
     195                 :            :         }
     196                 :            : 
     197                 :         21 :         spdk_jsonrpc_send_bool_response(request, true);
     198                 :            : }
     199                 :         21 : SPDK_RPC_REGISTER("test_null_params", rpc_test_method_null_params,
     200                 :            :                   SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
     201                 :            : 
     202                 :            : static bool g_conn_close_detected;
     203                 :            : 
     204                 :            : static void
     205                 :         21 : rpc_test_conn_close_cb(struct spdk_jsonrpc_server_conn *conn, void *ctx)
     206                 :            : {
     207         [ -  + ]:         21 :         assert((intptr_t)ctx == 42);
     208                 :         21 :         g_conn_close_detected = true;
     209                 :         21 : }
     210                 :            : 
     211                 :            : static void
     212                 :         21 : rpc_hook_conn_close(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
     213                 :            : {
     214                 :         21 :         struct spdk_jsonrpc_server_conn *conn = spdk_jsonrpc_get_conn(request);
     215                 :            :         int rc;
     216                 :            : 
     217                 :         21 :         rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
     218         [ -  + ]:         21 :         if (rc != 0) {
     219                 :            : 
     220                 :          0 :                 rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
     221         [ #  # ]:          0 :                 assert(rc == -ENOSPC);
     222                 :            :         }
     223                 :            : 
     224                 :         21 :         rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(42));
     225         [ -  + ]:         21 :         if (rc != -EEXIST) {
     226                 :          0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     227                 :            :                                                  "rpc_test_method_conn_close_detect(): rc != -EEXIST");
     228                 :          0 :                 return;
     229                 :            :         }
     230                 :            : 
     231                 :         21 :         rc = spdk_jsonrpc_conn_add_close_cb(conn, rpc_test_conn_close_cb, (void *)(intptr_t)(43));
     232         [ -  + ]:         21 :         if (rc != -ENOSPC) {
     233                 :          0 :                 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
     234                 :            :                                                  "rpc_test_method_conn_close_detect(): rc != -ENOSPC");
     235                 :          0 :                 return;
     236                 :            :         }
     237                 :            : 
     238                 :         21 :         spdk_jsonrpc_send_bool_response(request, true);
     239                 :            : }
     240                 :         21 : SPDK_RPC_REGISTER("hook_conn_close", rpc_hook_conn_close, SPDK_RPC_RUNTIME | SPDK_RPC_STARTUP)
     241                 :            : 
     242                 :            : static int
     243                 :         21 : spdk_jsonrpc_client_hook_conn_close(struct spdk_jsonrpc_client *client)
     244                 :            : {
     245                 :            :         int rc;
     246                 :         21 :         bool res = false;
     247                 :         21 :         struct spdk_jsonrpc_client_response *json_resp = NULL;
     248                 :            :         struct spdk_json_write_ctx *w;
     249                 :            :         struct spdk_jsonrpc_client_request *request;
     250                 :            : 
     251                 :         21 :         request = spdk_jsonrpc_client_create_request();
     252         [ -  + ]:         21 :         if (request == NULL) {
     253                 :          0 :                 return -ENOMEM;
     254                 :            :         }
     255                 :            : 
     256                 :         21 :         w = spdk_jsonrpc_begin_request(request, 1, "hook_conn_close");
     257                 :         21 :         spdk_jsonrpc_end_request(request, w);
     258                 :         21 :         spdk_jsonrpc_client_send_request(client, request);
     259                 :            : 
     260                 :         21 :         rc = _rpc_client_wait_for_response(client);
     261         [ -  + ]:         21 :         if (rc <= 0) {
     262                 :          0 :                 goto out;
     263                 :            :         }
     264                 :            : 
     265                 :         21 :         json_resp = spdk_jsonrpc_client_get_response(client);
     266         [ -  + ]:         21 :         if (json_resp == NULL) {
     267                 :          0 :                 SPDK_ERRLOG("spdk_jsonrpc_client_get_response() failed\n");
     268                 :          0 :                 rc = -errno;
     269                 :          0 :                 goto out;
     270                 :            : 
     271                 :            :         }
     272                 :            : 
     273                 :            :         /* Check for error response */
     274         [ -  + ]:         21 :         if (json_resp->error != NULL) {
     275                 :          0 :                 SPDK_ERRLOG("Unexpected error response: %.*s\n", json_resp->error->len,
     276                 :            :                             (char *)json_resp->error->start);
     277                 :          0 :                 rc = -EIO;
     278                 :          0 :                 goto out;
     279                 :            :         }
     280                 :            : 
     281         [ -  + ]:         21 :         assert(json_resp->result);
     282   [ +  -  -  +  :         21 :         if (spdk_json_decode_bool(json_resp->result, &res) != 0 || res != true) {
                   -  + ]
     283                 :          0 :                 SPDK_ERRLOG("Response is not and boolean or if not 'true'\n");
     284                 :          0 :                 rc = -EINVAL;
     285                 :          0 :                 goto out;
     286                 :            :         }
     287                 :            : 
     288                 :         21 :         rc = 0;
     289                 :         21 : out:
     290                 :         21 :         spdk_jsonrpc_client_free_response(json_resp);
     291                 :         21 :         return rc;
     292                 :            : }
     293                 :            : 
     294                 :            : volatile int g_rpc_server_th_stop;
     295                 :            : static sem_t g_rpc_server_th_listening;
     296                 :            : 
     297                 :            : static void *
     298                 :         21 : rpc_server_th(void *arg)
     299                 :            : {
     300                 :            :         int rc;
     301                 :            : 
     302                 :         21 :         rc = spdk_rpc_listen(g_rpcsock_addr);
     303         [ -  + ]:         21 :         if (rc) {
     304   [ #  #  #  # ]:          0 :                 fprintf(stderr, "spdk_rpc_listen() failed: %d\n", rc);
     305         [ #  # ]:          0 :                 sem_post(&g_rpc_server_th_listening);
     306                 :          0 :                 goto out;
     307                 :            :         }
     308                 :            : 
     309         [ -  + ]:         21 :         sem_post(&g_rpc_server_th_listening);
     310                 :            : 
     311         [ +  + ]:        276 :         while (!g_rpc_server_th_stop) {
     312                 :        255 :                 spdk_rpc_accept();
     313                 :        255 :                 usleep(50);
     314                 :            :         }
     315                 :            : 
     316                 :         21 :         spdk_rpc_close();
     317                 :         21 : out:
     318                 :         21 :         return (void *)(intptr_t)rc;
     319                 :            : }
     320                 :            : 
     321                 :            : static void *
     322                 :         21 : rpc_client_th(void *arg)
     323                 :            : {
     324                 :         21 :         struct spdk_jsonrpc_client *client = NULL;
     325                 :         21 :         char *method_name = "rpc_get_methods";
     326                 :            :         int rc;
     327                 :            : 
     328                 :            : 
     329                 :         21 :         rc = sem_wait(&g_rpc_server_th_listening);
     330         [ -  + ]:         21 :         if (rc == -1) {
     331         [ #  # ]:          0 :                 fprintf(stderr, "Timeout waiting for server thread to start listening: rc=%d errno=%d\n", rc,
     332                 :          0 :                         errno);
     333                 :          0 :                 goto out;
     334                 :            :         }
     335                 :            : 
     336                 :         21 :         client = spdk_jsonrpc_client_connect(g_rpcsock_addr, g_addr_family);
     337         [ -  + ]:         21 :         if (!client) {
     338         [ #  # ]:          0 :                 fprintf(stderr, "spdk_jsonrpc_client_connect() failed: %d\n", errno);
     339                 :          0 :                 rc = -1;
     340                 :          0 :                 goto out;
     341                 :            :         }
     342                 :            : 
     343                 :         21 :         rc = spdk_jsonrpc_client_check_rpc_method(client, method_name);
     344         [ -  + ]:         21 :         if (rc) {
     345         [ #  # ]:          0 :                 fprintf(stderr, "spdk_jsonrpc_client_check_rpc_method() failed: rc=%d errno=%d\n", rc, errno);
     346                 :          0 :                 goto out;
     347                 :            :         }
     348                 :            : 
     349                 :         21 :         rc = spdk_jsonrpc_client_check_null_params_method(client);
     350         [ -  + ]:         21 :         if (rc) {
     351         [ #  # ]:          0 :                 fprintf(stderr, "spdk_jsonrpc_client_null_params_method() failed: rc=%d errno=%d\n", rc, errno);
     352                 :          0 :                 goto out;
     353                 :            :         }
     354                 :            : 
     355                 :         21 :         rc = spdk_jsonrpc_client_hook_conn_close(client);
     356         [ +  - ]:         21 :         if (rc) {
     357         [ #  # ]:          0 :                 fprintf(stderr, "spdk_jsonrpc_client_hook_conn_close() failed: rc=%d errno=%d\n", rc, errno);
     358                 :          0 :                 goto out;
     359                 :            :         }
     360                 :            : 
     361                 :         21 : out:
     362         [ +  - ]:         21 :         if (client) {
     363                 :         21 :                 spdk_jsonrpc_client_close(client);
     364                 :            :         }
     365                 :            : 
     366                 :         21 :         return (void *)(intptr_t)rc;
     367                 :            : }
     368                 :            : 
     369                 :            : int
     370                 :         21 : main(int argc, char **argv)
     371                 :            : {
     372                 :         10 :         pthread_t srv_tid, client_tid;
     373                 :            :         int srv_tid_valid;
     374                 :         21 :         int client_tid_valid = -1;
     375                 :         21 :         intptr_t th_rc = INTPTR_MIN;
     376                 :         21 :         int rc = 0, err_cnt = 0;
     377                 :            : 
     378         [ -  + ]:         21 :         sem_init(&g_rpc_server_th_listening, 0, 0);
     379                 :            : 
     380   [ -  +  -  + ]:         21 :         srv_tid_valid = pthread_create(&srv_tid, NULL, rpc_server_th, NULL);
     381         [ -  + ]:         21 :         if (srv_tid_valid != 0) {
     382   [ #  #  #  # ]:          0 :                 fprintf(stderr, "pthread_create() failed to create server thread: %d\n", srv_tid_valid);
     383                 :          0 :                 goto out;
     384                 :            :         }
     385                 :            : 
     386   [ -  +  -  + ]:         21 :         client_tid_valid = pthread_create(&client_tid, NULL, rpc_client_th, NULL);
     387         [ +  - ]:         21 :         if (client_tid_valid != 0) {
     388   [ #  #  #  # ]:          0 :                 fprintf(stderr, "pthread_create(): failed to create client thread: %d\n", client_tid_valid);
     389                 :          0 :                 goto out;
     390                 :            :         }
     391                 :            : 
     392                 :         21 : out:
     393         [ +  - ]:         21 :         if (client_tid_valid == 0) {
     394                 :         21 :                 rc = pthread_join(client_tid, (void **)&th_rc);
     395         [ -  + ]:         21 :                 if (rc) {
     396   [ #  #  #  # ]:          0 :                         fprintf(stderr, "pthread_join() on client thread failed (rc: %d)\n", rc);
     397                 :          0 :                         err_cnt++;
     398         [ -  + ]:         21 :                 } else if (th_rc) {
     399   [ #  #  #  # ]:          0 :                         fprintf(stderr, "client thread failed reported failure(thread rc: %d)\n", (int)th_rc);
     400                 :          0 :                         err_cnt++;
     401                 :            :                 }
     402                 :            :         }
     403                 :            : 
     404                 :         21 :         g_rpc_server_th_stop = 1;
     405                 :            : 
     406         [ +  - ]:         21 :         if (srv_tid_valid == 0) {
     407                 :         21 :                 rc = pthread_join(srv_tid, (void **)&th_rc);
     408         [ -  + ]:         21 :                 if (rc) {
     409   [ #  #  #  # ]:          0 :                         fprintf(stderr, "pthread_join() on server thread failed (rc: %d)\n", rc);
     410                 :          0 :                         err_cnt++;
     411         [ -  + ]:         21 :                 } else if (th_rc) {
     412   [ #  #  #  # ]:          0 :                         fprintf(stderr, "server thread failed reported failure(thread rc: %d)\n", (int)th_rc);
     413                 :          0 :                         err_cnt++;
     414                 :            :                 }
     415                 :            :         }
     416                 :            : 
     417   [ -  +  -  + ]:         21 :         if (g_conn_close_detected == false) {
     418   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Connection close not detected\n");
     419                 :          0 :                 err_cnt++;
     420                 :            :         }
     421                 :            : 
     422         [ -  + ]:         21 :         sem_destroy(&g_rpc_server_th_listening);
     423                 :            : 
     424   [ +  -  -  +  :         21 :         fprintf(stderr, "%s\n", err_cnt == 0 ? "OK" : "FAILED");
                   -  + ]
     425                 :         21 :         return err_cnt ? EXIT_FAILURE : 0;
     426                 :            : }

Generated by: LCOV version 1.14