massive_record 0.2.0 → 0.2.1.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. data/CHANGELOG.md +43 -4
  2. data/Gemfile.lock +3 -1
  3. data/README.md +5 -0
  4. data/lib/massive_record/adapters/thrift/connection.rb +23 -16
  5. data/lib/massive_record/adapters/thrift/row.rb +13 -33
  6. data/lib/massive_record/adapters/thrift/table.rb +24 -10
  7. data/lib/massive_record/orm/attribute_methods.rb +27 -1
  8. data/lib/massive_record/orm/attribute_methods/dirty.rb +2 -2
  9. data/lib/massive_record/orm/attribute_methods/read.rb +36 -1
  10. data/lib/massive_record/orm/attribute_methods/time_zone_conversion.rb +81 -0
  11. data/lib/massive_record/orm/attribute_methods/write.rb +18 -0
  12. data/lib/massive_record/orm/base.rb +52 -10
  13. data/lib/massive_record/orm/callbacks.rb +1 -1
  14. data/lib/massive_record/orm/default_id.rb +20 -0
  15. data/lib/massive_record/orm/errors.rb +4 -0
  16. data/lib/massive_record/orm/finders.rb +102 -57
  17. data/lib/massive_record/orm/finders/rescue_missing_table_on_find.rb +45 -0
  18. data/lib/massive_record/orm/id_factory.rb +1 -1
  19. data/lib/massive_record/orm/log_subscriber.rb +85 -0
  20. data/lib/massive_record/orm/persistence.rb +82 -37
  21. data/lib/massive_record/orm/query_instrumentation.rb +64 -0
  22. data/lib/massive_record/orm/relations/interface.rb +10 -0
  23. data/lib/massive_record/orm/relations/metadata.rb +2 -0
  24. data/lib/massive_record/orm/relations/proxy/references_one_polymorphic.rb +1 -1
  25. data/lib/massive_record/orm/schema/field.rb +33 -6
  26. data/lib/massive_record/orm/timestamps.rb +1 -1
  27. data/lib/massive_record/orm/validations.rb +2 -2
  28. data/lib/massive_record/rails/controller_runtime.rb +55 -0
  29. data/lib/massive_record/rails/railtie.rb +16 -0
  30. data/lib/massive_record/version.rb +1 -1
  31. data/lib/massive_record/wrapper/cell.rb +32 -3
  32. data/massive_record.gemspec +1 -0
  33. data/spec/{wrapper/cases → adapter/thrift}/adapter_spec.rb +0 -0
  34. data/spec/adapter/thrift/atomic_increment_spec.rb +55 -0
  35. data/spec/{wrapper/cases → adapter/thrift}/connection_spec.rb +0 -10
  36. data/spec/adapter/thrift/table_find_spec.rb +40 -0
  37. data/spec/{wrapper/cases → adapter/thrift}/table_spec.rb +55 -13
  38. data/spec/orm/cases/attribute_methods_spec.rb +6 -1
  39. data/spec/orm/cases/base_spec.rb +18 -4
  40. data/spec/orm/cases/callbacks_spec.rb +1 -1
  41. data/spec/orm/cases/default_id_spec.rb +38 -0
  42. data/spec/orm/cases/default_values_spec.rb +37 -0
  43. data/spec/orm/cases/dirty_spec.rb +25 -1
  44. data/spec/orm/cases/encoding_spec.rb +3 -3
  45. data/spec/orm/cases/finder_default_scope.rb +8 -1
  46. data/spec/orm/cases/finder_scope_spec.rb +2 -2
  47. data/spec/orm/cases/finders_spec.rb +8 -18
  48. data/spec/orm/cases/id_factory_spec.rb +38 -21
  49. data/spec/orm/cases/log_subscriber_spec.rb +133 -0
  50. data/spec/orm/cases/mass_assignment_security_spec.rb +97 -0
  51. data/spec/orm/cases/persistence_spec.rb +132 -27
  52. data/spec/orm/cases/single_table_inheritance_spec.rb +2 -2
  53. data/spec/orm/cases/time_zone_awareness_spec.rb +157 -0
  54. data/spec/orm/cases/timestamps_spec.rb +15 -0
  55. data/spec/orm/cases/validation_spec.rb +2 -2
  56. data/spec/orm/models/model_without_default_id.rb +5 -0
  57. data/spec/orm/models/person.rb +1 -0
  58. data/spec/orm/models/test_class.rb +1 -0
  59. data/spec/orm/relations/interface_spec.rb +2 -2
  60. data/spec/orm/relations/metadata_spec.rb +1 -1
  61. data/spec/orm/relations/proxy/references_many_spec.rb +21 -15
  62. data/spec/orm/relations/proxy/references_one_polymorphic_spec.rb +7 -1
  63. data/spec/orm/relations/proxy/references_one_spec.rb +7 -0
  64. data/spec/orm/schema/field_spec.rb +61 -5
  65. data/spec/support/connection_helpers.rb +2 -1
  66. data/spec/support/mock_massive_record_connection.rb +7 -0
  67. data/spec/support/time_zone_helper.rb +25 -0
  68. metadata +51 -14
@@ -175,7 +175,7 @@ describe MassiveRecord::ORM::Base do
175
175
  end
176
176
 
177
177
  it "should return the id if persisted" do
178
- TestClass.create!(:id => 1).to_param.should == "1"
178
+ TestClass.create!(1).to_param.should == "1"
179
179
  end
180
180
  end
181
181
 
@@ -185,7 +185,7 @@ describe MassiveRecord::ORM::Base do
185
185
  end
186
186
 
187
187
  it "should return id in an array persisted" do
188
- TestClass.create!(:id => "1").to_key.should == ["1"]
188
+ TestClass.create!("1").to_key.should == ["1"]
189
189
  end
190
190
  end
191
191
 
@@ -215,7 +215,7 @@ describe MassiveRecord::ORM::Base do
215
215
 
216
216
  it "should start with the record's id if it has any" do
217
217
  @person.id = 3
218
- @person.inspect.should include "#<Person id: 3,"
218
+ @person.inspect.should include '#<Person id: "3",'
219
219
  end
220
220
 
221
221
  it "should start with the record's id if it has any" do
@@ -286,7 +286,7 @@ describe MassiveRecord::ORM::Base do
286
286
 
287
287
  describe "#clone" do
288
288
  before do
289
- @test_object = TestClass.create!(:id => "1", :foo => 'bar')
289
+ @test_object = TestClass.create!("1", :foo => 'bar')
290
290
  @clone_object = @test_object.clone
291
291
  end
292
292
 
@@ -313,4 +313,18 @@ describe MassiveRecord::ORM::Base do
313
313
  Person.coder.should be_instance_of MassiveRecord::ORM::Coders::JSON
314
314
  end
315
315
  end
316
+
317
+ describe "id as first argument to" do
318
+ [:new, :create, :create!].each do |creation_method|
319
+ describe creation_method do
320
+ it "sets first argument as records id" do
321
+ TestClass.send(creation_method, "idfirstarg").id.should == "idfirstarg"
322
+ end
323
+
324
+ it "sets first argument as record id, hash as it's attribute" do
325
+ TestClass.send(creation_method, "idfirstarg", foo: 'works').foo.should == 'works'
326
+ end
327
+ end
328
+ end
329
+ end
316
330
  end
@@ -175,7 +175,7 @@ describe "callbacks for" do
175
175
  end
176
176
 
177
177
  it "create should run in correct order" do
178
- thorbjorn = CallbackDeveloper.create :id => "dummy"
178
+ thorbjorn = CallbackDeveloper.create "dummy"
179
179
  thorbjorn.history.should == [
180
180
  [:after_initialize, :method],
181
181
  [:after_initialize, :string],
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'orm/models/model_without_default_id'
3
+
4
+ describe ModelWithoutDefaultId do
5
+ include MockMassiveRecordConnection
6
+ #include SetUpHbaseConnectionBeforeAll
7
+ #include SetTableNamesToTestTable
8
+
9
+ context "with auto increment id" do
10
+ its(:id) { be_nil }
11
+ its(:auto_increment_id) { be_true }
12
+
13
+ it "sets id to what next_id returns" do
14
+ subject.should_receive(:next_id).and_return 1
15
+ subject.save
16
+ subject.id.should eq "1"
17
+ end
18
+
19
+ it "does nothing if the id is set before create" do
20
+ subject.id = 2
21
+ subject.should_not_receive(:next_id)
22
+ subject.save
23
+ subject.id.should eq "2"
24
+ end
25
+ end
26
+
27
+ context "without auto increment id" do
28
+ before(:all) { subject.class.auto_increment_id = false }
29
+ after(:all) { subject.class.auto_increment_id = true }
30
+
31
+ its(:id) { be_nil }
32
+ its(:auto_increment_id) { be_false }
33
+
34
+ it "raises error as expected when id is missing" do
35
+ expect { subject.save }.to raise_error MassiveRecord::ORM::IdMissing
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe "default values" do
4
+ include SetUpHbaseConnectionBeforeAll
5
+ include SetTableNamesToTestTable
6
+
7
+ subject do
8
+ Person.new("id", {
9
+ :name => "Thorbjorn",
10
+ :age => 22,
11
+ :points => 1
12
+ })
13
+ end
14
+
15
+ context "new record" do
16
+ its(:addresses) { should eq Hash.new }
17
+ its(:points) { should eq 1 }
18
+ its(:status) { should eq false }
19
+ its(:phone_numbers) { should eq [] }
20
+ end
21
+
22
+ context "persisted record" do
23
+ before do
24
+ subject.addresses = nil
25
+ subject.points = nil
26
+ subject.status = nil
27
+ subject.phone_numbers = nil
28
+ subject.save!
29
+ subject.reload
30
+ end
31
+
32
+ its(:addresses) { should be_nil }
33
+ its(:points) { should be_nil }
34
+ its(:status) { should be_nil }
35
+ its(:phone_numbers) { should eq [] }
36
+ end
37
+ end
@@ -5,7 +5,7 @@ describe "dirty" do
5
5
  include MockMassiveRecordConnection
6
6
 
7
7
  before do
8
- @person = Person.new :id => 1, :name => "Alice", :age => 20, :email => "foo@bar.com"
8
+ @person = Person.new '1', :name => "Alice", :age => 20, :email => "foo@bar.com"
9
9
  end
10
10
 
11
11
  it "should not be changed after created" do
@@ -22,6 +22,30 @@ describe "dirty" do
22
22
  @person.should be_changed
23
23
  end
24
24
 
25
+ it "should notice changes in boolean values from false to true" do
26
+ @person.status = !@person.status
27
+ @person.should be_status_changed
28
+ end
29
+
30
+ it "should notice changes in boolean values from true to false" do
31
+ @person.status = true
32
+ @person.save
33
+ @person.status = false
34
+ @person.should be_status_changed
35
+ end
36
+
37
+ it "should not consider age set as string to the same as integer a change" do
38
+ @person.age = "20"
39
+ @person.should_not be_age_changed
40
+ end
41
+
42
+ it "should not consider age set as string back to original value a change" do
43
+ @person.age = 30
44
+ @person.age = "20"
45
+ @person.should_not be_age_changed
46
+ end
47
+
48
+
25
49
  it "should know when a attribute is set to it's original value" do
26
50
  original_name = @person.name
27
51
  @person.name = "Bob"
@@ -9,7 +9,7 @@ describe "encoding" do
9
9
  include SetTableNamesToTestTable
10
10
 
11
11
  before do
12
- @person = Person.create! :id => "new_id", :name => "Thorbjørn", :age => "22"
12
+ @person = Person.create! "new_id", :name => "Thorbjørn", :age => "22"
13
13
  @person_from_db = Person.find(@person.id)
14
14
  end
15
15
 
@@ -39,11 +39,11 @@ describe "encoding" do
39
39
  end
40
40
 
41
41
  it "should be able to store UTF-8 encoded strings" do
42
- @row_from_db.values["info:name"].should == "Thorbjørn"
42
+ @row_from_db.values["info:name"].force_encoding(Encoding::UTF_8).should == "Thorbjørn"
43
43
  end
44
44
 
45
45
  it "should return string as UTF-8 encoded strings" do
46
- @row_from_db.values["info:name"].encoding.should == Encoding::UTF_8
46
+ @row_from_db.values["info:name"].encoding.should == Encoding::BINARY
47
47
  end
48
48
  end
49
49
  end
@@ -1,12 +1,13 @@
1
1
  require 'spec_helper'
2
2
  require 'orm/models/person'
3
+ require 'orm/models/test_class'
3
4
 
4
5
  describe "Default scope in" do
5
6
  include SetUpHbaseConnectionBeforeAll
6
7
  include SetTableNamesToTestTable
7
8
 
8
9
  describe Person do
9
- let(:subject) { Person.new :id => "ID1", :name => "Person1", :email => "one@person.com", :age => 11, :points => 111, :status => true }
10
+ let(:subject) { Person.new "ID1", :name => "Person1", :email => "one@person.com", :age => 11, :points => 111, :status => true }
10
11
 
11
12
  before do
12
13
  subject.save!
@@ -49,5 +50,11 @@ describe "Default scope in" do
49
50
  person.points.should == 111
50
51
  person.name.should be_nil
51
52
  end
53
+
54
+ it "should not share scopes between classes" do
55
+ Person.class_eval { default_scope :select => :base }
56
+ Person.default_scoping.should be_instance_of MassiveRecord::ORM::Finders::Scope
57
+ TestClass.default_scoping.should be_nil
58
+ end
52
59
  end
53
60
  end
@@ -217,8 +217,8 @@ describe MassiveRecord::ORM::Finders::Scope do
217
217
  include SetTableNamesToTestTable
218
218
 
219
219
  describe "with a person" do
220
- let(:person_1) { Person.create :id => "ID1", :name => "Person1", :email => "one@person.com", :age => 11, :points => 111, :status => true }
221
- let(:person_2) { Person.create :id => "ID2", :name => "Person2", :email => "two@person.com", :age => 22, :points => 222, :status => false }
220
+ let(:person_1) { Person.create "ID1", :name => "Person1", :email => "one@person.com", :age => 11, :points => 111, :status => true }
221
+ let(:person_2) { Person.create "ID2", :name => "Person2", :email => "two@person.com", :age => 22, :points => 222, :status => false }
222
222
 
223
223
  before do
224
224
  person_1.save!
@@ -23,21 +23,6 @@ describe "finders" do
23
23
  lambda { Person.find }.should raise_error ArgumentError
24
24
  end
25
25
 
26
- it "should simply return nil on first if table does not exists" do
27
- Person.table.should_receive(:exists?).and_return false
28
- Person.first.should be_nil
29
- end
30
-
31
- it "should raise record not found error on find if table does not exists" do
32
- Person.table.should_receive(:exists?).and_return false
33
- lambda { Person.find(1) }.should raise_error MassiveRecord::ORM::RecordNotFound
34
- end
35
-
36
- it "should simply return empty array if table does not exists" do
37
- Person.table.should_receive(:exists?).and_return false
38
- Person.all.should == []
39
- end
40
-
41
26
  it "should raise RecordNotFound if id is nil" do
42
27
  lambda { Person.find(nil) }.should raise_error MassiveRecord::ORM::RecordNotFound
43
28
  end
@@ -164,10 +149,15 @@ describe "finders" do
164
149
  @bob = Person.find("ID2")
165
150
  end
166
151
 
167
- it "should return nil if id is not found" do
152
+ it "should raise record not found error" do
168
153
  lambda { Person.find("not_found") }.should raise_error MassiveRecord::ORM::RecordNotFound
169
154
  end
170
155
 
156
+ it "should raise MassiveRecord::ORM::RecordNotFound error if table does not exist" do
157
+ Person.table.destroy
158
+ expect { Person.find("id") }.to raise_error MassiveRecord::ORM::RecordNotFound
159
+ end
160
+
171
161
  it "should return the person object when found" do
172
162
  @person.name.should == "John Doe"
173
163
  @person.email.should == "john@base.com"
@@ -185,7 +175,7 @@ describe "finders" do
185
175
  end
186
176
 
187
177
  it "should find all persons, even if it is more than 10" do
188
- 15.times { |i| Person.create! :id => "id-#{i}", :name => "Going to die :-(", :age => i + 20 }
178
+ 15.times { |i| Person.create! "id-#{i}", :name => "Going to die :-(", :age => i + 20 }
189
179
  Person.all.length.should > 10
190
180
  end
191
181
 
@@ -214,7 +204,7 @@ describe "finders" do
214
204
  end
215
205
 
216
206
  it "should not do a thing if table does not exist" do
217
- Person.table.should_receive(:exists?).and_return false
207
+ Person.table.destroy
218
208
 
219
209
  counter = 0
220
210
 
@@ -2,6 +2,8 @@ require 'spec_helper'
2
2
  require 'orm/models/person'
3
3
 
4
4
  describe "id factory" do
5
+ subject { MassiveRecord::ORM::IdFactory.instance }
6
+
5
7
  it "should be a singleton" do
6
8
  MassiveRecord::ORM::IdFactory.included_modules.should include(Singleton)
7
9
  end
@@ -10,32 +12,28 @@ describe "id factory" do
10
12
  describe "dry" do
11
13
  include MockMassiveRecordConnection
12
14
 
13
- before do
14
- @factory = MassiveRecord::ORM::IdFactory.instance
15
- end
16
-
17
15
  it "should respond to next_for" do
18
- @factory.should respond_to :next_for
16
+ subject.should respond_to :next_for
19
17
  end
20
18
 
21
19
  it "should use incomming table name if it's a string" do
22
- @factory.should_receive(:next_id).with(hash_including(:table => "test_table"))
23
- @factory.next_for "test_table"
20
+ subject.should_receive(:next_id).with(hash_including(:table => "test_table"))
21
+ subject.next_for "test_table"
24
22
  end
25
23
 
26
24
  it "should use incomming table name if it's a symbol" do
27
- @factory.should_receive(:next_id).with(hash_including(:table => "test_table"))
28
- @factory.next_for :test_table
25
+ subject.should_receive(:next_id).with(hash_including(:table => "test_table"))
26
+ subject.next_for :test_table
29
27
  end
30
28
 
31
29
  it "should ask object for it's table name if it responds to that" do
32
30
  Person.should_receive(:table_name).and_return("people")
33
- @factory.should_receive(:next_id).with(hash_including(:table => "people"))
34
- @factory.next_for(Person)
31
+ subject.should_receive(:next_id).with(hash_including(:table => "people"))
32
+ subject.next_for(Person)
35
33
  end
36
34
 
37
35
  it "should have class method next_for and delegate it to it's instance" do
38
- @factory.should_receive(:next_for).with("cars")
36
+ subject.should_receive(:next_for).with("cars")
39
37
  MassiveRecord::ORM::IdFactory.next_for("cars")
40
38
  end
41
39
  end
@@ -46,29 +44,48 @@ describe "id factory" do
46
44
  include SetUpHbaseConnectionBeforeAll
47
45
  include SetTableNamesToTestTable
48
46
 
49
- before do
50
- @factory = MassiveRecord::ORM::IdFactory.instance
51
- end
52
-
53
47
  after do
54
48
  MassiveRecord::ORM::IdFactory.destroy_all
55
- MassiveRecord::ORM::IdFactory.instance_variable_set(:@instance, nil)
56
49
  end
57
50
 
58
51
  it "should increment start a new sequence on 1" do
59
- @factory.next_for(Person).should == 1
52
+ subject.next_for(Person).should == 1
60
53
  end
61
54
 
62
55
  it "should increment value one by one" do
63
56
  5.times do |index|
64
57
  expected_id = index + 1
65
- @factory.next_for(Person).should == expected_id
58
+ subject.next_for(Person).should == expected_id
66
59
  end
67
60
  end
68
61
 
69
62
  it "should maintain ids separate for each table" do
70
- 3.times { @factory.next_for(Person) }
71
- @factory.next_for("cars").should == 1
63
+ 3.times { subject.next_for(Person) }
64
+ subject.next_for("cars").should == 1
65
+ end
66
+
67
+
68
+ describe "old string representation of integers" do
69
+ it "increments correctly when value is '1'" do
70
+ old_ensure = MassiveRecord::ORM::Base.backward_compatibility_integers_might_be_persisted_as_strings
71
+ MassiveRecord::ORM::Base.backward_compatibility_integers_might_be_persisted_as_strings = true
72
+
73
+ subject.next_for(Person)
74
+
75
+ # Enter incompatible data, number as string.
76
+ MassiveRecord::ORM::IdFactory.table.first.tap do |row|
77
+ row.update_column(
78
+ MassiveRecord::ORM::IdFactory::COLUMN_FAMILY_FOR_TABLES,
79
+ Person.table_name,
80
+ MassiveRecord::ORM::Base.coder.dump(1)
81
+ )
82
+ row.save
83
+ end
84
+
85
+ subject.next_for(Person).should eq 2
86
+
87
+ MassiveRecord::ORM::Base.backward_compatibility_integers_might_be_persisted_as_strings = old_ensure
88
+ end
72
89
  end
73
90
  end
74
91
  end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+ require "active_support/log_subscriber/test_helper"
3
+
4
+ describe "log subscriber" do
5
+ include ActiveSupport::BufferedLogger::Severity
6
+
7
+ include SetUpHbaseConnectionBeforeAll
8
+ include SetTableNamesToTestTable
9
+
10
+ let(:level) { DEBUG }
11
+ subject { ActiveSupport::LogSubscriber::TestHelper::MockLogger.new(level) }
12
+
13
+ before do
14
+ @old_logger = MassiveRecord::ORM::Base.logger
15
+ @notifier = ActiveSupport::Notifications::Fanout.new
16
+
17
+ ActiveSupport::LogSubscriber.colorize_logging = false
18
+
19
+ MassiveRecord::ORM::Base.logger = subject
20
+ ActiveSupport::Notifications.notifier = @notifier
21
+
22
+ MassiveRecord::ORM::LogSubscriber.attach_to :massive_record
23
+ end
24
+
25
+ after do
26
+ MassiveRecord::ORM::Base.logger = @old_logger
27
+ ActiveSupport::Notifications.notifier = nil
28
+ end
29
+
30
+
31
+
32
+ context "debug" do
33
+ it "should have nothing loged to begin with" do
34
+ subject.logged(:debug).size.should be_zero
35
+ end
36
+
37
+
38
+ describe "loading records" do
39
+ it "should have one lined log to debug when doing a all" do
40
+ Person.all
41
+ wait
42
+ subject.logged(:debug).size.should eq 1
43
+ end
44
+
45
+ it "should include a the class name of what is loading, time it took, a description about what has been done" do
46
+ Person.all
47
+ wait
48
+ subject.logged(:debug).last.should match /Person.+?load.+?([\d.]+).+?all/
49
+ end
50
+
51
+ it "should have one log line when doing first" do
52
+ Person.first
53
+ wait
54
+ subject.logged(:debug).size.should eq 1
55
+ end
56
+
57
+ it "should have some clue written that it is first" do
58
+ Person.first
59
+ wait
60
+ subject.logged(:debug).first.should include "options: [:all, {:limit=>1}]"
61
+ end
62
+
63
+ it "should have one log when doing find" do
64
+ Person.find("dummy") rescue nil
65
+ wait
66
+ subject.logged(:debug).first.should include 'options: ["dummy", {}]'
67
+ end
68
+ end
69
+
70
+
71
+ describe "store records" do
72
+ before do
73
+ @person = Person.create! "first", :name => "Name", :age => 20
74
+ wait
75
+ end
76
+
77
+ describe "create" do
78
+ it "should have one line log when creating a record" do
79
+ subject.logged(:debug).size.should eq 1
80
+ end
81
+
82
+ it "should include class of what is being save, time it took an what kind of save it was" do
83
+ subject.logged(:debug).first.should match /Person.+?save.+?([\d.]+).+?create/
84
+ end
85
+ end
86
+
87
+ describe "update" do
88
+ before do
89
+ # Resetting the logger. Kinda hackish, might break if MockLogger changes internal implementation
90
+ subject.instance_variable_set(:@logged, Hash.new { |h,k| h[k] = [] })
91
+ @person.name = "New Name"
92
+ @person.save!
93
+ end
94
+
95
+ it "should have one line log when updating a record" do
96
+ subject.logged(:debug).size.should eq 1
97
+ end
98
+
99
+ it "should include class of what is being save, time it took an what kind of save it was" do
100
+ subject.logged(:debug).first.should match /Person.+?save.+?([\d.]+).+?update.+?id: first/
101
+ end
102
+
103
+ it "should include a list of attributes which was updated" do
104
+ subject.logged(:debug).first.should match /attributes: name/
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+
111
+ context "info" do
112
+ let(:level) { INFO }
113
+
114
+ it "should have nothing logged to begin with" do
115
+ subject.logged(:debug).size.should be_zero
116
+ end
117
+
118
+ it "should have nothing logged when doing an all call" do
119
+ Person.all
120
+ wait
121
+ subject.logged(:debug).size.should be_zero
122
+ end
123
+ end
124
+
125
+
126
+
127
+
128
+ private
129
+
130
+ def wait
131
+ @notifier.wait
132
+ end
133
+ end