Imported Upstream version 3.3.3
[debian/amanda] / common-src / ipc-binary-test.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of U.M. not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  U.M. makes no representations about the
14  * suitability of this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  *
17  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Authors: the Amanda Development Team.  Its members are listed in a
25  * file named AUTHORS, in the root directory of this distribution.
26  */
27
28 #include "amanda.h"
29 #include "testutils.h"
30 #include "glib-util.h"
31 #include "ipc-binary.h"
32
33 enum {
34     MY_PROTO_CMD1 = 1,
35     MY_PROTO_CMD2 = 2,
36 };
37
38 enum {
39     MY_PROTO_HOSTNAME = 1,
40     MY_PROTO_DISK = 2,
41     MY_PROTO_DATA = 3,
42 };
43
44 struct proto_and_fd {
45     ipc_binary_proto_t *proto;
46     int fd;
47 };
48
49 /*
50  * Test a basic synchronous conversation between two endpoints.  Because
51  * sync is implemented in terms of the async functions, this tests all of
52  * the module's functionality.
53  */
54 static gpointer
55 test_sync_child(gpointer d)
56 {
57     struct proto_and_fd *data = (struct proto_and_fd *)d;
58     ipc_binary_proto_t *proto = data->proto;
59     ipc_binary_channel_t *chan;
60     ipc_binary_message_t *msg;
61     int fd = data->fd;
62
63     g_usleep(G_USEC_PER_SEC / 8);
64
65     chan = ipc_binary_new_channel(proto);
66     msg = ipc_binary_new_message(chan, MY_PROTO_CMD1);
67     ipc_binary_add_arg(msg, MY_PROTO_HOSTNAME, 0, "localhost", 0);
68     if (ipc_binary_write_message(chan, fd, msg) < 0) return NULL;
69
70     g_usleep(G_USEC_PER_SEC / 8);
71
72     msg = ipc_binary_new_message(chan, MY_PROTO_CMD1);
73     ipc_binary_add_arg(msg, MY_PROTO_HOSTNAME, 0, "otherhost", 0);
74     ipc_binary_add_arg(msg, MY_PROTO_DISK, 0, "/usr", 0);
75     if (ipc_binary_write_message(chan, fd, msg) < 0) return NULL;
76
77     msg = ipc_binary_new_message(chan, MY_PROTO_CMD2);
78     ipc_binary_add_arg(msg, MY_PROTO_DATA, 9, "some-data", 0);
79     if (ipc_binary_write_message(chan, fd, msg) < 0) return NULL;
80
81     return GINT_TO_POINTER(1);
82 }
83
84 static int
85 test_sync_parent(ipc_binary_proto_t *proto, int fd)
86 {
87     ipc_binary_channel_t *chan;
88     ipc_binary_message_t *msg;
89
90     chan = ipc_binary_new_channel(proto);
91     tu_dbg("parent: created channel\n");
92
93     msg = ipc_binary_read_message(chan, fd);
94     tu_dbg("parent: read message 1\n");
95     if (msg->cmd_id != MY_PROTO_CMD1) {
96         tu_dbg("got bad cmd_id %d\n", (int)msg->cmd_id);
97         return 0;
98     }
99     if (msg->args[MY_PROTO_HOSTNAME].data == NULL) {
100         tu_dbg("got NULL hostname\n");
101         return 0;
102     }
103     if (0 != strcmp((gchar *)msg->args[MY_PROTO_HOSTNAME].data, "localhost")) {
104         tu_dbg("got bad hostname %s\n", (gchar *)msg->args[MY_PROTO_HOSTNAME].data);
105         return 0;
106     }
107     if (msg->args[MY_PROTO_DISK].data != NULL) {
108         tu_dbg("got non-NULL disk\n");
109         return 0;
110     }
111     ipc_binary_free_message(msg);
112
113     msg = ipc_binary_read_message(chan, fd);
114     tu_dbg("parent: read message 2\n");
115     if (msg->cmd_id != MY_PROTO_CMD1) {
116         tu_dbg("got bad cmd_id %d\n", (int)msg->cmd_id);
117         return 0;
118     }
119     if (msg->args[MY_PROTO_HOSTNAME].data == NULL) {
120         tu_dbg("got NULL hostname\n");
121         return 0;
122     }
123     if (0 != strcmp((gchar *)msg->args[MY_PROTO_HOSTNAME].data, "otherhost")) {
124         tu_dbg("got bad hostname %s\n", (gchar *)msg->args[MY_PROTO_HOSTNAME].data);
125         return 0;
126     }
127     if (msg->args[MY_PROTO_DISK].data == NULL) {
128         tu_dbg("got NULL disk\n");
129         return 0;
130     }
131     if (0 != strcmp((gchar *)msg->args[MY_PROTO_DISK].data, "/usr")) {
132         tu_dbg("got bad disk %s\n", (gchar *)msg->args[MY_PROTO_DISK].data);
133         return 0;
134     }
135     ipc_binary_free_message(msg);
136
137     g_usleep(G_USEC_PER_SEC / 8);
138
139     msg = ipc_binary_read_message(chan, fd);
140     tu_dbg("parent: read message 3\n");
141     if (msg->cmd_id != MY_PROTO_CMD2) {
142         tu_dbg("got bad cmd_id %d\n", (int)msg->cmd_id);
143         return 0;
144     }
145     if (msg->args[MY_PROTO_DATA].data == NULL) {
146         tu_dbg("got NULL data\n");
147         return 0;
148     }
149     if (msg->args[MY_PROTO_DATA].len != 9) {
150         tu_dbg("got data length %d, expected 9\n", (int)msg->args[MY_PROTO_DATA].len);
151         return 0;
152     }
153     if (0 != strncmp((gchar *)msg->args[MY_PROTO_DATA].data, "some-data", 9)) {
154         tu_dbg("got bad data\n");
155         return 0;
156     }
157     ipc_binary_free_message(msg);
158
159     return 1;
160 }
161
162 static gboolean
163 test_sync(void)
164 {
165     int rv;
166     int p[2];
167     ipc_binary_proto_t *proto;
168     ipc_binary_cmd_t *cmd;
169     struct proto_and_fd data;
170     GThread *child;
171
172     if (pipe(p) == -1) {
173         perror("pipe");
174         return FALSE;
175     }
176
177     proto = ipc_binary_proto_new(0xE10E);
178     cmd = ipc_binary_proto_add_cmd(proto, MY_PROTO_CMD1);
179     ipc_binary_cmd_add_arg(cmd, MY_PROTO_HOSTNAME, IPC_BINARY_STRING);
180     ipc_binary_cmd_add_arg(cmd, MY_PROTO_DISK, IPC_BINARY_STRING|IPC_BINARY_OPTIONAL);
181     cmd = ipc_binary_proto_add_cmd(proto, MY_PROTO_CMD2);
182     ipc_binary_cmd_add_arg(cmd, MY_PROTO_DATA, 0);
183
184     /* start the child thread */
185     data.proto = proto;
186     data.fd = p[1];
187     child = g_thread_create(test_sync_child, &data, TRUE, NULL);
188
189     /* run the parent and collect the results */
190     rv = test_sync_parent(proto, p[0]) && GPOINTER_TO_INT(g_thread_join(child));
191     return (rv) ? TRUE : FALSE;
192 }
193
194 int
195 main(int argc, char **argv)
196 {
197     static TestUtilsTest tests[] = {
198         TU_TEST(test_sync, 60),
199         TU_END()
200     };
201
202     glib_init();
203     return testutils_run_tests(argc, argv, tests);
204 }