Release 1.6.4
[yazpp-moved-to-github.git] / zlint / zlint.cpp
index 3093d0b..7ed83b7 100644 (file)
-/*
- * Copyright (c) 2004, Index Data.
+/* This file is part of the yazpp toolkit.
+ * Copyright (C) Index Data 
  * See the file LICENSE for details.
- * 
- * $Id: zlint.cpp,v 1.4 2004-03-20 15:06:53 adam Exp $
  */
 
-#include <yaz/pquery.h>
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <yaz/comstack.h>
 #include <yaz/options.h>
 #include <yaz/otherinfo.h>
 #include <yaz/charneg.h>
-#include <yaz/sortspec.h>
 #include <yaz/log.h>
-#include <yaz++/pdu-assoc.h>
-#include <yaz++/socket-manager.h>
-#include <yaz++/z-assoc.h>
-
-#define REFID_BUF1 "zlint\000check1"
-#define REFID_LEN1 12
-#define REFID_BUF2 "zlint\000check2"
-#define REFID_LEN2 12
-
-enum Zlint_code {
-    TEST_FINISHED,
-    TEST_CONTINUE,
-};
-
-class Zlint;
-    
-class Zlint_test {
-public:
-    virtual Zlint_code init(Zlint *z) = 0;
-    virtual Zlint_code recv_gdu(Zlint *z, Z_GDU *gdu) = 0;
-    virtual Zlint_code recv_fail(Zlint *z, int reason) = 0;
-};
-
-const char *try_syntax [] = {
-    "usmarc",
-    "unimarc",
-    "danmarc",
-    "sutrs",
-    "grs1",
-    "xml",
-    "normarc",
-    0
-};
-const char *try_query[] = {
-    "@attr 1=4 petersson",
-    "@attr 1=1016 petersson",
-    "@attr 1=4 kingdom",
-    "@attr 1=1016 kingdom",
-    "@attr 1=62 sword",
-    "sword"
-    "seven",
-    "@attr 1=4 water",
-    "@attr 1=1016 water",
-    "computer",
-    "@attr 1=4 computer",
-    "@attr 1=1016 computer",
-    "water",
-    "join",
-    "about",
-    "map",
-    0,
-};
-
-const char *try_sort [] = {
-    "1=4 <",
-    "1=4 >",
-    "1=62 >",
-    "1=62 <",
-    0
-};
-const char *try_scan [] = {
-    "@attr 1=4 ab",
-    "@attr 1=1003 ab",
-    "@attr 1=1016 ab",
-    0
-};
+#include <yaz/odr.h>
 
-#define TEST_STATE_FAIL 0
-#define TEST_STATE_UNKNOWN 1
-#define TEST_STATE_OK   2
-#define TEST_STATE_NOT_APPLIC 3
+#include <zlint.h>
 
-class Zlint : public Yaz_Z_Assoc {
-    int m_tst_no;
+Zlint_test::~Zlint_test()
+{
 
-    int m_subtst_no;
+}
 
-    int m_test_state;
-    int m_query_no;
-    int m_scan_no;
-    int m_sort_no;
-    int m_record_syntax_no;
-    int m_got_result_set;
-    IYaz_PDU_Observable *m_PDU_Observable;
-    char *m_host;
-    char *m_database;
-    int m_timeout_init;
-    int m_timeout_connect;
-    int m_protocol_version;
-    char m_session_str[20];
+class Zlint_t {
 public:
-    int initResponseGetVersion(Z_InitResponse *init);
-    void prepare();
-    void recv_GDU(Z_GDU *apdu, int len);
-    Zlint(IYaz_PDU_Observable *the_PDU_Observable);
-    void args(int argc, char **argv);
-    void connectNotify();
-    void failNotify();
-    void closeNextTest();
-    void sendTest();
-    int nextTest();
-    void testContinue();
-    void timeoutNotify();
-    IYaz_PDU_Observer *sessionNotify(
-       IYaz_PDU_Observable *the_PDU_Observable, int fd);
-    void connect();
-    Z_ReferenceId *mk_refid(const char *buf, int len);
+    friend class Zlint;
+    Zlint_t(Zlint_test *t);
+    ~Zlint_t();
+private:
+    Zlint_test *m_t;
+    Zlint_t *m_next;
+    int m_test_number_sequence;
+    int m_test_ok;
+    int m_test_reported;
 };
 
-int Zlint::initResponseGetVersion(Z_InitResponse *init)
-{
-    int no = 0;
-    int off = 0;
-    int i;
-    for (i = 0; i<12; i++)
-       if (ODR_MASK_GET(init->protocolVersion, no))
-       {
-           no = i+1;
-           if (off)
-               yaz_log(LOG_WARN, "%sbad formatted version");
-       }
-       else
-           off = 1;
-    return no;
-}
-
-Z_ReferenceId *Zlint::mk_refid(const char *buf, int len)
-{
-    Z_ReferenceId *id = 
-       (Z_ReferenceId *) odr_malloc(odr_encode(), sizeof(*id));
-    id->size = id->len = len;
-    id->buf = (unsigned char*) odr_malloc(odr_encode(), len);
-    memcpy(id->buf, buf, len);
-    return id;
-}
+Zlint::Zlint(IPDU_Observable *the_PDU_Observable) :
+    Z_Assoc(the_PDU_Observable)
 
-void Zlint::recv_GDU(Z_GDU *gdu, int len)
-{
-    if (gdu->which != Z_GDU_Z3950)
-    {
-       yaz_log(LOG_LOG, "%sreceived non-Z39.50 response", m_session_str);
-       closeNextTest();
-    }
-    if (gdu->u.z3950 && gdu->u.z3950->which == Z_APDU_initResponse)
-    {
-       int i;
-       Z_InitResponse *init = gdu->u.z3950->u.initResponse;
-       int ver = initResponseGetVersion(init);
-       int result = init->result ? *init->result : 0;
-       if (!result)
-           yaz_log(LOG_WARN, "%sinit rejected");
-       switch(m_tst_no)
-       {
-       case 0:
-           if (ver > 3 || ver < 2)
-               yaz_log(LOG_WARN, "%sgot version %d, expected 2 or 3",
-                       m_session_str, ver);
-           else
-               m_test_state = TEST_STATE_OK;
-           m_protocol_version = ver;
-           if (!result)
-               closeNextTest();
-           else
-           {
-               close();
-               nextTest();
-           }
-           break;
-       case 1:
-           if (ver != 2)
-               yaz_log(LOG_WARN, "%sgot version %d, expected 2",
-                       m_session_str, ver);
-           else
-               m_test_state = TEST_STATE_OK;
-           closeNextTest();
-           break;
-       case 2:
-           if (ver < 2 || ver > 5)
-               yaz_log(LOG_WARN, "%sgot version %d, expected 2-5",
-                       m_session_str,ver);
-           else
-               m_test_state = TEST_STATE_OK;
-           closeNextTest();
-           break;
-       case 3:
-           if (!init->referenceId)
-               yaz_log(LOG_WARN, "%smissing referenceID from init response",
-                       m_session_str);
-           else if (init->referenceId->len != REFID_LEN1
-                    || memcmp(init->referenceId->buf, REFID_BUF1, REFID_LEN1))
-               yaz_log(LOG_WARN, "%sreference ID does not match");
-           else
-               m_test_state = TEST_STATE_OK;
-           closeNextTest();
-           break;
-       case 4:
-           if (m_subtst_no == 0)
-           {
-               if (!init->referenceId)
-                   yaz_log(LOG_WARN, "%smissing referenceID from first init response",
-                           m_session_str);
-               else if (init->referenceId->len != REFID_LEN1
-                        || memcmp(init->referenceId->buf, REFID_BUF1, REFID_LEN1))
-                   yaz_log(LOG_WARN, "%sreference ID does not match");
-               m_subtst_no++;
-           }
-           else
-           {
-               if (!init->referenceId)
-                   yaz_log(LOG_WARN, "%smissing referenceID from second init response",
-                           m_session_str);
-               else if (init->referenceId->len != REFID_LEN2
-                        || memcmp(init->referenceId->buf, REFID_BUF2, REFID_LEN2))
-                   yaz_log(LOG_WARN, "%sreference ID does not match");
-               else
-                   m_test_state = TEST_STATE_OK;
-               closeNextTest();
-           }       
-           break;
-       case 5:
-           if (init->options)
-           {
-               int i;
-               int no_set = 0;
-               int no_reset = 0;
-               for (i = 0; i <= 24; i++)
-                   if (ODR_MASK_GET(init->options, i))
-                       no_set++;
-                   else
-                       no_reset++;
-               if (no_set < 2)
-                   yaz_log(LOG_WARN, "%ssuspicuously few option bits set",
-                           m_session_str);
-               if (no_reset == 0)
-                   yaz_log(LOG_WARN, "%ssuspicuously many option bits set",
-                           m_session_str);
-               if (no_set >= 2 && no_reset)
-                   m_test_state = TEST_STATE_OK;
-           }
-           closeNextTest();
-           break;
-       case 6:
-           if (ODR_MASK_GET(init->options, Z_Options_negotiationModel))
-           {
-               Z_CharSetandLanguageNegotiation *p =
-                   yaz_get_charneg_record(init->otherInfo);
-               
-               if (p) {
-                   
-                   char *charset=NULL, *lang=NULL;
-                   int selected;
-                   NMEM m = nmem_create();
-                   
-                   yaz_get_response_charneg(m, p, &charset, &lang,
-                                            &selected);
-                   yaz_log(LOG_DEBUG, "%sAccepted character set : %s",
-                           m_session_str, charset);
-                   yaz_log(LOG_DEBUG, "%sAccepted code language : %s",
-                           m_session_str, lang ? lang : "none");
-                   yaz_log(LOG_DEBUG, "%sAccepted records in ...: %d",
-                           m_session_str, selected );
-                   nmem_destroy(m);
-                   m_test_state = TEST_STATE_OK;
-               }
-           }
-           else
-               m_test_state = TEST_STATE_NOT_APPLIC;
-           closeNextTest();
-           break;
-       case 7:
-           if (m_subtst_no * m_subtst_no * 100000 + 2000 < *init->maximumRecordSize)
-           {
-               yaz_log(LOG_WARN, "%smaximumRecordSize bigger than proposed size");
-               closeNextTest();
-           }
-           else if (m_subtst_no * m_subtst_no * 100000 + 2000 < *init->preferredMessageSize)
-           {
-               yaz_log(LOG_WARN, "%smaximumRecordSize bigger than proposed size");
-               closeNextTest();
-           }
-           else if (m_subtst_no < 3)
-           {
-               close();
-               m_subtst_no++;
-               connect();
-           }
-           else
-           {
-               m_test_state = TEST_STATE_OK;
-               closeNextTest();
-           }
-           break;
-       case 9:
-           if (result && ODR_MASK_GET(init->options, Z_Options_scan))
-               sendTest();
-           else
-           {
-               m_test_state = TEST_STATE_NOT_APPLIC;
-               closeNextTest();
-           }
-           break;
-       case 10:
-           if (result && ODR_MASK_GET(init->options, Z_Options_sort))
-               sendTest();
-           else
-           {
-               m_test_state = TEST_STATE_NOT_APPLIC;
-               closeNextTest();
-           }
-           break;
-       default:
-           if (result)
-               sendTest();
-           else
-           {
-               m_test_state = TEST_STATE_NOT_APPLIC;
-               closeNextTest();
-           }
-       }
-    }
-    else if (gdu->u.z3950 && gdu->u.z3950->which == Z_APDU_searchResponse)
-    {
-       Z_SearchResponse *sr = gdu->u.z3950->u.searchResponse;
-       switch(m_tst_no)
-       {
-       case 8:
-           if (sr->records && (sr->records->which == Z_Records_NSD 
-                               || 
-                               sr->records->which == Z_Records_multipleNSD))
-           {
-               yaz_log(LOG_WARN, "%sSearch Error", m_session_str);
-               m_query_no++;
-               sendTest();
-           }
-           else if (!sr->resultCount || *sr->resultCount == 0)
-           {
-               m_query_no++;
-               sendTest();
-           }
-           else
-           {
-               yaz_log(LOG_DEBUG, "%sgot %d result count with %s",
-                       m_session_str, *sr->resultCount,
-                       try_query[m_query_no]);
-               m_got_result_set = 1;
-               sendTest();
-           }
-           break;
-       case 10:
-           if (sr->resultCount && *sr->resultCount > 0)
-           {
-               m_got_result_set = 1;
-               sendTest();
-           }
-           else
-           {
-               closeNextTest();
-           }
-           break;
-       default:
-           closeNextTest();
-       }
-    }
-    else if (gdu->u.z3950 && gdu->u.z3950->which == Z_APDU_presentResponse)
-    {
-       Z_PresentResponse *sr = gdu->u.z3950->u.presentResponse;
-       switch(m_tst_no)
-       {
-       case 8:
-           if (sr->records && (sr->records->which == Z_Records_NSD 
-                               || 
-                               sr->records->which == Z_Records_multipleNSD))
-           {
-               yaz_log(LOG_LOG, "%spresent returned NSD for %s",
-                       m_session_str, try_syntax[m_record_syntax_no]);
-           }
-           else if (sr->records && sr->records->which == Z_Records_DBOSD
-                    && sr->records->u.databaseOrSurDiagnostics->num_records>0
-                    && sr->records->u.databaseOrSurDiagnostics->records[0])
-           {
-               if (sr->records->u.databaseOrSurDiagnostics->records[0]->which == Z_NamePlusRecord_databaseRecord)
-               {
-                   Z_External *ext = sr->records->u.databaseOrSurDiagnostics->records[0]->u.databaseRecord;
-                   Odr_oid *expectRecordSyntax =
-                       yaz_str_to_z3950oid(odr_decode(), CLASS_RECSYN,
-                                           try_syntax[m_record_syntax_no]);
-                   if (oid_oidcmp(expectRecordSyntax,
-                              ext->direct_reference))
-                       yaz_log(LOG_WARN, "%sGot Record in different syntax from that required %s",
-                               m_session_str,
-                               try_syntax[m_record_syntax_no]);
-                   else
-                   {
-                       yaz_log(LOG_DEBUG, "%spresent OK for %s", m_session_str,
-                               try_syntax[m_record_syntax_no]);
-                       m_test_state = TEST_STATE_OK;
-                   }
-               }
-               else if (sr->records->u.databaseOrSurDiagnostics->records[0]->which == Z_NamePlusRecord_surrogateDiagnostic)
-                   yaz_log(LOG_DEBUG, "%spresent returned SD %s", m_session_str,
-                           try_syntax[m_record_syntax_no]);
-               else
-                   yaz_log(LOG_WARN, "%spresent returned fragment %s",
-                           m_session_str,
-                           try_syntax[m_record_syntax_no]);
-           }
-           else
-           {
-               yaz_log(LOG_WARN, "%spresent returned no records or diagnostics", m_session_str);
-               
-           }
-           m_record_syntax_no++;
-           sendTest();
-       }
-    }
-    else if (gdu->u.z3950 && gdu->u.z3950->which == Z_APDU_scanResponse)
-    {
-       Z_ScanResponse *sr =  gdu->u.z3950->u.scanResponse;
-       switch(m_tst_no)
-       {
-       case 9:
-           if (sr->entries->nonsurrogateDiagnostics)
-           {
-               yaz_log(LOG_LOG, "%sscan NSD for %s", m_session_str,
-                       try_scan[m_scan_no]);
-               m_scan_no++;
-               sendTest();
-           }
-           else if (sr->entries->entries && sr->entries->num_entries > 0)
-           {
-               yaz_log(LOG_DEBUG, "%sscan OK for %s", m_session_str,
-                       try_scan[m_scan_no]);
-               m_test_state = TEST_STATE_OK;
-               closeNextTest();
-           }
-           else
-           {
-               yaz_log(LOG_WARN, "%sscan no entries/diagnostics for %s",
-                       m_session_str,
-                       try_scan[m_scan_no]);
-               m_scan_no++;
-               sendTest();
-           }
-           break;
-       default:
-           closeNextTest();
-       }
-    }
-    else if (gdu->u.z3950 && gdu->u.z3950->which == Z_APDU_sortResponse)
-    {
-       Z_SortResponse *sr =  gdu->u.z3950->u.sortResponse;
-       switch(m_tst_no)
-       {
-       case 10:
-           if (sr->diagnostics)
-           {
-               yaz_log(LOG_LOG, "%ssort NSD for %s", m_session_str,
-                       try_sort[m_sort_no]);
-               m_sort_no++;
-               sendTest();
-           }
-           else
-           {
-               yaz_log(LOG_DEBUG, "%ssort OK for %s", m_session_str,
-                       try_sort[m_sort_no]);
-               m_test_state = TEST_STATE_OK;
-               closeNextTest();
-           }
-           break;
-       default:
-           closeNextTest();
-       }
-    }
-    else
-       closeNextTest();
-}
-
-Zlint::Zlint(IYaz_PDU_Observable *the_PDU_Observable) : 
-    Yaz_Z_Assoc(the_PDU_Observable)
 {
     m_PDU_Observable = the_PDU_Observable;
     m_host = 0;
+    m_tests = 0;
+    m_cur_test = 0;
     m_database = 0;
-    m_timeout_connect = 30;
-    m_timeout_init = 30;
-    m_tst_no = -1;
-    m_subtst_no = 0;
-    m_protocol_version = 0;
-    sprintf(m_session_str, "%d ", m_tst_no);
 }
 
-void Zlint::connectNotify()
+Zlint::~Zlint()
 {
-    Z_APDU *apdu = create_Z_PDU(Z_APDU_initRequest);
-    Z_InitRequest *init = apdu->u.initRequest;
-    int len;
-    Z_OtherInformation **oi;
-
-    timeout(m_timeout_init);
-
-    switch(m_tst_no)
+    while (m_tests)
     {
-    case 0:
-       /* check if target properly negotiates to v3 .. */
-       ODR_MASK_ZERO(init->protocolVersion);
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_1);
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_2);
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       break;
-    case 1:
-       /* check if target properly negotiates to v2 .. */
-       ODR_MASK_ZERO(init->protocolVersion);
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_1);
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_2);
-       break;
-    case 2:
-       /* check latest version of target  - up to v9 */
-       ODR_MASK_ZERO(init->protocolVersion);
-       int i;
-       for (i = 0; i< 9; i++)
-           ODR_MASK_SET(init->protocolVersion, i);
-       break;
-    case 3:
-       /* send refID in init request */
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       init->referenceId = mk_refid(REFID_BUF1, REFID_LEN1);
-       break;
-    case 4:
-       /* send double init with differnet refID's */
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       ODR_MASK_SET(init->options, Z_Options_concurrentOperations);
-       init->referenceId = mk_refid(REFID_BUF1, REFID_LEN1);
-       send_Z_PDU(apdu, &len);
-       
-       apdu = create_Z_PDU(Z_APDU_initRequest);
-       init = apdu->u.initRequest;
-
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       ODR_MASK_SET(init->options, Z_Options_concurrentOperations);
-
-       init->referenceId = mk_refid(REFID_BUF2, REFID_LEN2);
-       break;
-    case 5:
-       /* set all options.. see what target really supports .. */
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       ODR_MASK_ZERO(init->options);
-       for (i = 0; i <= 24; i++)
-           ODR_MASK_SET(init->options, i);
-       break;
-    case 6:
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       yaz_oi_APDU(apdu, &oi);
-       if (oi)
-       {
-           Z_OtherInformationUnit *p0;
-           const char *negotiationCharset[] = {
-               "UTF-8",
-               "UTF-16",
-               "UCS-2",
-               "UCS-4",
-               "ISO-8859-1"
-           };
-           char *yazLang = 0;
-
-           if ((p0=yaz_oi_update(oi, odr_encode(), NULL, 0, 0))) {
-               ODR_MASK_SET(init->options, Z_Options_negotiationModel);
-
-               p0->which = Z_OtherInfo_externallyDefinedInfo;
-               p0->information.externallyDefinedInfo =
-
-                   yaz_set_proposal_charneg(
-                       odr_encode(),
-                       negotiationCharset, 5,
-                       (const char**)&yazLang, yazLang ? 1 : 0, 1);
-           }
-       }
-       break;
-    case 7:
-       *init->maximumRecordSize = m_subtst_no * m_subtst_no* 100000 + 2000;
-       *init->preferredMessageSize = m_subtst_no * m_subtst_no *100000 + 2000;
-       break;
-    case 8:
-       /* search */
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       ODR_MASK_SET(init->options, Z_Options_namedResultSets);
-       break;
-    case 9:
-       /* scan */
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       ODR_MASK_SET(init->options, Z_Options_namedResultSets);
-       ODR_MASK_SET(init->options, Z_Options_scan);
-       break;
-    case 10:
-       /* sort */
-       ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-       ODR_MASK_SET(init->options, Z_Options_namedResultSets);
-       ODR_MASK_SET(init->options, Z_Options_sort);
-       break;
+        Zlint_t *t = m_tests;
+        m_tests = t->m_next;
+        delete t;
     }
-    int r = send_Z_PDU(apdu, &len);
+    xfree(m_host);
+    xfree(m_database);
 }
 
-int Zlint::nextTest()
+void Zlint::set_host(const char *cp)
 {
-    if (m_tst_no >= 0)
-    {
-       switch(m_test_state)
-       {
-       case TEST_STATE_FAIL:
-           yaz_log(LOG_LOG, "%sTest Failed", m_session_str);
-           break;
-       case TEST_STATE_OK:
-           yaz_log(LOG_LOG, "%sTest Passed", m_session_str);
-           break;
-       case TEST_STATE_NOT_APPLIC:
-           yaz_log(LOG_LOG, "%sTest Not Applicable", m_session_str);
-           break;
-       case TEST_STATE_UNKNOWN:
-           yaz_log(LOG_LOG, "%sTest Could not be performed", m_session_str);
-       }
-    }
-    m_test_state = TEST_STATE_FAIL;
-    m_subtst_no = 0;
-    connect();
-    while(1)
-    {
-       m_tst_no++;
-       sprintf(m_session_str, "%d ", m_tst_no);
-       switch(m_tst_no)
-       {
-       case 0:
-           yaz_log(LOG_LOG, "%sCheck for init v3",
-                   m_session_str);
-           return 1;
-       case 1:
-           yaz_log(LOG_LOG, "%sCheck for init v2",
-                   m_session_str);
-           return 1;
-       case 2:
-           yaz_log(LOG_LOG, "%sCheck for init protocol version negotiation",
-                   m_session_str);
-           return 1;
-       case 3:
-           yaz_log(LOG_LOG, "%sCheck for init reference ID",
-                   m_session_str);
-           return 1;
-       case 4:
-           yaz_log(LOG_LOG, "%sCheck for double init request",
-                   m_session_str);
-           return 1;
-       case 5:
-           yaz_log(LOG_LOG, "%sCheck for init options",
-                   m_session_str);
-           return 1;
-       case 6:
-           yaz_log(LOG_LOG, "%sCheck for character set negotiation",
-                   m_session_str);
-           return 1;
-       case 7:
-           yaz_log(LOG_LOG, "%sCheck for messages size negotiation",
-                   m_session_str);
-           return 1;
-       case 8:
-           yaz_log(LOG_LOG, "%sCheck for basic search and retrieve",
-                   m_session_str);
-           m_query_no = 0;
-           m_record_syntax_no = 0;
-           m_got_result_set = 0;
-           return 1;
-       case 9:
-           yaz_log(LOG_LOG, "%sCheck for scan", m_session_str);
-           m_scan_no = 0;
-           return 1;
-       case 10:
-           yaz_log(LOG_LOG, "%sCheck for sort", m_session_str);
-           m_got_result_set = 0;
-           m_sort_no = 0;
-           return 1;
-       default:
-           close();
-           return 0;
-       }
-    }
-    return 0;
+    xfree(m_host);
+    m_host = xstrdup(cp);
+    client(m_host);
+    timeout(30);
+
+    const char *basep;
+    cs_get_host_args(m_host, &basep);
+    if (!basep || !*basep)
+        basep = "Default";
+    xfree(m_database);
+    m_database = xstrdup(basep);
 }
 
-// current test failed badly - goto next or stop..
-void Zlint::closeNextTest()
+void Zlint::timeoutNotify()
 {
-    close();
-    if (m_tst_no != 0)
+    if (m_cur_test)
     {
-       nextTest();
+        if (m_cur_test->m_t->recv_fail(this, 2) != TEST_FINISHED)
+        {
+            client(m_host);
+            timeout(30);
+            return;
+        }
+        close_goto_next();
     }
 }
 
 void Zlint::failNotify()
 {
-    yaz_log(LOG_WARN, "%sconnection closed by foreign host", m_session_str);
-    testContinue();
-}
-
-void Zlint::timeoutNotify()
-{
-    yaz_log(LOG_WARN, "%sconnection timed out", m_session_str);
-    testContinue();
-}
-
-void Zlint::testContinue()
-{
-    close();
-    switch(m_tst_no)
+    if (m_cur_test)
     {
-    case 8:
-       if (m_got_result_set)
-       {
-           // must search again to establish.. keep query
-           m_got_result_set = 0;
-           m_record_syntax_no++;
-       }
-       else
-       {
-           // try new search ..
-           m_query_no++;
-       }
-       connect();
-       return;
-    case 9:
-       m_scan_no++;
-       connect();
-       return;
-    case 10:
-       if (m_got_result_set)
-       {
-           // if sort test fails during sort, we'll continue to next
-           m_got_result_set = 0;
-           m_sort_no++;
-           connect();
-           return;
-       }
+        if (m_cur_test->m_t->recv_fail(this, 1) != TEST_FINISHED)
+        {
+            client(m_host);
+            timeout(30);
+            return;
+        }
+        close_goto_next();
     }
-    nextTest();
 }
 
-void Zlint::sendTest()
+void Zlint::connectNotify()
 {
-    Z_APDU *apdu;
-    switch(m_tst_no)
+    if (m_cur_test)
     {
-    case 8:
-       if (!m_got_result_set)
-       {
-           apdu = zget_APDU(odr_encode(), Z_APDU_searchRequest);
-           Z_SearchRequest *sr;
-           sr = apdu->u.searchRequest;
-           sr->query = (Z_Query *) odr_malloc(odr_encode(), sizeof(*sr->query));
-           if (try_query[m_query_no] && sr)
-           {
-               sr->query->which = Z_Query_type_1;
-               Z_RPNQuery *rpn;
-               YAZ_PQF_Parser pqf_parser = yaz_pqf_create ();
-               
-               sr->databaseNames = &m_database;
-               sr->num_databaseNames = 1;
-               
-               rpn = yaz_pqf_parse(pqf_parser, odr_encode(), try_query[m_query_no]);
-
-               yaz_pqf_destroy (pqf_parser);
-
-               if (rpn)
-               {
-                   int len;
-                   yaz_log(LOG_DEBUG, "%spqf: %s",
-                           m_session_str, try_query[m_query_no]);
-
-                   sr->query->u.type_1 = rpn;
-                   send_Z_PDU(apdu, &len);
-               }
-               else
-                   closeNextTest();
-           }
-           else
-           {
-               yaz_log(LOG_WARN, "%sunable to get any hit count", 
-                       m_session_str);
-               closeNextTest();
-           }
-       }
-       else if (m_got_result_set && try_syntax[m_record_syntax_no])
-       {
-           int len;
-           apdu = zget_APDU(odr_encode(), Z_APDU_presentRequest);
-           Z_PresentRequest *pr = apdu->u.presentRequest;
-           *pr->numberOfRecordsRequested = 1;
-           *pr->resultSetStartPoint = 1;
-           
-           pr->preferredRecordSyntax =
-               yaz_str_to_z3950oid(odr_encode(), CLASS_RECSYN,
-                                   try_syntax[m_record_syntax_no]);
-           send_Z_PDU(apdu, &len);
-       }
-       else
-           closeNextTest();
-       break;
-    case 9:
-       apdu = zget_APDU(odr_encode(), Z_APDU_scanRequest);
-       if (apdu && try_scan[m_scan_no])
-       {
-           int len;
-           YAZ_PQF_Parser pqf_parser = yaz_pqf_create ();
-           Z_ScanRequest *sr = apdu->u.scanRequest;
-           sr->termListAndStartPoint = yaz_pqf_scan(pqf_parser,
-                                                    odr_encode(),
-                                                    &sr->attributeSet,
-                                                    try_scan[m_scan_no]);
-
-           sr->databaseNames = &m_database;
-           sr->num_databaseNames = 1;
-
-           yaz_pqf_destroy (pqf_parser);
-           send_Z_PDU(apdu, &len);
-       }
-       else
-           closeNextTest();
-       break;
-    case 10:
-       if (!m_got_result_set)
-       {
-           apdu = zget_APDU(odr_encode(), Z_APDU_searchRequest);
-           Z_SearchRequest *sr;
-           sr = apdu->u.searchRequest;
-           sr->query = (Z_Query *) odr_malloc(odr_encode(), sizeof(*sr->query));
-           if (try_query[m_query_no] && sr)
-           {
-               sr->query->which = Z_Query_type_1;
-               Z_RPNQuery *rpn;
-               YAZ_PQF_Parser pqf_parser = yaz_pqf_create ();
-               
-               sr->databaseNames = &m_database;
-               sr->num_databaseNames = 1;
-               
-               rpn = yaz_pqf_parse(pqf_parser, odr_encode(), try_query[m_query_no]);
-
-               yaz_pqf_destroy (pqf_parser);
-
-               if (rpn)
-               {
-                   int len;
-                   yaz_log(LOG_DEBUG, "%spqf: %s",
-                           m_session_str, try_query[m_query_no]);
-
-                   sr->query->u.type_1 = rpn;
-                   send_Z_PDU(apdu, &len);
-               }
-               else
-                   closeNextTest();
-           }
-           else
-           {
-               yaz_log(LOG_WARN, "%sunable to get any hit count", 
-                       m_session_str);
-               closeNextTest();
-           }
-       }
-       else 
-       {
-           apdu = zget_APDU(odr_encode(), Z_APDU_sortRequest);
-           if (apdu && try_sort[m_sort_no])
-           {
-               char *setstring = "default";
-               int len;
-               Z_SortRequest *sr = apdu->u.sortRequest;
-               
-               sr->num_inputResultSetNames = 1;
-               sr->num_inputResultSetNames = 1;
-               sr->inputResultSetNames = (Z_InternationalString **)
-                   odr_malloc (odr_encode(), sizeof(*sr->inputResultSetNames));
-               sr->inputResultSetNames[0] = odr_strdup (odr_encode(), setstring);
-               sr->sortedResultSetName = odr_strdup(odr_encode(), setstring);
-               sr->sortSequence = yaz_sort_spec(odr_encode(), try_sort[m_sort_no]);
-               send_Z_PDU(apdu, &len);
-           }
-           else
-               closeNextTest();
-       }
-       break;
-    default:
-       closeNextTest();
+        if (m_cur_test->m_t->init(this) != TEST_FINISHED)
+            return;
+        close_goto_next();
     }
 }
 
-IYaz_PDU_Observer *Zlint::sessionNotify(
-    IYaz_PDU_Observable *the_PDU_Observable, int fd)
-{
-    return 0;
-}
-
-void Zlint::connect()
+void Zlint::recv_GDU(Z_GDU *gdu, int len)
 {
-    if (m_host)
+    if (m_cur_test)
     {
-       yaz_log(LOG_DEBUG, "%sconnecting to %s", m_session_str, m_host);
-       timeout(m_timeout_connect);
-       client(m_host);
+        int r = m_cur_test->m_t->recv_gdu(this, gdu);
+        if (r == TEST_CONTINUE)
+            return;
+        if (r == TEST_REOPEN)
+        {
+            client(m_host);
+            timeout(30);
+            return;
+        }
+        close_goto_next();
     }
 }
 
-void Zlint::args(int argc, char **argv)
+void Zlint::close_goto_next()
 {
-    char *arg;
-    int ret;
-    while ((ret = options("a:v:", argv, argc, &arg)) != -2)
+    if (m_cur_test)
+        m_cur_test = m_cur_test->m_next;
+    if (m_cur_test)
     {
-        switch (ret)
-       {
-       case 'v':
-            yaz_log_init(yaz_log_mask_str(arg), "", 0);        
-           break;
-       case 'a':
-           set_APDU_log(arg);
-           break;
-       case 0:
-           if (arg)
-           {
-               const char *basep;
-               m_host = xstrdup(arg);
-               cs_get_host_args(m_host, &basep);
-               if (!basep || !*basep)
-                   basep = "Default";
-               m_database = xstrdup(basep);
-           }
-           break;
-       }
+        client(m_host);
+        timeout(30);
     }
+    else
+        close();
 }
 
-class Zlint_driver_t;
-class Zlint_driver : public Yaz_Z_Assoc {
-public:
-    Zlint_driver(IYaz_PDU_Observable *the_PDU_Observable);
-    ~Zlint_driver();
-    void add_test(Zlint_test *i);
-    void set_host(const char *cp);
-private:
-    void connectNotify();
-    void timeoutNotify();
-    void failNotify();
-    void recv_GDU(Z_GDU *apdu, int len);
-    IYaz_PDU_Observable *m_PDU_Observable;
-    IYaz_PDU_Observer *sessionNotify(
-       IYaz_PDU_Observable *the_PDU_Observable, int fd);
-    Zlint_driver_t *m_tests;
-    char *m_host;
-};
-
-class Zlint_driver_t {
-public:
-    friend class Zlint_driver;
-    Zlint_driver_t(Zlint_test *t);
-private:
-    Zlint_test *m_t;
-    Zlint_driver_t *m_next;
-};
-
-void Zlint_driver::set_host(const char *cp)
-{
-    xfree(m_host);
-    m_host = xstrdup(cp);
-}
-
-Zlint_driver::Zlint_driver(IYaz_PDU_Observable *the_PDU_Observable) : 
-    Yaz_Z_Assoc(the_PDU_Observable)
-    
-{
-    m_PDU_Observable = the_PDU_Observable;
-    m_host = 0;
-    m_tests = 0;
-}
-
-
-Zlint_driver::~Zlint_driver()
+IPDU_Observer *Zlint::sessionNotify(
+    IPDU_Observable *the_PDU_Observable, int fd)
 {
-    xfree(m_host);
+    return 0;
 }
 
-void Zlint_driver::timeoutNotify()
+Z_ReferenceId *Zlint::mk_refid(const char *buf, int len)
 {
+    return odr_create_Odr_oct(odr_encode(),
+#if YAZ_VERSIONL < 0x50000
+                              (unsigned char *)
+#endif
+                              buf, len);
 }
 
-void Zlint_driver::failNotify()
+int Zlint::initResponseGetVersion(Z_InitResponse *init)
 {
+    int no = 0;
+    int i;
+    for (i = 0; i<12; i++)
+        if (ODR_MASK_GET(init->protocolVersion, no))
+        {
+            no = i+1;
+        }
+    return no;
 }
 
-void Zlint_driver::connectNotify()
+void Zlint::add_test(Zlint_test *t)
 {
+    Zlint_t **d = &m_tests;
+    while (*d)
+        d = &(*d)->m_next;
+    *d = new Zlint_t(t);
+    if (!m_cur_test)
+        m_cur_test = m_tests;
 }
 
-void Zlint_driver::recv_GDU(Z_GDU *gdu, int len)
+void Zlint::msg_check_for(const char *fmt, ...)
 {
-
+    m_cur_test->m_test_ok = 0;
+    m_cur_test->m_test_number_sequence++;
+    m_cur_test->m_test_reported = 0;
+
+    va_list ap;
+    va_start(ap, fmt);
+    char buf[1024];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    printf ("Checking %s .. ", buf);
+    va_end(ap);
 }
 
-IYaz_PDU_Observer *Zlint_driver::sessionNotify(
-    IYaz_PDU_Observable *the_PDU_Observable, int fd)
+void Zlint::msg_check_info(const char *fmt, ...)
 {
-    return 0;
+    va_list ap;
+    va_start(ap, fmt);
+    char buf[1024];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    printf (" %s\n", buf);
+    va_end(ap);
 }
 
-void Zlint_driver::add_test(Zlint_test *t)
+void Zlint::msg_check_ok()
 {
-    Zlint_driver_t **d = &m_tests;
-    while (*d)
-       d = &(*d)->m_next;
-    *d = new Zlint_driver_t(t);
+    if (!m_cur_test->m_test_reported)
+    {
+        m_cur_test->m_test_ok = 1;
+        m_cur_test->m_test_reported = 1;
+        printf ("OK\n");
+    }
 }
 
-Zlint_driver_t::Zlint_driver_t(Zlint_test *t)
+void Zlint::msg_check_fail(const char *fmt, ...)
 {
-    m_t = t;
-    m_next = 0;
+    if (!m_cur_test->m_test_reported)
+    {
+        m_cur_test->m_test_ok = 0;
+        m_cur_test->m_test_reported = 1;
+        printf ("Fail\n");
+    }
+    va_list ap;
+    va_start(ap, fmt);
+    char buf[1024];
+    vsnprintf(buf, sizeof(buf), fmt, ap);
+    printf (" %s\n", buf);
+    va_end(ap);
 }
 
-class Zlint_test_01 : public Zlint_test {
-public:
-    Zlint_test_01();
-    virtual ~Zlint_test_01();
-    Zlint_code init(Zlint *z);
-    Zlint_code recv_gdu(Zlint *z, Z_GDU *gdu);
-    Zlint_code recv_fail(Zlint *z, int reason);
-};
-    
-Zlint_test_01::Zlint_test_01()
+void Zlint::msg_check_notapp()
 {
+    if (!m_cur_test->m_test_reported)
+    {
+        m_cur_test->m_test_ok = 2;
+        m_cur_test->m_test_reported = 1;
+        printf ("Unsupported\n");
+    }
 }
 
-Zlint_test_01::~Zlint_test_01()
+void Zlint::getDatabase(char ***db, int *num)
 {
+    *db = (char**) odr_malloc(odr_encode(), 2*sizeof(char *));
+    (*db)[0] = m_database;
+    (*db)[1] = 0;
+    *num = 1;
 }
 
-Zlint_code Zlint_test_01::init(Zlint *z)
+Zlint_t::Zlint_t(Zlint_test *t)
 {
-    int len;
-    Z_APDU *apdu = z->create_Z_PDU(Z_APDU_initRequest);
-    Z_InitRequest *init = apdu->u.initRequest;
-
-    ODR_MASK_ZERO(init->protocolVersion);
-    ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_1);
-    ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_2);
-    ODR_MASK_SET(init->protocolVersion, Z_ProtocolVersion_3);
-    
-    int r = z->send_Z_PDU(apdu, &len);
-    if (r < 0)
-       return TEST_FINISHED;
-    return TEST_CONTINUE;
+    m_test_number_sequence = 0;
+    m_test_ok = 0;
+    m_test_reported = 0;
+    m_t = t;
+    m_next = 0;
 }
 
-Zlint_code Zlint_test_01::recv_gdu(Zlint *z, Z_GDU *gdu)
+Zlint_t::~Zlint_t()
 {
-    if (gdu->which == Z_GDU_Z3950 &&
-       gdu->u.z3950 && gdu->u.z3950->which == Z_APDU_initResponse)
-    {
-       Z_InitResponse *init = gdu->u.z3950->u.initResponse;
-       int ver = z->initResponseGetVersion(init);
-       int result = init->result ? *init->result : 0;
-       if (ver > 3 || ver < 2)
-           yaz_log(LOG_WARN, "got version %d, expected 2 or 3", ver);
-       if (!result)
-           return TEST_FINISHED;
-    }
-    return TEST_FINISHED;
+    delete m_t;
 }
 
-Zlint_code Zlint_test_01::recv_fail(Zlint *z, int reason)
+Zlint_code Zlint_test_simple::recv_fail(Zlint *z, int reason)
 {
+    z->msg_check_fail("target closed connection");
     return TEST_FINISHED;
 }
-
-int main(int argc, char **argv)
-{
-    Yaz_SocketManager mySocketManager;
-    Zlint z(new Yaz_PDU_Assoc(&mySocketManager));
-    
-    z.args(argc, argv);
-
-    z.nextTest();
-
-    while (mySocketManager.processEvent() > 0)
-       ;
-    exit (0);
-}
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */