1 #include <stdio.h>
2 #include <string.h>
3
4 #include <glib.h>
5 #include <glib-object.h>
6
7 #define DFT_DOMAIN g_quark_from_string("TEST")
8 #include <searpc.h>
9
10 #include "searpc-server.h"
11 #include "searpc-client.h"
12 #include "searpc-named-pipe-transport.h"
13 #include "clar.h"
14
15 #if !defined(WIN32)
16 static const char *pipe_path = "/tmp/.searpc-test";
17 #else
18 static const char *pipe_path = "\\\\.\\pipe\\libsearpc-test";
19 #endif
20
21 /* sample class */
22
23 #define MAMAN_TYPE_BAR (maman_bar_get_type ())
24 #define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
25 #define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
26 #define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
27 #define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
28 #define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
29
30 #define NAMED_PIPE_SERVER_THREAD_POOL_SIZE 50
31
32 typedef struct _MamanBar MamanBar;
33 typedef struct _MamanBarClass MamanBarClass;
34
35 struct _MamanBar
36 {
37 GObject parent_instance;
38
39 gchar *name;
40 int papa_number;
41 };
42
43 struct _MamanBarClass
44 {
45 GObjectClass parent_class;
46 };
47
48 G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
49
50 enum
51 {
52 PROP_0,
53 PROP_MAMAN_NAME,
54 PROP_PAPA_NUMBER
55 };
56
57 static void
maman_bar_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)58 maman_bar_set_property (GObject *object,
59 guint property_id,
60 const GValue *value,
61 GParamSpec *pspec)
62 {
63 MamanBar *self = MAMAN_BAR (object);
64
65 switch (property_id) {
66 case PROP_MAMAN_NAME:
67 g_free (self->name);
68 self->name = g_value_dup_string (value);
69 break;
70
71 case PROP_PAPA_NUMBER:
72 self->papa_number = g_value_get_uchar (value);
73 break;
74
75 default:
76 /* We don't have any other property... */
77 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
78 break;
79 }
80 }
81
82 static void
maman_bar_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)83 maman_bar_get_property (GObject *object,
84 guint property_id,
85 GValue *value,
86 GParamSpec *pspec)
87 {
88 MamanBar *self = MAMAN_BAR (object);
89
90 switch (property_id) {
91 case PROP_MAMAN_NAME:
92 g_value_set_string (value, self->name);
93 break;
94
95 case PROP_PAPA_NUMBER:
96 g_value_set_uchar (value, self->papa_number);
97 break;
98
99 default:
100 /* We don't have any other property... */
101 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
102 break;
103 }
104 }
105
106 static void
maman_bar_finalize(GObject * gobject)107 maman_bar_finalize (GObject *gobject)
108 {
109 MamanBar *self = MAMAN_BAR (gobject);
110
111 g_free (self->name);
112
113 /* Chain up to the parent class */
114 G_OBJECT_CLASS (maman_bar_parent_class)->finalize (gobject);
115 }
116
117 static void
maman_bar_class_init(MamanBarClass * klass)118 maman_bar_class_init (MamanBarClass *klass)
119 {
120 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
121 GParamSpec *pspec;
122
123 gobject_class->set_property = maman_bar_set_property;
124 gobject_class->get_property = maman_bar_get_property;
125 gobject_class->finalize = maman_bar_finalize;
126
127 pspec = g_param_spec_string ("name",
128 "Maman name",
129 "Set maman's name",
130 "no-name-set" /* default value */,
131 G_PARAM_READWRITE);
132 g_object_class_install_property (gobject_class,
133 PROP_MAMAN_NAME,
134 pspec);
135
136 pspec = g_param_spec_uchar ("papa-number",
137 "Number of current Papa",
138 "Set/Get papa's number",
139 0 /* minimum value */,
140 10 /* maximum value */,
141 2 /* default value */,
142 G_PARAM_READWRITE);
143 g_object_class_install_property (gobject_class,
144 PROP_PAPA_NUMBER,
145 pspec);
146 }
147
148 static void
maman_bar_init(MamanBar * self)149 maman_bar_init (MamanBar *self)
150 {
151
152 }
153
154 /* sample client */
155 static SearpcClient *client;
156 /* sample client with named pipe as transport */
157 static SearpcClient *client_with_pipe_transport;
158
159 char *
sample_send(void * arg,const gchar * fcall_str,size_t fcall_len,size_t * ret_len)160 sample_send(void *arg, const gchar *fcall_str,
161 size_t fcall_len, size_t *ret_len)
162 {
163 cl_assert_ (strcmp(arg, "test") == 0, arg);
164
165 char *ret;
166 /* directly call in memory, instead of send via network */
167 gchar *temp = g_strdup(fcall_str);
168 ret = searpc_server_call_function ("test", temp, fcall_len, ret_len);
169 g_free (temp);
170 return ret;
171 }
172
173 int
sample_async_send(void * arg,gchar * fcall_str,size_t fcall_len,void * rpc_priv)174 sample_async_send (void *arg, gchar *fcall_str,
175 size_t fcall_len, void *rpc_priv)
176 {
177 cl_assert (strcmp(arg, "test_async") == 0);
178
179 char *ret;
180 size_t ret_len;
181 gchar *temp = g_strdup(fcall_str);
182
183 ret = searpc_server_call_function ("test", temp, fcall_len, &ret_len);
184 g_free (temp);
185
186 searpc_client_generic_callback (ret, ret_len, rpc_priv, NULL);
187
188 g_free (ret);
189 return 0;
190 }
191
192 gchar *
get_substring(const gchar * orig_str,int sub_len,GError ** error)193 get_substring (const gchar *orig_str, int sub_len, GError **error)
194 {
195 if (sub_len > strlen(orig_str)) {
196 g_set_error (error, DFT_DOMAIN, 100,
197 "Substring length larger than the length of origin string");
198 return NULL;
199 }
200 gchar *ret = g_malloc0(sub_len+1);
201 memcpy(ret, orig_str, sub_len);
202 ret[sub_len] = '\0';
203 return ret;
204 }
205
206 static SearpcClient *
do_create_client_with_pipe_transport()207 do_create_client_with_pipe_transport()
208 {
209 SearpcNamedPipeClient *pipe_client = searpc_create_named_pipe_client(pipe_path);
210 cl_must_pass_(searpc_named_pipe_client_connect(pipe_client), "named pipe client failed to connect");
211 return searpc_client_with_named_pipe_transport(pipe_client, "test");
212 }
213
214
215 void
test_searpc__simple_call(void)216 test_searpc__simple_call (void)
217 {
218 gchar* result;
219 GError *error = NULL;
220
221 result = searpc_client_call__string (client, "get_substring", &error,
222 2, "string", "hello", "int", 2);
223 cl_assert (error == NULL);
224 cl_assert (strcmp(result, "he") == 0);
225 g_free (result);
226
227 /* error should return */
228 result = NULL;
229 result = searpc_client_call__string (client, "get_substring", &error,
230 2, "string", "hello", "int", 10);
231 cl_assert (error->message);
232 g_free (result);
233 g_error_free(error);
234 }
235
236 void
test_searpc__invalid_call(void)237 test_searpc__invalid_call (void)
238 {
239 gchar* result;
240 GError *error = NULL;
241
242 result = searpc_client_call__string (client, "nonexist_func", &error,
243 2, "string", "hello", "int", 2);
244 cl_assert (error != NULL);
245 g_free (result);
246 g_error_free (error);
247 }
248
249 GObject *
get_maman_bar(const char * name,GError ** error)250 get_maman_bar(const char *name, GError **error)
251 {
252 return g_object_new(MAMAN_TYPE_BAR, "name", name, NULL);
253 }
254
255 void
test_searpc__object_call(void)256 test_searpc__object_call (void)
257 {
258 GObject *result;
259 GError *error = NULL;
260
261 result = searpc_client_call__object (client, "get_maman_bar",
262 MAMAN_TYPE_BAR, &error,
263 1, "string", "kitty");
264 cl_assert (error == NULL);
265 g_object_unref (result);
266 }
267
268 GList *
get_maman_bar_list(const char * name,int num,GError ** error)269 get_maman_bar_list (const char *name, int num, GError **error)
270 {
271 char buf[256];
272 GList *ret = 0;
273 int i;
274 GObject *obj;
275
276 if (num < 0) {
277 g_set_error (error, DFT_DOMAIN, 100, "num must be positive.");
278 return NULL;
279 }
280 if (num > 1000) {
281 g_set_error (error, DFT_DOMAIN, 100, "num must no larger than 1000.");
282 return NULL;
283 }
284
285 for (i = 0; i < num; i++) {
286 sprintf (buf, "%s%d", name, i);
287 obj = g_object_new(MAMAN_TYPE_BAR, "name", buf, NULL);
288 ret = g_list_prepend (ret, obj);
289 }
290 ret = g_list_reverse (ret);
291 return ret;
292 }
293
294
295 void
test_searpc__objlist_call(void)296 test_searpc__objlist_call (void)
297 {
298 GList *result, *ptr;
299 GError *error = NULL;
300
301 result = searpc_client_call__objlist (client, "get_maman_bar_list",
302 MAMAN_TYPE_BAR, &error,
303 2, "string", "kitty", "int", 10);
304 cl_assert (error == NULL);
305 for (ptr = result; ptr; ptr = ptr->next)
306 g_object_unref (ptr->data);
307 g_list_free (result);
308
309 result = searpc_client_call__objlist (client, "get_maman_bar_list",
310 MAMAN_TYPE_BAR, &error,
311 2, "string", "kitty", "int", 0);
312 cl_assert (error == NULL);
313 for (ptr = result; ptr; ptr = ptr->next)
314 g_object_unref (ptr->data);
315 g_list_free (result);
316 }
317
318 json_t *
simple_json_rpc(const char * name,int num,GError ** error)319 simple_json_rpc (const char *name, int num, GError **error)
320 {
321 json_t * ret = json_object();
322 json_object_set_new (ret, name, json_integer (num));
323 return ret;
324 }
325
326 void
test_searpc__json_return_type(void)327 test_searpc__json_return_type (void)
328 {
329 json_t *result;
330 GError *error = NULL;
331
332 result = searpc_client_call__json (client, "simple_json_rpc",
333 &error, 2,
334 "string", "year",
335 "int", 2016);
336 cl_assert (error == NULL);
337 cl_assert (json_integer_value(json_object_get(result, "year")) == 2016);
338 json_decref(result);
339 }
340
341 json_t *
count_json_kvs(const json_t * obj,GError ** error)342 count_json_kvs (const json_t *obj, GError **error)
343 {
344 int count = 0;
345
346 json_t *member;
347 member = json_object_iter ((json_t*)obj);
348 while (member != NULL) {
349 member = json_object_iter_next ((json_t*)obj, member);
350 count++;
351 }
352
353 json_t * ret = json_object();
354 json_object_set_new (ret, "number_of_kvs", json_integer (count));
355 return ret;
356 }
357
358 void
test_searpc__json_param_type(void)359 test_searpc__json_param_type (void)
360 {
361 json_t *result;
362 GError *error = NULL;
363
364 json_t *param = json_object();
365 json_object_set_new (param, "a", json_integer (1));
366 json_object_set_new (param, "b", json_integer (2));
367
368 result = searpc_client_call__json (client, "count_json_kvs",
369 &error, 1,
370 "json", param);
371
372 cl_assert_ (error == NULL, error ? error->message : "");
373 int count = json_integer_value(json_object_get((json_t*)result, "number_of_kvs"));
374 char *msg = json_dumps(result, JSON_INDENT(2));
375 cl_assert_(count == 2, msg);
376 free (msg);
377 json_decref(param);
378 json_decref(result);
379 }
380
381
simple_callback(void * result,void * user_data,GError * error)382 void simple_callback (void *result, void *user_data, GError *error)
383 {
384 char *res = (char *)result;
385
386 cl_assert (strcmp(res, "he") == 0);
387 }
388
simple_callback_error(void * result,void * user_data,GError * error)389 void simple_callback_error (void *result, void *user_data, GError *error)
390 {
391 cl_assert (result == NULL);
392 cl_assert (error != NULL);
393 g_error_free (error);
394 }
395
396 void
test_searpc__simple_call_async(void)397 test_searpc__simple_call_async (void)
398 {
399 searpc_client_async_call__string (client, "get_substring",
400 simple_callback, NULL,
401 2, "string", "hello", "int", 2);
402
403 searpc_client_async_call__string (client, "get_substring",
404 simple_callback_error, NULL,
405 2, "string", "hello", "int", 10);
406 }
407
async_callback_json(void * result,void * user_data,GError * error)408 void async_callback_json (void *result, void *user_data, GError *error)
409 {
410 cl_assert(json_integer_value(json_object_get((json_t*)result, "hello")) == 10);
411 }
412
413 void
test_searpc__simple_call_async_json(void)414 test_searpc__simple_call_async_json (void)
415 {
416 searpc_client_async_call__json (client, "simple_json_rpc",
417 async_callback_json, NULL,
418 2, "string", "hello", "int", 10);
419 }
420
421 void
test_searpc__pipe_simple_call(void)422 test_searpc__pipe_simple_call (void)
423 {
424 gchar* result;
425 GError *error = NULL;
426
427 result = searpc_client_call__string (client_with_pipe_transport, "get_substring", &error,
428 2, "string", "hello", "int", 2);
429 cl_assert_ (error == NULL, error ? error->message : "");
430 cl_assert (strcmp(result, "he") == 0);
431 g_free (result);
432
433 /* error should return */
434 result = searpc_client_call__string (client_with_pipe_transport, "get_substring", &error,
435 2, "string", "hello", "int", 10);
436 cl_assert (error->message);
437 g_free (result);
438 }
439
440 void
test_searpc__pipe_large_request(void)441 test_searpc__pipe_large_request (void)
442 {
443 gchar* result;
444 GError *error = NULL;
445
446 // 10MB
447 int size = 10 * 1024 * 1024;
448 GString *large_string = g_string_sized_new(size);
449 while (large_string->len < size) {
450 g_string_append(large_string, "aaaa");
451 }
452
453 // Large request
454 result = searpc_client_call__string (client_with_pipe_transport, "get_substring", &error,
455 2, "string", large_string->str, "int", 2);
456 cl_assert_ (error == NULL, error ? error->message : "");
457 cl_assert_ (strcmp(result, "aa") == 0, result);
458 g_free (result);
459
460 // Large request & Large response
461 result = searpc_client_call__string (client_with_pipe_transport, "get_substring", &error,
462 2, "string", large_string->str, "int", size - 2);
463 cl_assert_ (error == NULL, error ? error->message : "");
464 // cl_assert (strcmp(result, "aa") == 0);
465 g_free (result);
466
467 g_string_free (large_string, TRUE);
468 }
469
do_pipe_connect_and_request(void * arg)470 static void * do_pipe_connect_and_request(void *arg)
471 {
472 SearpcClient *client = do_create_client_with_pipe_transport();
473
474 // 100KB
475 int size = 100 * 1024;
476 GString *large_string = g_string_sized_new(size);
477 while (large_string->len < size) {
478 g_string_append(large_string, "aaaa");
479 }
480
481 gchar* result;
482 GError *error = NULL;
483 result = searpc_client_call__string (client, "get_substring", &error,
484 2, "string", large_string->str, "int", 2);
485 cl_assert_ (error == NULL, error ? error->message : "");
486 cl_assert_ (strcmp(result, "aa") == 0, result);
487 g_free (result);
488
489 g_string_free (large_string, TRUE);
490 searpc_free_client_with_pipe_transport(client);
491
492 return NULL;
493 }
494
495 // Simulate the situation that the server can handle multiple clients connecting
496 // at the same time.
497 void
test_searpc__pipe_concurrent_clients(void)498 test_searpc__pipe_concurrent_clients (void)
499 {
500 // M concurrent clients, and run the test for N times.
501 int m_clients = 5;
502 int n_times = 20;
503
504 int i;
505 for (i = 0; i < n_times; i++) {
506 g_usleep(100000);
507 pthread_t *threads = g_new0(pthread_t, m_clients);
508
509 int j;
510 for (j = 0; j < m_clients; j++) {
511 pthread_create(&threads[j], NULL, do_pipe_connect_and_request, NULL);
512 }
513
514 void *ret;
515 for (j = 0; j < m_clients; j++) {
516 pthread_join(threads[j], &ret);
517 }
518 g_free (threads);
519 }
520 }
521
522
523 #include "searpc-signature.h"
524 #include "searpc-marshal.h"
525
526 void
test_searpc__initialize(void)527 test_searpc__initialize (void)
528 {
529 searpc_server_init (register_marshals);
530 searpc_create_service ("test");
531 searpc_server_register_function ("test", get_substring, "get_substring",
532 searpc_signature_string__string_int());
533 searpc_server_register_function ("test", get_maman_bar, "get_maman_bar",
534 searpc_signature_object__string());
535 searpc_server_register_function ("test", get_maman_bar_list, "get_maman_bar_list",
536 searpc_signature_objlist__string_int());
537 searpc_server_register_function ("test", simple_json_rpc, "simple_json_rpc",
538 searpc_signature_json__string_int());
539 searpc_server_register_function ("test", count_json_kvs, "count_json_kvs",
540 searpc_signature_json__json());
541
542 /* sample client */
543 client = searpc_client_new();
544 client->send = sample_send;
545 client->arg = "test";
546
547 client->async_send = sample_async_send;
548 client->async_arg = "test_async";
549
550 SearpcNamedPipeServer *pipe_server = searpc_create_named_pipe_server_with_threadpool(pipe_path, NAMED_PIPE_SERVER_THREAD_POOL_SIZE);
551 cl_must_pass_(searpc_named_pipe_server_start(pipe_server), "named pipe server failed to start");
552 #if defined(WIN32)
553 // Wait for the server thread to start
554 Sleep(1000);
555 #endif
556
557 client_with_pipe_transport = do_create_client_with_pipe_transport();
558 }
559
560 void
test_searpc__cleanup(void)561 test_searpc__cleanup (void)
562 {
563 searpc_free_client_with_pipe_transport(client_with_pipe_transport);
564
565 /* free memory for memory debug with valgrind */
566 searpc_server_final();
567 }
568