2 Unix SMB/CIFS implementation.
3 test suite for echo rpc operations
5 Copyright (C) Andrew Tridgell 2003
6 Copyright (C) Stefan (metze) Metzmacher 2005
7 Copyright (C) Jelmer Vernooij 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "torture/torture.h"
26 #include "torture/rpc/rpc.h"
27 #include "lib/events/events.h"
28 #include "librpc/gen_ndr/ndr_echo_c.h"
32 test the AddOne interface
34 #define TEST_ADDONE(tctx, value) do { \
37 r.out.out_data = &n; \
38 status = dcerpc_echo_AddOne(p, tctx, &r); \
39 torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "AddOne(%d) failed", i)); \
40 torture_assert (tctx, n == i+1, talloc_asprintf(tctx, "%d + 1 != %u (should be %u)\n", i, n, i+1)); \
41 torture_comment (tctx, "%d + 1 = %u\n", i, n); \
44 static bool test_addone(struct torture_context
*tctx
,
45 struct dcerpc_pipe
*p
)
56 TEST_ADDONE(tctx
, 0x7FFFFFFE);
57 TEST_ADDONE(tctx
, 0xFFFFFFFE);
58 TEST_ADDONE(tctx
, 0xFFFFFFFF);
59 TEST_ADDONE(tctx
, random() & 0xFFFFFFFF);
64 test the EchoData interface
66 static bool test_echodata(struct torture_context
*tctx
,
67 struct dcerpc_pipe
*p
)
71 uint8_t *data_in
, *data_out
;
73 struct echo_EchoData r
;
75 if (torture_setting_bool(tctx
, "quick", false) &&
76 (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_BOTH
)) {
77 len
= 1 + (random() % 500);
79 len
= 1 + (random() % 5000);
82 data_in
= talloc_size(tctx
, len
);
83 data_out
= talloc_size(tctx
, len
);
89 r
.in
.in_data
= data_in
;
91 status
= dcerpc_echo_EchoData(p
, tctx
, &r
);
92 torture_assert_ntstatus_ok(tctx
, status
, talloc_asprintf(tctx
,
93 "EchoData(%d) failed\n", len
));
95 data_out
= r
.out
.out_data
;
98 if (data_in
[i
] != data_out
[i
]) {
99 torture_comment(tctx
, "Bad data returned for len %d at offset %d\n",
101 torture_comment(tctx
, "in:\n");
102 dump_data(0, data_in
+i
, MIN(len
-i
, 16));
103 torture_comment(tctx
, "out:\n");
104 dump_data(0, data_out
+i
, MIN(len
-1, 16));
112 test the SourceData interface
114 static bool test_sourcedata(struct torture_context
*tctx
,
115 struct dcerpc_pipe
*p
)
120 struct echo_SourceData r
;
122 if (torture_setting_bool(tctx
, "quick", false) &&
123 (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_BOTH
)) {
124 len
= 100 + (random() % 500);
126 len
= 200000 + (random() % 5000);
131 status
= dcerpc_echo_SourceData(p
, tctx
, &r
);
132 torture_assert_ntstatus_ok(tctx
, status
, talloc_asprintf(tctx
,
133 "SourceData(%d) failed", len
));
135 for (i
=0;i
<len
;i
++) {
136 uint8_t *v
= (uint8_t *)r
.out
.data
;
137 torture_assert(tctx
, v
[i
] == (i
& 0xFF),
138 talloc_asprintf(tctx
,
139 "bad data 0x%x at %d\n", (uint8_t)r
.out
.data
[i
], i
));
145 test the SinkData interface
147 static bool test_sinkdata(struct torture_context
*tctx
,
148 struct dcerpc_pipe
*p
)
154 struct echo_SinkData r
;
156 if (torture_setting_bool(tctx
, "quick", false) &&
157 (p
->conn
->flags
& DCERPC_DEBUG_VALIDATE_BOTH
)) {
158 len
= 100 + (random() % 5000);
160 len
= 200000 + (random() % 5000);
163 data_in
= talloc_size(tctx
, len
);
164 for (i
=0;i
<len
;i
++) {
171 status
= dcerpc_echo_SinkData(p
, tctx
, &r
);
172 torture_assert_ntstatus_ok(tctx
, status
, talloc_asprintf(tctx
,
173 "SinkData(%d) failed",
176 torture_comment(tctx
, "sunk %d bytes\n", len
);
182 test the testcall interface
184 static bool test_testcall(struct torture_context
*tctx
,
185 struct dcerpc_pipe
*p
)
188 struct echo_TestCall r
;
189 const char *s
= NULL
;
191 r
.in
.s1
= "input string";
194 status
= dcerpc_echo_TestCall(p
, tctx
, &r
);
195 torture_assert_ntstatus_ok(tctx
, status
, "TestCall failed");
197 torture_assert_str_equal(tctx
, s
, "input string", "Didn't receive back same string");
203 test the testcall interface
205 static bool test_testcall2(struct torture_context
*tctx
,
206 struct dcerpc_pipe
*p
)
209 struct echo_TestCall2 r
;
214 r
.out
.info
= talloc(tctx
, union echo_Info
);
216 torture_comment(tctx
, "Testing TestCall2 level %d\n", i
);
217 status
= dcerpc_echo_TestCall2(p
, tctx
, &r
);
218 torture_assert_ntstatus_ok(tctx
, status
, "TestCall2 failed");
224 test the TestSleep interface
226 static bool test_sleep(struct torture_context
*tctx
,
227 struct dcerpc_pipe
*p
)
231 #define ASYNC_COUNT 3
232 struct rpc_request
*req
[ASYNC_COUNT
];
233 struct echo_TestSleep r
[ASYNC_COUNT
];
234 BOOL done
[ASYNC_COUNT
];
235 struct timeval snd
[ASYNC_COUNT
];
236 struct timeval rcv
[ASYNC_COUNT
];
237 struct timeval diff
[ASYNC_COUNT
];
238 struct event_context
*ctx
;
241 if (torture_setting_bool(tctx
, "quick", false)) {
242 torture_skip(tctx
, "TestSleep disabled - use \"torture:quick=no\" to enable\n");
244 torture_comment(tctx
, "Testing TestSleep - use \"torture:quick=no\" to disable\n");
246 for (i
=0;i
<ASYNC_COUNT
;i
++) {
248 snd
[i
] = timeval_current();
249 rcv
[i
] = timeval_zero();
250 r
[i
].in
.seconds
= ASYNC_COUNT
-i
;
251 req
[i
] = dcerpc_echo_TestSleep_send(p
, tctx
, &r
[i
]);
252 torture_assert(tctx
, req
[i
], "Failed to send async sleep request\n");
255 ctx
= dcerpc_event_context(p
);
256 while (total_done
< ASYNC_COUNT
) {
257 torture_assert(tctx
, event_loop_once(ctx
) == 0,
258 "Event context loop failed");
259 for (i
=0;i
<ASYNC_COUNT
;i
++) {
260 if (done
[i
] == False
&& req
[i
]->state
== RPC_REQUEST_DONE
) {
264 rcv
[i
] = timeval_current();
265 diff
[i
] = timeval_until(&snd
[i
], &rcv
[i
]);
266 rounded_tdiff
= (int)(0.5 + diff
[i
].tv_sec
+ (1.0e-6*diff
[i
].tv_usec
));
267 status
= dcerpc_ndr_request_recv(req
[i
]);
268 printf("rounded_tdiff=%d\n", rounded_tdiff
);
269 torture_assert_ntstatus_ok(tctx
, status
,
270 talloc_asprintf(tctx
, "TestSleep(%d) failed", i
));
271 torture_assert(tctx
, r
[i
].out
.result
== r
[i
].in
.seconds
,
272 talloc_asprintf(tctx
, "Failed - Asked to sleep for %u seconds (server replied with %u seconds and the reply takes only %u seconds)",
273 r
[i
].out
.result
, r
[i
].in
.seconds
, (uint_t
)diff
[i
].tv_sec
));
274 torture_assert(tctx
, r
[i
].out
.result
<= rounded_tdiff
,
275 talloc_asprintf(tctx
, "Failed - Slept for %u seconds (but reply takes only %u.%06u seconds)",
276 r
[i
].out
.result
, (uint_t
)diff
[i
].tv_sec
, (uint_t
)diff
[i
].tv_usec
));
277 if (r
[i
].out
.result
+1 == rounded_tdiff
) {
278 torture_comment(tctx
, "Slept for %u seconds (but reply takes %u.%06u seconds - busy server?)\n",
279 r
[i
].out
.result
, (uint_t
)diff
[i
].tv_sec
, (uint_t
)diff
[i
].tv_usec
);
280 } else if (r
[i
].out
.result
== rounded_tdiff
) {
281 torture_comment(tctx
, "Slept for %u seconds (reply takes %u.%06u seconds - ok)\n",
282 r
[i
].out
.result
, (uint_t
)diff
[i
].tv_sec
, (uint_t
)diff
[i
].tv_usec
);
284 torture_comment(tctx
, "(Failed) - Not async - Slept for %u seconds (but reply takes %u.%06u seconds)",
285 r
[i
].out
.result
, (uint_t
)diff
[i
].tv_sec
, (uint_t
)diff
[i
].tv_usec
);
286 /* TODO: let the test fail here, when we support async rpc on ncacn_np */
297 static bool test_enum(struct torture_context
*tctx
,
298 struct dcerpc_pipe
*p
)
301 struct echo_TestEnum r
;
302 enum echo_Enum1 v
= ECHO_ENUM1
;
303 struct echo_Enum2 e2
;
314 e2
.e2
= ECHO_ENUM1_32
;
317 status
= dcerpc_echo_TestEnum(p
, tctx
, &r
);
318 torture_assert_ntstatus_ok(tctx
, status
, "TestEnum failed");
323 test surrounding conformant array handling
325 static bool test_surrounding(struct torture_context
*tctx
,
326 struct dcerpc_pipe
*p
)
329 struct echo_TestSurrounding r
;
332 r
.in
.data
= talloc(tctx
, struct echo_Surrounding
);
335 r
.in
.data
->surrounding
= talloc_zero_array(tctx
, uint16_t, r
.in
.data
->x
);
337 r
.out
.data
= talloc(tctx
, struct echo_Surrounding
);
339 status
= dcerpc_echo_TestSurrounding(p
, tctx
, &r
);
340 torture_assert_ntstatus_ok(tctx
, status
, "TestSurrounding failed");
342 torture_assert(tctx
, r
.out
.data
->x
== 2 * r
.in
.data
->x
,
343 "TestSurrounding did not make the array twice as large");
349 test multiple levels of pointers
351 static bool test_doublepointer(struct torture_context
*tctx
,
352 struct dcerpc_pipe
*p
)
355 struct echo_TestDoublePointer r
;
357 uint16_t *pvalue
= &value
;
358 uint16_t **ppvalue
= &pvalue
;
361 r
.in
.data
= &ppvalue
;
363 status
= dcerpc_echo_TestDoublePointer(p
, tctx
, &r
);
364 torture_assert_ntstatus_ok(tctx
, status
, "TestDoublePointer failed");
366 torture_assert_int_equal(tctx
, value
, r
.out
.result
,
367 "TestDoublePointer did not return original value");
373 test request timeouts
375 static bool test_timeout(struct torture_context
*tctx
,
376 struct dcerpc_pipe
*p
)
379 struct rpc_request
*req
;
380 struct echo_TestSleep r
;
381 int timeout_saved
= p
->request_timeout
;
383 if (torture_setting_bool(tctx
, "quick", false)) {
384 torture_skip(tctx
, "timeout testing disabled - use \"torture:quick=no\" to enable\n");
387 torture_comment(tctx
, "testing request timeouts\n");
389 p
->request_timeout
= 1;
391 torture_assert(tctx
, req
= dcerpc_echo_TestSleep_send(p
, tctx
, &r
),
392 "Failed to send async sleep request");
394 status
= dcerpc_ndr_request_recv(req
);
395 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_IO_TIMEOUT
,
396 "request should have timed out");
398 torture_comment(tctx
, "testing request destruction\n");
399 req
= dcerpc_echo_TestSleep_send(p
, tctx
, &r
);
401 torture_comment(tctx
, "Failed to send async sleep request\n");
406 req
= dcerpc_echo_TestSleep_send(p
, tctx
, &r
);
408 torture_comment(tctx
, "Failed to send async sleep request\n");
411 status
= dcerpc_ndr_request_recv(req
);
412 torture_assert_ntstatus_equal(tctx
, status
, NT_STATUS_IO_TIMEOUT
,
413 "request should have timed out");
415 p
->request_timeout
= timeout_saved
;
417 return test_addone(tctx
, p
);
420 p
->request_timeout
= timeout_saved
;
425 struct torture_suite
*torture_rpc_echo(void)
427 struct torture_suite
*suite
= torture_suite_create(
428 talloc_autofree_context(), "ECHO");
429 struct torture_tcase
*tcase
;
431 tcase
= torture_suite_add_rpc_iface_tcase(suite
, "echo",
432 &dcerpc_table_rpcecho
);
434 torture_rpc_tcase_add_test(tcase
, "addone", test_addone
);
435 torture_rpc_tcase_add_test(tcase
, "sinkdata", test_sinkdata
);
436 torture_rpc_tcase_add_test(tcase
, "echodata", test_echodata
);
437 torture_rpc_tcase_add_test(tcase
, "sourcedata", test_sourcedata
);
438 torture_rpc_tcase_add_test(tcase
, "testcall", test_testcall
);
439 torture_rpc_tcase_add_test(tcase
, "testcall2", test_testcall2
);
440 torture_rpc_tcase_add_test(tcase
, "enum", test_enum
);
441 torture_rpc_tcase_add_test(tcase
, "surrounding", test_surrounding
);
442 torture_rpc_tcase_add_test(tcase
, "doublepointer", test_doublepointer
);
443 torture_rpc_tcase_add_test(tcase
, "sleep", test_sleep
);
444 torture_rpc_tcase_add_test(tcase
, "timeout", test_timeout
);