searchengine/cpix/tsrc/cpixunittest/src/destructivetests.cpp
changeset 0 671dee74050a
child 3 ae3f1779f6da
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/searchengine/cpix/tsrc/cpixunittest/src/destructivetests.cpp	Mon Apr 19 14:40:16 2010 +0300
@@ -0,0 +1,687 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+#include "testutils.h"
+#include "testcorpus.h"
+#include "config.h"
+#include "itk.h"
+#include "setupsentry.h"
+
+#include <iostream>
+
+#include "cpixsearch.h"
+
+// Disable test cases, which prevent running other cases
+#define DISABLE_CRASHING_TEST_CASES
+
+class DestructiveTests : public Itk::ITestContext
+{
+private: // data
+	
+    SmsIdxUtil* idxUtil_; 
+    LineTestCorpusRef testCorpus_; 
+		
+    cpix_Analyzer* analyzer_;
+    cpix_QueryParser* uidQueryParser_;
+    cpix_QueryParser* contentQueryParser_;
+    cpix_IdxSearcher * searcher_;
+		
+public: // Constructors & destructors
+	
+    DestructiveTests() 
+        : idxUtil_(NULL),
+          testCorpus_(DEFAULT_TEST_CORPUS_PATH),
+          analyzer_(NULL),
+          uidQueryParser_(NULL),
+          contentQueryParser_(NULL),
+          searcher_(NULL)
+    {
+        ;
+    }
+
+
+    ~DestructiveTests() 
+    {
+        cleanup();
+    }
+		
+
+    void setup() throw (Itk::PanicExc) 
+    {
+        SetupSentry
+            ss(*this);
+
+        cpix_Result
+            result;
+
+        // cpix_setLogLevel(CPIX_LL_DEBUG);
+
+        cpix_IdxDb_dbgScrapAll(&result);
+
+        if (cpix_Failed(&result))
+            {
+                ITK_PANIC("Could not scrap all");
+            }
+
+        idxUtil_ = new SmsIdxUtil; 
+        idxUtil_->init( true );
+
+        analyzer_ = cpix_CreateSimpleAnalyzer(&result);
+        if ( !analyzer_ )
+            {
+                ITK_PANIC("Analyzer could not be created");
+            }
+        
+        uidQueryParser_ = cpix_QueryParser_create( &result,
+                                                                   LCPIX_DOCUID_FIELD, 
+                                                                   analyzer_ );
+        if ( !( uidQueryParser_ ) )
+            {
+                ITK_PANIC("Query parser could not be created");
+            }
+	
+        contentQueryParser_ = cpix_QueryParser_create( &result,
+                                                                       LBODY_FIELD, 
+                                                                       analyzer_ );
+        if ( !( contentQueryParser_ ) )
+            {
+                ITK_PANIC("Query parser could not be created");
+            }
+
+        ss.setupComplete();
+    }
+		
+
+
+    void tearDown() throw () 
+    {
+        cleanup();
+
+        // cpix_setLogLevel(CPIX_LL_TRACE);
+    }
+		
+public: // Test cases
+
+    void cleanup()
+    {
+        cpix_Analyzer_destroy( analyzer_ ); 
+        analyzer_ = NULL;
+        cpix_QueryParser_destroy( uidQueryParser_ ); 
+        uidQueryParser_ = NULL;
+        cpix_QueryParser_destroy( contentQueryParser_ ); 
+        contentQueryParser_ = NULL;
+        delete idxUtil_;
+        idxUtil_ = NULL;
+        cpix_IdxSearcher_releaseDb(searcher_);
+        searcher_ = NULL;
+    }
+		
+    void testWritingWhenHitIterating(Itk::TestMgr* testMgr) {
+        testWritingWhenHitIterating(testMgr,
+                                    idxUtil_->idxDb(),
+                                    &cpix_IdxDb_search,
+                                    3);
+    }
+
+
+    void testWritingWhenHitIterating2(Itk::TestMgr* testMgr) {
+        testWritingWhenHitIterating(testMgr,
+                                    searcher(testMgr),
+                                    &cpix_IdxSearcher_search,
+                                    3);
+    }
+
+    void testInvalidation(Itk::TestMgr* testMgr) 
+    {
+        for (int i = 0; i < 25; i++) 
+            {
+                idxUtil_->indexSms( i, 
+                                    testCorpus_.item(i).c_str(), 
+                                    analyzer_, 
+                                    testMgr, 
+                                    false ); 
+            }
+        idxUtil_->flush();
+
+        cpix_Query* query = cpix_QueryParser_parse( contentQueryParser_, L"ok" );
+	
+        ITK_ASSERT( testMgr, query, "Query parsing failed" );
+
+        cpix_Hits *hits =
+            cpix_IdxDb_search(idxUtil_->idxDb(), query );
+		
+        if ( cpix_Failed( idxUtil_->idxDb() ) ) {
+            cpix_Query_destroy( query );
+            ITK_PANIC( "Search failed" );
+        }
+        printf("Accessing hits before closing... ");
+
+        cpix_Hits_length( hits ); 
+        ITK_ASSERT( testMgr, cpix_Succeeded( hits  ), "Accessing hit length failed" ); 
+        printf("OK. Hits could be accessed.\n");
+
+        /* OBS
+        // cleanup
+        idxUtil_->close(); 
+        */
+
+
+        for (int i = 0; i < 5; i++) 
+            {
+                idxUtil_->indexSms( i, 
+                                    testCorpus_.item(i).c_str(), 
+                                    analyzer_, 
+                                    testMgr, 
+                                    false ); 
+            }
+        cpix_IdxDb_flush(idxUtil_->idxDb());
+        ITK_EXPECT(testMgr,
+                   cpix_Succeeded(idxUtil_->idxDb()),
+                   "Flushing failed");
+        
+
+        cpix_IdxSearcher_releaseDb(searcher_);
+        searcher_ = NULL;
+        idxUtil_->close();
+
+        // Confirm no crash and that access fails
+
+        printf("Accessing hits after closing... \n");
+        cpix_Document
+            doc;
+
+        printf("doc #0: ");
+        cpix_Hits_doc(hits,
+                      0,
+                      &doc);
+        ITK_EXPECT( testMgr, 
+                    cpix_Succeeded( hits ), 
+                    "Accessing hit(0) should succeeded for closed database (hits still holds a reference to its originator)." ); 
+
+        if (cpix_Failed(hits))
+            {
+                wchar_t
+                    buf[256];
+                cpix_Error_report(hits->err_,
+                                  buf,
+                                  sizeof(buf) / sizeof(wchar_t));
+                printf("%S\n", buf);
+                cpix_ClearError(hits);
+            }
+
+        printf("\ndoc #20: ");
+        cpix_Hits_doc(hits,
+                      20,
+                      &doc);
+        ITK_EXPECT( testMgr, 
+                    cpix_Failed( hits ), 
+                    "Accessing hit(20) should NOT succeeded for closed database (hits still holds a reference to its originator)." ); 
+
+        if (cpix_Failed(hits))
+            {
+                wchar_t
+                    buf[256];
+                cpix_Error_report(hits->err_,
+                                  buf,
+                                  sizeof(buf) / sizeof(wchar_t));
+                printf("%S\n", buf);
+                cpix_ClearError(hits);
+            }
+        
+        cpix_Hits_destroy( hits );
+        cpix_Query_destroy( query );
+    }
+
+
+    /**
+     * The purpose of this test is to test the stack unwinding problem, 
+     * which occurs e.g. if we provide bad schema and the idxdb will react 
+     * by throwing an exception.
+     */
+    void testStackunwinding(Itk::TestMgr* testMgr) 
+    {
+        SchemaId wrongSchema = idxUtil_->schemaId();
+        cpix_Result
+            result;
+		
+        delete idxUtil_;
+        idxUtil_ = NULL;
+		
+        cpix_IdxDb
+            * idxDb = cpix_IdxDb_openDb(&result,
+                                        SMS_QBASEAPPCLASS,
+                                        cpix_IDX_OPEN);
+        // Open index without redefining schema
+        
+        if (cpix_Failed(&result))
+            {
+                ITK_PANIC("Index could not be opened");
+            }
+
+        // Try to index things
+        for (int i = 0; i < 5; i++) 
+            {
+                std::wstring id = GetItemId( i );
+                std::wstring content = testCorpus_.item( i );
+
+                const wchar_t
+                    * fields[4];
+                fields[0] = L"+3585553412"; // to
+                fields[1] = L"+3585559078"; // from
+                fields[2] = L"inbox"; // folder
+                fields[3] = content.c_str();// body
+
+					
+                cpix_IdxDb_add2( idxDb,
+                                 wrongSchema,
+                                 id.c_str(),
+                                 // OBS DEFAULT_APPTYPE,
+                                 SMSAPPCLASS,
+                                 content.c_str(),
+                                 NULL,
+                                 fields,
+                                 analyzer_ );
+
+                bool
+                    succeeded = cpix_Succeeded(idxDb);
+
+                ITK_ASSERT( testMgr, !succeeded, "Schema is persistent?" ); 
+            }
+			
+        cpix_IdxDb_releaseDb(idxDb);
+        idxDb = NULL; 
+			
+        idxUtil_ = new SmsIdxUtil; 
+        idxUtil_->init( true );
+			
+    }
+
+
+private:
+    template<typename IDX>
+    void testWritingWhenHitIterating(Itk::TestMgr * testMgr,
+                                     IDX          * idx,
+                                     cpix_Hits * (* searcher)(IDX*,cpix_Query*),
+                                     int32_t       matches) 
+    {
+        wprintf(L"Testing writing to index, while hit object is continuosly read.\n");
+	
+        // Index 
+        for (int i = 0; i < 25; i++) {
+            idxUtil_->indexSms( i, 
+                                testCorpus_.item(i).c_str(), 
+                                analyzer_, 
+                                testMgr, 
+                                false ); 
+        }
+        idxUtil_->flush();
+	
+        printf("25 items indexed.\n");
+	
+        cpix_Query* query = cpix_QueryParser_parse( contentQueryParser_, L"ok" );
+			
+        if ( query != NULL ) {
+            cpix_Hits *hits =
+                (*searcher)(idx, query );
+		
+            if ( hits )
+                {
+                    // We know that 25 first message contain this many 'ok's. 
+                    ITK_EXPECT( testMgr, cpix_Hits_length( hits ) == matches,
+                                "There should be %d matches instead of %d",
+                                matches,
+                                cpix_Hits_length(hits));
+                    int length = 0; 
+					 
+                    printf("Hits after indexing: \n");
+                    idxUtil_->printHits( hits, testMgr ); 
+										
+                    // Should this also crash? By the way, this is one of the document results
+                    idxUtil_->indexSms( 25, 
+                                        testCorpus_.item(25).c_str(), 
+                                        analyzer_, 
+                                        testMgr, 
+                                        false ); 
+					 
+                    ITK_EXPECT( testMgr, cpix_Succeeded( idx ), "Adding 25th item failed" ); 
+	
+                    printf("1 item indexed. \n");
+	
+                    cpix_Hits_length( hits );
+                    ITK_EXPECT( testMgr, cpix_Succeeded( hits  ), "Accessing hit of index 1 failed" ); 
+					
+                    printf("Hits after adding 1 item.\n");
+                    idxUtil_->printHits( hits, testMgr ); 
+								
+                    cpix_IdxDb_deleteDocuments(idxUtil_->idxDb(), GetItemId( 15 ).c_str() );
+                    ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Deleting document 15 failed" ); 
+					
+                    printf("Line 16 deleted.\n");
+	
+                    printf("Hits after deletion: \n");
+                    idxUtil_->printHits( hits, testMgr ); 
+					
+                    cpix_IdxDb_flush(idxUtil_->idxDb() );
+                    ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Flushing failed" );
+                    printf("Flushed.\n");
+					
+                    printf("Hits after flush:\n");
+                    idxUtil_->printHits( hits, testMgr, true ); 
+					 
+                    cpix_IdxDb_deleteDocuments(idxUtil_->idxDb(), GetItemId( 14 ).c_str() );
+                    ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Deleting document 14 failed" ); 
+	
+                    printf("Line 15 deleted.\n");
+                    printf("Hits after deletion:\n");
+                    idxUtil_->printHits( hits, testMgr ); 
+	
+                    cpix_IdxDb_deleteDocuments(idxUtil_->idxDb(), GetItemId( 9 ).c_str() );
+                    ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Deleting document 9 failed" ); 
+	
+                    printf("Line 10 deleted.\n");
+                    printf("Hits after deletion:\n");
+                    idxUtil_->printHits( hits, testMgr ); 
+	
+                    cpix_IdxDb_flush(idxUtil_->idxDb() );
+                    ITK_EXPECT( testMgr, cpix_Succeeded( idxUtil_->idxDb() ), "Flushing failed" );
+                    printf("Flushed.\n");
+					
+                    printf("Hits after flush:\n");
+                    idxUtil_->printHits( hits, testMgr, true ); 
+					 
+                    ITK_EXPECT( testMgr, cpix_Succeeded( hits  ), "Accessing hit length failed" ); 
+                    ITK_EXPECT( testMgr, length == 0, "The items were not deleted." ); 
+					
+                    cpix_Hits_destroy( hits );
+                }
+            else 
+                {
+                    ITK_PANIC("Hits was null"); 
+                }
+            cpix_Query_destroy( query );
+        } else  {
+            ITK_PANIC("Could not create query"); 
+        }
+    }
+
+
+    cpix_IdxSearcher * searcher(Itk::TestMgr * )
+    {
+        if (searcher_ == NULL)
+            {
+                cpix_Result
+                    result;
+                searcher_ = cpix_IdxSearcher_openDb(&result,
+                                                    SMSAPPCLASS);
+                if (searcher_ == NULL)
+                    {
+                        ITK_PANIC("Searcher could not be created");
+                    }
+            }
+        return searcher_;
+    }
+};
+
+
+
+
+
+/**
+ * This test case is incomplete, it is supposed to test for a fix for
+ * the LuceneError flying through the catch(...) problem - but the
+ * real cause is still unidentified, so this test is not enabled yet.
+ */
+class CLuceneErrorBugCtxt : public Itk::ITestContext
+{
+private:
+    SmsIdxUtil * idxUtil_;
+    
+    cpix_Analyzer * analyzer_;
+    cpix_Query    * query_;
+    cpix_QueryParser * queryParser_;
+
+
+public:
+
+    CLuceneErrorBugCtxt()
+        : idxUtil_(NULL),
+          analyzer_(NULL),
+          query_(NULL),
+          queryParser_(NULL)
+    {
+        ;
+    }
+
+
+    ~CLuceneErrorBugCtxt()
+    {
+        cleanup();
+    }
+
+
+    void setup() throw (Itk::PanicExc)
+    {
+        SetupSentry
+            ss(*this);
+
+        idxUtil_ = new SmsIdxUtil;
+        idxUtil_->init(true);
+
+        cpix_Result
+            result;
+
+        analyzer_ = cpix_CreateSimpleAnalyzer(&result);
+        if (cpix_Failed(&result))
+            {
+                ITK_PANIC("Analyzer could not be created");
+            }
+
+
+        queryParser_ = cpix_QueryParser_create(&result,
+                                               LBODY_FIELD,
+                                               analyzer_);
+
+        if (cpix_Failed(&result))
+            {
+                ITK_PANIC("QueryParser could not be create4d");
+            }
+
+        query_ = cpix_QueryParser_parse(queryParser_,
+                                        L"c*");
+
+        if (query_ == NULL)
+            {
+                ITK_PANIC("Query could not be created for 'c*'");
+            }
+    
+        ss.setupComplete();
+    }
+    
+
+    void tearDown() throw ()
+    {
+        cleanup();
+    }
+
+
+    void indexGeneratedLines(Itk::TestMgr * testMgr)
+    {
+        static const int
+            wordsPerLine = 10;
+
+        // we generate a lot of lines, like "a... a... a...",
+        // "b... b... b...", ..., "j... j... j..." even if what we are
+        // interested in is "c... c... c...". Reason: we need a big
+        // index to produce crash-failure.
+        static const int
+            prefixCount = 10;
+
+        std::wstring
+            lines[prefixCount];
+
+        for (int i = 0; i < 1030; ++i)
+            {
+                if (i % 50 == 0)
+                    {
+                        ITK_DBGMSG(testMgr,
+                                   ".");
+                    }
+                
+
+                if (i % wordsPerLine == 0)
+                    {
+                        for (int j = 0; j < prefixCount; ++j)
+                            {
+                                lines[j] = L'a' + j;
+                            }
+                    }
+                else
+                    {
+                        for (int j = 0; j < prefixCount; ++j)
+                            {
+                                lines[j] += L' ';
+                                lines[j] += L'a' + j;
+                            }
+                    }
+                
+                std::wstring
+                    postfix;
+                
+                static const int
+                    charNum = int('z') - int('a') + 1;
+                static const int
+                    digits = 4;
+                
+                // we generate a postfix
+                int
+                    generator = i;
+                for (int d = 0; d < digits; ++d)
+                    {
+                        postfix += char('a' + generator % charNum);
+                        generator /= charNum;
+                    }
+                
+                for (int j = 0; j < prefixCount; ++j)
+                    {
+                        lines[j] += postfix;
+                        
+                        if (i % wordsPerLine == (wordsPerLine - 1))
+                            {
+                                idxUtil_->indexSms(i - j,
+                                                   lines[j].c_str(),
+                                                   analyzer_,
+                                                   testMgr,
+                                                   false); // addition, not update
+
+                                ITK_ASSERT(testMgr,
+                                           cpix_Succeeded(idxUtil_->idxDb()),
+                                           "Addition of c... words should have succeeded");
+                            }
+                    }
+            }
+    }
+
+
+    void searchCWildCard(Itk::TestMgr * testMgr)
+    {
+        cpix_Hits
+            * hits = cpix_IdxDb_search(idxUtil_->idxDb(),
+                                       query_);
+
+        ITK_EXPECT(testMgr,
+                   cpix_Failed(idxUtil_->idxDb()),
+                   "Wildcard search 'c*' should fail gracefully");
+
+        cpix_Hits_destroy(hits);
+    }
+
+
+
+private:
+    void cleanup()
+    {
+        cpix_Analyzer_destroy(analyzer_);
+        analyzer_ = NULL;
+
+        cpix_Query_destroy(query_);
+        query_ = NULL;
+
+        delete idxUtil_;
+        idxUtil_ = NULL;
+
+        cpix_QueryParser_destroy(queryParser_);
+        queryParser_ = NULL;
+    }
+};
+
+
+Itk::TesterBase * CreateCLuceneErrorTests()
+{
+    using namespace Itk;
+
+    CLuceneErrorBugCtxt
+        * cebc = new CLuceneErrorBugCtxt;
+    ContextTester
+        * ct = new ContextTester("clerror",
+                                 cebc);
+
+    ct->add("indexGeneratedLines",
+            cebc,
+            &CLuceneErrorBugCtxt::indexGeneratedLines,
+            "indexGeneratedLines");
+    ct->add("searchCWildCard",
+            cebc,
+            &CLuceneErrorBugCtxt::searchCWildCard);
+
+    return ct;
+}
+
+
+Itk::TesterBase * CreateDestructiveTests()
+{
+    using namespace Itk;
+    
+    DestructiveTests* context = new DestructiveTests(); 
+
+    SuiteTester
+        * suiteTester = new Itk::ContextTester("destructive", context);
+
+    suiteTester->add( "stackUnwinding", 
+                    context,
+                    &DestructiveTests::testStackunwinding );
+
+#define TEST "writingWhenHitIterating"
+    suiteTester->add(TEST, 
+                     context,
+                     &DestructiveTests::testWritingWhenHitIterating,
+                     TEST);
+#undef TEST
+
+#define TEST "writingWhenHitIterating2"
+    suiteTester->add(TEST, 
+                     context,
+                     &DestructiveTests::testWritingWhenHitIterating2,
+                     TEST);
+#undef TEST
+
+    suiteTester->add("invalidation", 
+					 context,
+                     &DestructiveTests::testInvalidation,
+                     "invalidation");
+                
+    return suiteTester;
+}