Skip to content

Commit 36af696

Browse files
tadeas-vintrlikmichalvasko
authored andcommitted
test FEATURE add test for multithreaded receiving of messages
1 parent 54f142a commit 36af696

3 files changed

Lines changed: 200 additions & 1 deletion

File tree

tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ if (${SOURCE_FORMAT_ENABLED})
88
endif()
99

1010
# list of all the tests in each directory
11-
set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread)
11+
set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages)
1212
set(client_tests test_client test_client_messages)
1313

1414
# add -Wl,--wrap flags

tests/data/modules/notif1.yang

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module notif1 {
2+
namespace "n1";
3+
prefix "n1";
4+
5+
notification n1 {
6+
leaf first {
7+
type string;
8+
}
9+
}
10+
}

tests/test_thread_messages.c

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/**
2+
* \file test_thread_messages
3+
* \author Tadeas Vintrlik <xvint04@stud.fit.vutbr.cz>
4+
* \brief libnetconf2 tests - thread-safety for receiving messages
5+
*
6+
* Copyright 2021 Deutsche Telekom AG.
7+
* Copyright 2021 CESNET, z.s.p.o.
8+
*
9+
* This source code is licensed under BSD 3-Clause License (the "License").
10+
* You may not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* https://opensource.org/licenses/BSD-3-Clause
14+
*/
15+
16+
#include <pthread.h>
17+
#include <stdio.h>
18+
#include <stdlib.h>
19+
#include <string.h>
20+
#include <sys/types.h>
21+
#include <sys/wait.h>
22+
#include <unistd.h>
23+
24+
#include <libyang/libyang.h>
25+
26+
#include <log.h>
27+
#include <messages_p.h>
28+
#include <messages_server.h>
29+
#include <session_client.h>
30+
#include <session_server.h>
31+
#include "tests/config.h"
32+
33+
/* millisec */
34+
#define NC_ACCEPT_TIMEOUT 5000
35+
/* millisec */
36+
#define NC_PS_POLL_TIMEOUT 5000
37+
/* sec */
38+
#define CLIENT_SSH_AUTH_TIMEOUT 10
39+
40+
#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); exit(1); }
41+
42+
#if _POSIX_BARRIERS >= 200112L
43+
pthread_barrier_t barrier;
44+
pthread_barrier_t barrier_msg;
45+
#endif
46+
47+
typedef struct arg {
48+
int in;
49+
int out;
50+
struct ly_ctx *ctx;
51+
} arg_t;
52+
53+
struct nc_server_reply *
54+
rpc_clb(struct lyd_node *rpc, struct nc_session *session)
55+
{
56+
(void)rpc; (void)session;
57+
return nc_server_reply_ok();
58+
}
59+
60+
static void *
61+
server_thread(void *arg)
62+
{
63+
struct nc_session *sess;
64+
struct nc_server_notif *notif;
65+
struct lyd_node *ntf;
66+
struct ly_in *in;
67+
struct nc_pollsession *ps;
68+
arg_t args = *(arg_t *)arg;
69+
char *eventtime;
70+
struct timespec ts;
71+
const char *data;
72+
int poll;
73+
74+
nc_assert(!nc_server_init(args.ctx));
75+
nc_assert(nc_accept_inout(args.in, args.out, "test", &sess) == NC_MSG_HELLO);
76+
nc_session_inc_notif_status(sess);
77+
data =
78+
"<n1 xmlns=\"n1\">\n"
79+
" <first>Test</first>\n"
80+
"</n1>\n";
81+
82+
nc_assert(ly_in_new_memory(data, &in) == LY_SUCCESS);
83+
nc_assert(lyd_parse_op(args.ctx, NULL, in, LYD_XML, LYD_TYPE_NOTIF_YANG, &ntf, NULL) == LY_SUCCESS);
84+
ly_in_free(in, 0);
85+
86+
nc_assert(clock_gettime(CLOCK_REALTIME, &ts) != -1);
87+
nc_assert(ly_time_ts2str(&ts, &eventtime) == LY_SUCCESS);
88+
notif = nc_server_notif_new(ntf, eventtime, NC_PARAMTYPE_FREE);
89+
90+
ps = nc_ps_new();
91+
nc_assert(ps);
92+
nc_ps_add_session(ps, sess);
93+
poll = nc_ps_poll(ps, 1000, &sess);
94+
nc_server_notif_send(sess, notif, 1000);
95+
nc_assert(poll == NC_PSPOLL_RPC);
96+
nc_ps_clear(ps, 1, NULL);
97+
nc_ps_free(ps);
98+
99+
/* Waiting for end of test */
100+
pthread_barrier_wait(&barrier);
101+
102+
nc_server_notif_free(notif);
103+
return arg;
104+
}
105+
106+
static void *
107+
notif_thread(void *arg)
108+
{
109+
struct nc_session *sess = (struct nc_session *)arg;
110+
struct lyd_node *envp;
111+
struct lyd_node *op;
112+
NC_MSG_TYPE msgtype;
113+
114+
/* Sync threads for receiving message to increase chance of datarace */
115+
pthread_barrier_wait(&barrier_msg);
116+
do {
117+
msgtype = nc_recv_notif(sess, 1000, &envp, &op);
118+
} while (msgtype == NC_MSG_REPLY);
119+
nc_assert(msgtype == NC_MSG_NOTIF);
120+
lyd_free_tree(envp);
121+
lyd_free_tree(op);
122+
return arg;
123+
}
124+
125+
int
126+
main(void)
127+
{
128+
int pipes[4];
129+
struct nc_session *sess;
130+
struct lyd_node *op, *envp;
131+
struct ly_ctx *ctx;
132+
struct nc_rpc *rpc;
133+
uint64_t msgid;
134+
NC_MSG_TYPE msgtype;
135+
const char *features[] = {"startup", NULL};
136+
arg_t thread_arg;
137+
pthread_t t[2];
138+
139+
pthread_barrier_init(&barrier, NULL, 2);
140+
pthread_barrier_init(&barrier_msg, NULL, 2);
141+
142+
/* Create a two pipes */
143+
nc_assert(pipe(pipes) != -1);
144+
nc_assert(pipe(pipes + 2) != -1);
145+
thread_arg.in = pipes[0];
146+
thread_arg.out = pipes[3];
147+
148+
/* Create context */
149+
nc_assert(ly_ctx_new(TESTS_DIR "/data/modules", 0, &ctx) == LY_SUCCESS);
150+
nc_assert(ly_ctx_load_module(ctx, "ietf-netconf", NULL, features));
151+
nc_assert(ly_ctx_load_module(ctx, "notif1", NULL, NULL));
152+
thread_arg.ctx = ctx;
153+
nc_set_global_rpc_clb(rpc_clb);
154+
155+
/* Start server thread */
156+
pthread_create(&t[0], NULL, server_thread, &thread_arg);
157+
nc_client_init();
158+
159+
/* Listen for notifications */
160+
sess = nc_connect_inout(pipes[2], pipes[1], ctx);
161+
nc_assert(sess);
162+
pthread_create(&t[1], NULL, notif_thread, sess);
163+
164+
/* Send rpc */
165+
rpc = nc_rpc_delete(NC_DATASTORE_STARTUP, NULL, NC_PARAMTYPE_CONST);
166+
nc_assert(nc_send_rpc(sess, rpc, 1000, &msgid) == NC_MSG_RPC);
167+
168+
/* Sync threads for receiving message to increase chance of datarace */
169+
pthread_barrier_wait(&barrier_msg);
170+
do {
171+
msgtype = nc_recv_reply(sess, rpc, msgid, 1000, &envp, &op);
172+
} while (msgtype == NC_MSG_NOTIF);
173+
nc_assert(msgtype == NC_MSG_REPLY);
174+
nc_rpc_free(rpc);
175+
lyd_free_tree(envp);
176+
177+
/* Waiting of end of test */
178+
pthread_barrier_wait(&barrier);
179+
pthread_join(t[0], NULL);
180+
pthread_join(t[1], NULL);
181+
182+
/* Cleanup */
183+
nc_session_free(sess, NULL);
184+
ly_ctx_destroy(ctx);
185+
for (uint8_t i = 0; i < 4; i++) {
186+
close(pipes[i]);
187+
}
188+
return 0;
189+
}

0 commit comments

Comments
 (0)