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