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) && \
42     !defined(NDMOS_OPTION_NO_TEST_AGENTS)
43 
ndmca_test_query_conn_types(struct ndm_session * sess,struct ndmconn * ref_conn)44 int 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:
54       return -1234;
55 
56 #ifndef NDMOS_OPTION_NO_NDMP2
57     case NDMP2VER:
58       NDMC_WITH_VOID_REQUEST(ndmp2_config_get_mover_type, NDMP2VER)
59       rc = NDMC_CALL(conn);
60       if (rc) {
61         ndmalogf(sess, "Test", 1, "GET_MOVER_TYPE failed");
62         return rc;
63       }
64 
65       for (i = 0; i < reply->methods.methods_len; i++) {
66         switch (reply->methods.methods_val[i]) {
67           case NDMP2_ADDR_LOCAL:
68             ca->has_local_addr = 1;
69             break;
70           case NDMP2_ADDR_TCP:
71             ca->has_tcp_addr = 1;
72             break;
73           default:
74             break;
75         }
76       }
77 
78       NDMC_FREE_REPLY();
79       NDMC_ENDWITH
80       break;
81 #endif /* !NDMOS_OPTION_NO_NDMP2 */
82 
83 #ifndef NDMOS_OPTION_NO_NDMP3
84     case NDMP3VER:
85       NDMC_WITH_VOID_REQUEST(ndmp3_config_get_connection_type, NDMP3VER)
86       rc = NDMC_CALL(conn);
87       if (rc) {
88         ndmalogf(sess, "Test", 1, "GET_CONNECTION_TYPE failed");
89         return rc;
90       }
91 
92       for (i = 0; i < reply->addr_types.addr_types_len; i++) {
93         switch (reply->addr_types.addr_types_val[i]) {
94           case NDMP3_ADDR_LOCAL:
95             ca->has_local_addr = 1;
96             break;
97           case NDMP3_ADDR_TCP:
98             ca->has_tcp_addr = 1;
99             break;
100           default:
101             break;
102         }
103       }
104       NDMC_FREE_REPLY();
105       NDMC_ENDWITH
106       break;
107 #endif /* !NDMOS_OPTION_NO_NDMP3 */
108 
109 #ifndef NDMOS_OPTION_NO_NDMP4
110     case NDMP4VER:
111       NDMC_WITH_VOID_REQUEST(ndmp4_config_get_connection_type, NDMP4VER)
112       rc = NDMC_CALL(conn);
113       if (rc) {
114         ndmalogf(sess, "Test", 1, "GET_CONNECTION_TYPE failed");
115         return rc;
116       }
117 
118       for (i = 0; i < reply->addr_types.addr_types_len; i++) {
119         switch (reply->addr_types.addr_types_val[i]) {
120           case NDMP4_ADDR_LOCAL:
121             ca->has_local_addr = 1;
122             break;
123           case NDMP4_ADDR_TCP:
124             ca->has_tcp_addr = 1;
125             break;
126           default:
127             break;
128         }
129       }
130       NDMC_FREE_REPLY();
131       NDMC_ENDWITH
132       break;
133 #endif /* !NDMOS_OPTION_NO_NDMP4 */
134   }
135 
136   return 0;
137 }
138 
139 
ndmca_test_load_tape(struct ndm_session * sess)140 int 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 
ndmca_test_unload_tape(struct ndm_session * sess)166 int 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 
ndmca_test_check_expect_errs(struct ndmconn * conn,int rc,ndmp9_error expect_errs[])175 int ndmca_test_check_expect_errs(struct ndmconn* conn,
176                                  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 && expect_errs[0] != NDMP9_NO_ERR) {
202         /* both are errors, don't be picky */
203         rc = 2;
204       } else {
205         /* intolerable mismatch */
206       }
207     } else {
208       /* Worked as expected */
209     }
210   }
211 
212   if (rc != 0) {
213     char tmpbuf[128];
214 
215     for (i = 0; (int)expect_errs[i] >= 0; i++) {
216       ndmalogf(sess, "Test", 1, "%s #%d -- .... %s %s",
217                sess->control_acb->test_phase, sess->control_acb->test_step,
218                (i == 0) ? "expected" : "or",
219                ndmp9_error_to_str(expect_errs[i]));
220     }
221 
222     snprintf(tmpbuf, sizeof(tmpbuf), "got %s (error expected)",
223              ndmp9_error_to_str(reply_error));
224 
225     if (rc == 2)
226       ndmca_test_warn(sess, tmpbuf);
227     else
228       ndmca_test_fail(sess, tmpbuf);
229 
230     ndma_tattle(conn, xa, rc);
231 
232     if (rc == 2) rc = 0;
233   }
234 
235   return rc;
236 }
237 
ndmca_test_check_expect(struct ndmconn * conn,int rc,ndmp9_error expect_err)238 int ndmca_test_check_expect(struct ndmconn* conn,
239                             int rc,
240                             ndmp9_error expect_err)
241 {
242   ndmp9_error errs[2];
243 
244   errs[0] = expect_err;
245   errs[1] = -1;
246 
247   return ndmca_test_check_expect_errs(conn, rc, errs);
248 }
249 
ndmca_test_check_expect_no_err(struct ndmconn * conn,int rc)250 int ndmca_test_check_expect_no_err(struct ndmconn* conn, int rc)
251 {
252   return ndmca_test_check_expect(conn, rc, NDMP9_NO_ERR);
253 }
254 
ndmca_test_check_expect_illegal_state(struct ndmconn * conn,int rc)255 int ndmca_test_check_expect_illegal_state(struct ndmconn* conn, int rc)
256 {
257   return ndmca_test_check_expect(conn, rc, NDMP9_ILLEGAL_STATE_ERR);
258 }
259 
ndmca_test_check_expect_illegal_args(struct ndmconn * conn,int rc)260 int ndmca_test_check_expect_illegal_args(struct ndmconn* conn, int rc)
261 {
262   return ndmca_test_check_expect(conn, rc, NDMP9_ILLEGAL_ARGS_ERR);
263 }
264 
265 
ndmca_test_call(struct ndmconn * conn,struct ndmp_xa_buf * xa,ndmp9_error expect_err)266 int ndmca_test_call(struct ndmconn* conn,
267                     struct ndmp_xa_buf* xa,
268                     ndmp9_error expect_err)
269 {
270   struct ndm_session* sess = conn->context;
271   int protocol_version = conn->protocol_version;
272   unsigned msg = xa->request.header.message;
273   char* msgname = ndmp_message_to_str(protocol_version, msg);
274   unsigned reply_error;
275   int rc;
276 
277   /* close previous test if there is one */
278   ndmca_test_close(sess);
279 
280   /* open new 'test' */
281   ndmca_test_open(sess, msgname, ndmp9_error_to_str(expect_err));
282 
283   rc = ndma_call_no_tattle(conn, xa);
284 
285   reply_error = ndmnmb_get_reply_error(&xa->reply);
286 
287   if (rc >= 0) {
288     /* Call succeeded. Body valid */
289     if (reply_error == expect_err) {
290       /* Worked exactly as expected */
291       rc = 0;
292     } else if (reply_error != NDMP9_NO_ERR && expect_err != NDMP9_NO_ERR) {
293       /* both are errors, don't be picky about the codes */
294       rc = 2;
295     } else {
296       /* intolerable mismatch */
297       rc = 1;
298     }
299   }
300 
301   if (rc != 0) {
302     char tmpbuf[128];
303     snprintf(tmpbuf, sizeof(tmpbuf), "got %s (call)",
304              ndmp9_error_to_str(reply_error));
305     if (rc == 2)
306       ndmca_test_warn(sess, tmpbuf);
307     else
308       ndmca_test_fail(sess, tmpbuf);
309 
310     ndma_tattle(conn, xa, rc);
311 
312     if (rc == 2) rc = 0;
313   }
314 
315   return rc;
316 }
317 
318 /*
319  * start or open a test if not already opened
320  */
ndmca_test_open(struct ndm_session * sess,char * test_name,char * sub_test_name)321 void ndmca_test_open(struct ndm_session* sess,
322                      char* test_name,
323                      char* sub_test_name)
324 {
325   static char test_name_buf[512];
326 
327   if (sess->control_acb->active_test == 0) {
328     /* record name */
329     if (sub_test_name)
330       snprintf(test_name_buf, sizeof(test_name_buf), "%s/%s", test_name,
331                sub_test_name);
332     else
333       strcpy(test_name_buf, test_name);
334     sess->control_acb->active_test = test_name_buf;
335 
336     /* make sure flags are cleared */
337     sess->control_acb->active_test_failed = (char*)0;
338     sess->control_acb->active_test_warned = (char*)0;
339   }
340 }
341 
ndmca_test_warn(struct ndm_session * sess,char * warn_msg)342 void ndmca_test_warn(struct ndm_session* sess, char* warn_msg)
343 {
344   static char warn_msg_buf[512];
345 
346   ndmca_test_open(sess, "UNKNOWN WARN", 0);
347 
348   strcpy(warn_msg_buf, warn_msg);
349   sess->control_acb->active_test_warned = warn_msg_buf;
350 }
351 
ndmca_test_fail(struct ndm_session * sess,char * fail_msg)352 void ndmca_test_fail(struct ndm_session* sess, char* fail_msg)
353 {
354   static char fail_msg_buf[512];
355 
356   ndmca_test_open(sess, "UNKNOWN FAIL", 0);
357 
358   strcpy(fail_msg_buf, fail_msg);
359   sess->control_acb->active_test_failed = fail_msg_buf;
360 }
361 
362 
363 /*
364  * close or end a test if not already closed
365  */
ndmca_test_close(struct ndm_session * sess)366 void ndmca_test_close(struct ndm_session* sess)
367 {
368   if (sess->control_acb->active_test != 0) {
369     /* count test */
370     sess->control_acb->n_step_tests++;
371 
372     /* display results */
373     if (sess->control_acb->active_test_failed) {
374       ndmalogf(sess, "Test", 1, "%s #%d -- Failed %s %s",
375                sess->control_acb->test_phase, sess->control_acb->test_step,
376                sess->control_acb->active_test,
377                sess->control_acb->active_test_failed);
378       sess->control_acb->n_step_fail++;
379       exit(1);
380     } else if (sess->control_acb->active_test_warned) {
381       ndmalogf(sess, "Test", 1, "%s #%d -- Almost %s %s",
382                sess->control_acb->test_phase, sess->control_acb->test_step,
383                sess->control_acb->active_test,
384                sess->control_acb->active_test_warned);
385       sess->control_acb->n_step_warn++;
386       exit(1);
387     } else {
388       ndmalogf(sess, "Test", 2, "%s #%d -- Passed %s",
389                sess->control_acb->test_phase, sess->control_acb->test_step,
390                sess->control_acb->active_test);
391       sess->control_acb->n_step_pass++;
392     }
393 
394     /* clear flags */
395     sess->control_acb->active_test = (char*)0;
396     sess->control_acb->active_test_failed = (char*)0;
397     sess->control_acb->active_test_warned = (char*)0;
398 
399     /* advance test count */
400     sess->control_acb->test_step++;
401   }
402 }
403 
404 
405 /*
406  * start a test phase (part of a series)
407  */
ndmca_test_phase(struct ndm_session * sess,char * test_phase,char * desc)408 void ndmca_test_phase(struct ndm_session* sess, char* test_phase, char* desc)
409 {
410   ndmalogf(sess, "TEST", 0, "Test %s -- %s", test_phase, desc);
411 
412   sess->control_acb->test_phase = test_phase;
413   sess->control_acb->test_step = 1;
414   sess->control_acb->n_step_pass = 0;
415   sess->control_acb->n_step_fail = 0;
416   sess->control_acb->n_step_warn = 0;
417   sess->control_acb->n_step_tests = 0;
418 }
419 
ndmca_test_log_step(struct ndm_session * sess,int level,char * msg)420 void ndmca_test_log_step(struct ndm_session* sess, int level, char* msg)
421 {
422   int had_active = (sess->control_acb->active_test != 0);
423 
424   ndmalogf(sess, "Test", level, "%s #%d -- %s", sess->control_acb->test_phase,
425            sess->control_acb->test_step, msg);
426 
427   /* in case we have a open test -- close it */
428   ndmca_test_close(sess);
429 
430   /* advance test count if we didn't have an active test */
431   if (!had_active) sess->control_acb->test_step++;
432 }
433 
ndmca_test_log_note(struct ndm_session * sess,int level,char * msg)434 void ndmca_test_log_note(struct ndm_session* sess, int level, char* msg)
435 {
436   ndmalogf(sess, "Test", level, "%s #%d %s", sess->control_acb->test_phase,
437            sess->control_acb->test_step, msg);
438 }
439 
440 /*
441  * finish a test phase (part of a series)
442  */
ndmca_test_done_phase(struct ndm_session * sess)443 void ndmca_test_done_phase(struct ndm_session* sess)
444 {
445   struct ndm_control_agent* ca = sess->control_acb;
446   char* status;
447   int had_active = (sess->control_acb->active_test != 0);
448 
449   /* close previous test if there is one */
450   ndmca_test_close(sess);
451 
452   if (ca->n_step_fail)
453     status = "Failed";
454   else if (ca->n_step_warn)
455     status = "Almost";
456   else if (ca->n_step_pass > 0)
457     status = "Passed";
458   else
459     status = "Whiffed";
460 
461   ndmalogf(sess, "TEST", 0, "Test %s %s -- pass=%d warn=%d fail=%d (total %d)",
462            ca->test_phase, status, ca->n_step_pass, ca->n_step_warn,
463            ca->n_step_fail, ca->n_step_tests);
464 
465   ca->total_n_step_pass += ca->n_step_pass;
466   ca->total_n_step_warn += ca->n_step_warn;
467   ca->total_n_step_fail += ca->n_step_fail;
468   ca->total_n_step_tests += ca->n_step_tests;
469 
470   /* advance test count if we didn't have an active test so
471    * clean up phases have a new test count
472    */
473   if (!had_active) sess->control_acb->test_step++;
474 }
475 
476 /*
477  * finish a test series (which may include test phases)
478  */
ndmca_test_done_series(struct ndm_session * sess,char * series_name)479 void ndmca_test_done_series(struct ndm_session* sess, char* series_name)
480 {
481   struct ndm_control_agent* ca = sess->control_acb;
482   char* status;
483 
484   /* close previous test if there is one */
485   ndmca_test_close(sess);
486 
487   if (ca->total_n_step_fail)
488     status = "Failed";
489   else if (ca->total_n_step_warn)
490     status = "Almost";
491   else
492     status = "Passed";
493 
494   ndmalogf(sess, "TEST", 0, "FINAL %s %s -- pass=%d warn=%d fail=%d (total %d)",
495            series_name, status, ca->total_n_step_pass, ca->total_n_step_warn,
496            ca->total_n_step_fail, ca->total_n_step_tests);
497 }
498 
499 
ndmca_test_fill_data(char * buf,int bufsize,int recno,int fileno)500 void ndmca_test_fill_data(char* buf, int bufsize, int recno, int fileno)
501 {
502   char* src;
503   char* srcend;
504   char* dst = buf;
505   char* dstend = buf + bufsize;
506   uint16_t sequence = 0;
507   struct {
508     uint16_t fileno;
509     uint16_t sequence;
510     uint32_t recno;
511   } x;
512 
513   x.fileno = fileno;
514   x.recno = recno;
515 
516   srcend = (char*)&x;
517   srcend += sizeof x;
518 
519   while (dst < dstend) {
520     x.sequence = sequence++;
521     src = (char*)&x;
522 
523     while (src < srcend && dst < dstend) *dst++ = *src++;
524   }
525 }
526 #endif /* !defined(NDMOS_OPTION_NO_CONTROL_AGENT) && \
527           !defined(NDMOS_OPTION_NO_TEST_AGENTS) */
528