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