1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name of Intel Corporation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "spdk/stdinc.h" 36 #include "spdk_cunit.h" 37 #include "spdk/jsonrpc.h" 38 #include "spdk_internal/mock.h" 39 #include "common/lib/test_env.c" 40 #include "spdk/log.h" 41 42 #include "rpc/rpc.c" 43 44 #include "unit/lib/json_mock.c" 45 46 static int g_rpc_err; 47 void fn_rpc_method_handler(struct spdk_jsonrpc_request *request, 48 const struct spdk_json_val *params); 49 50 DEFINE_STUB_V(spdk_jsonrpc_end_result, (struct spdk_jsonrpc_request *request, 51 struct spdk_json_write_ctx *w)); 52 DEFINE_STUB(spdk_jsonrpc_begin_result, struct spdk_json_write_ctx *, 53 (struct spdk_jsonrpc_request *request), (void *)1); 54 DEFINE_STUB(spdk_json_decode_bool, int, (const struct spdk_json_val *val, void *out), 0); 55 DEFINE_STUB(spdk_jsonrpc_server_listen, struct spdk_jsonrpc_server *, (int domain, int protocol, 56 struct sockaddr *listen_addr, socklen_t addrlen, spdk_jsonrpc_handle_request_fn handle_request), 57 (struct spdk_jsonrpc_server *)0Xdeaddead); 58 DEFINE_STUB(spdk_jsonrpc_server_poll, int, (struct spdk_jsonrpc_server *server), 0); 59 DEFINE_STUB_V(spdk_jsonrpc_server_shutdown, (struct spdk_jsonrpc_server *server)); 60 61 DECLARE_WRAPPER(open, int, (const char *pathname, int flags, mode_t mode)); 62 DECLARE_WRAPPER(close, int, (int fd)); 63 DECLARE_WRAPPER(flock, int, (int fd, int operation)); 64 DEFINE_WRAPPER(open, int, (const char *pathname, int flags, mode_t mode), (pathname, flags, mode)); 65 DEFINE_WRAPPER(close, int, (int fd), (fd)); 66 DEFINE_WRAPPER(flock, int, (int fd, int operation), (fd, operation)); 67 68 int spdk_json_decode_object(const struct spdk_json_val *values, 69 const struct spdk_json_object_decoder *decoders, size_t num_decoders, void *out) 70 { 71 if (values ->type == SPDK_JSON_VAL_INVALID) { 72 return 1; 73 } 74 return 0; 75 } 76 77 bool 78 spdk_json_strequal(const struct spdk_json_val *val, const char *str) 79 { 80 size_t len; 81 82 if (val->type != SPDK_JSON_VAL_STRING && val->type != SPDK_JSON_VAL_NAME) { 83 return false; 84 } 85 86 len = strlen(str); 87 if (val->len != len) { 88 return false; 89 } 90 91 return memcmp(val->start, str, len) == 0; 92 } 93 94 void 95 spdk_jsonrpc_send_error_response(struct spdk_jsonrpc_request *request, 96 int error_code, const char *msg) 97 { 98 g_rpc_err = error_code; 99 } 100 101 void 102 spdk_jsonrpc_send_error_response_fmt(struct spdk_jsonrpc_request *request, 103 int error_code, const char *fmt, ...) 104 { 105 g_rpc_err = error_code; 106 } 107 108 void fn_rpc_method_handler(struct spdk_jsonrpc_request *request, 109 const struct spdk_json_val *params) 110 { 111 g_rpc_err = 0; 112 } 113 114 static void 115 test_jsonrpc_handler(void) 116 { 117 struct spdk_jsonrpc_request *request = (struct spdk_jsonrpc_request *)0xdeadbeef; 118 struct spdk_json_val method = {}; 119 struct spdk_json_val params = {}; 120 char *str = "test"; 121 struct spdk_rpc_method m = { 122 .name = "test", 123 }; 124 125 struct spdk_rpc_method is_alias_of = { 126 .name = "aliastest", 127 .is_deprecated = false, 128 .deprecation_warning_printed = false, 129 .func = fn_rpc_method_handler, 130 .state_mask = SPDK_RPC_STARTUP, 131 }; 132 133 /* Case 1: Method not found */ 134 method.type = SPDK_JSON_VAL_INVALID; 135 jsonrpc_handler(request, &method, ¶ms); 136 CU_ASSERT(g_rpc_err == SPDK_JSONRPC_ERROR_METHOD_NOT_FOUND); 137 138 /* Case 2: Method is alias */ 139 method.type = SPDK_JSON_VAL_STRING; 140 method.start = str; 141 method.len = 4; 142 m.is_alias_of = &is_alias_of; 143 m.is_deprecated = true; 144 m.deprecation_warning_printed = false; 145 m.state_mask = SPDK_RPC_STARTUP; 146 SLIST_INSERT_HEAD(&g_rpc_methods, &m, slist); 147 148 /* m->state_mask & g_rpc_state == g_rpc_state */ 149 g_rpc_err = -1; 150 g_rpc_state = SPDK_RPC_STARTUP; 151 jsonrpc_handler(request, &method, ¶ms); 152 CU_ASSERT(g_rpc_err == 0); 153 154 /* g_rpc_state == SPDK_RPC_STARTUP */ 155 is_alias_of.state_mask = SPDK_RPC_RUNTIME; 156 g_rpc_err = -1; 157 g_rpc_state = SPDK_RPC_STARTUP; 158 jsonrpc_handler(request, &method, ¶ms); 159 CU_ASSERT(g_rpc_err == SPDK_JSONRPC_ERROR_INVALID_STATE); 160 161 /* SPDK_RPC_RUNTIME is invalid for the aliastest RPC */ 162 is_alias_of.state_mask = SPDK_RPC_STARTUP; 163 g_rpc_err = -1; 164 g_rpc_state = SPDK_RPC_RUNTIME; 165 jsonrpc_handler(request, &method, ¶ms); 166 CU_ASSERT(g_rpc_err == SPDK_JSONRPC_ERROR_INVALID_STATE); 167 168 SLIST_REMOVE_HEAD(&g_rpc_methods, slist); 169 } 170 171 static void 172 test_spdk_rpc_is_method_allowed(void) 173 { 174 const char method[] = "test"; 175 uint32_t state_mask = SPDK_RPC_STARTUP; 176 struct spdk_rpc_method m = {}; 177 int rc = 0; 178 179 /* Case 1: Expect return -EPERM */ 180 m.name = method; 181 m.state_mask = SPDK_RPC_RUNTIME; 182 SLIST_INSERT_HEAD(&g_rpc_methods, &m, slist); 183 rc = spdk_rpc_is_method_allowed(method, state_mask); 184 CU_ASSERT(rc == -EPERM); 185 186 /* Case 2: Expect return 0 */ 187 state_mask = SPDK_RPC_RUNTIME; 188 rc = spdk_rpc_is_method_allowed(method, state_mask); 189 CU_ASSERT(rc == 0); 190 191 /* Case 3: Expect return -ENOENT */ 192 SLIST_REMOVE_HEAD(&g_rpc_methods, slist); 193 rc = spdk_rpc_is_method_allowed(method, state_mask); 194 CU_ASSERT(rc == -ENOENT); 195 } 196 197 static void 198 test_rpc_get_methods(void) 199 { 200 struct spdk_jsonrpc_request *request = (struct spdk_jsonrpc_request *)0xbeefbeef; 201 struct spdk_json_val params = {}; 202 struct spdk_rpc_method m = {}; 203 204 /* Case 1: spdk_json_decode_object failed */ 205 g_rpc_err = -1; 206 params.type = SPDK_JSON_VAL_INVALID; 207 rpc_get_methods(request, ¶ms); 208 CU_ASSERT(g_rpc_err == SPDK_JSONRPC_ERROR_INVALID_PARAMS); 209 210 /* Case 2: Expect pass */ 211 params.type = SPDK_JSON_VAL_TRUE; 212 m.state_mask = SPDK_RPC_RUNTIME; 213 g_rpc_state = SPDK_RPC_STARTUP; 214 SLIST_INSERT_HEAD(&g_rpc_methods, &m, slist); 215 rpc_get_methods(request, ¶ms); 216 SLIST_REMOVE_HEAD(&g_rpc_methods, slist); 217 } 218 219 static void 220 test_rpc_spdk_get_version(void) 221 { 222 struct spdk_jsonrpc_request *request = (struct spdk_jsonrpc_request *)0xdeadbeef; 223 struct spdk_json_val params = {}; 224 225 /* Case 1: spdk_get_version method requires no parameters */ 226 g_rpc_err = -1; 227 params.type = SPDK_JSON_VAL_INVALID; 228 rpc_spdk_get_version(request, ¶ms); 229 CU_ASSERT(g_rpc_err == SPDK_JSONRPC_ERROR_INVALID_PARAMS); 230 231 /* Case 2: Expect pass */ 232 rpc_spdk_get_version(request, NULL); 233 } 234 235 static void 236 test_spdk_rpc_listen_close(void) 237 { 238 const char listen_addr[128] = "/var/tmp/spdk-rpc-ut.sock"; 239 char rpc_lock_path[128] = {}; 240 241 MOCK_SET(open, 1); 242 MOCK_SET(close, 0); 243 MOCK_SET(flock, 0); 244 245 spdk_rpc_listen(listen_addr); 246 snprintf(rpc_lock_path, sizeof(g_rpc_lock_path), "%s.lock", 247 g_rpc_listen_addr_unix.sun_path); 248 249 CU_ASSERT(g_rpc_listen_addr_unix.sun_family == AF_UNIX); 250 CU_ASSERT(strcmp(g_rpc_listen_addr_unix.sun_path, listen_addr) == 0); 251 CU_ASSERT(strcmp(g_rpc_lock_path, rpc_lock_path) == 0); 252 CU_ASSERT(g_jsonrpc_server == (struct spdk_jsonrpc_server *)0Xdeaddead); 253 254 spdk_rpc_close(); 255 256 CU_ASSERT(g_rpc_listen_addr_unix.sun_path[0] == '\0'); 257 CU_ASSERT(g_jsonrpc_server == NULL); 258 CU_ASSERT(g_rpc_lock_fd == -1); 259 CU_ASSERT(g_rpc_lock_path[0] == '\0'); 260 261 MOCK_CLEAR(open); 262 MOCK_CLEAR(close); 263 MOCK_CLEAR(flock); 264 } 265 266 int main(int argc, char **argv) 267 { 268 CU_pSuite suite = NULL; 269 unsigned int num_failures; 270 271 CU_set_error_action(CUEA_ABORT); 272 CU_initialize_registry(); 273 274 suite = CU_add_suite("rpc", NULL, NULL); 275 276 CU_ADD_TEST(suite, test_jsonrpc_handler); 277 CU_ADD_TEST(suite, test_spdk_rpc_is_method_allowed); 278 CU_ADD_TEST(suite, test_rpc_get_methods); 279 CU_ADD_TEST(suite, test_rpc_spdk_get_version); 280 CU_ADD_TEST(suite, test_spdk_rpc_listen_close); 281 282 CU_basic_set_mode(CU_BRM_VERBOSE); 283 CU_basic_run_tests(); 284 num_failures = CU_get_number_of_failures(); 285 CU_cleanup_registry(); 286 return num_failures; 287 } 288