1 /*
2 * Copyright (c) 1998,1999,2000
3 * Traakan, Inc., Los Altos, CA
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
11 * disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * Project: NDMJOB
31 * Ident: $Id: $
32 *
33 * Description:
34 *
35 */
36
37
38 #include "ndmagents.h"
39
40
41 #if !defined(NDMOS_OPTION_NO_CONTROL_AGENT) && !defined(NDMOS_OPTION_NO_TEST_AGENTS)
42
43 int
ndmca_test_query_conn_types(struct ndm_session * sess,struct ndmconn * ref_conn)44 ndmca_test_query_conn_types (struct ndm_session *sess,
45 struct ndmconn *ref_conn)
46 {
47 struct ndmconn *conn = ref_conn;
48 struct ndm_control_agent *ca = sess->control_acb;
49 int rc;
50 unsigned int i;
51
52 switch (conn->protocol_version) {
53 default: return -1234;
54
55 #ifndef NDMOS_OPTION_NO_NDMP2
56 case NDMP2VER:
57 NDMC_WITH_VOID_REQUEST(ndmp2_config_get_mover_type, NDMP2VER)
58 rc = NDMC_CALL(conn);
59 if (rc) {
60 ndmalogf (sess, "Test", 1, "GET_MOVER_TYPE failed");
61 return rc;
62 }
63
64 for (i = 0; i < reply->methods.methods_len; i++) {
65 switch(reply->methods.methods_val[i]) {
66 case NDMP2_ADDR_LOCAL:
67 ca->has_local_addr = 1;
68 break;
69 case NDMP2_ADDR_TCP:
70 ca->has_tcp_addr = 1;
71 break;
72 default:
73 break;
74 }
75 }
76
77 NDMC_FREE_REPLY();
78 NDMC_ENDWITH
79 break;
80 #endif /* !NDMOS_OPTION_NO_NDMP2 */
81
82 #ifndef NDMOS_OPTION_NO_NDMP3
83 case NDMP3VER:
84 NDMC_WITH_VOID_REQUEST(ndmp3_config_get_connection_type, NDMP3VER)
85 rc = NDMC_CALL(conn);
86 if (rc) {
87 ndmalogf (sess, "Test", 1, "GET_CONNECTION_TYPE failed");
88 return rc;
89 }
90
91 for (i = 0; i < reply->addr_types.addr_types_len; i++) {
92 switch(reply->addr_types.addr_types_val[i]) {
93 case NDMP3_ADDR_LOCAL:
94 ca->has_local_addr = 1;
95 break;
96 case NDMP3_ADDR_TCP:
97 ca->has_tcp_addr = 1;
98 break;
99 default:
100 break;
101 }
102 }
103 NDMC_FREE_REPLY();
104 NDMC_ENDWITH
105 break;
106 #endif /* !NDMOS_OPTION_NO_NDMP3 */
107
108 #ifndef NDMOS_OPTION_NO_NDMP4
109 case NDMP4VER:
110 NDMC_WITH_VOID_REQUEST(ndmp4_config_get_connection_type, NDMP4VER)
111 rc = NDMC_CALL(conn);
112 if (rc) {
113 ndmalogf (sess, "Test", 1, "GET_CONNECTION_TYPE failed");
114 return rc;
115 }
116
117 for (i = 0; i < reply->addr_types.addr_types_len; i++) {
118 switch(reply->addr_types.addr_types_val[i]) {
119 case NDMP4_ADDR_LOCAL:
120 ca->has_local_addr = 1;
121 break;
122 case NDMP4_ADDR_TCP:
123 ca->has_tcp_addr = 1;
124 break;
125 default:
126 break;
127 }
128 }
129 NDMC_FREE_REPLY();
130 NDMC_ENDWITH
131 break;
132 #endif /* !NDMOS_OPTION_NO_NDMP4 */
133 }
134
135 return 0;
136 }
137
138
139 int
ndmca_test_load_tape(struct ndm_session * sess)140 ndmca_test_load_tape (struct ndm_session *sess)
141 {
142 struct ndm_control_agent *ca = sess->control_acb;
143 int rc;
144
145 ca->tape_mode = NDMP9_TAPE_READ_MODE;
146 ca->is_label_op = 1;
147
148 rc = ndmca_op_robot_startup (sess, 1);
149 if (rc) return rc;
150
151 rc = ndmca_connect_tape_agent(sess);
152 if (rc) {
153 ndmconn_destruct (sess->plumb.tape);
154 sess->plumb.tape = NULL;
155 return rc; /* already tattled */
156 }
157
158 rc = ndmca_media_load_first (sess);
159 if (rc) return rc;
160
161 ndmca_tape_close (sess);
162
163 return 0;
164 }
165
166 int
ndmca_test_unload_tape(struct ndm_session * sess)167 ndmca_test_unload_tape (struct ndm_session *sess)
168 {
169 ndmca_tape_open (sess);
170
171 ndmca_media_unload_current(sess);
172
173 return 0;
174 }
175
176 int
ndmca_test_check_expect_errs(struct ndmconn * conn,int rc,ndmp9_error expect_errs[])177 ndmca_test_check_expect_errs (struct ndmconn *conn, int rc,
178 ndmp9_error expect_errs[])
179 {
180 struct ndm_session *sess = conn->context;
181 int protocol_version = conn->protocol_version;
182 struct ndmp_xa_buf *xa = &conn->call_xa_buf;
183 unsigned msg = xa->request.header.message;
184 char * msgname = ndmp_message_to_str (protocol_version, msg);
185 ndmp9_error reply_error = conn->last_reply_error;
186 int i;
187
188 /* make sure we have a 'test' active */
189 ndmca_test_open (sess, msgname, ndmp9_error_to_str (expect_errs[0]));
190
191 if (rc >= 0) {
192 /* Call succeeded. Body valid */
193 rc = 1;
194 for (i = 0; (int)expect_errs[i] >= 0; i++) {
195 if (reply_error == expect_errs[i]) {
196 rc = 0;
197 break;
198 }
199 }
200
201 if (rc) {
202 if (reply_error != NDMP9_NO_ERR
203 && expect_errs[0] != NDMP9_NO_ERR) {
204 /* both are errors, don't be picky */
205 rc = 2;
206 } else {
207 /* intolerable mismatch */
208 }
209 } else {
210 /* Worked as expected */
211 }
212 }
213
214 if (rc != 0) {
215 char tmpbuf[128];
216
217 for (i = 0; (int)expect_errs[i] >= 0; i++) {
218 ndmalogf (sess, "Test", 1,
219 "%s #%d -- .... %s %s",
220 sess->control_acb->test_phase,
221 sess->control_acb->test_step,
222 (i==0) ? "expected" : "or",
223 ndmp9_error_to_str (expect_errs[i]));
224 }
225
226 snprintf(tmpbuf, sizeof(tmpbuf), "got %s (error expected)", ndmp9_error_to_str (reply_error));
227
228 if (rc == 2)
229 ndmca_test_warn (sess, tmpbuf);
230 else
231 ndmca_test_fail (sess, tmpbuf);
232
233 ndma_tattle (conn, xa, rc);
234
235 if (rc == 2)
236 rc = 0;
237 }
238
239 return rc;
240 }
241
242 int
ndmca_test_check_expect(struct ndmconn * conn,int rc,ndmp9_error expect_err)243 ndmca_test_check_expect (struct ndmconn *conn, int rc, ndmp9_error expect_err)
244 {
245 ndmp9_error errs[2];
246
247 errs[0] = expect_err;
248 errs[1] = -1;
249
250 return ndmca_test_check_expect_errs (conn, rc, errs);
251 }
252
253 int
ndmca_test_check_expect_no_err(struct ndmconn * conn,int rc)254 ndmca_test_check_expect_no_err (struct ndmconn *conn, int rc)
255 {
256 return ndmca_test_check_expect (conn, rc, NDMP9_NO_ERR);
257 }
258
259 int
ndmca_test_check_expect_illegal_state(struct ndmconn * conn,int rc)260 ndmca_test_check_expect_illegal_state (struct ndmconn *conn, int rc)
261 {
262 return ndmca_test_check_expect (conn, rc, NDMP9_ILLEGAL_STATE_ERR);
263 }
264
265 int
ndmca_test_check_expect_illegal_args(struct ndmconn * conn,int rc)266 ndmca_test_check_expect_illegal_args (struct ndmconn *conn, int rc)
267 {
268 return ndmca_test_check_expect (conn, rc, NDMP9_ILLEGAL_ARGS_ERR);
269 }
270
271
272 int
ndmca_test_call(struct ndmconn * conn,struct ndmp_xa_buf * xa,ndmp9_error expect_err)273 ndmca_test_call (struct ndmconn *conn,
274 struct ndmp_xa_buf *xa, ndmp9_error expect_err)
275 {
276 struct ndm_session *sess = conn->context;
277 int protocol_version = conn->protocol_version;
278 unsigned msg = xa->request.header.message;
279 char * msgname = ndmp_message_to_str (protocol_version, msg);
280 unsigned reply_error;
281 int rc;
282
283 /* close previous test if there is one */
284 ndmca_test_close (sess);
285
286 /* open new 'test' */
287 ndmca_test_open (sess, msgname, ndmp9_error_to_str (expect_err));
288
289 rc = ndma_call_no_tattle (conn, xa);
290
291 reply_error = ndmnmb_get_reply_error (&xa->reply);
292
293 if (rc >= 0) {
294 /* Call succeeded. Body valid */
295 if (reply_error == expect_err) {
296 /* Worked exactly as expected */
297 rc = 0;
298 } else if (reply_error != NDMP9_NO_ERR
299 && expect_err != NDMP9_NO_ERR) {
300 /* both are errors, don't be picky about the codes */
301 rc = 2;
302 } else {
303 /* intolerable mismatch */
304 rc = 1;
305 }
306 }
307
308 if (rc != 0) {
309 char tmpbuf[128];
310 snprintf(tmpbuf, sizeof(tmpbuf), "got %s (call)", ndmp9_error_to_str (reply_error));
311 if (rc == 2)
312 ndmca_test_warn (sess, tmpbuf);
313 else
314 ndmca_test_fail (sess, tmpbuf);
315
316 ndma_tattle (conn, xa, rc);
317
318 if (rc == 2)
319 rc = 0;
320 }
321
322 return rc;
323 }
324
325 /*
326 * start or open a test if not already opened
327 */
328 void
ndmca_test_open(struct ndm_session * sess,char * test_name,char * sub_test_name)329 ndmca_test_open (struct ndm_session *sess, char *test_name, char *sub_test_name)
330 {
331 static char test_name_buf[512];
332
333 if (sess->control_acb->active_test == 0) {
334 /* record name */
335 if (sub_test_name)
336 snprintf(test_name_buf, sizeof(test_name_buf), "%s/%s", test_name, sub_test_name);
337 else
338 strcpy(test_name_buf, test_name);
339 sess->control_acb->active_test = test_name_buf;
340
341 /* make sure flags are cleared */
342 sess->control_acb->active_test_failed = (char *)0;
343 sess->control_acb->active_test_warned = (char *)0;
344 }
345 }
346
347 void
ndmca_test_warn(struct ndm_session * sess,char * warn_msg)348 ndmca_test_warn (struct ndm_session *sess, char *warn_msg)
349 {
350 static char warn_msg_buf[512];
351
352 ndmca_test_open (sess, "UNKNOWN WARN", 0);
353
354 strcpy(warn_msg_buf, warn_msg);
355 sess->control_acb->active_test_warned = warn_msg_buf;
356 }
357
358 void
ndmca_test_fail(struct ndm_session * sess,char * fail_msg)359 ndmca_test_fail (struct ndm_session *sess, char *fail_msg)
360 {
361 static char fail_msg_buf[512];
362
363 ndmca_test_open (sess, "UNKNOWN FAIL", 0);
364
365 strcpy(fail_msg_buf, fail_msg);
366 sess->control_acb->active_test_failed = fail_msg_buf;
367 }
368
369
370
371 /*
372 * close or end a test if not already closed
373 */
374 void
ndmca_test_close(struct ndm_session * sess)375 ndmca_test_close (struct ndm_session *sess)
376 {
377 if (sess->control_acb->active_test != 0) {
378 /* count test */
379 sess->control_acb->n_step_tests++;
380
381 /* display results */
382 if (sess->control_acb->active_test_failed) {
383 ndmalogf (sess, "Test", 1,
384 "%s #%d -- Failed %s %s",
385 sess->control_acb->test_phase,
386 sess->control_acb->test_step,
387 sess->control_acb->active_test,
388 sess->control_acb->active_test_failed);
389 sess->control_acb->n_step_fail++;
390 exit(1);
391 } else if (sess->control_acb->active_test_warned) {
392 ndmalogf (sess, "Test", 1,
393 "%s #%d -- Almost %s %s",
394 sess->control_acb->test_phase,
395 sess->control_acb->test_step,
396 sess->control_acb->active_test,
397 sess->control_acb->active_test_warned);
398 sess->control_acb->n_step_warn++;
399 exit(1);
400 } else {
401 ndmalogf (sess, "Test", 2,
402 "%s #%d -- Passed %s",
403 sess->control_acb->test_phase,
404 sess->control_acb->test_step,
405 sess->control_acb->active_test);
406 sess->control_acb->n_step_pass++;
407 }
408
409 /* clear flags */
410 sess->control_acb->active_test = (char *)0;
411 sess->control_acb->active_test_failed = (char *)0;
412 sess->control_acb->active_test_warned = (char *)0;
413
414 /* advance test count */
415 sess->control_acb->test_step++;
416 }
417 }
418
419
420 /*
421 * start a test phase (part of a series)
422 */
423 void
ndmca_test_phase(struct ndm_session * sess,char * test_phase,char * desc)424 ndmca_test_phase (struct ndm_session *sess, char *test_phase, char *desc)
425 {
426 ndmalogf (sess, "TEST", 0, "Test %s -- %s", test_phase, desc);
427
428 sess->control_acb->test_phase = test_phase;
429 sess->control_acb->test_step = 1;
430 sess->control_acb->n_step_pass = 0;
431 sess->control_acb->n_step_fail = 0;
432 sess->control_acb->n_step_warn = 0;
433 sess->control_acb->n_step_tests = 0;
434 }
435
436 void
ndmca_test_log_step(struct ndm_session * sess,int level,char * msg)437 ndmca_test_log_step (struct ndm_session *sess, int level, char *msg)
438 {
439 int had_active = (sess->control_acb->active_test != 0);
440
441 ndmalogf (sess, "Test", level, "%s #%d -- %s",
442 sess->control_acb->test_phase,
443 sess->control_acb->test_step,
444 msg);
445
446 /* in case we have a open test -- close it */
447 ndmca_test_close (sess);
448
449 /* advance test count if we didn't have an active test */
450 if (!had_active)
451 sess->control_acb->test_step++;
452
453 }
454
455 void
ndmca_test_log_note(struct ndm_session * sess,int level,char * msg)456 ndmca_test_log_note (struct ndm_session *sess, int level, char *msg)
457 {
458 ndmalogf (sess, "Test", level, "%s #%d %s",
459 sess->control_acb->test_phase,
460 sess->control_acb->test_step,
461 msg);
462 }
463
464 /*
465 * finish a test phase (part of a series)
466 */
467 void
ndmca_test_done_phase(struct ndm_session * sess)468 ndmca_test_done_phase (struct ndm_session *sess)
469 {
470 struct ndm_control_agent *ca = sess->control_acb;
471 char * status;
472 int had_active = (sess->control_acb->active_test != 0);
473
474 /* close previous test if there is one */
475 ndmca_test_close (sess);
476
477 if (ca->n_step_fail)
478 status = "Failed";
479 else if (ca->n_step_warn)
480 status = "Almost";
481 else if (ca->n_step_pass > 0)
482 status = "Passed";
483 else
484 status = "Whiffed";
485
486 ndmalogf (sess, "TEST", 0, "Test %s %s -- pass=%d warn=%d fail=%d (total %d)",
487 ca->test_phase,
488 status,
489 ca->n_step_pass,
490 ca->n_step_warn,
491 ca->n_step_fail,
492 ca->n_step_tests);
493
494 ca->total_n_step_pass += ca->n_step_pass;
495 ca->total_n_step_warn += ca->n_step_warn;
496 ca->total_n_step_fail += ca->n_step_fail;
497 ca->total_n_step_tests += ca->n_step_tests;
498
499 /* advance test count if we didn't have an active test so
500 * clean up phases have a new test count
501 */
502 if (!had_active)
503 sess->control_acb->test_step++;
504 }
505
506 /*
507 * finish a test series (which may include test phases)
508 */
509 void
ndmca_test_done_series(struct ndm_session * sess,char * series_name)510 ndmca_test_done_series (struct ndm_session *sess, char *series_name)
511 {
512 struct ndm_control_agent *ca = sess->control_acb;
513 char * status;
514
515 /* close previous test if there is one */
516 ndmca_test_close (sess);
517
518 if (ca->total_n_step_fail)
519 status = "Failed";
520 else if (ca->total_n_step_warn)
521 status = "Almost";
522 else
523 status = "Passed";
524
525 ndmalogf (sess, "TEST", 0, "FINAL %s %s -- pass=%d warn=%d fail=%d (total %d)",
526 series_name,
527 status,
528 ca->total_n_step_pass,
529 ca->total_n_step_warn,
530 ca->total_n_step_fail,
531 ca->total_n_step_tests);
532 }
533
534
535
536 void
ndmca_test_fill_data(char * buf,int bufsize,int recno,int fileno)537 ndmca_test_fill_data (char *buf, int bufsize, int recno, int fileno)
538 {
539 char * src;
540 char * srcend;
541 char * dst = buf;
542 char * dstend = buf+bufsize;
543 uint16_t sequence = 0;
544 struct {
545 uint16_t fileno;
546 uint16_t sequence;
547 uint32_t recno;
548 } x;
549
550 x.fileno = fileno;
551 x.recno = recno;
552
553 srcend = (char *) &x;
554 srcend += sizeof x;
555
556 while (dst < dstend) {
557 x.sequence = sequence++;
558 src = (char *) &x;
559
560 while (src < srcend && dst < dstend)
561 *dst++ = *src++;
562 }
563 }
564 #endif /* !defined(NDMOS_OPTION_NO_CONTROL_AGENT) && !defined(NDMOS_OPTION_NO_TEST_AGENTS) */
565