2 #include "uniclientconn.h"
3 #include "uniconfdaemon.h"
4 #include "uniconfroot.h"
5 #include "unitempgen.h"
6 #include "wvstringlist.h"
7 #include "wvistreamlist.h"
8 #include "wvunixsocket.h"
9 #include "wvstreamclone.h"
11 #include "wvtclstring.h"
15 #include "wvstringlist.h"
16 #include "wvfileutils.h"
19 /**** Generic daemon testing helpers ****/
21 DeclareWvList(WvStringList
);
23 class UniConfDaemonTestConn
: public WvStreamClone
26 UniConfDaemonTestConn(IWvStream
*s
, WvStringList
*_commands
,
27 WvStringListList
*_expected_responses
) :
30 expected_responses(_expected_responses
),
31 log("UniConfDaemonTestConn", WvLog::Debug
)
33 uses_continue_select
= true;
35 virtual ~UniConfDaemonTestConn()
38 terminate_continue_select();
43 log("Closing connection\n");
44 WvStreamClone::close();
47 virtual void execute()
49 WvStreamClone::execute();
51 // order is always process responses to last command (or conn),
52 // then send the next command
53 // if we're out of expected responses, that means we're done
54 if (expected_responses
->count())
56 while (expected_responses
->first()->count())
58 WvString line
= blocking_getline(-1);
59 WvString expected
= expected_responses
->first()->popstr();
60 log(">> '%s' (expect: '%s')\n", line
, expected
);
61 WVPASS(!strcmp(line
.cstr(), expected
.cstr()));
63 expected_responses
->unlink_first();
65 if (commands
->count() > 0)
67 WvString command
= commands
->popstr();
68 print("%s\n", command
);
69 log("<< %s\n", command
);
73 // expecting nothing more, can close
74 if (!expected_responses
->count())
76 log("no more responses expected, closing\n");
79 log("um, why are we still ok?\n");
84 WvStringList
*commands
;
85 WvStringListList
*expected_responses
;
90 /**** Daemon surprise close test and helpers ****/
92 static void spin(WvIStreamList
&l
)
95 for (max
= 0; max
< 100 && l
.select(10); max
++)
106 static void appendbuf(WvStream
&s
, void *_buf
)
108 wvcon
->print("append!\n");
109 WvDynBuf
*buf
= (WvDynBuf
*)_buf
;
114 static void linecmp(WvIStreamList
&sl
, WvBuf
&buf
,
115 const char *w1
, const char *w2
= NULL
,
116 const char *w3
= NULL
)
118 wvcon
->print("Awaiting '%s' '%s' '%s'\n", w1
, w2
, w3
);
121 WvString line
= wvtcl_getword(buf
, "\r\n");
126 wvtcl_decode(l
, line
);
128 size_t nargs
= w3
? 3 : (w2
? 2 : 1);
129 WVPASS(l
.count() < 4);
131 WVPASSEQ(l
.popstr(), w1
);
132 if (nargs
>= 2) WVPASSEQ(l
.popstr(), w2
);
133 if (nargs
>= 3) WVPASSEQ(l
.popstr(), w3
);
137 WVTEST_MAIN("daemon surprise close")
140 WVPASSEQ(WvIStreamList::globallist
.count(), 0);
141 spin(WvIStreamList::globallist
);
143 signal(SIGPIPE
, SIG_IGN
);
144 WvIPPortAddr
addr("0.0.0.0:4113");
146 UniConfRoot
cfg("temp:");
147 UniConfDaemon
daemon(cfg
, false, NULL
);
151 WVPASS(daemon
.isok());
152 daemon
.setuptcpsocket(addr
);
153 WVPASS(daemon
.isok());
159 tcp
.setcallback(appendbuf
, &buf
);
162 l
.append(&daemon
, false);
163 l
.append(&tcp
, false);
165 linecmp(l
, buf
, "HELLO");
168 tcp
.write("SET /x/y z\n");
171 //linecmp(l, buf, "NOTICE", "", "");
172 //linecmp(l, buf, "NOTICE", "x", "");
173 //linecmp(l, buf, "NOTICE", "x/y", "z");
177 /**** Daemon multimount test ****/
180 WVTEST_MAIN("daemon multimount")
182 signal(SIGPIPE
, SIG_IGN
);
184 UniConfRoot
cfg("temp:");
186 cfg
["pickles"].setme("foo");
187 cfg
["subtree/fries"].setme("bar1");
188 cfg
["subtree/ketchup"].setme("bar2");
189 cfg
["subt"].mount("temp:");
190 cfg
["subt/mayo"].setme("baz");
192 UniConfDaemon
daemon(cfg
, false, NULL
);
194 WvStringList commands
;
195 commands
.append("subt / 1");
196 WvStringListList expected_responses
;
197 WvStringList hello_response
;
198 hello_response
.append(WvString("HELLO {UniConf Server ready.} %s",
199 UNICONF_PROTOCOL_VERSION
));
200 expected_responses
.add(&hello_response
, false);
201 WvStringList expected_quit_response
;
202 expected_quit_response
.append("VAL subtree {}");
203 expected_quit_response
.append("VAL subtree/fries bar1");
204 expected_quit_response
.append("VAL subtree/ketchup bar2");
205 expected_quit_response
.append("VAL subt {}");
206 expected_quit_response
.append("VAL subt/mayo baz");
207 expected_quit_response
.append("VAL pickles foo");
208 expected_quit_response
.append("OK ");
209 expected_responses
.add(&expected_quit_response
, false);
211 WvString pipename
= wvtmpfilename("uniconfd.t-pipe");
212 daemon
.listen(WvString("unix:%s", pipename
));
213 WvUnixAddr
addr(pipename
);
214 WvUnixConn
*sock
= new WvUnixConn(addr
);
215 UniConfDaemonTestConn
conn(sock
, &commands
, &expected_responses
);
217 WvIStreamList::globallist
.append(&conn
, false, "connection");
218 WvIStreamList::globallist
.append(&daemon
, false, "daemon");
219 wvcon
->print("You are about to enter the no spin zone\n");
220 while (!WvIStreamList::globallist
.isempty() &&
221 conn
.isok() && daemon
.isok())
223 wvcon
->print("Spinning: streams left: %s\n",
224 WvIStreamList::globallist
.count());
225 WvIStreamList::globallist
.runonce();
228 WVPASS(daemon
.isok());
229 WvIStreamList::globallist
.zap();
233 /**** Daemon quit test ****/
235 // sort of useless: this functionality already exists in
236 // daemon/tests and is automatically exercised. furthermore, we only
237 // test that the server responds with 'OK' upon close (rather than
238 // actually testing whether or not it closed). leaving this
239 // here as a simple (generic) example to write future tests
240 WVTEST_MAIN("daemon quit")
242 UniConfRoot
cfg("temp:");
243 signal(SIGPIPE
, SIG_IGN
);
245 cfg
["pickles"].setme("foo");
246 cfg
["subtree/fries"].setme("bar1");
247 cfg
["subtree/ketchup"].setme("bar2");
248 UniConfDaemon
daemon(cfg
, false, NULL
);
250 WvStringList commands
;
251 commands
.append("quit");
252 WvStringListList expected_responses
;
253 WvStringList hello_response
;
254 hello_response
.append(WvString("HELLO {UniConf Server ready.} %s",
255 UNICONF_PROTOCOL_VERSION
));
256 expected_responses
.add(&hello_response
, false);
257 WvStringList expected_quit_response
;
258 expected_quit_response
.append("OK ");
259 expected_responses
.add(&expected_quit_response
, false);
261 WvString pipename
= wvtmpfilename("uniconfd.t-pipe");
262 daemon
.listen(WvString("unix:%s", pipename
));
263 WvUnixAddr
addr(pipename
);
264 WvUnixConn
*sock
= new WvUnixConn(addr
);
265 UniConfDaemonTestConn
conn(sock
, &commands
, &expected_responses
);
267 WvIStreamList::globallist
.append(&conn
, false, "conn");
268 WvIStreamList::globallist
.append(&daemon
, false, "daemon");
269 wvcon
->print("You are about to enter the no spin zone\n");
270 while (!WvIStreamList::globallist
.isempty() &&
271 conn
.isok() && daemon
.isok())
273 wvcon
->print("Spinning: streams left: %s\n",
274 WvIStreamList::globallist
.count());
275 WvIStreamList::globallist
.runonce();
278 WVPASS(daemon
.isok());
279 WvIStreamList::globallist
.zap();
283 /**** Daemon proxying test ****/
285 // test that proxying between two uniconf daemons works
286 // e.g.: client -> uniconfd -> uniconfd
288 static WvPipe
* setup_master_daemon(bool implicit_root
,
289 WvString
&masterpipename
, WvString
&ininame
)
291 ininame
= wvtmpfilename("uniconfd.t-ini");
292 WvString pidfile
= wvtmpfilename("uniconfd.t-mpid");
294 WvFile
stuff(ininame
, (O_CREAT
| O_WRONLY
));
295 stuff
.print("pickles/apples/foo=1\n");
296 stuff
.print("pickles/mangos/bar=1\n");
299 masterpipename
= wvtmpfilename("uniconfd.t-sock");
301 WvString
inimount("/cfg=ini:%s", ininame
);
302 WvString mount1
, mount2
;
311 WvString
lmoniker("unix:%s", masterpipename
);
312 const char * const uniconfd_args
[] = {
313 "uniconf/daemon/uniconfd",
314 "-d", "--pid-file", pidfile
.cstr(),
315 "-l", lmoniker
.cstr(),
321 return new WvPipe(uniconfd_args
[0], uniconfd_args
, false, true, false);
325 static WvPipe
* setup_slave_daemon(bool implicit_root
, WvStringParm masterpipename
,
326 WvString
&slavepipename
)
328 slavepipename
= wvtmpfilename("uniconfd.t-sock");
329 WvString pidfile
= wvtmpfilename("uiconfd.t-spid");
333 rootmount
.append("/=retry:unix:%s", masterpipename
);
335 rootmount
.append("/=retry:cache:unix:%s", masterpipename
);
337 WvString
lmoniker("unix:%s", slavepipename
);
338 const char * const uniconfd_args
[] = {
339 "uniconf/daemon/uniconfd",
340 "--pid-file", pidfile
.cstr(),
346 return new WvPipe(uniconfd_args
[0], uniconfd_args
, false, false, false);
350 static void wait_for_pipe_ready(WvStringParm pipename
)
352 // If we can't get a connection in 100ms, something is seriously wrong..
354 WvUnixAddr
addr(pipename
);
355 WvUnixConn
*sock
= new WvUnixConn(addr
);
358 line
= sock
->getline(100);
362 sock
= new WvUnixConn(addr
);
363 line
= sock
->getline(100);
366 wvcon
->print("Pipe ready! (%s)\n", line
);
370 static void daemon_proxy_test(bool implicit_root
)
372 wvcon
->print("Setting up master daemon.\n");
373 WvString masterpipename
, ininame
;
374 WvPipe
*master
= setup_master_daemon(implicit_root
, masterpipename
, ininame
);
375 master
->setcallback(wv::bind(WvPipe::ignore_read
, wv::ref(*master
)));
377 wait_for_pipe_ready(masterpipename
);
379 wvcon
->print("Setting up slave daemon.\n");
380 WvString slavepipename
;
381 WvPipe
*slave
= setup_slave_daemon(implicit_root
, masterpipename
, slavepipename
);
382 slave
->setcallback(wv::bind(WvPipe::ignore_read
, wv::ref(*slave
)));
384 wait_for_pipe_ready(slavepipename
);
386 WvStringList commands
;
387 commands
.append("get /cfg/pickles/apples/foo");
388 commands
.append("subt /");
389 WvStringListList expected_responses
;
390 WvStringList hello_response
;
391 hello_response
.append(WvString("HELLO {UniConf Server ready.} %s",
392 UNICONF_PROTOCOL_VERSION
));
393 expected_responses
.add(&hello_response
, false);
394 WvStringList expected_get_response
;
395 expected_get_response
.append("ONEVAL cfg/pickles/apples/foo 1");
396 expected_responses
.add(&expected_get_response
, false);
397 WvStringList expected_subt_response
;
398 expected_subt_response
.append("VAL cfg {}");
399 expected_responses
.add(&expected_subt_response
, false);
401 WvUnixAddr
addr(slavepipename
);
402 WvUnixConn
*sock
= new WvUnixConn(addr
);
403 UniConfDaemonTestConn
conn(sock
, &commands
, &expected_responses
);
405 WvIStreamList::globallist
.append(&conn
, false, "conn");
407 wvcon
->print("Spinning: streams left: %s\n",
408 WvIStreamList::globallist
.count());
409 while (!WvIStreamList::globallist
.isempty() &&
412 wvcon
->print("Spinning: streams left: %s\n",
413 WvIStreamList::globallist
.count());
414 WvIStreamList::globallist
.runonce();
417 WvIStreamList::globallist
.zap();
421 unlink(slavepipename
.cstr());
422 unlink(masterpipename
.cstr());
423 unlink(ininame
.cstr());
427 WVTEST_MAIN("daemon proxying - with cache")
429 signal(SIGPIPE
, SIG_IGN
);
431 daemon_proxy_test(false);
435 WVTEST_MAIN("daemon proxying - cfg the only mount")
437 signal(SIGPIPE
, SIG_IGN
);
439 daemon_proxy_test(true);