From d3324decd29f5fec469d0b9285f62c2656bd2034 Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Fri, 4 Jan 2013 18:11:36 -0800 Subject: [PATCH] CUnit tests now working for first 2 suites, but Makefile.am not correct yet. --- Makefile.am | 14 +- test-tool/iscsi-support.c | 7 +- test-tool/iscsi-support.h | 2 +- test-tool/iscsi-test-cu.c | 455 +++++++++++++++++++------- test-tool/iscsi-test-cu.h | 48 +++ test-tool/iscsi-test.c | 2 + test-tool/iscsi-test.h | 4 + test-tool/test_read10_0blocks.c | 73 +++++ test-tool/test_read10_beyond_eol.c | 88 +++++ test-tool/test_read10_flags.c | 131 ++++++++ test-tool/test_read10_invalid.c | 145 ++++++++ test-tool/test_read10_rdprotect.c | 68 ++++ test-tool/test_read10_simple.c | 53 +++ test-tool/test_testunitready_simple.c | 33 ++ 14 files changed, 993 insertions(+), 130 deletions(-) create mode 100644 test-tool/iscsi-test-cu.h create mode 100644 test-tool/test_read10_0blocks.c create mode 100644 test-tool/test_read10_beyond_eol.c create mode 100644 test-tool/test_read10_flags.c create mode 100644 test-tool/test_read10_invalid.c create mode 100644 test-tool/test_read10_rdprotect.c create mode 100644 test-tool/test_read10_simple.c create mode 100644 test-tool/test_testunitready_simple.c diff --git a/Makefile.am b/Makefile.am index 4012698..83047e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -167,10 +167,18 @@ bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \ noinst_PROGRAMS += bin/iscsi-test-cu # dist_noinst_HEADERS += test-tool/iscsi-test-cu.h -bin_iscsi_test_cu_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/test-tool -bin_iscsi_test_cu_LDFLAGS = -ldl +bin_iscsi_test_cu_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/test-tool \ + -I/usr/local/include +bin_iscsi_test_cu_LDFLAGS = -ldl -lcunit bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ - test-tool/iscsi-support.c + test-tool/iscsi-support.c \ + test-tool/test_testunitready_simple.c \ + test-tool/test_read10_simple.c \ + test-tool/test_read10_beyond_eol.c \ + test-tool/test_read10_0blocks.c \ + test-tool/test_read10_rdprotect.c \ + test-tool/test_read10_flags.c \ + test-tool/test_read10_invalid.c endif diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index b720ba0..8a402b4 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -36,11 +36,16 @@ #include "iscsi-support.h" +/***************************************************************** + * globals + *****************************************************************/ const char *initiatorname1 = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test"; const char *initiatorname2 = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-test-2"; +const char *tgt_url; + uint32_t block_size; uint64_t num_blocks; int lbpme; @@ -50,9 +55,7 @@ int removable; enum scsi_inquiry_peripheral_device_type device_type; int sccs; int encserv; - int data_loss; -int show_info; int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); diff --git a/test-tool/iscsi-support.h b/test-tool/iscsi-support.h index 47ca5fa..89daa8f 100644 --- a/test-tool/iscsi-support.h +++ b/test-tool/iscsi-support.h @@ -27,6 +27,7 @@ extern const char *initiatorname1; extern const char *initiatorname2; +extern const char *tgt_url; extern uint32_t block_size; extern uint64_t num_blocks; @@ -34,7 +35,6 @@ extern int lbpme; extern int lbppb; extern int lbpme; extern int data_loss; -extern int show_info; extern int removable; extern enum scsi_inquiry_peripheral_device_type device_type; extern int sccs; diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index d035b7d..a34ebc3 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -24,17 +24,22 @@ #include #include #include -#include +#include #include -#include -#include +#include #include -#include "slist.h" + +#include +#include + #include "iscsi.h" #include "scsi-lowlevel.h" #include "iscsi-private.h" -// #include "iscsi-test.h" + #include "iscsi-support.h" +#include "iscsi-test-cu.h" + + #ifndef discard_const #define discard_const(ptr) ((void *)((intptr_t)(ptr))) @@ -43,133 +48,314 @@ #define PROG "iscsi-test-cu" +/* XXX what is this for? */ int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); +/***************************************************************** + * + * list of tests and test suites + * + *****************************************************************/ +static CU_TestInfo tests_testunitready[] = { + { (char *)"testTurSimple", test_testunitready_simple }, + CU_TEST_INFO_NULL +}; + +static CU_TestInfo tests_read10[] = { + { (char *)"testRead10Simple", test_read10_simple }, + { (char *)"testRead10BeyondEol", test_read10_beyond_eol }, + { (char *)"testRead10ZeroBlocks", test_read10_0blocks }, + { (char *)"testRead10ReadProtect", test_read10_rdprotect }, + { (char *)"testRead10Flags", test_read10_flags }, + { (char *)"testRead10Invalid", test_read10_invalid }, + CU_TEST_INFO_NULL +}; + +static CU_SuiteInfo suites[] = { + { (char *)"TestTestUnitReady", test_setup, test_teardown, + tests_testunitready }, + { (char *)"TestRead10", test_setup, test_teardown, + tests_read10 }, + CU_SUITE_INFO_NULL +}; + +/* + * globals for test setup and teardown + */ +int tgt_lun; +struct iscsi_context *iscsic; +struct scsi_task *task; + - static void print_usage(void) { fprintf(stderr, - "Usage: %s [-?] [-?|--help] [--usage] [-t|--test=] [-s|--skip=]\n" - "\t\t[-l|--list] [--info] [-i|--initiator-name=]\n" - "\t\t\n", PROG); -} - -static void -print_help(void) -{ - fprintf(stderr,\ -"Usage: %s [OPTIONS] \n" -" -i, --initiator-name=iqn-name Initiatorname to use\n" -" -I, --initiator-name-2=iqn-name Second initiatorname to use\n" -" -t, --test=test-name Which test to run. Default is to run all tests.\n" -" -s, --skip=test-name Which test to skip. Default is to run all tests.\n" -" -l, --list List all tests.\n" -" --info, Print extra info about a test.\n" -" --dataloss Allow destructive tests.\n" -"\n" -"Help options:\n" -" -?, --help Show this help message\n" -" --usage Display brief usage message\n" -"\n" -"iSCSI URL format : %s\n" -"\n" -" is either of:\n" -" \"hostname\" iscsi.example\n" -" \"ipv4-address\" 10.1.1.27\n" -" \"ipv6-address\" [fce0::1]\n", - PROG, ISCSI_URL_SYNTAX); + "Usage: %s [-?|--help] print this message and exit\n", + PROG); + fprintf(stderr, + "or %s [OPTIONS] \n", PROG); + fprintf(stderr, + "Where OPTIONS are from:\n"); + fprintf(stderr, + " -i|--initiator-name=iqn-name Initiatorname to use [%s]\n", + initiatorname1); + fprintf(stderr, + " -I|--initiator-name-2=iqn-name 2nd Initiatorname to use [%s]\n", + initiatorname2); + fprintf(stderr, + " -t|--test=test-name-reg-exp Test(s) to run [ALL] \n"); + fprintf(stderr, + " -l|--list List all tests and exit\n"); + fprintf(stderr, + " -X|--dataloss Allow destructive tests\n"); + fprintf(stderr, + " -g|--ignore Error Action: Ignore test errors [DEFAULT]\n"); + fprintf(stderr, + " -f|--fail Error Action: FAIL if any tests fail\n"); + fprintf(stderr, + " -A|--abort Error Action: ABORT if any tests fail\n"); + fprintf(stderr, + " -s|--silent Test Mode: Silent\n"); + fprintf(stderr, + " -n|--normal Test Mode: Normal\n"); + fprintf(stderr, + " -v|--verbose Test Mode: Verbose [DEFAULT]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, + "Where iSCSI URL format is: %s\n", ISCSI_URL_SYNTAX); + fprintf(stderr, "\n"); + fprintf(stderr, + " is one of:\n"); + fprintf(stderr, + " \"hostname\" e.g. iscsi.example\n"); + fprintf(stderr, + " \"ipv4-address\" e.g. 10.1.1.27\n"); + fprintf(stderr, + " \"ipv6-address\" e.g. [fce0::1]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, + "and is of the form: SUITENAME_RE[.[SUBTESTNAME_RE]]\n"); + fprintf(stderr, "\n"); } int -main(int argc, const char *argv[]) +test_setup(void) { - poptContext pc; - const char **extra_argv; - int extra_argc = 0; - const char *url = NULL; - int show_help = 0, show_usage = 0, list_tests = 0; - int res; - char *testname = NULL; - char *skipname = NULL; + iscsic = iscsi_context_login(initiatorname1, tgt_url, &tgt_lun); + if (iscsic == NULL) { + fprintf(stderr, + "error: Failed to login to target for test set-up\n"); + return 1; + } + task = NULL; + return 0; +} + + +int +test_teardown(void) +{ + if (task) + scsi_free_scsi_task(task); + iscsi_logout_sync(iscsic); + iscsi_destroy_context(iscsic); + return 0; +} + + +static void +list_all_tests(void) +{ + CU_SuiteInfo *sp; + CU_TestInfo *tp; + + for (sp = suites; sp->pName != NULL; sp++) + for (tp = sp->pTests; tp->pName != NULL; tp++) + printf("%s.%s\n", sp->pName, tp->pName); +} + + +static CU_ErrorCode +add_tests(const char *testname_re) +{ + char *suitename_re = NULL; + char *subtestname_re = NULL; + char *cp; + CU_SuiteInfo *sp; + CU_TestInfo *tp; + + + /* if not testname(s) register all tests and return */ + if (!testname_re) + return CU_register_suites(suites); + + /* + * break testname_re into suitename_re and subtestname_re + * + * syntax is: SUITE_RE[.[SUBTEST_RE]] + */ + + /* is there a subtest name? */ + if ((cp = strchr(testname_re, '.')) == NULL) { + suitename_re = strdup(testname_re); + } else { + size_t suitename_sz; + size_t subtestname_sz; + + suitename_sz = cp - testname_re; + suitename_re = malloc(suitename_sz+1); + memset(suitename_re, 0, suitename_sz+1); + strncpy(suitename_re, testname_re, suitename_sz); + + subtestname_sz = strlen(testname_re) - (suitename_sz+1); + if (subtestname_sz) { + subtestname_re = malloc(subtestname_sz+1); + memset(subtestname_re, 0, subtestname_sz+1); + strncpy(subtestname_re, cp+1, subtestname_sz); + } + } + if (!suitename_re) { + fprintf(stderr, "error: can't parse testsuite name: %s\n", + testname_re); + return CUE_NOTEST; + } + + /* + * cycle through the test suites and tests, adding + * ones that match + */ + for (sp = suites; sp->pName != NULL; sp++) { + int suite_added = 0; + CU_pSuite pSuite = NULL; + + if (fnmatch(suitename_re, sp->pName, 0) != 0) + continue; + + for (tp = sp->pTests; tp->pName != NULL; tp++) { + if (subtestname_re) + if (fnmatch(subtestname_re, tp->pName, 0) != 0) + continue; + if (!suite_added) { + suite_added++; + pSuite = CU_add_suite(sp->pName, + sp->pInitFunc, sp->pCleanupFunc); + } + CU_add_test(pSuite, tp->pName, tp->pTestFunc); + } + } + + /* all done -- clean up */ + if (suitename_re) + free(suitename_re); + if (subtestname_re) + free(subtestname_re); + + return CUE_SUCCESS; +} + + +int +main(int argc, char *argv[]) +{ + char *testname_re = NULL; int lun; - struct iscsi_context *iscsi; - struct scsi_task *task; + CU_BasicRunMode mode = CU_BRM_VERBOSE; + CU_ErrorAction error_action = CUEA_IGNORE; + int res; struct scsi_readcapacity10 *rc10; struct scsi_readcapacity16 *rc16; struct scsi_inquiry_standard *inq; int full_size; - - struct poptOption popt_options[] = { - { "help", '?', POPT_ARG_NONE, - &show_help, 0, "Show this help message", NULL }, - { "usage", 0, POPT_ARG_NONE, - &show_usage, 0, "Display brief usage message", NULL }, - { "list", 'l', POPT_ARG_NONE, - &list_tests, 0, "List all tests", NULL }, - { "initiator-name", 'i', POPT_ARG_STRING, - &initiatorname1, 0, "Initiatorname to use", "iqn-name" }, - { "initiator-name-2", 'I', POPT_ARG_STRING, - &initiatorname2, 0, "Second initiatorname to use for tests using more than one session", "iqn-name" }, - { "test", 't', POPT_ARG_STRING, - &testname, 0, "Which test to run", "testname" }, - { "skip", 's', POPT_ARG_STRING, - &skipname, 0, "Which test to skip", "skipname" }, - { "info", 0, POPT_ARG_NONE, - &show_info, 0, "Show information about the test", "testname" }, - { "dataloss", 0, POPT_ARG_NONE, - &data_loss, 0, "Allow destructuve tests", NULL }, - POPT_TABLEEND + static struct option long_opts[] = { + { "help", no_argument, 0, '?' }, + { "list", no_argument, 0, 'l' }, + { "initiator-name", required_argument, 0, 'i' }, + { "initiator-name-2", required_argument, 0, 'I' }, + { "test", required_argument, 0, 't' }, + { "dataloss", no_argument, 0, 'd' }, + { "ignore", no_argument, 0, 'g' }, + { "fail", no_argument, 0, 'f' }, + { "abort", no_argument, 0, 'A' }, + { "silent", no_argument, 0, 's' }, + { "normal", no_argument, 0, 'n' }, + { "verbose", no_argument, 0, 'v' }, + { NULL, 0, 0, 0 } }; + int c; + int opt_idx = 0; - real_iscsi_queue_pdu = dlsym(RTLD_NEXT, "iscsi_queue_pdu"); - - pc = poptGetContext(argv[0], argc, argv, popt_options, - POPT_CONTEXT_POSIXMEHARDER); - if ((res = poptGetNextOpt(pc)) < -1) { - fprintf(stderr, "Failed to parse option : %s %s\n", - poptBadOption(pc, 0), poptStrerror(res)); - return 10; - } - extra_argv = poptGetArgs(pc); - if (extra_argv) { - url = strdup(*extra_argv); - extra_argv++; - while (extra_argv[extra_argc]) { - extra_argc++; + while ((c = getopt_long(argc, argv, "?hli:I:t:sdgfAsnv", long_opts, + &opt_idx)) > 0) { + switch (c) { + case 'h': + case '?': + print_usage(); + return 0; + case 'l': + list_all_tests(); + return 0; + case 'i': + initiatorname1 = strdup(optarg); + break; + case 'I': + initiatorname2 = strdup(optarg); + break; + case 't': + testname_re = strdup(optarg); + break; + case 'd': + data_loss++; + break; + case 'g': + error_action = CUEA_IGNORE; /* default */ + break; + case 'f': + error_action = CUEA_FAIL; + break; + case 'A': + error_action = CUEA_ABORT; + break; + case 's': + mode = CU_BRM_SILENT; + break; + case 'n': + mode = CU_BRM_NORMAL; + break; + case 'v': + mode = CU_BRM_VERBOSE; /* default */ + break; + default: + fprintf(stderr, + "error: unknown option return: %c (option %s)\n", + c, argv[optind]); + return 1; } } - if (show_help != 0) { - print_help(); - return 0; + if (optind < argc) { + tgt_url = strdup(argv[optind++]); } - - if (show_usage != 0) { + if (optind < argc) { + fprintf(stderr, "error: too many arguments\n"); print_usage(); - return 0; + return 1; } - if (list_tests != 0) { - /* - * XXX list tests here ... - */ - return 0; - } - poptFreeContext(pc); + /* XXX why is this done? */ + real_iscsi_queue_pdu = dlsym(RTLD_NEXT, "iscsi_queue_pdu"); - if (url == NULL) { + if (tgt_url == NULL) { fprintf(stderr, "You must specify the URL\n"); print_usage(); - free(skipname); - free(testname); + if (testname_re) + free(testname_re); return 10; } - iscsi = iscsi_context_login(initiatorname1, url, &lun); - if (iscsi == NULL) { + iscsic = iscsi_context_login(initiatorname1, tgt_url, &lun); + if (iscsic == NULL) { printf("Failed to login to target\n"); return -1; } @@ -179,46 +365,46 @@ main(int argc, const char *argv[]) * All devices support readcapacity10 but only some support * readcapacity16 */ - task = iscsi_readcapacity10_sync(iscsi, lun, 0, 0); + task = iscsi_readcapacity10_sync(iscsic, lun, 0, 0); if (task == NULL) { printf("Failed to send READCAPACITY10 command: %s\n", - iscsi_get_error(iscsi)); - iscsi_destroy_context(iscsi); + iscsi_get_error(iscsic)); + iscsi_destroy_context(iscsic); return -1; } if (task->status != SCSI_STATUS_GOOD) { printf("READCAPACITY10 command: failed with sense. %s\n", - iscsi_get_error(iscsi)); + iscsi_get_error(iscsic)); scsi_free_scsi_task(task); - iscsi_destroy_context(iscsi); + iscsi_destroy_context(iscsic); return -1; } rc10 = scsi_datain_unmarshall(task); if (rc10 == NULL) { printf("failed to unmarshall READCAPACITY10 data. %s\n", - iscsi_get_error(iscsi)); + iscsi_get_error(iscsic)); scsi_free_scsi_task(task); - iscsi_destroy_context(iscsi); + iscsi_destroy_context(iscsic); return -1; } block_size = rc10->block_size; num_blocks = rc10->lba; scsi_free_scsi_task(task); - task = iscsi_readcapacity16_sync(iscsi, lun); + task = iscsi_readcapacity16_sync(iscsic, lun); if (task == NULL) { printf("Failed to send READCAPACITY16 command: %s\n", - iscsi_get_error(iscsi)); - iscsi_destroy_context(iscsi); + iscsi_get_error(iscsic)); + iscsi_destroy_context(iscsic); return -1; } if (task->status == SCSI_STATUS_GOOD) { rc16 = scsi_datain_unmarshall(task); if (rc16 == NULL) { printf("failed to unmarshall READCAPACITY16 data. %s\n", - iscsi_get_error(iscsi)); + iscsi_get_error(iscsic)); scsi_free_scsi_task(task); - iscsi_destroy_context(iscsi); + iscsi_destroy_context(iscsic); return -1; } block_size = rc16->block_length; @@ -230,10 +416,9 @@ main(int argc, const char *argv[]) scsi_free_scsi_task(task); } - - task = iscsi_inquiry_sync(iscsi, lun, 0, 0, 64); + task = iscsi_inquiry_sync(iscsic, lun, 0, 0, 64); if (task == NULL || task->status != SCSI_STATUS_GOOD) { - printf("Inquiry command failed : %s\n", iscsi_get_error(iscsi)); + printf("Inquiry command failed : %s\n", iscsi_get_error(iscsic)); return -1; } full_size = scsi_datain_getfullsize(task); @@ -241,10 +426,10 @@ main(int argc, const char *argv[]) scsi_free_scsi_task(task); /* we need more data for the full list */ - task = iscsi_inquiry_sync(iscsi, lun, 0, 0, full_size); + task = iscsi_inquiry_sync(iscsic, lun, 0, 0, full_size); if (task == NULL) { printf("Inquiry command failed : %s\n", - iscsi_get_error(iscsi)); + iscsi_get_error(iscsic)); return -1; } } @@ -260,16 +445,38 @@ main(int argc, const char *argv[]) encserv = inq->encserv; scsi_free_scsi_task(task); - iscsi_logout_sync(iscsi); - iscsi_destroy_context(iscsi); + iscsi_logout_sync(iscsic); + iscsi_destroy_context(iscsic); + + if (CU_initialize_registry() != 0) { + fprintf(stderr, "error: unable to initialize test registry\n"); + return 1; + } + if (CU_is_test_running()) { + fprintf(stderr, "error: test suite(s) already running!?\n"); + exit(1); + } + + if (add_tests(testname_re) != CUE_SUCCESS) { + fprintf(stderr, "error: suite registration failed: %s\n", + CU_get_error_msg()); + exit(1); + } + CU_basic_set_mode(mode); + CU_set_error_action(error_action); + printf("\n"); /* - * XXX do tests here + * this actually runs the tests ... */ + res = CU_basic_run_tests(); - free(skipname); - free(testname); - free(discard_const(url)); + printf("Tests completed with return value: %d\n", res); - return 0; /* XXX 0??? */ + CU_cleanup_registry(); + if (testname_re) + free(testname_re); + free(discard_const(tgt_url)); + + return 0; } diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h new file mode 100644 index 0000000..06d62f9 --- /dev/null +++ b/test-tool/iscsi-test-cu.h @@ -0,0 +1,48 @@ +/* + iscsi-test tool + + Copyright (C) 2012 by Lee Duncan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef _ISCSI_TEST_CU_H_ +#define _ISCSI_TEST_CU_H_ + +#include +#include +#include +#include + +#include "iscsi-support.h" + +/* globals between setup, tests, and teardown */ +extern struct iscsi_context *iscsic; +extern int tgt_lun; +extern struct scsi_task *task; + +int test_setup(void); +int test_teardown(void); + +void test_testunitready_simple(void); + +void test_read10_simple(void); +void test_read10_beyond_eol(void); +void test_read10_0blocks(void); +void test_read10_rdprotect(void); +void test_read10_flags(void); +void test_read10_invalid(void); + + +#endif /* _ISCSI_TEST_CU_H_ */ diff --git a/test-tool/iscsi-test.c b/test-tool/iscsi-test.c index d4f2cd4..b91b829 100644 --- a/test-tool/iscsi-test.c +++ b/test-tool/iscsi-test.c @@ -44,6 +44,8 @@ int (*real_iscsi_queue_pdu)(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); +int show_info; + struct scsi_test { const char *name; int (*test)(const char *initiator, const char *url); diff --git a/test-tool/iscsi-test.h b/test-tool/iscsi-test.h index d6cb652..a8b85c7 100644 --- a/test-tool/iscsi-test.h +++ b/test-tool/iscsi-test.h @@ -27,6 +27,10 @@ #include "iscsi-support.h" + +extern int show_info; + + int T0000_testunitready_simple(const char *initiator, const char *url); int T0100_read10_simple(const char *initiator, const char *url); diff --git a/test-tool/test_read10_0blocks.c b/test-tool/test_read10_0blocks.c new file mode 100644 index 0000000..789f380 --- /dev/null +++ b/test-tool/test_read10_0blocks.c @@ -0,0 +1,73 @@ +/* + Copyright (C) 2012 by Lee Duncan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + +void +test_read10_0blocks(void) +{ + /* read zero blocks at LBA 0 ... */ + task = iscsi_read10_sync(iscsic, tgt_lun, 0, 0, block_size, + 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* READ10 0blocks at one block beyond ... */ + if (num_blocks > 0x80000000) { + CU_PASS("[SKIPPED] LUN is too big"); + return; + } + task = iscsi_read10_sync(iscsic, tgt_lun, num_blocks + 1, 0, + block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + + /* READ10 0blocks at LBA 2^31 ... */ + task = iscsi_read10_sync(iscsic, tgt_lun, 0x80000000, 0, block_size, + 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + + /* READ10 0blocks at LBA -1 ... */ + task = iscsi_read10_sync(iscsic, tgt_lun, -1, 0, block_size, + 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; +} diff --git a/test-tool/test_read10_beyond_eol.c b/test-tool/test_read10_beyond_eol.c new file mode 100644 index 0000000..d8f8188 --- /dev/null +++ b/test-tool/test_read10_beyond_eol.c @@ -0,0 +1,88 @@ +/* + Copyright (C) 2012 by Lee Duncan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + + +void +test_read10_beyond_eol(void) +{ + int i; + + if (num_blocks >= 0x80000000) { + CU_PASS("LUN is too big for read-beyond-eol tests with READ10. Skipping test.\n"); + return; + } + + /* read 1-256 blocks, one block beyond the end-of-lun */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, num_blocks + 2 - i, + i * block_size, block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + } + + /* Reading 1-256 blocks at LBA 2^31 */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, 0x80000000, + i * block_size, block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + } + + /* read 1 - 256 blocks at LBA -1 */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, -1, i * block_size, + block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + } + + /* read 2-256 blocks, all but one block beyond the eol */ + for (i = 2; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, num_blocks, + i * block_size, block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_LBA_OUT_OF_RANGE); + scsi_free_scsi_task(task); + task = NULL; + } +} diff --git a/test-tool/test_read10_flags.c b/test-tool/test_read10_flags.c new file mode 100644 index 0000000..d52adce --- /dev/null +++ b/test-tool/test_read10_flags.c @@ -0,0 +1,131 @@ +/* + Copyright (C) 2012 by Lee Duncan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + +void +test_read10_flags(void) +{ + struct scsi_task *task_ret; + + + fprintf(stderr, "DEBUG: %s: entering\n", __FUNCTION__); + + /* This test is only valid for SBC devices */ + if (device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { + CU_PASS("[SKIPPED] LUN is not SBC device. Skipping test"); + return; + } + + /* Try out READ10 with DPO : 1 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* Try out READ10 with FUA : 1 FUA_NV : 0 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x08; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* Try out READ10 with FUA : 1 FUA_NV : 1 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x0a; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* Try out READ10 with FUA : 0 FUA_NV : 1 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x02; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + + /* Try out READM10 with DPO : 1 FUA : 1 FUA_NV : 1 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = 0x18; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; +} diff --git a/test-tool/test_read10_invalid.c b/test-tool/test_read10_invalid.c new file mode 100644 index 0000000..e10cc88 --- /dev/null +++ b/test-tool/test_read10_invalid.c @@ -0,0 +1,145 @@ +/* + Copyright (C) 2012 by Lee Duncan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include +#include + +#include + +#include "iscsi.h" +#include "iscsi-private.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + + +void +test_read10_invalid(void) +{ + struct iscsi_data data; + char buf[4096]; + struct scsi_task *task_ret; + + + fprintf(stderr, "DEBUG: %s: entering\n", __FUNCTION__); + + /* Try a read10 of 1 block but xferlength == 0 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = 0; + + /* + * we dont want autoreconnect since some targets will drop the session + * on this condition. + */ + iscsi_set_noautoreconnect(iscsic, 1); + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_NOT_EQUAL(task->status, SCSI_STATUS_CANCELLED); /* XXX redundant? */ + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); + CU_ASSERT_EQUAL(task->residual, (int64_t)block_size); + scsi_free_scsi_task(task); + task = NULL; + + /* in case the previous test failed the session */ + iscsi_set_noautoreconnect(iscsic, 0); + + /* Try a read10 of 1 block but xferlength == 1024 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = 1024; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); + CU_ASSERT_EQUAL(task->residual, (int64_t)block_size); + scsi_free_scsi_task(task); + task = NULL; + + /* Try a read10 of 1 block but xferlength == 200 */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = 200; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); + CU_ASSERT_EQUAL(task->residual, (int64_t)block_size - 200); + scsi_free_scsi_task(task); + task = NULL; + + /* Try a read10 of 2 blocks but xferlength == 'block_size' */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 2; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + CU_ASSERT_EQUAL(task->residual_status, SCSI_RESIDUAL_OVERFLOW); + CU_ASSERT_EQUAL(task->residual, (int64_t)block_size); + scsi_free_scsi_task(task); + task = NULL; + + /* Try a read10 of 1 block but make it a data-out write on the iscsi layer */ + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_WRITE; + task->expxferlen = sizeof(buf); + + data.size = sizeof(buf); + data.data = (unsigned char *)&buf[0]; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, &data); + CU_ASSERT_PTR_NOT_NULL(task_ret); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; +} diff --git a/test-tool/test_read10_rdprotect.c b/test-tool/test_read10_rdprotect.c new file mode 100644 index 0000000..f72db9c --- /dev/null +++ b/test-tool/test_read10_rdprotect.c @@ -0,0 +1,68 @@ +/* + Copyright (C) 2012 by Lee Duncan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + +void +test_read10_rdprotect(void) +{ + int i; + + + if (device_type != SCSI_INQUIRY_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS) { + CU_PASS("[SKIPPED] LUN is not SBC device. Skipping test"); + return; + } + + /* + * Try out Different non-zero values for RDPROTECT. + * They should all fail. + */ + + /* Read10 with non-zero RDPROTECT ... */ + for (i = 1; i < 8; i++) { + struct scsi_task *task_ret; + + task = malloc(sizeof(struct scsi_task)); + CU_ASSERT_PTR_NOT_NULL(task); + + memset(task, 0, sizeof(struct scsi_task)); + task->cdb[0] = SCSI_OPCODE_READ10; + task->cdb[1] = (i<<5)&0xe0; + task->cdb[8] = 1; + task->cdb_size = 10; + task->xfer_dir = SCSI_XFER_READ; + task->expxferlen = block_size; + + task_ret = iscsi_scsi_command_sync(iscsic, tgt_lun, task, NULL); + CU_ASSERT_PTR_NOT_NULL(task_ret); + + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task->sense.key, SCSI_SENSE_ILLEGAL_REQUEST); + CU_ASSERT_EQUAL(task->sense.ascq, SCSI_SENSE_ASCQ_INVALID_FIELD_IN_CDB); + scsi_free_scsi_task(task); + task = NULL; + } +} diff --git a/test-tool/test_read10_simple.c b/test-tool/test_read10_simple.c new file mode 100644 index 0000000..66dddf1 --- /dev/null +++ b/test-tool/test_read10_simple.c @@ -0,0 +1,53 @@ + +/* + Copyright (C) 2012 by Lee Duncan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + + +void +test_read10_simple(void) +{ + int i; + + + /* read the first 1 - 256 blocks at the start of the LUN */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, 0, i * block_size, + block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + } + + /* read the last 1 - 256 blocks at the end of the LUN */ + for (i = 1; i <= 256; i++) { + task = iscsi_read10_sync(iscsic, tgt_lun, num_blocks +1 - i, + i * block_size, block_size, 0, 0, 0, 0, 0); + CU_ASSERT_PTR_NOT_NULL(task); + CU_ASSERT_EQUAL(task->status, SCSI_STATUS_GOOD); + scsi_free_scsi_task(task); + task = NULL; + } +} diff --git a/test-tool/test_testunitready_simple.c b/test-tool/test_testunitready_simple.c new file mode 100644 index 0000000..e223d18 --- /dev/null +++ b/test-tool/test_testunitready_simple.c @@ -0,0 +1,33 @@ +/* + Copyright (C) 2012 by Lee Duncan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include + +#include + +#include "iscsi.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + +void +test_testunitready_simple(void) +{ + int ret; + + ret = testunitready(iscsic, tgt_lun); + CU_ASSERT_EQUAL(ret, 0); +}