/*
* 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 */