jens@0: /*
jens@0:  *  Ottoman_test.cpp
jens@0:  *  Ottoman
jens@0:  *
jens@0:  *  Created by Jens Alfke on 9/11/09.
jens@0:  *  Copyright 2009 Jens Alfke. All rights reserved.
jens@0:  *  BSD-Licensed: See the file "LICENSE.txt" for details.
jens@0:  */
jens@0: 
jens@0: #include <gtest/gtest.h>
jens@0: #include "TestUtils.h"
jens@0: #include "Chunk.h"
jens@0: #include "Ottoman.h"
jens@0: #include "VersionDictionary.h"
jens@0: #include <fcntl.h>
jens@0: #include <stdio.h>
jens@0: 
jens@0: using namespace Mooseyard;
jens@0: 
jens@0: 
jens@0: TEST(Ottoman,Build) {
jens@0:     ASSERT_EQ(8, sizeof(Chunk));
jens@0:     ASSERT_EQ(8, sizeof(KeyValueChunk));
jens@0:         
jens@0:     time_t startTime = ::time(NULL);
jens@0:     time_t createTime;
jens@0:     {
jens@0:         Ottoman otto;
jens@0:         EXPECT_EQ((void*)NULL, otto.lastVersion());
jens@0:         ASSERT_NE((void*)NULL, otto.currentVersion());
jens@0:         readWords();
jens@0:         for( int i=0; i<sNWords; i++) {
jens@0:             Blob kv(sWords[i]);
jens@0:             otto.currentVersion()->put(Key(kv),kv);
jens@0:         }
jens@0:         Timer t("Saving Ottoman", sNWords);
jens@0:         otto.saveAs("/tmp/test.ottoman");
jens@0:         
jens@0:         VersionDictionary *last = otto.lastVersion();
jens@0:         ASSERT_NE((void*)NULL, last);
jens@0:         EXPECT_EQ(sNWords, last->count());
jens@0:         ASSERT_NE((void*)NULL, otto.currentVersion());
jens@0:         EXPECT_FALSE(otto.currentVersion()->isChanged());
jens@0:         createTime = last->timestamp();
jens@0:         EXPECT_GE(createTime, startTime);
jens@0:         EXPECT_LE(createTime, ::time(NULL));
jens@0:     }
jens@0:     {
jens@0:         Ottoman otto("/tmp/test.ottoman");
jens@0:         VersionDictionary *last = otto.lastVersion();
jens@0:         ASSERT_NE((void*)NULL, last);
jens@0:         ASSERT_EQ(0, last->generation());
jens@0:         ASSERT_EQ(createTime, last->timestamp());
jens@0:         {
jens@0:             Timer t("Reading from Ottoman", sNWords);
jens@0:             EXPECT_EQ( sNWords ,  last->count() );
jens@0:             for( int i=0; i<sNWords; i++) {
jens@0:                 Key key(sWords[i]);
jens@0:                 Blob value = last->get(key);
jens@0:                 ASSERT_TRUE(value);
jens@0:                 ASSERT_TRUE( value.equals(key) ) << "expected '" << key << "', got '" << value << "' (i=" << i <<")";
jens@0:             }
jens@0:         }
jens@0:         
jens@0:         printf("Iterating through the Ottoman...\n");
jens@0:         Timer t("Iterating Ottoman", sNWords);
jens@0:         int n=0;
jens@0:         for( VersionDictionary::Iterator it(last); it; ++it) {
jens@0:             n++;
jens@0:             ASSERT_TRUE(it.key().length > 0 && it.key().length < 50);
jens@0:             ASSERT_TRUE(it.key().equals(it.value()));
jens@0:             ASSERT_EQ( 0, ((size_t)it.value().bytes & 0x3) );  // 4-byte aligned
jens@0:         }
jens@0:         ASSERT_EQ(sNWords, n);
jens@0:     }
jens@0:     {
jens@0:         printf("Opening Ottoman...\n");
jens@0:         Ottoman otto("/tmp/test.ottoman");
jens@0:         OverlayDictionary *current = otto.currentVersion();
jens@0:         ASSERT_TRUE(current != NULL);
jens@0:         EXPECT_EQ( sNWords ,  current->count() );
jens@0:         EXPECT_TRUE(current->get("asparagus").equals("asparagus"));
jens@0:         
jens@0:         current->put("animal", "AMINAL");
jens@0:         current->put("growf", "growf");
jens@0:         EXPECT_TRUE(current->remove("asparagus"));
jens@0:         
jens@0:         EXPECT_EQ( sNWords, current->count() );
jens@0:         EXPECT_TRUE(current->get("animal").equals("AMINAL"));
jens@0:         EXPECT_TRUE(current->get("growf").equals("growf"));
jens@0:         EXPECT_EQ( NULL, current->get("asparagus").bytes );
jens@0:         EXPECT_TRUE(!current->contains("asparagus"));
jens@0:         
jens@0:         int n=0;
jens@0:         for( OverlayDictionary::Iterator it(*current); it; ++it) {
jens@0:             n++;
jens@0:             ASSERT_TRUE(!it.key().equals("asparagus"));
jens@0:         }
jens@0:         ASSERT_EQ(sNWords, n);
jens@0:         
jens@0:         printf("Saving Ottoman...\n");
jens@0:         {
jens@0:             Timer t("Saving Ottoman");
jens@0:             otto.save();
jens@0:         }
jens@0:         
jens@0:         EXPECT_EQ( sNWords, current->count() );
jens@0:         EXPECT_TRUE(current->get("animal").equals("AMINAL"));
jens@0:         EXPECT_TRUE(current->get("growf").equals("growf"));
jens@0:         EXPECT_EQ( NULL, current->get("asparagus").bytes );
jens@0:         EXPECT_TRUE(!current->contains("asparagus"));
jens@0:         
jens@0:         n=0;
jens@0:         for( OverlayDictionary::Iterator it(*current); it; ++it) {
jens@0:             n++;
jens@0:             ASSERT_TRUE(!it.key().equals("asparagus"));
jens@0:         }
jens@0:         ASSERT_EQ(sNWords, n);
jens@0:         
jens@0:         EXPECT_EQ(1, otto.lastVersion()->generation());
jens@0:         const VersionDictionary *prev = otto.lastVersion()->previousVersion();
jens@0:         ASSERT_TRUE(prev != NULL);
jens@0:         EXPECT_EQ(0, prev->generation());
jens@0:         EXPECT_TRUE(prev->get("asparagus").equals("asparagus"));
jens@0:         EXPECT_TRUE(prev->get("growf").equals(NULL));
jens@0:     }
jens@0:     {
jens@0:         printf("Re-opening Ottoman...\n");
jens@0:         Ottoman otto("/tmp/test.ottoman", false);
jens@0:         ASSERT_EQ(NULL, otto.currentVersion());
jens@0:         VersionDictionary *last = otto.lastVersion();
jens@0:         ASSERT_TRUE(last != NULL);
jens@0:         EXPECT_EQ(1, last->generation());
jens@0:         EXPECT_GE(last->timestamp(), createTime);
jens@0:         EXPECT_LE(last->timestamp(), ::time(NULL));
jens@0:         EXPECT_EQ( sNWords ,  last->count() );
jens@0:         EXPECT_TRUE(last->get("animal").equals("AMINAL"));
jens@0:         EXPECT_TRUE(last->get("growf").equals("growf"));
jens@0:         EXPECT_EQ( NULL, last->get("asparagus").bytes );
jens@0:         EXPECT_TRUE(!last->contains("asparagus"));
jens@0:         
jens@0:         int n=0;
jens@0:         for( VersionDictionary::Iterator it(last); it; ++it) {
jens@0:             n++;
jens@0:             ASSERT_TRUE(!it.key().equals("asparagus"));
jens@0:         }
jens@0:         ASSERT_EQ(sNWords, n);
jens@0:     }
jens@0:     {
jens@0:         printf("Writing Ottoman to a new file...\n");
jens@0:         Ottoman oldhf("/tmp/test.ottoman");
jens@0:         
jens@0:         oldhf.saveAs("/tmp/test2.ottoman");
jens@0:     }
jens@0:     {
jens@0:         printf("Opening new file...\n");
jens@0:         Ottoman otto("/tmp/test2.ottoman");
jens@0:         OverlayDictionary *current = otto.currentVersion();
jens@0:         ASSERT_TRUE(current != NULL);
jens@0:         
jens@0:         EXPECT_EQ( sNWords ,  current->count() );
jens@0:         EXPECT_TRUE(current->get("animal").equals("AMINAL"));
jens@0:         EXPECT_TRUE(current->get("growf").equals("growf"));
jens@0:         EXPECT_EQ( NULL, current->get("asparagus").bytes );
jens@0:         EXPECT_TRUE(!current->contains("asparagus"));
jens@0:         
jens@0:         int n=0;
jens@0:         for( OverlayDictionary::Iterator it(*current); it; ++it) {
jens@0:             n++;
jens@0:             ASSERT_TRUE(!it.key().equals("asparagus"));
jens@0:         }
jens@0:         ASSERT_EQ(sNWords, n);
jens@0: 
jens@0:         printf("Iterating the chunks...\n");
jens@0:         int lastType = -1;
jens@0:         int count = 0;
jens@0:         n = 0;
jens@0:         ChunkIterator *it = otto.chunkIterator();
jens@0:         for (; *it; it->next()) {
jens@0:             uint16_t type = it->chunk()->type();
jens@0:             if (type != lastType) {
jens@0:                 if (count > 0)
jens@0:                     printf("%6d\n", count);
jens@0:                 printf("type %u ... ", type);
jens@0:                 lastType = type;
jens@0:                 count = 0;
jens@0:             }
jens@0:             count++;
jens@0:             ASSERT_LE(type, 3);
jens@0:             if (type != 0)      // don't count padding chunks
jens@0:                 n++;
jens@0:         }
jens@0:         if (count > 0)
jens@0:             printf("%6d\n", count);
jens@0:         printf("Iterated over %i chunks\n",n);
jens@0:         EXPECT_EQ(sNWords+256+1, n);
jens@0:         EXPECT_TRUE(it->atEOF());
jens@0:         
jens@0:         printf("Scavenging...\n");
jens@0:         EXPECT_TRUE( otto.scavenge() );
jens@0:     }
jens@0: }    
jens@0: