--- /dev/null
+/*
+ * Copyright (c) 1998,1999,2000
+ * Traakan, Inc., Los Altos, CA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Project: NDMJOB
+ * Ident: $Id: $
+ *
+ * Description:
+ *
+ */
+
+
+#include "ndmagents.h"
+
+
+#ifndef NDMOS_OPTION_NO_CONTROL_AGENT
+
+int
+ndmca_test_query_conn_types (struct ndm_session *sess,
+ struct ndmconn *ref_conn)
+{
+ struct ndmconn *conn = ref_conn;
+ struct ndm_control_agent *ca = &sess->control_acb;
+ int rc;
+ unsigned int i;
+
+ switch (conn->protocol_version) {
+ default: return -1234;
+
+#ifndef NDMOS_OPTION_NO_NDMP2
+ case NDMP2VER:
+ NDMC_WITH_VOID_REQUEST(ndmp2_config_get_mover_type, NDMP2VER)
+ rc = NDMC_CALL(conn);
+ if (rc) {
+ ndmalogf (sess, "Test", 1, "GET_MOVER_TYPE failed");
+ return rc;
+ }
+
+ for (i = 0; i < reply->methods.methods_len; i++) {
+ switch(reply->methods.methods_val[i]) {
+ case NDMP2_ADDR_LOCAL:
+ ca->has_local_addr = 1;
+ break;
+ case NDMP2_ADDR_TCP:
+ ca->has_tcp_addr = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ NDMC_FREE_REPLY();
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP2 */
+
+#ifndef NDMOS_OPTION_NO_NDMP3
+ case NDMP3VER:
+ NDMC_WITH_VOID_REQUEST(ndmp3_config_get_connection_type, NDMP3VER)
+ rc = NDMC_CALL(conn);
+ if (rc) {
+ ndmalogf (sess, "Test", 1, "GET_CONNECTION_TYPE failed");
+ return rc;
+ }
+
+ for (i = 0; i < reply->addr_types.addr_types_len; i++) {
+ switch(reply->addr_types.addr_types_val[i]) {
+ case NDMP3_ADDR_LOCAL:
+ ca->has_local_addr = 1;
+ break;
+ case NDMP3_ADDR_TCP:
+ ca->has_tcp_addr = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ NDMC_FREE_REPLY();
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP3 */
+
+#ifndef NDMOS_OPTION_NO_NDMP4
+ case NDMP4VER:
+ NDMC_WITH_VOID_REQUEST(ndmp4_config_get_connection_type, NDMP4VER)
+ rc = NDMC_CALL(conn);
+ if (rc) {
+ ndmalogf (sess, "Test", 1, "GET_CONNECTION_TYPE failed");
+ return rc;
+ }
+
+ for (i = 0; i < reply->addr_types.addr_types_len; i++) {
+ switch(reply->addr_types.addr_types_val[i]) {
+ case NDMP4_ADDR_LOCAL:
+ ca->has_local_addr = 1;
+ break;
+ case NDMP4_ADDR_TCP:
+ ca->has_tcp_addr = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ NDMC_FREE_REPLY();
+ NDMC_ENDWITH
+ break;
+#endif /* !NDMOS_OPTION_NO_NDMP4 */
+ }
+
+ return 0;
+}
+
+
+int
+ndmca_test_load_tape (struct ndm_session *sess)
+{
+ struct ndm_control_agent *ca = &sess->control_acb;
+ int rc;
+
+ ca->tape_mode = NDMP9_TAPE_READ_MODE;
+ ca->is_label_op = 1;
+
+ rc = ndmca_op_robot_startup (sess, 1);
+ if (rc) return rc;
+
+ rc = ndmca_connect_tape_agent(sess);
+ if (rc) {
+ ndmconn_destruct (sess->plumb.tape);
+ return rc; /* already tattled */
+ }
+
+ rc = ndmca_media_load_first (sess);
+ if (rc) return rc;
+
+ ndmca_tape_close (sess);
+
+ return 0;
+}
+
+int
+ndmca_test_unload_tape (struct ndm_session *sess)
+{
+ ndmca_tape_open (sess);
+
+ ndmca_media_unload_current(sess);
+
+ return 0;
+}
+
+int
+ndmca_test_check_expect_errs (struct ndmconn *conn, int rc,
+ ndmp9_error expect_errs[])
+{
+ struct ndm_session *sess = conn->context;
+ int protocol_version = conn->protocol_version;
+ struct ndmp_xa_buf *xa = &conn->call_xa_buf;
+ unsigned msg = xa->request.header.message;
+ char * msgname = ndmp_message_to_str (protocol_version, msg);
+ ndmp9_error reply_error = conn->last_reply_error;
+ int i;
+
+ /* make sure we have a 'test' active */
+ ndmca_test_open (sess, msgname, ndmp9_error_to_str (expect_errs[0]));
+
+ if (rc >= 0) {
+ /* Call succeeded. Body valid */
+ rc = 1;
+ for (i = 0; (int)expect_errs[i] >= 0; i++) {
+ if (reply_error == expect_errs[i]) {
+ rc = 0;
+ break;
+ }
+ }
+
+ if (rc) {
+ if (reply_error != NDMP9_NO_ERR
+ && expect_errs[0] != NDMP9_NO_ERR) {
+ /* both are errors, don't be picky */
+ rc = 2;
+ } else {
+ /* intolerable mismatch */
+ }
+ } else {
+ /* Worked as expected */
+ }
+ }
+
+ if (rc != 0) {
+ char tmpbuf[128];
+
+ for (i = 0; (int)expect_errs[i] >= 0; i++) {
+ ndmalogf (sess, "Test", 1,
+ "%s #%d -- .... %s %s",
+ sess->control_acb.test_phase,
+ sess->control_acb.test_step,
+ (i==0) ? "expected" : "or",
+ ndmp9_error_to_str (expect_errs[i]));
+ }
+
+ sprintf(tmpbuf, "got %s (error expected)", ndmp9_error_to_str (reply_error));
+
+ if (rc == 2)
+ ndmca_test_warn (sess, tmpbuf);
+ else
+ ndmca_test_fail (sess, tmpbuf);
+
+ ndma_tattle (conn, xa, rc);
+
+ if (rc == 2)
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int
+ndmca_test_check_expect (struct ndmconn *conn, int rc, ndmp9_error expect_err)
+{
+ ndmp9_error errs[2];
+
+ errs[0] = expect_err;
+ errs[1] = -1;
+
+ return ndmca_test_check_expect_errs (conn, rc, errs);
+}
+
+int
+ndmca_test_check_expect_no_err (struct ndmconn *conn, int rc)
+{
+ return ndmca_test_check_expect (conn, rc, NDMP9_NO_ERR);
+}
+
+int
+ndmca_test_check_expect_illegal_state (struct ndmconn *conn, int rc)
+{
+ return ndmca_test_check_expect (conn, rc, NDMP9_ILLEGAL_STATE_ERR);
+}
+
+int
+ndmca_test_check_expect_illegal_args (struct ndmconn *conn, int rc)
+{
+ return ndmca_test_check_expect (conn, rc, NDMP9_ILLEGAL_ARGS_ERR);
+}
+
+
+int
+ndmca_test_call (struct ndmconn *conn,
+ struct ndmp_xa_buf *xa, ndmp9_error expect_err)
+{
+ struct ndm_session *sess = conn->context;
+ int protocol_version = conn->protocol_version;
+ unsigned msg = xa->request.header.message;
+ char * msgname = ndmp_message_to_str (protocol_version, msg);
+ unsigned reply_error;
+ int rc;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ /* open new 'test' */
+ ndmca_test_open (sess, msgname, ndmp9_error_to_str (expect_err));
+
+ rc = ndma_call_no_tattle (conn, xa);
+
+ reply_error = ndmnmb_get_reply_error (&xa->reply);
+
+ if (rc >= 0) {
+ /* Call succeeded. Body valid */
+ if (reply_error == expect_err) {
+ /* Worked exactly as expected */
+ rc = 0;
+ } else if (reply_error != NDMP9_NO_ERR
+ && expect_err != NDMP9_NO_ERR) {
+ /* both are errors, don't be picky about the codes */
+ rc = 2;
+ } else {
+ /* intolerable mismatch */
+ rc = 1;
+ }
+ }
+
+ if (rc != 0) {
+ char tmpbuf[128];
+ sprintf(tmpbuf, "got %s (call)", ndmp9_error_to_str (reply_error));
+ if (rc == 2)
+ ndmca_test_warn (sess, tmpbuf);
+ else
+ ndmca_test_fail (sess, tmpbuf);
+
+ ndma_tattle (conn, xa, rc);
+
+ if (rc == 2)
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/*
+ * start or open a test if not already opened
+ */
+void
+ndmca_test_open (struct ndm_session *sess, char *test_name, char *sub_test_name)
+{
+ static char test_name_buf[512];
+
+ if (sess->control_acb.active_test == 0) {
+ /* record name */
+ if (sub_test_name)
+ sprintf(test_name_buf, "%s/%s", test_name, sub_test_name);
+ else
+ strcpy(test_name_buf, test_name);
+ sess->control_acb.active_test = test_name_buf;
+
+ /* make sure flags are cleared */
+ sess->control_acb.active_test_failed = (char *)0;
+ sess->control_acb.active_test_warned = (char *)0;
+
+ }
+}
+
+void
+ndmca_test_warn (struct ndm_session *sess, char *warn_msg)
+{
+ static char warn_msg_buf[512];
+
+ ndmca_test_open (sess, "UNKNOWN WARN", 0);
+
+ strcpy(warn_msg_buf, warn_msg);
+ sess->control_acb.active_test_warned = warn_msg_buf;
+}
+
+void
+ndmca_test_fail (struct ndm_session *sess, char *fail_msg)
+{
+ static char fail_msg_buf[512];
+
+ ndmca_test_open (sess, "UNKNOWN FAIL", 0);
+
+ strcpy(fail_msg_buf, fail_msg);
+ sess->control_acb.active_test_failed = fail_msg_buf;
+}
+
+
+
+/*
+ * close or end a test if not already closed
+ */
+void
+ndmca_test_close (struct ndm_session *sess)
+{
+ if (sess->control_acb.active_test != 0) {
+ /* count test */
+ sess->control_acb.n_step_tests++;
+
+ /* display results */
+ if (sess->control_acb.active_test_failed) {
+ ndmalogf (sess, "Test", 1,
+ "%s #%d -- Failed %s %s",
+ sess->control_acb.test_phase,
+ sess->control_acb.test_step,
+ sess->control_acb.active_test,
+ sess->control_acb.active_test_failed);
+ sess->control_acb.n_step_fail++;
+ exit(1);
+ } else if (sess->control_acb.active_test_warned) {
+ ndmalogf (sess, "Test", 1,
+ "%s #%d -- Almost %s %s",
+ sess->control_acb.test_phase,
+ sess->control_acb.test_step,
+ sess->control_acb.active_test,
+ sess->control_acb.active_test_warned);
+ sess->control_acb.n_step_warn++;
+ exit(1);
+ } else {
+ ndmalogf (sess, "Test", 2,
+ "%s #%d -- Passed %s",
+ sess->control_acb.test_phase,
+ sess->control_acb.test_step,
+ sess->control_acb.active_test);
+ sess->control_acb.n_step_pass++;
+ }
+
+ /* clear flags */
+ sess->control_acb.active_test = (char *)0;
+ sess->control_acb.active_test_failed = (char *)0;
+ sess->control_acb.active_test_warned = (char *)0;
+
+ /* advance test count */
+ sess->control_acb.test_step++;
+
+ }
+}
+
+
+/*
+ * start a test phase (part of a series)
+ */
+void
+ndmca_test_phase (struct ndm_session *sess, char *test_phase, char *desc)
+{
+ ndmalogf (sess, "TEST", 0, "Test %s -- %s", test_phase, desc);
+
+ sess->control_acb.test_phase = test_phase;
+ sess->control_acb.test_step = 1;
+ sess->control_acb.n_step_pass = 0;
+ sess->control_acb.n_step_fail = 0;
+ sess->control_acb.n_step_warn = 0;
+ sess->control_acb.n_step_tests = 0;
+}
+
+void
+ndmca_test_log_step (struct ndm_session *sess, int level, char *msg)
+{
+ int had_active = (sess->control_acb.active_test != 0);
+
+ ndmalogf (sess, "Test", level, "%s #%d -- %s",
+ sess->control_acb.test_phase,
+ sess->control_acb.test_step,
+ msg);
+
+ /* in case we have a open test -- close it */
+ ndmca_test_close (sess);
+
+ /* advance test count if we didn't have an active test */
+ if (!had_active)
+ sess->control_acb.test_step++;
+
+}
+
+void
+ndmca_test_log_note (struct ndm_session *sess, int level, char *msg)
+{
+ ndmalogf (sess, "Test", level, "%s #%d %s",
+ sess->control_acb.test_phase,
+ sess->control_acb.test_step,
+ msg);
+}
+
+/*
+ * finish a test phase (part of a series)
+ */
+void
+ndmca_test_done_phase (struct ndm_session *sess)
+{
+ struct ndm_control_agent *ca = &sess->control_acb;
+ char * status;
+ int had_active = (sess->control_acb.active_test != 0);
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ if (ca->n_step_fail)
+ status = "Failed";
+ else if (ca->n_step_warn)
+ status = "Almost";
+ else if (ca->n_step_pass > 0)
+ status = "Passed";
+ else
+ status = "Whiffed";
+
+ ndmalogf (sess, "TEST", 0, "Test %s %s -- pass=%d warn=%d fail=%d (total %d)",
+ ca->test_phase,
+ status,
+ ca->n_step_pass,
+ ca->n_step_warn,
+ ca->n_step_fail,
+ ca->n_step_tests);
+
+ ca->total_n_step_pass += ca->n_step_pass;
+ ca->total_n_step_warn += ca->n_step_warn;
+ ca->total_n_step_fail += ca->n_step_fail;
+ ca->total_n_step_tests += ca->n_step_tests;
+
+ /* advance test count if we didn't have an active test so
+ * clean up phases have a new test count
+ */
+ if (!had_active)
+ sess->control_acb.test_step++;
+}
+
+/*
+ * finish a test series (which may include test phases)
+ */
+void
+ndmca_test_done_series (struct ndm_session *sess, char *series_name)
+{
+ struct ndm_control_agent *ca = &sess->control_acb;
+ char * status;
+
+ /* close previous test if there is one */
+ ndmca_test_close (sess);
+
+ if (ca->total_n_step_fail)
+ status = "Failed";
+ else if (ca->total_n_step_warn)
+ status = "Almost";
+ else
+ status = "Passed";
+
+ ndmalogf (sess, "TEST", 0, "FINAL %s %s -- pass=%d warn=%d fail=%d (total %d)",
+ series_name,
+ status,
+ ca->total_n_step_pass,
+ ca->total_n_step_warn,
+ ca->total_n_step_fail,
+ ca->total_n_step_tests);
+}
+
+
+
+void
+ndmca_test_fill_data (char *buf, int bufsize, int recno, int fileno)
+{
+ char * src;
+ char * srcend;
+ char * dst = buf;
+ char * dstend = buf+bufsize;
+ unsigned short sequence = 0;
+ struct {
+ unsigned short fileno;
+ unsigned short sequence;
+ unsigned long recno;
+ } x;
+
+ x.fileno = fileno;
+ x.recno = recno;
+
+ srcend = (char *) &x;
+ srcend += sizeof x;
+
+ while (dst < dstend) {
+ x.sequence = sequence++;
+ src = (char *) &x;
+
+ while (src < srcend && dst < dstend)
+ *dst++ = *src++;
+ }
+}
+#endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */