test/VersionDictionary_test.cpp
changeset 0 31a43d94cc26
child 8 21a6c17f4e3e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/test/VersionDictionary_test.cpp	Sun Sep 20 15:14:12 2009 -0700
     1.3 @@ -0,0 +1,265 @@
     1.4 +/*
     1.5 + *  VersionDictionary_test.cpp
     1.6 + *  Ottoman
     1.7 + *
     1.8 + *  Created by Jens Alfke on 9/2/09.
     1.9 + *  Copyright 2009 Jens Alfke. All rights reserved.
    1.10 + *  BSD-Licensed: See the file "LICENSE.txt" for details.
    1.11 + */
    1.12 +
    1.13 +
    1.14 +#define VERSIONDICTIONARY_TESTING 1
    1.15 +
    1.16 +#include <gtest/gtest.h>
    1.17 +#include "TestUtils.h"
    1.18 +#include "Chunk.h"
    1.19 +#include "File.h"
    1.20 +#include "VersionDictionary.h"
    1.21 +#include "Hash.h"
    1.22 +#include <fcntl.h>
    1.23 +#include <stdio.h>
    1.24 +
    1.25 +using namespace Mooseyard;
    1.26 +
    1.27 +
    1.28 +class OverlayVersionDictionary :public OverlayDictionary {
    1.29 +public:
    1.30 +    OverlayVersionDictionary (File *file)
    1.31 +    :OverlayDictionary(new VersionDictionary(file))
    1.32 +    { }  
    1.33 +    
    1.34 +    int generation() const                  {return ((VersionDictionary*)base())->generation();}
    1.35 +    time_t timestamp() const                {return ((VersionDictionary*)base())->timestamp();}
    1.36 +
    1.37 +    void save(){
    1.38 +        saveAs(((VersionDictionary*)base())->file());
    1.39 +    }
    1.40 +    
    1.41 +    void saveAs (File *dstFile) {
    1.42 +        VersionDictionary* oldBase = (VersionDictionary*) base();
    1.43 +        revertTo( ((VersionDictionary*)base())->_appendAndOpen(overlay(), dstFile, baseReplaced()) );
    1.44 +        delete oldBase;
    1.45 +    }
    1.46 +};
    1.47 +
    1.48 +
    1.49 +
    1.50 +TEST(File,HasPath) {
    1.51 +    {
    1.52 +        File f("/tmp/jubba", O_RDWR | O_CREAT | O_TRUNC);
    1.53 +        f.write("howdy");
    1.54 +    }
    1.55 +    {
    1.56 +        File f("/tmp/jubba", O_RDWR);
    1.57 +        EXPECT_TRUE(f.hasPath("/tmp/jubba"));
    1.58 +        File::unlink("/tmp/jubba");
    1.59 +        EXPECT_FALSE(f.hasPath("/tmp/jubba"));
    1.60 +        
    1.61 +        File f2("/tmp/jubba", O_RDWR | O_CREAT | O_TRUNC);
    1.62 +        f2.write("howdy");
    1.63 +        f2.flush();
    1.64 +
    1.65 +        EXPECT_FALSE(f.hasPath("/tmp/jubba"));
    1.66 +        EXPECT_TRUE(f2.hasPath("/tmp/jubba"));
    1.67 +    }
    1.68 +    File::unlink("/tmp/jubba");
    1.69 +}
    1.70 +
    1.71 +
    1.72 +static int TestIterate (File *file) {
    1.73 +    printf("Iterating the chunks...\n");
    1.74 +    int lastType = -1;
    1.75 +    int count = 0;
    1.76 +    int n = 0;
    1.77 +    ChunkIterator it(file, 4);
    1.78 +    for (; it; ++it) {
    1.79 +        uint16_t type = it.chunk()->type();
    1.80 +        if (type != lastType) {
    1.81 +            if (count > 0)
    1.82 +                printf("%6d\n", count);
    1.83 +            printf("type %u ... ", type);
    1.84 +            lastType = type;
    1.85 +            count = 0;
    1.86 +        }
    1.87 +        count++;
    1.88 +        EXPECT_LE(type, 3);
    1.89 +        if (type != 0)      // don't count padding chunks
    1.90 +            n++;
    1.91 +    }
    1.92 +    if (count > 0)
    1.93 +        printf("%6d\n", count);
    1.94 +    EXPECT_TRUE(it.atEOF());
    1.95 +    return n;
    1.96 +}    
    1.97 +
    1.98 +
    1.99 +static void TestWithWords (const int nWords) {
   1.100 +    ASSERT_EQ(8, sizeof(Chunk));
   1.101 +    ASSERT_EQ(8, sizeof(KeyValueChunk));
   1.102 +    
   1.103 +    printf("Building dictionary of %i words...\n", nWords);
   1.104 +    readWords();
   1.105 +    HashDictionary dict;
   1.106 +    for( int i=0; i<nWords; i++) {
   1.107 +        Blob kv(sWords[i]);
   1.108 +        dict.put(Key(kv),kv);
   1.109 +    }
   1.110 +    
   1.111 +    time_t startTime = ::time(NULL);
   1.112 +    time_t createTime;
   1.113 +    {
   1.114 +        File file("/tmp/hashfiletest", O_RDWR | O_CREAT | O_TRUNC);
   1.115 +        VersionDictionary *hf;
   1.116 +        {
   1.117 +            Timer t("Creating & writing VersionDictionary", nWords);
   1.118 +            file.write("Ha5h", 4);     // VersionDictionary won't write to an empty file
   1.119 +            hf = VersionDictionary::create(&file, &dict);
   1.120 +        }
   1.121 +        printf("File size: %llu bytes\n", file.length());
   1.122 +        ASSERT_TRUE(hf!=NULL);
   1.123 +        ASSERT_EQ(0, hf->generation());
   1.124 +        createTime = hf->timestamp();
   1.125 +        ASSERT_GE(createTime, startTime);
   1.126 +        ASSERT_LE(createTime, ::time(NULL));
   1.127 +        delete hf;
   1.128 +    }
   1.129 +    {
   1.130 +        File file("/tmp/hashfiletest");
   1.131 +        VersionDictionary hf(&file);
   1.132 +        ASSERT_EQ(0, hf.generation());
   1.133 +        ASSERT_EQ(createTime, hf.timestamp());
   1.134 +        {
   1.135 +            Timer t("Reading from VersionDictionary", nWords);
   1.136 +            EXPECT_EQ( nWords ,  hf.count() );
   1.137 +            for( int i=0; i<nWords; i++) {
   1.138 +                Key key(sWords[i]);
   1.139 +                Blob value = hf.get(key);
   1.140 +                ASSERT_TRUE(value);
   1.141 +                ASSERT_TRUE( value.equals(key) ) << "expected '" << key << "', got '" << value << "' (i=" << i <<")";
   1.142 +            }
   1.143 +        }
   1.144 +        
   1.145 +        printf("Iterating through the VersionDictionary...\n");
   1.146 +        Timer t("Iterating VersionDictionary", nWords);
   1.147 +        int n=0;
   1.148 +        for( VersionDictionary::Iterator it(&hf); it; ++it) {
   1.149 +            n++;
   1.150 +            ASSERT_TRUE(it.key().length > 0 && it.key().length < 50);
   1.151 +            ASSERT_TRUE(it.key().equals(it.value()));
   1.152 +            ASSERT_EQ( 0, ((size_t)it.value().bytes & 0x3) );  // 4-byte aligned
   1.153 +        }
   1.154 +        ASSERT_EQ(nWords, n);
   1.155 +    }
   1.156 +    {
   1.157 +        printf("Opening OverlayVersionDictionary...\n");
   1.158 +        File file("/tmp/hashfiletest", O_RDWR);
   1.159 +        OverlayVersionDictionary hf(&file);
   1.160 +        EXPECT_EQ( nWords ,  hf.count() );
   1.161 +        EXPECT_TRUE(hf.get("abatement").equals("abatement"));
   1.162 +        
   1.163 +        hf.put("abaser", "DEBASER");
   1.164 +        hf.put("growf", "growf");
   1.165 +        EXPECT_TRUE(hf.remove("abatement"));
   1.166 +        
   1.167 +        EXPECT_EQ( nWords, hf.count() );
   1.168 +        EXPECT_TRUE(hf.get("abaser").equals("DEBASER"));
   1.169 +        EXPECT_TRUE(hf.get("growf").equals("growf"));
   1.170 +        EXPECT_EQ( NULL, hf.get("abatement").bytes );
   1.171 +        EXPECT_TRUE(!hf.contains("abatement"));
   1.172 +        
   1.173 +        int n=0;
   1.174 +        for( OverlayVersionDictionary::Iterator it(hf); it; ++it) {
   1.175 +            n++;
   1.176 +            ASSERT_TRUE(!it.key().equals("abatement"));
   1.177 +        }
   1.178 +        ASSERT_EQ(nWords, n);
   1.179 +        
   1.180 +        printf("Saving OverlayVersionDictionary...\n");
   1.181 +        {
   1.182 +            Timer t("Saving OverlayVersionDictionary");
   1.183 +            hf.save();
   1.184 +        }
   1.185 +        printf("File size: %llu bytes\n", file.length());
   1.186 +        
   1.187 +        EXPECT_EQ( nWords, hf.count() );
   1.188 +        EXPECT_TRUE(hf.get("abaser").equals("DEBASER"));
   1.189 +        EXPECT_TRUE(hf.get("growf").equals("growf"));
   1.190 +        EXPECT_EQ( NULL, hf.get("abatement").bytes );
   1.191 +        EXPECT_TRUE(!hf.contains("abatement"));
   1.192 +        
   1.193 +        n=0;
   1.194 +        for( OverlayVersionDictionary::Iterator it(hf); it; ++it) {
   1.195 +            n++;
   1.196 +            ASSERT_TRUE(!it.key().equals("abatement"));
   1.197 +        }
   1.198 +        ASSERT_EQ(nWords, n);
   1.199 +    }
   1.200 +    {
   1.201 +        printf("Re-opening OverlayVersionDictionary...\n");
   1.202 +        File file("/tmp/hashfiletest");
   1.203 +        OverlayVersionDictionary hf(&file);
   1.204 +        
   1.205 +        ASSERT_EQ(1, hf.generation());
   1.206 +        ASSERT_GE(hf.timestamp(), createTime);
   1.207 +        ASSERT_LE(hf.timestamp(), ::time(NULL));
   1.208 +        EXPECT_EQ( nWords ,  hf.count() );
   1.209 +        EXPECT_TRUE(hf.get("abaser").equals("DEBASER"));
   1.210 +        EXPECT_TRUE(hf.get("growf").equals("growf"));
   1.211 +        EXPECT_EQ( NULL, hf.get("abatement").bytes );
   1.212 +        EXPECT_TRUE(!hf.contains("abatement"));
   1.213 +        
   1.214 +        int n=0;
   1.215 +        for( OverlayVersionDictionary::Iterator it(hf); it; ++it) {
   1.216 +            n++;
   1.217 +            ASSERT_TRUE(!it.key().equals("abatement"));
   1.218 +        }
   1.219 +        ASSERT_EQ(nWords, n);
   1.220 +
   1.221 +        n = TestIterate(&file);
   1.222 +        EXPECT_GE(n, nWords+1+4);
   1.223 +        if (nWords > 1000)
   1.224 +            EXPECT_GE(n, nWords+256+4);
   1.225 +    }
   1.226 +    {
   1.227 +        printf("Writing VersionDictionary to a new file...\n");
   1.228 +        File oldFile("/tmp/hashfiletest");
   1.229 +        OverlayVersionDictionary oldhf(&oldFile);
   1.230 +        
   1.231 +        File newFile("/tmp/hashfiletest2", O_RDWR | O_CREAT | O_TRUNC);
   1.232 +        newFile.write("Ha5h", 4);     // VersionDictionary won't write to an empty file
   1.233 +        oldhf.saveAs(&newFile);
   1.234 +        printf("File size: %llu bytes\n", newFile.length());
   1.235 +    }
   1.236 +    {
   1.237 +        printf("Opening new file...\n");
   1.238 +        File file("/tmp/hashfiletest2");
   1.239 +        OverlayVersionDictionary hf(&file);
   1.240 +        
   1.241 +        EXPECT_EQ( nWords ,  hf.count() );
   1.242 +        EXPECT_TRUE(hf.get("abaser").equals("DEBASER"));
   1.243 +        EXPECT_TRUE(hf.get("growf").equals("growf"));
   1.244 +        EXPECT_EQ( NULL, hf.get("abatement").bytes );
   1.245 +        EXPECT_TRUE(!hf.contains("abatement"));
   1.246 +        
   1.247 +        int n=0;
   1.248 +        for( OverlayVersionDictionary::Iterator it(hf); it; ++it) {
   1.249 +            n++;
   1.250 +            ASSERT_TRUE(!it.key().equals("abatement"));
   1.251 +        }
   1.252 +        ASSERT_EQ(nWords, n);
   1.253 +        
   1.254 +        n = TestIterate(&file);
   1.255 +        EXPECT_GE(n, nWords+1+1);
   1.256 +        if (nWords > 1000)
   1.257 +            EXPECT_EQ(nWords+256+1, n);
   1.258 +    }
   1.259 +}    
   1.260 +
   1.261 +
   1.262 +TEST(VersionDictionary,BuildSmall) {
   1.263 +    TestWithWords(100);
   1.264 +}
   1.265 +
   1.266 +TEST(VersionDictionary,BuildLarge) {
   1.267 +    TestWithWords(sNWords);
   1.268 +}