Imported Upstream version 3.1.0
[debian/amanda] / ndmp-src / ndma_ctst_subr.c
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 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
42
43 int
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
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                 return rc;      /* already tattled */
155         }
156
157         rc = ndmca_media_load_first (sess);
158         if (rc) return rc;
159
160         ndmca_tape_close (sess);
161
162         return 0;
163 }
164
165 int
166 ndmca_test_unload_tape (struct ndm_session *sess)
167 {
168         ndmca_tape_open (sess);
169
170         ndmca_media_unload_current(sess);
171
172         return 0;
173 }
174
175 int
176 ndmca_test_check_expect_errs (struct ndmconn *conn, int rc,
177   ndmp9_error expect_errs[])
178 {
179         struct ndm_session *sess = conn->context;
180         int             protocol_version = conn->protocol_version;
181         struct ndmp_xa_buf *xa = &conn->call_xa_buf;
182         unsigned        msg = xa->request.header.message;
183         char *          msgname = ndmp_message_to_str (protocol_version, msg);
184         ndmp9_error     reply_error = conn->last_reply_error;
185         int             i;
186
187         /* make sure we have a 'test' active */
188         ndmca_test_open (sess, msgname, ndmp9_error_to_str (expect_errs[0]));
189
190         if (rc >= 0) {
191                 /* Call succeeded. Body valid */
192                 rc = 1;
193                 for (i = 0; (int)expect_errs[i] >= 0; i++) {
194                         if (reply_error == expect_errs[i]) {
195                                 rc = 0;
196                                 break;
197                         }
198                 }
199
200                 if (rc) {
201                         if (reply_error != NDMP9_NO_ERR
202                           && expect_errs[0] != NDMP9_NO_ERR) {
203                                 /* both are errors, don't be picky */
204                                 rc = 2;
205                         } else {
206                                 /* intolerable mismatch */
207                         }
208                 } else {
209                         /* Worked as expected */
210                 }
211         }
212
213         if (rc != 0) {
214             char tmpbuf[128];
215
216             for (i = 0; (int)expect_errs[i] >= 0; i++) {
217                 ndmalogf (sess, "Test", 1,
218                           "%s #%d -- .... %s %s",
219                           sess->control_acb.test_phase,
220                           sess->control_acb.test_step,
221                           (i==0) ? "expected" : "or",
222                           ndmp9_error_to_str (expect_errs[i]));
223             }
224
225             sprintf(tmpbuf, "got %s (error expected)", ndmp9_error_to_str (reply_error));
226
227             if (rc == 2)
228                 ndmca_test_warn (sess, tmpbuf);
229             else
230                 ndmca_test_fail (sess, tmpbuf);
231
232             ndma_tattle (conn, xa, rc);
233
234             if (rc == 2)
235                 rc = 0;
236         }
237
238         return rc;
239 }
240
241 int
242 ndmca_test_check_expect (struct ndmconn *conn, int rc, ndmp9_error expect_err)
243 {
244         ndmp9_error             errs[2];
245
246         errs[0] = expect_err;
247         errs[1] = -1;
248
249         return ndmca_test_check_expect_errs (conn, rc, errs);
250 }
251
252 int
253 ndmca_test_check_expect_no_err (struct ndmconn *conn, int rc)
254 {
255         return ndmca_test_check_expect (conn, rc, NDMP9_NO_ERR);
256 }
257
258 int
259 ndmca_test_check_expect_illegal_state (struct ndmconn *conn, int rc)
260 {
261         return ndmca_test_check_expect (conn, rc, NDMP9_ILLEGAL_STATE_ERR);
262 }
263
264 int
265 ndmca_test_check_expect_illegal_args (struct ndmconn *conn, int rc)
266 {
267         return ndmca_test_check_expect (conn, rc, NDMP9_ILLEGAL_ARGS_ERR);
268 }
269
270
271 int
272 ndmca_test_call (struct ndmconn *conn,
273   struct ndmp_xa_buf *xa, ndmp9_error expect_err)
274 {
275         struct ndm_session *sess = conn->context;
276         int             protocol_version = conn->protocol_version;
277         unsigned        msg = xa->request.header.message;
278         char *          msgname = ndmp_message_to_str (protocol_version, msg);
279         unsigned        reply_error;
280         int             rc;
281
282         /* close previous test if there is one */
283         ndmca_test_close (sess);
284
285         /* open new 'test' */
286         ndmca_test_open (sess, msgname, ndmp9_error_to_str (expect_err));
287
288         rc = ndma_call_no_tattle (conn, xa);
289
290         reply_error = ndmnmb_get_reply_error (&xa->reply);
291
292         if (rc >= 0) {
293                 /* Call succeeded. Body valid */
294                 if (reply_error == expect_err) {
295                         /* Worked exactly as expected */
296                         rc = 0;
297                 } else if (reply_error != NDMP9_NO_ERR
298                         && expect_err != NDMP9_NO_ERR) {
299                         /* both are errors, don't be picky about the codes */
300                         rc = 2;
301                 } else {
302                         /* intolerable mismatch */
303                         rc = 1;
304                 }
305         }
306
307         if (rc != 0) {
308             char tmpbuf[128];
309             sprintf(tmpbuf, "got %s (call)", ndmp9_error_to_str (reply_error));
310             if (rc == 2)
311                 ndmca_test_warn (sess, tmpbuf);
312             else
313                 ndmca_test_fail (sess, tmpbuf);
314
315             ndma_tattle (conn, xa, rc);
316
317             if (rc == 2)
318                 rc = 0;
319         }
320
321         return rc;
322 }
323
324 /*
325  * start or open a test if not already opened
326  */
327 void
328 ndmca_test_open (struct ndm_session *sess, char *test_name, char *sub_test_name)
329 {
330     static char test_name_buf[512];
331
332     if (sess->control_acb.active_test == 0) {
333         /* record name */
334         if (sub_test_name)
335             sprintf(test_name_buf, "%s/%s", test_name, sub_test_name);
336         else
337             strcpy(test_name_buf, test_name);
338         sess->control_acb.active_test = test_name_buf;
339
340         /* make sure flags are cleared */
341         sess->control_acb.active_test_failed = (char *)0;
342         sess->control_acb.active_test_warned = (char *)0;
343
344     }
345 }
346
347 void
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
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
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 /*
422  * start a test phase (part of a series)
423  */
424 void
425 ndmca_test_phase (struct ndm_session *sess, char *test_phase, char *desc)
426 {
427         ndmalogf (sess, "TEST", 0, "Test %s -- %s", test_phase, desc);
428
429         sess->control_acb.test_phase = test_phase;
430         sess->control_acb.test_step = 1;
431         sess->control_acb.n_step_pass = 0;
432         sess->control_acb.n_step_fail = 0;
433         sess->control_acb.n_step_warn = 0;
434         sess->control_acb.n_step_tests = 0;
435 }
436
437 void
438 ndmca_test_log_step (struct ndm_session *sess, int level, char *msg)
439 {
440         int had_active = (sess->control_acb.active_test != 0);
441
442         ndmalogf (sess, "Test", level, "%s #%d -- %s",
443                   sess->control_acb.test_phase,
444                   sess->control_acb.test_step,
445                   msg);
446
447         /* in case we have a open test -- close it */
448         ndmca_test_close (sess);
449
450         /* advance test count if we didn't have an active test */
451         if (!had_active)
452             sess->control_acb.test_step++;
453
454 }
455
456 void
457 ndmca_test_log_note (struct ndm_session *sess, int level, char *msg)
458 {
459         ndmalogf (sess, "Test", level, "%s #%d %s",
460                 sess->control_acb.test_phase,
461                 sess->control_acb.test_step,
462                 msg);
463 }
464
465 /*
466  * finish a test phase (part of a series)
467  */
468 void
469 ndmca_test_done_phase (struct ndm_session *sess)
470 {
471         struct ndm_control_agent *ca = &sess->control_acb;
472         char *                  status;
473         int had_active = (sess->control_acb.active_test != 0);
474
475         /* close previous test if there is one */
476         ndmca_test_close (sess);
477
478         if (ca->n_step_fail)
479                 status = "Failed";
480         else if (ca->n_step_warn)
481                 status = "Almost";
482         else if (ca->n_step_pass > 0)
483                 status = "Passed";
484         else
485                 status = "Whiffed";
486
487         ndmalogf (sess, "TEST", 0, "Test %s %s -- pass=%d warn=%d fail=%d (total %d)",
488                         ca->test_phase,
489                         status,
490                         ca->n_step_pass,
491                         ca->n_step_warn,
492                         ca->n_step_fail,
493                         ca->n_step_tests);
494
495         ca->total_n_step_pass += ca->n_step_pass;
496         ca->total_n_step_warn += ca->n_step_warn;
497         ca->total_n_step_fail += ca->n_step_fail;
498         ca->total_n_step_tests += ca->n_step_tests;
499
500         /* advance test count if we didn't have an active test so
501          * clean up phases have a new test count
502          */
503         if (!had_active)
504             sess->control_acb.test_step++;
505 }
506
507 /*
508  * finish a test series (which may include test phases)
509  */
510 void
511 ndmca_test_done_series (struct ndm_session *sess, char *series_name)
512 {
513         struct ndm_control_agent *ca = &sess->control_acb;
514         char *                  status;
515
516         /* close previous test if there is one */
517         ndmca_test_close (sess);
518
519         if (ca->total_n_step_fail)
520                 status = "Failed";
521         else if (ca->total_n_step_warn)
522                 status = "Almost";
523         else
524                 status = "Passed";
525
526         ndmalogf (sess, "TEST", 0, "FINAL %s %s -- pass=%d warn=%d fail=%d (total %d)",
527                         series_name,
528                         status,
529                         ca->total_n_step_pass,
530                         ca->total_n_step_warn,
531                         ca->total_n_step_fail,
532                         ca->total_n_step_tests);
533 }
534
535
536
537 void
538 ndmca_test_fill_data (char *buf, int bufsize, int recno, int fileno)
539 {
540         char *          src;
541         char *          srcend;
542         char *          dst = buf;
543         char *          dstend = buf+bufsize;
544         unsigned short  sequence = 0;
545         struct {
546                 unsigned short  fileno;
547                 unsigned short  sequence;
548                 unsigned long   recno;
549         }               x;
550
551         x.fileno = fileno;
552         x.recno = recno;
553
554         srcend = (char *) &x;
555         srcend += sizeof x;
556
557         while (dst < dstend) {
558                 x.sequence = sequence++;
559                 src = (char *) &x;
560
561                 while (src < srcend && dst < dstend)
562                         *dst++ = *src++;
563         }
564 }
565 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */