242 lines
7.8 KiB
Ruby
242 lines
7.8 KiB
Ruby
# encoding: utf-8
|
|
require 'spec_helper'
|
|
|
|
describe CouchRest::Model::DesignDoc do
|
|
|
|
before :all do
|
|
reset_test_db!
|
|
end
|
|
|
|
describe "CouchRest Extension" do
|
|
|
|
it "should have created a checksum! method" do
|
|
::CouchRest::Design.new.should respond_to(:checksum!)
|
|
end
|
|
|
|
it "should calculate a consistent checksum for model" do
|
|
WithTemplateAndUniqueID.design_doc.checksum!.should eql('caa2b4c27abb82b4e37421de76d96ffc')
|
|
end
|
|
|
|
it "should calculate checksum for complex model" do
|
|
Article.design_doc.checksum!.should eql('70dff8caea143bf40fad09adf0701104')
|
|
end
|
|
|
|
it "should cache the generated checksum value" do
|
|
Article.design_doc.checksum!
|
|
Article.design_doc['couchrest-hash'].should_not be_blank
|
|
end
|
|
end
|
|
|
|
describe "class methods" do
|
|
|
|
describe ".design_doc" do
|
|
it "should provide Design document" do
|
|
Article.design_doc.should be_a(::CouchRest::Design)
|
|
end
|
|
end
|
|
|
|
describe ".design_doc_id" do
|
|
it "should provide a reasonable id" do
|
|
Article.design_doc_id.should eql("_design/Article")
|
|
end
|
|
end
|
|
|
|
describe ".design_doc_slug" do
|
|
it "should provide slug part of design doc" do
|
|
Article.design_doc_slug.should eql('Article')
|
|
end
|
|
end
|
|
|
|
describe ".design_doc_uri" do
|
|
it "should provide complete url" do
|
|
Article.design_doc_uri.should eql("#{COUCHHOST}/#{TESTDB}/_design/Article")
|
|
end
|
|
it "should provide complete url for new DB" do
|
|
db = mock("Database")
|
|
db.should_receive(:root).and_return('db')
|
|
Article.design_doc_uri(db).should eql("db/_design/Article")
|
|
end
|
|
end
|
|
|
|
describe ".stored_design_doc" do
|
|
it "should load a stored design from the database" do
|
|
Article.by_date
|
|
Article.stored_design_doc['_rev'].should_not be_blank
|
|
end
|
|
it "should return nil if not already stored" do
|
|
WithDefaultValues.stored_design_doc.should be_nil
|
|
end
|
|
end
|
|
|
|
describe ".save_design_doc" do
|
|
it "should call up the design updater" do
|
|
Article.should_receive(:update_design_doc).with('db', false)
|
|
Article.save_design_doc('db')
|
|
end
|
|
end
|
|
|
|
describe ".save_design_doc!" do
|
|
it "should call save_design_doc with force" do
|
|
Article.should_receive(:save_design_doc).with('db', true)
|
|
Article.save_design_doc!('db')
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
describe "basics" do
|
|
|
|
before :all do
|
|
reset_test_db!
|
|
end
|
|
|
|
it "should have been instantiated with views" do
|
|
d = Article.design_doc
|
|
d['views']['all']['map'].should include('Article')
|
|
end
|
|
|
|
it "should not have been saved yet" do
|
|
lambda { Article.database.get(Article.design_doc.id) }.should raise_error(RestClient::ResourceNotFound)
|
|
end
|
|
|
|
describe "after requesting a view" do
|
|
before :each do
|
|
Article.all
|
|
end
|
|
it "should have saved the design doc after view request" do
|
|
Article.database.get(Article.design_doc.id).should_not be_nil
|
|
end
|
|
end
|
|
|
|
describe "model with simple views" do
|
|
before(:all) do
|
|
Article.all.map{|a| a.destroy(true)}
|
|
Article.database.bulk_delete
|
|
written_at = Time.now - 24 * 3600 * 7
|
|
@titles = ["this and that", "also interesting", "more fun", "some junk"]
|
|
@titles.each do |title|
|
|
a = Article.new(:title => title)
|
|
a.date = written_at
|
|
a.save
|
|
written_at += 24 * 3600
|
|
end
|
|
end
|
|
|
|
it "will send request for the saved design doc on view request" do
|
|
reset_test_db!
|
|
Article.should_receive(:stored_design_doc).and_return(nil)
|
|
Article.by_date
|
|
end
|
|
|
|
it "should have generated a design doc" do
|
|
Article.design_doc["views"]["by_date"].should_not be_nil
|
|
end
|
|
it "should save the design doc when view requested" do
|
|
Article.by_date
|
|
doc = Article.database.get Article.design_doc.id
|
|
doc['views']['by_date'].should_not be_nil
|
|
end
|
|
it "should save design doc if a view changed" do
|
|
Article.by_date
|
|
orig = Article.stored_design_doc
|
|
design = Article.design_doc
|
|
view = design['views']['by_date']['map']
|
|
design['views']['by_date']['map'] = view + ' ' # little bit of white space
|
|
Article.by_date
|
|
Article.stored_design_doc['_rev'].should_not eql(orig['_rev'])
|
|
orig['views']['by_date']['map'].should_not eql(Article.design_doc['views']['by_date']['map'])
|
|
end
|
|
it "should not save design doc if not changed" do
|
|
Article.by_date
|
|
orig = Article.stored_design_doc['_rev']
|
|
Article.by_date
|
|
Article.stored_design_doc['_rev'].should eql(orig)
|
|
end
|
|
it "should recreate the design doc if database deleted" do
|
|
Article.database.recreate!
|
|
lambda { Article.by_date }.should_not raise_error(RestClient::ResourceNotFound)
|
|
end
|
|
end
|
|
|
|
describe "when auto_update_design_doc false" do
|
|
# We really do need a new class for each of example. If we try
|
|
# to use the same class the examples interact with each in ways
|
|
# that can hide failures because the design document gets cached
|
|
# at the class level.
|
|
let(:model_class) {
|
|
class_name = "#{example.metadata[:full_description].gsub(/\s+/,'_').camelize}Model"
|
|
doc = CouchRest::Document.new("_id" => "_design/#{class_name}")
|
|
doc["language"] = "javascript"
|
|
doc["views"] = {"all" => {"map" =>
|
|
"function(doc) {
|
|
if (doc['type'] == 'Article') {
|
|
emit(doc['_id'],1);
|
|
}
|
|
}"},
|
|
"by_name" => {"map" =>
|
|
"function(doc) {
|
|
if ((doc['type'] == '#{class_name}') && (doc['name'] != null)) {
|
|
emit(doc['name'], null);
|
|
}",
|
|
"reduce" =>
|
|
"function(keys, values, rereduce) {
|
|
return sum(values);
|
|
}"}}
|
|
|
|
DB.save_doc doc
|
|
|
|
eval <<-KLASS
|
|
class ::#{class_name} < CouchRest::Model::Base
|
|
use_database DB
|
|
self.auto_update_design_doc = false
|
|
design do
|
|
view :by_name
|
|
end
|
|
property :name, String
|
|
end
|
|
KLASS
|
|
|
|
class_name.constantize
|
|
}
|
|
|
|
it "will not update stored design doc if view changed" do
|
|
model_class.by_name
|
|
orig = model_class.stored_design_doc
|
|
design = model_class.design_doc
|
|
view = design['views']['by_name']['map']
|
|
design['views']['by_name']['map'] = view + ' '
|
|
model_class.by_name
|
|
model_class.stored_design_doc['_rev'].should eql(orig['_rev'])
|
|
end
|
|
|
|
it "will update stored design if forced" do
|
|
model_class.by_name
|
|
orig = model_class.stored_design_doc
|
|
design = model_class.design_doc
|
|
view = design['views']['by_name']['map']
|
|
design['views']['by_name']['map'] = view + ' '
|
|
model_class.save_design_doc!
|
|
model_class.stored_design_doc['_rev'].should_not eql(orig['_rev'])
|
|
end
|
|
|
|
it "is able to use predefined views" do
|
|
model_class.by_name(key: "special").all
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "lazily refreshing the design document" do
|
|
before(:all) do
|
|
@db = reset_test_db!
|
|
WithTemplateAndUniqueID.new('slug' => '1').save
|
|
end
|
|
it "should not save the design doc twice" do
|
|
WithTemplateAndUniqueID.all
|
|
rev = WithTemplateAndUniqueID.design_doc['_rev']
|
|
WithTemplateAndUniqueID.design_doc['_rev'].should eql(rev)
|
|
end
|
|
end
|
|
|
|
|
|
end
|