1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "lix/libstore/nar-info-disk-cache.hh"

#include <gtest/gtest.h>
#include <rapidcheck/gtest.h>
#include "lix/libstore/sqlite.hh"
#include "lix/libstore/temporary-dir.hh"
#include "lix/libutil/types.hh"
#include <sqlite3.h>


namespace nix {

TEST(NarInfoDiskCacheImpl, create_and_read) {
    // This is a large single test to avoid some setup overhead.

    int prio = 12345;
    bool wantMassQuery = true;

    Path tmpDir = createTempDir();
    AutoDelete delTmpDir(tmpDir);
    Path dbPath(tmpDir + "/test-narinfo-disk-cache.sqlite");

    int savedId;
    int barId;
    SQLite db;
    SQLiteStmt getIds;

    {
        auto cache = getTestNarInfoDiskCache(dbPath);

        // Set up "background noise" and check that different caches receive different ids
        {
            auto bc1 = cache->createCache("https://bar", "/nix/storedir", wantMassQuery, prio);
            auto bc2 = cache->createCache("https://xyz", "/nix/storedir", false, 12);
            ASSERT_NE(bc1, bc2);
            barId = bc1;
        }

        // Check that the fields are saved and returned correctly. This does not test
        // the select statement yet, because of in-memory caching.
        savedId = cache->createCache("http://foo", "/nix/storedir", wantMassQuery, prio);;
        {
            auto r = cache->upToDateCacheExists("http://foo");
            ASSERT_TRUE(r);
            ASSERT_EQ(r->priority, prio);
            ASSERT_EQ(r->wantMassQuery, wantMassQuery);
            ASSERT_EQ(savedId, r->id);
        }

        // We're going to pay special attention to the id field because we had a bug
        // that changed it.
        db = SQLite(dbPath);
        getIds = db.create("select id from BinaryCaches where url = 'http://foo'");

        {
            auto q(getIds.use());
            ASSERT_TRUE(q.next());
            ASSERT_EQ(savedId, q.getInt(0));
            ASSERT_FALSE(q.next());
        }

        // Pretend that the caches are older, but keep one up to date, as "background noise"
        db.exec("update BinaryCaches set timestamp = timestamp - 1 - 7 * 24 * 3600 where url <> 'https://xyz';", always_progresses);

        // This shows that the in-memory cache works
        {
            auto r = cache->upToDateCacheExists("http://foo");
            ASSERT_TRUE(r);
            ASSERT_EQ(r->priority, prio);
            ASSERT_EQ(r->wantMassQuery, wantMassQuery);
        }
    }

    {
        // We can't clear the in-memory cache, so we use a new cache object. This is
        // more realistic anyway.
        auto cache2 = getTestNarInfoDiskCache(dbPath);

        {
            auto r = cache2->upToDateCacheExists("http://foo");
            ASSERT_FALSE(r);
        }

        // "Update", same data, check that the id number is reused
        cache2->createCache("http://foo", "/nix/storedir", wantMassQuery, prio);

        {
            auto r = cache2->upToDateCacheExists("http://foo");
            ASSERT_TRUE(r);
            ASSERT_EQ(r->priority, prio);
            ASSERT_EQ(r->wantMassQuery, wantMassQuery);
            ASSERT_EQ(r->id, savedId);
        }

        {
            auto q(getIds.use());
            ASSERT_TRUE(q.next());
            auto currentId = q.getInt(0);
            ASSERT_FALSE(q.next());
            ASSERT_EQ(currentId, savedId);
        }

        // Check that the fields can be modified, and the id remains the same
        {
            auto r0 = cache2->upToDateCacheExists("https://bar");
            ASSERT_FALSE(r0);

            cache2->createCache("https://bar", "/nix/storedir", !wantMassQuery, prio + 10);
            auto r = cache2->upToDateCacheExists("https://bar");
            ASSERT_EQ(r->wantMassQuery, !wantMassQuery);
            ASSERT_EQ(r->priority, prio + 10);
            ASSERT_EQ(r->id, barId);
        }

        // // Force update (no use case yet; we only retrieve cache metadata when stale based on timestamp)
        // {
        //     cache2->createCache("https://bar", "/nix/storedir", wantMassQuery, prio + 20);
        //     auto r = cache2->upToDateCacheExists("https://bar");
        //     ASSERT_EQ(r->wantMassQuery, wantMassQuery);
        //     ASSERT_EQ(r->priority, prio + 20);
        // }
    }
}

}