188 lines
6 KiB
Crystal
188 lines
6 KiB
Crystal
require "spec"
|
|
require "./db-cars.cr"
|
|
|
|
# NOTE: the following tests access both database and triggers' caches directly.
|
|
# It must not be done in real applications.
|
|
# `data` and `lru` properties are implementation details.
|
|
|
|
describe "SPECDB::Common" do
|
|
it "basics, 3 values" do
|
|
car0 = Car.new "Corvet-0", "red", [] of String
|
|
car1 = Car.new "Corvet-1", "red", [] of String
|
|
car2 = Car.new "Corvet-2", "red", [] of String
|
|
car3 = Car.new "Corvet-3", "red", [] of String
|
|
|
|
db = SPECDB::Common(Car).new "", 3
|
|
|
|
db.data.keys.sort.should eq([] of Int32)
|
|
|
|
db << car0
|
|
db.data.keys.sort.should eq([0] of Int32)
|
|
|
|
db << car1
|
|
db.data.keys.sort.should eq([0, 1] of Int32)
|
|
|
|
db << car2
|
|
db.data.keys.sort.should eq([0, 1, 2] of Int32)
|
|
db[0] # Let's use the first value, it shouldn't be the one to be dropped.
|
|
|
|
db << car3
|
|
db.data.keys.sort.should eq([0, 2, 3] of Int32)
|
|
db.lru.to_s.should eq "[ 3, 0, 2 ]"
|
|
|
|
db.delete 2
|
|
db.data.keys.sort.should eq([0, 3] of Int32)
|
|
db.lru.to_s.should eq "[ 3, 0 ]"
|
|
end
|
|
|
|
it "add some values, reindex, check the values" do
|
|
car0 = Car.new "Corvet-0", "red", [] of String
|
|
car1 = Car.new "Corvet-1", "red", [] of String
|
|
car2 = Car.new "Corvet-2", "red", [] of String
|
|
car3 = Car.new "Corvet-3", "red", [] of String
|
|
|
|
db = SPECDB::Common(Car).new "reindex", 2
|
|
index_name = db.new_index "name", &.name
|
|
index_color = db.new_partition "color", &.color
|
|
|
|
db.data.keys.sort.should eq([] of Int32)
|
|
|
|
db << car0
|
|
db.data.keys.sort.should eq([0] of Int32)
|
|
|
|
db << car1
|
|
db.data.keys.sort.should eq([0, 1] of Int32)
|
|
db.lru.to_s.should eq "[ 1, 0 ]"
|
|
|
|
db.data.keys.sort.should eq([0, 1] of Int32)
|
|
db.lru.to_s.should eq "[ 1, 0 ]"
|
|
|
|
db << car2
|
|
db.data.keys.sort.should eq([1, 2] of Int32)
|
|
db.lru.to_s.should eq "[ 2, 1 ]"
|
|
db[0] # Let's use the first value, it shouldn't be the one to be dropped.
|
|
|
|
db << car3
|
|
db.data.keys.sort.should eq([0, 3] of Int32)
|
|
db.lru.to_s.should eq "[ 3, 0 ]"
|
|
|
|
# Actually remove the value indexed "2".
|
|
db.delete 2
|
|
# The "delete" action actually puts the value in the cache before removing it.
|
|
db.data.keys.sort.should eq([3] of Int32)
|
|
db.lru.to_s.should eq "[ 3 ]"
|
|
|
|
# db2: further tests for the LRU behavior, with `reindex_everything!` for example.
|
|
db2 = SPECDB::Common(Car).new "reindex", 2, false
|
|
index2_name = db2.new_index "name", &.name
|
|
|
|
# For now, we didn't use any value in the database.
|
|
# Also, triggers should have empty caches.
|
|
db2.data.keys.sort.should eq([] of Int32)
|
|
db2.lru.to_s.should eq "[ ]"
|
|
index2_name.get?("Corvet-0").should eq car0
|
|
|
|
# Reindex removes all triggers (hard rm -rf trigger-dir) then reads all
|
|
# data from the file-system to run the triggers. Data is put into the cache
|
|
# of the `Common` database.
|
|
db2.reindex_everything!
|
|
|
|
# Values 1 and 3 are the last recently used values following `reindex_everything!`.
|
|
db2.data.keys.sort.should eq([1, 3] of Int32)
|
|
db2.lru.to_s.should eq "[ 3, 1 ]"
|
|
|
|
total_values = 0
|
|
db2.each_with_key do |v, k|
|
|
total_values += 1
|
|
end
|
|
total_values.should eq 3
|
|
|
|
# db3: no need for a reindex to access values from the database,
|
|
# with `each` or `each_with_key` for example.
|
|
db3 = SPECDB::Common(Car).new "reindex", 2, false
|
|
total_values = 0
|
|
db3.each do |v|
|
|
total_values += 1
|
|
end
|
|
total_values.should eq 3
|
|
|
|
# db4: no need for a reindex to access values from triggers.
|
|
db4 = SPECDB::Common(Car).new "reindex", 2, false
|
|
index4_name = db4.new_index "name", &.name
|
|
index4_color = db4.new_partition "color", &.color
|
|
|
|
index4_name.data.size.should eq 0 # trigger cache is empty
|
|
index4_name.get?("Corvet-3").should eq car3
|
|
index4_name.data.size.should eq 1 # trigger cache: one value, Corvet-3
|
|
|
|
index4_color.data.size.should eq 0 # trigger cache is empty
|
|
index4_color.get("red").size.should eq 3 # read from the disk
|
|
index4_color.data.size.should eq 1 # trigger cache: 1, the color "red"
|
|
index4_color.data["red"].size.should eq 3 # 3 values in "red"
|
|
end
|
|
|
|
it "testing caches: add some values, clear cache, check the values" do
|
|
car0 = Car.new "Corvet-0", "red", [] of String
|
|
car1 = Car.new "Corvet-1", "red", [] of String
|
|
car2 = Car.new "Corvet-2", "blue", [] of String
|
|
car3 = Car.new "Corvet-3", "violet", [] of String
|
|
|
|
db = SPECDB::Common(Car).new "reindex", 2
|
|
index_name = db.new_index "name", &.name
|
|
index_color = db.new_partition "color", &.color
|
|
|
|
db << car0
|
|
|
|
# First entry, each cache should have one item.
|
|
index_name.data.size.should eq 1
|
|
index_color.data.size.should eq 1
|
|
|
|
db << car1
|
|
db << car2
|
|
db << car3
|
|
|
|
# Storage cache should only have the maximum number of allowed entries (2).
|
|
db.data.keys.size.should eq 2
|
|
|
|
# Trigger caches don't have limits on the number of entries, therefore they should have:
|
|
# 4 entries for the name index (each entry = 1 car).
|
|
index_name.data.size.should eq 4
|
|
# 3 entries for the color index (each entry = 1 color).
|
|
index_color.data.size.should eq 3
|
|
|
|
# All cached entries are dropped.
|
|
db.clear_cache!
|
|
|
|
# Caches should be empty.
|
|
db.data.keys.sort.should eq([] of Int32)
|
|
index_name.data.size.should eq 0
|
|
index_color.data.size.should eq 0
|
|
|
|
# Get a car from stored data based on its name.
|
|
index_name.get?("Corvet-2").should eq car2
|
|
index_name.data.size.should eq 1
|
|
# This doesn't fill up the cache in the color index.
|
|
index_color.data.size.should eq 0
|
|
|
|
# Get a car from stored data based on its color.
|
|
index_color.get?("violet").size.should eq 1
|
|
|
|
# The "Storage" database should have both found items in cache.
|
|
db.data.keys.sort.should eq([2, 3] of Int32)
|
|
|
|
# Trigger caches should have a single value given that we searched a single item through each one.
|
|
index_name.data.size.should eq 1
|
|
index_color.data.size.should eq 1
|
|
|
|
# Loop over entries, filling up the cache for Storage.
|
|
total_values = 0
|
|
db.each_with_key do |v, k|
|
|
total_values += 1
|
|
end
|
|
total_values.should eq 4
|
|
|
|
# Caches should still have a single entry since we only searched through them only once.
|
|
index_name.data.size.should eq 1
|
|
index_color.data.size.should eq 1
|
|
end
|
|
end
|