massive_record 0.2.0 → 0.2.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +43 -4
- data/Gemfile.lock +3 -1
- data/README.md +5 -0
- data/lib/massive_record/adapters/thrift/connection.rb +23 -16
- data/lib/massive_record/adapters/thrift/row.rb +13 -33
- data/lib/massive_record/adapters/thrift/table.rb +24 -10
- data/lib/massive_record/orm/attribute_methods.rb +27 -1
- data/lib/massive_record/orm/attribute_methods/dirty.rb +2 -2
- data/lib/massive_record/orm/attribute_methods/read.rb +36 -1
- data/lib/massive_record/orm/attribute_methods/time_zone_conversion.rb +81 -0
- data/lib/massive_record/orm/attribute_methods/write.rb +18 -0
- data/lib/massive_record/orm/base.rb +52 -10
- data/lib/massive_record/orm/callbacks.rb +1 -1
- data/lib/massive_record/orm/default_id.rb +20 -0
- data/lib/massive_record/orm/errors.rb +4 -0
- data/lib/massive_record/orm/finders.rb +102 -57
- data/lib/massive_record/orm/finders/rescue_missing_table_on_find.rb +45 -0
- data/lib/massive_record/orm/id_factory.rb +1 -1
- data/lib/massive_record/orm/log_subscriber.rb +85 -0
- data/lib/massive_record/orm/persistence.rb +82 -37
- data/lib/massive_record/orm/query_instrumentation.rb +64 -0
- data/lib/massive_record/orm/relations/interface.rb +10 -0
- data/lib/massive_record/orm/relations/metadata.rb +2 -0
- data/lib/massive_record/orm/relations/proxy/references_one_polymorphic.rb +1 -1
- data/lib/massive_record/orm/schema/field.rb +33 -6
- data/lib/massive_record/orm/timestamps.rb +1 -1
- data/lib/massive_record/orm/validations.rb +2 -2
- data/lib/massive_record/rails/controller_runtime.rb +55 -0
- data/lib/massive_record/rails/railtie.rb +16 -0
- data/lib/massive_record/version.rb +1 -1
- data/lib/massive_record/wrapper/cell.rb +32 -3
- data/massive_record.gemspec +1 -0
- data/spec/{wrapper/cases → adapter/thrift}/adapter_spec.rb +0 -0
- data/spec/adapter/thrift/atomic_increment_spec.rb +55 -0
- data/spec/{wrapper/cases → adapter/thrift}/connection_spec.rb +0 -10
- data/spec/adapter/thrift/table_find_spec.rb +40 -0
- data/spec/{wrapper/cases → adapter/thrift}/table_spec.rb +55 -13
- data/spec/orm/cases/attribute_methods_spec.rb +6 -1
- data/spec/orm/cases/base_spec.rb +18 -4
- data/spec/orm/cases/callbacks_spec.rb +1 -1
- data/spec/orm/cases/default_id_spec.rb +38 -0
- data/spec/orm/cases/default_values_spec.rb +37 -0
- data/spec/orm/cases/dirty_spec.rb +25 -1
- data/spec/orm/cases/encoding_spec.rb +3 -3
- data/spec/orm/cases/finder_default_scope.rb +8 -1
- data/spec/orm/cases/finder_scope_spec.rb +2 -2
- data/spec/orm/cases/finders_spec.rb +8 -18
- data/spec/orm/cases/id_factory_spec.rb +38 -21
- data/spec/orm/cases/log_subscriber_spec.rb +133 -0
- data/spec/orm/cases/mass_assignment_security_spec.rb +97 -0
- data/spec/orm/cases/persistence_spec.rb +132 -27
- data/spec/orm/cases/single_table_inheritance_spec.rb +2 -2
- data/spec/orm/cases/time_zone_awareness_spec.rb +157 -0
- data/spec/orm/cases/timestamps_spec.rb +15 -0
- data/spec/orm/cases/validation_spec.rb +2 -2
- data/spec/orm/models/model_without_default_id.rb +5 -0
- data/spec/orm/models/person.rb +1 -0
- data/spec/orm/models/test_class.rb +1 -0
- data/spec/orm/relations/interface_spec.rb +2 -2
- data/spec/orm/relations/metadata_spec.rb +1 -1
- data/spec/orm/relations/proxy/references_many_spec.rb +21 -15
- data/spec/orm/relations/proxy/references_one_polymorphic_spec.rb +7 -1
- data/spec/orm/relations/proxy/references_one_spec.rb +7 -0
- data/spec/orm/schema/field_spec.rb +61 -5
- data/spec/support/connection_helpers.rb +2 -1
- data/spec/support/mock_massive_record_connection.rb +7 -0
- data/spec/support/time_zone_helper.rb +25 -0
- metadata +51 -14
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'orm/models/person'
|
3
|
+
|
4
|
+
describe "mass assignment security" do
|
5
|
+
def restore_mass_assignment_security_policy_after(klass)
|
6
|
+
accessible_attributes = klass._accessible_attributes
|
7
|
+
protected_attributes = klass._protected_attributes
|
8
|
+
active_authorizer = klass._active_authorizer
|
9
|
+
|
10
|
+
yield
|
11
|
+
|
12
|
+
klass._accessible_attributes = accessible_attributes
|
13
|
+
klass._protected_attributes = protected_attributes
|
14
|
+
klass._active_authorizer = active_authorizer
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
describe "settings and defaults" do
|
20
|
+
subject { Person }
|
21
|
+
its(:attributes_protected_by_default ) { should include 'id', Person.inheritance_attribute }
|
22
|
+
its(:protected_attributes) { should include 'id', Person.inheritance_attribute }
|
23
|
+
|
24
|
+
|
25
|
+
describe "#attr_accessible" do
|
26
|
+
it "sets attributes accessible" do
|
27
|
+
restore_mass_assignment_security_policy_after Person do
|
28
|
+
Person.class_eval do
|
29
|
+
attr_accessible :age
|
30
|
+
end
|
31
|
+
|
32
|
+
Person.accessible_attributes.should include 'age'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#attr_protected" do
|
38
|
+
it "sets attributes protected" do
|
39
|
+
restore_mass_assignment_security_policy_after Person do
|
40
|
+
Person.class_eval do
|
41
|
+
attr_protected :age
|
42
|
+
end
|
43
|
+
|
44
|
+
Person.protected_attributes.should include 'age'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "access test on" do
|
51
|
+
describe Person do
|
52
|
+
context "when only age is accessible" do
|
53
|
+
it "sets age with mass assignment" do
|
54
|
+
restore_mass_assignment_security_policy_after Person do
|
55
|
+
Person.class_eval do
|
56
|
+
attr_accessible :age
|
57
|
+
end
|
58
|
+
|
59
|
+
Person.new(:age => 33).age.should eq 33
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "does not set name with mass assignment" do
|
64
|
+
restore_mass_assignment_security_policy_after Person do
|
65
|
+
Person.class_eval do
|
66
|
+
attr_accessible :age
|
67
|
+
end
|
68
|
+
|
69
|
+
Person.new(:name => 'Thorbjorn').name.should be_nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when only age is protected" do
|
75
|
+
it "does not set age with mass assignment" do
|
76
|
+
restore_mass_assignment_security_policy_after Person do
|
77
|
+
Person.class_eval do
|
78
|
+
attr_protected :age
|
79
|
+
end
|
80
|
+
|
81
|
+
Person.new(:age => 33).age.should be_nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "sets name with mass assignment" do
|
86
|
+
restore_mass_assignment_security_policy_after Person do
|
87
|
+
Person.class_eval do
|
88
|
+
attr_protected :age
|
89
|
+
end
|
90
|
+
|
91
|
+
Person.new(:name => 'Thorbjorn').name.should eq "Thorbjorn"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -15,27 +15,27 @@ describe "persistence" do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should be persisted if saved" do
|
18
|
-
model = TestClass.new
|
18
|
+
model = TestClass.new "id1"
|
19
19
|
model.save
|
20
20
|
model.should be_persisted
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should be destroyed when destroyed" do
|
24
|
-
model = TestClass.new
|
24
|
+
model = TestClass.new "id1"
|
25
25
|
model.save
|
26
26
|
model.destroy
|
27
27
|
model.should be_destroyed
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should not be persisted if destroyed" do
|
31
|
-
model = TestClass.new
|
31
|
+
model = TestClass.new "id1"
|
32
32
|
model.save
|
33
33
|
model.destroy
|
34
34
|
model.should_not be_persisted
|
35
35
|
end
|
36
36
|
|
37
37
|
it "should be possible to create new objects" do
|
38
|
-
TestClass.create(
|
38
|
+
TestClass.create("id1").should be_persisted
|
39
39
|
end
|
40
40
|
|
41
41
|
it "should raise an error if validation fails on save!" do
|
@@ -91,23 +91,28 @@ describe "persistence" do
|
|
91
91
|
end
|
92
92
|
|
93
93
|
it "should return a row with id set" do
|
94
|
-
Person.new(
|
94
|
+
Person.new("foo").send(:row_for_record).id.should == "foo"
|
95
95
|
end
|
96
96
|
|
97
97
|
it "should return a row with table set" do
|
98
|
-
Person.new(
|
98
|
+
Person.new("foo").send(:row_for_record).table.should == Person.table
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
102
|
describe "#attributes_to_row_values_hash" do
|
103
103
|
before do
|
104
|
-
@person = Person.new(
|
104
|
+
@person = Person.new("new_id", :name => "Vincent", :points => 15)
|
105
105
|
end
|
106
106
|
|
107
107
|
it "should include the 'pts' field in the database which has 'points' as an alias" do
|
108
108
|
@person.send(:attributes_to_row_values_hash)["base"].keys.should include("pts")
|
109
109
|
@person.send(:attributes_to_row_values_hash)["base"].keys.should_not include("points")
|
110
110
|
end
|
111
|
+
|
112
|
+
it "should include integer value, even if it is set as string" do
|
113
|
+
@person.age = "20"
|
114
|
+
@person.send(:attributes_to_row_values_hash)["info"]["age"].should == 20
|
115
|
+
end
|
111
116
|
end
|
112
117
|
|
113
118
|
|
@@ -116,7 +121,7 @@ describe "persistence" do
|
|
116
121
|
include MockMassiveRecordConnection
|
117
122
|
|
118
123
|
before do
|
119
|
-
@person = Person.create!
|
124
|
+
@person = Person.create! "new_id", :name => "Thorbjorn", :age => "22"
|
120
125
|
end
|
121
126
|
|
122
127
|
it "should update given attriubte when valid" do
|
@@ -134,7 +139,7 @@ describe "persistence" do
|
|
134
139
|
include MockMassiveRecordConnection
|
135
140
|
|
136
141
|
before do
|
137
|
-
@person = Person.create!
|
142
|
+
@person = Person.create! "new_id", :name => "Thorbjorn", :age => "22"
|
138
143
|
end
|
139
144
|
|
140
145
|
it "should update given attriubtes when valid" do
|
@@ -162,7 +167,7 @@ describe "persistence" do
|
|
162
167
|
end
|
163
168
|
|
164
169
|
it "should delegate save to update if its a persisted record" do
|
165
|
-
person = Person.new
|
170
|
+
person = Person.new '14', :name => "Bob", :age => 33
|
166
171
|
person.should_receive(:new_record?).and_return(false)
|
167
172
|
person.should_receive(:update)
|
168
173
|
person.save
|
@@ -171,6 +176,7 @@ describe "persistence" do
|
|
171
176
|
|
172
177
|
describe "database test" do
|
173
178
|
include SetUpHbaseConnectionBeforeAll
|
179
|
+
include SetTableNamesToTestTable
|
174
180
|
|
175
181
|
describe "create" do
|
176
182
|
describe "when table does not exists" do
|
@@ -187,7 +193,7 @@ describe "persistence" do
|
|
187
193
|
end
|
188
194
|
end
|
189
195
|
|
190
|
-
@new_instance = @new_class.new
|
196
|
+
@new_instance = @new_class.new "id_of_foo", :foo => "bar"
|
191
197
|
end
|
192
198
|
|
193
199
|
after do
|
@@ -220,13 +226,38 @@ describe "persistence" do
|
|
220
226
|
include CreatePersonBeforeEach
|
221
227
|
|
222
228
|
it "should store (create) new objects" do
|
223
|
-
person = Person.new
|
229
|
+
person = Person.new "new_id", :name => "Thorbjorn", :age => "22"
|
224
230
|
person.save!
|
225
231
|
person_from_db = Person.find(person.id)
|
226
232
|
person_from_db.should == person
|
227
233
|
person_from_db.name.should == "Thorbjorn"
|
228
234
|
end
|
229
235
|
end
|
236
|
+
|
237
|
+
it "raises an error if id already exists" do
|
238
|
+
check_was = Person.check_record_uniqueness_on_create
|
239
|
+
Person.check_record_uniqueness_on_create = true
|
240
|
+
|
241
|
+
Person.create! "foo", :name => "Thorbjorn", :age => "22"
|
242
|
+
expect {
|
243
|
+
Person.create! "foo", :name => "Anders", :age => "22"
|
244
|
+
}.to raise_error MassiveRecord::ORM::RecordNotUnique
|
245
|
+
|
246
|
+
Person.find("foo").name.should eq "Thorbjorn"
|
247
|
+
|
248
|
+
Person.check_record_uniqueness_on_create = check_was
|
249
|
+
end
|
250
|
+
|
251
|
+
it "raises no error if exist checking is turned off" do
|
252
|
+
check_was = Person.check_record_uniqueness_on_create
|
253
|
+
Person.check_record_uniqueness_on_create = false
|
254
|
+
|
255
|
+
Person.create! "foo", :name => "Thorbjorn", :age => "22"
|
256
|
+
Person.create! "foo", :name => "Anders", :age => "22" # This will result in an "update"
|
257
|
+
Person.find("foo").name.should eq "Anders"
|
258
|
+
|
259
|
+
Person.check_record_uniqueness_on_create = check_was
|
260
|
+
end
|
230
261
|
end
|
231
262
|
|
232
263
|
describe "update" do
|
@@ -292,7 +323,7 @@ describe "persistence" do
|
|
292
323
|
include MockMassiveRecordConnection
|
293
324
|
|
294
325
|
before do
|
295
|
-
@person = Person.new
|
326
|
+
@person = Person.new "id1"
|
296
327
|
@person.stub!(:new_record?).and_return(false)
|
297
328
|
@row = MassiveRecord::Wrapper::Row.new({:id => @person.id, :table => @person.class.table})
|
298
329
|
@person.should_receive(:row_for_record).and_return(@row)
|
@@ -333,7 +364,7 @@ describe "persistence" do
|
|
333
364
|
include SetTableNamesToTestTable
|
334
365
|
|
335
366
|
before do
|
336
|
-
@person = Person.create!
|
367
|
+
@person = Person.create! "id1", :name => "Thorbjorn", :age => 29
|
337
368
|
end
|
338
369
|
|
339
370
|
it "should be removed by destroy" do
|
@@ -355,7 +386,7 @@ describe "persistence" do
|
|
355
386
|
|
356
387
|
describe "#destroy_all" do
|
357
388
|
it "should remove all when calling remove_all" do
|
358
|
-
Person.create!
|
389
|
+
Person.create! "id2", :name => "Going to die :-(", :age => 99
|
359
390
|
Person.destroy_all
|
360
391
|
Person.all.length.should == 0
|
361
392
|
end
|
@@ -365,7 +396,7 @@ describe "persistence" do
|
|
365
396
|
end
|
366
397
|
|
367
398
|
it "should destroy all even if it is above 10 rows (obviously)" do
|
368
|
-
15.times { |i| Person.create!
|
399
|
+
15.times { |i| Person.create! "id-#{i}", :name => "Going to die :-(", :age => i + 20 }
|
369
400
|
Person.destroy_all
|
370
401
|
Person.all.length.should == 0
|
371
402
|
end
|
@@ -380,7 +411,7 @@ describe "persistence" do
|
|
380
411
|
include MockMassiveRecordConnection
|
381
412
|
|
382
413
|
before do
|
383
|
-
@person = Person.create!
|
414
|
+
@person = Person.create! "id1", :name => "Thorbjorn", :age => 29
|
384
415
|
end
|
385
416
|
|
386
417
|
it "should being able to increment age" do
|
@@ -414,7 +445,7 @@ describe "persistence" do
|
|
414
445
|
include SetTableNamesToTestTable
|
415
446
|
|
416
447
|
before do
|
417
|
-
@person = Person.create!
|
448
|
+
@person = Person.create! "id1", :name => "Thorbjorn", :age => 29
|
418
449
|
end
|
419
450
|
|
420
451
|
it "should delegate it's call to increment" do
|
@@ -428,11 +459,44 @@ describe "persistence" do
|
|
428
459
|
@person.age.should == 30
|
429
460
|
end
|
430
461
|
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
462
|
+
|
463
|
+
describe "atomic increments" do
|
464
|
+
it "should be able to do atomic increments on existing objects" do
|
465
|
+
@person.atomic_increment!(:age).should == 30
|
466
|
+
@person.age.should == 30
|
467
|
+
@person.reload
|
468
|
+
@person.age.should == 30
|
469
|
+
end
|
470
|
+
|
471
|
+
it "is a persisted record after incrementation" do
|
472
|
+
person = Person.new('id2')
|
473
|
+
person.atomic_increment!(:age).should eq 1
|
474
|
+
person.should be_persisted
|
475
|
+
end
|
476
|
+
|
477
|
+
it "increments correctly when value is '1'" do
|
478
|
+
old_ensure = MassiveRecord::ORM::Base.backward_compatibility_integers_might_be_persisted_as_strings
|
479
|
+
MassiveRecord::ORM::Base.backward_compatibility_integers_might_be_persisted_as_strings = true
|
480
|
+
|
481
|
+
person = Person.new('id2')
|
482
|
+
person.atomic_increment!(:age).should eq 1
|
483
|
+
|
484
|
+
atomic_field = Person.attributes_schema['age']
|
485
|
+
|
486
|
+
# Enter incompatible data, number as string.
|
487
|
+
Person.table.find("id2").tap do |row|
|
488
|
+
row.update_column(
|
489
|
+
atomic_field.column_family.name,
|
490
|
+
atomic_field.name,
|
491
|
+
MassiveRecord::ORM::Base.coder.dump(1)
|
492
|
+
)
|
493
|
+
row.save
|
494
|
+
end
|
495
|
+
|
496
|
+
person.atomic_increment!(:age).should eq 2
|
497
|
+
|
498
|
+
MassiveRecord::ORM::Base.backward_compatibility_integers_might_be_persisted_as_strings = old_ensure
|
499
|
+
end
|
436
500
|
end
|
437
501
|
end
|
438
502
|
end
|
@@ -442,7 +506,7 @@ describe "persistence" do
|
|
442
506
|
include MockMassiveRecordConnection
|
443
507
|
|
444
508
|
before do
|
445
|
-
@person = Person.create!
|
509
|
+
@person = Person.create! "id1", :name => "Thorbjorn", :age => 29
|
446
510
|
end
|
447
511
|
|
448
512
|
it "should being able to decrement age" do
|
@@ -476,7 +540,7 @@ describe "persistence" do
|
|
476
540
|
include SetTableNamesToTestTable
|
477
541
|
|
478
542
|
before do
|
479
|
-
@person = Person.create!
|
543
|
+
@person = Person.create! "id1", :name => "Thorbjorn", :age => 29
|
480
544
|
end
|
481
545
|
|
482
546
|
it "should delegate it's call to decrement" do
|
@@ -496,17 +560,58 @@ describe "persistence" do
|
|
496
560
|
include MockMassiveRecordConnection
|
497
561
|
|
498
562
|
it "should raise an error if new record is read only and you try to save it" do
|
499
|
-
person = Person.new
|
563
|
+
person = Person.new "id1", :name => "Thorbjorn", :age => 29
|
500
564
|
person.readonly!
|
501
565
|
lambda { person.save }.should raise_error MassiveRecord::ORM::ReadOnlyRecord
|
502
566
|
end
|
503
567
|
|
504
568
|
it "should raise an error if record is read only and you try to save it" do
|
505
|
-
person = Person.create
|
569
|
+
person = Person.create "id1", :name => "Thorbjorn", :age => 29
|
506
570
|
person.should be_persisted
|
507
571
|
|
508
572
|
person.readonly!
|
509
573
|
lambda { person.save }.should raise_error MassiveRecord::ORM::ReadOnlyRecord
|
510
574
|
end
|
511
575
|
end
|
576
|
+
|
577
|
+
describe "id as int" do
|
578
|
+
include SetUpHbaseConnectionBeforeAll
|
579
|
+
include SetTableNamesToTestTable
|
580
|
+
|
581
|
+
it "saves id as string and reloads correctly" do
|
582
|
+
person = Person.new :name => "Thorbjorn", :age => 29
|
583
|
+
person.id = 1
|
584
|
+
person.save!
|
585
|
+
|
586
|
+
person.reload
|
587
|
+
person.id.should == "1"
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
|
592
|
+
describe "attributes with nil value" do
|
593
|
+
include SetUpHbaseConnectionBeforeAll
|
594
|
+
include SetTableNamesToTestTable
|
595
|
+
|
596
|
+
|
597
|
+
subject do
|
598
|
+
Person.create!("id", {
|
599
|
+
:name => "Thorbjorn",
|
600
|
+
:age => 22,
|
601
|
+
:points => 1,
|
602
|
+
:addresses => {'home' => 'Here'},
|
603
|
+
:status => true
|
604
|
+
})
|
605
|
+
end
|
606
|
+
|
607
|
+
%w(points addresses status).each do |attr|
|
608
|
+
it "removes the cell from hbase when #{attr} is set to nil" do
|
609
|
+
subject[attr] = nil
|
610
|
+
subject.save!
|
611
|
+
|
612
|
+
raw_values = Person.table.find(subject.id).values
|
613
|
+
raw_values[subject.attributes_schema[attr].unique_name].should be_nil
|
614
|
+
end
|
615
|
+
end
|
616
|
+
end
|
512
617
|
end
|
@@ -8,7 +8,7 @@ describe "Single table inheritance" do
|
|
8
8
|
|
9
9
|
[Friend, BestFriend, BestFriend::SuperBestFriend].each do |klass|
|
10
10
|
describe klass do
|
11
|
-
let(:subject) { klass.new(
|
11
|
+
let(:subject) { klass.new("ID1", :name => "Person1", :email => "one@person.com", :age => 11, :points => 111, :status => true) }
|
12
12
|
|
13
13
|
its(:type) { should == klass.to_s }
|
14
14
|
|
@@ -20,7 +20,7 @@ describe "Single table inheritance" do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should not set type if record being saved is base class" do
|
23
|
-
person = Person.new
|
23
|
+
person = Person.new "ID1", :name => "Person1", :email => "one@person.com", :age => 11, :points => 111, :status => true
|
24
24
|
person.type.should be_nil
|
25
25
|
end
|
26
26
|
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'orm/models/test_class'
|
3
|
+
require 'orm/models/person'
|
4
|
+
|
5
|
+
describe "Time zone awareness" do
|
6
|
+
include TimeZoneHelper
|
7
|
+
|
8
|
+
describe "configuration" do
|
9
|
+
it "should have a default time zone configuration" do
|
10
|
+
TestClass.default_timezone.should eq :local
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have default time zone awareness" do
|
14
|
+
TestClass.time_zone_aware_attributes.should eq false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should by default skip no attributes when doing time zone conversions" do
|
18
|
+
TestClass.skip_time_zone_conversion_for_attributes.should eq []
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be possible to skip some attributes in TestClass while Person is untuched" do
|
22
|
+
TestClass.skip_time_zone_conversion_for_attributes = [:test]
|
23
|
+
TestClass.skip_time_zone_conversion_for_attributes.should include :test
|
24
|
+
Person.skip_time_zone_conversion_for_attributes.should be_empty
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
describe "when to do conversion" do
|
30
|
+
let(:field) { MassiveRecord::ORM::Schema::Field.new :name => 'tested_at' }
|
31
|
+
|
32
|
+
it "should do conversion when attribute is time" do
|
33
|
+
in_time_zone "utc" do
|
34
|
+
field.type = :time
|
35
|
+
TestClass.send(:time_zone_conversion_on_field?, field).should be_true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not do conversion if time_zone_aware_attributes is false" do
|
40
|
+
field.type = :time
|
41
|
+
TestClass.time_zone_aware_attributes = false
|
42
|
+
TestClass.send(:time_zone_conversion_on_field?, field).should be_false
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not do conversion when attribute name is included in skip list" do
|
46
|
+
field.type = :time
|
47
|
+
TestClass.skip_time_zone_conversion_for_attributes = ['tested_at']
|
48
|
+
TestClass.send(:time_zone_conversion_on_field?, field).should be_false
|
49
|
+
TestClass.skip_time_zone_conversion_for_attributes = []
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should not do conversion when attribute is string field" do
|
53
|
+
field.type = :string
|
54
|
+
TestClass.send(:time_zone_conversion_on_field?, field).should be_false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
describe "conversion on attribute" do
|
61
|
+
include SetUpHbaseConnectionBeforeAll
|
62
|
+
include SetTableNamesToTestTable
|
63
|
+
|
64
|
+
subject { TestClass.new "test" }
|
65
|
+
let(:tz_europe) { "Europe/Stockholm" }
|
66
|
+
let(:tz_us) { "Pacific Time (US & Canada)" }
|
67
|
+
|
68
|
+
let(:time_as_string) { "2010-10-10 10:10:10" }
|
69
|
+
|
70
|
+
it "should be nil when set to nil" do
|
71
|
+
in_time_zone tz_europe do
|
72
|
+
subject.tested_at = nil
|
73
|
+
subject.tested_at.should be_nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should return time as TimeWithZone when attribute accessed directly" do
|
78
|
+
in_time_zone tz_europe do
|
79
|
+
subject.tested_at = time_as_string
|
80
|
+
subject.tested_at.should be_instance_of ActiveSupport::TimeWithZone
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return time as TimeWithZone when attribute accessed through read_attribute" do
|
85
|
+
in_time_zone tz_europe do
|
86
|
+
subject.tested_at = time_as_string
|
87
|
+
subject.read_attribute(:tested_at).should be_instance_of ActiveSupport::TimeWithZone
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should return time in local time" do
|
92
|
+
in_time_zone tz_europe do
|
93
|
+
subject.tested_at = time_as_string
|
94
|
+
subject.tested_at.time_zone.should eq ActiveSupport::TimeZone[tz_europe]
|
95
|
+
|
96
|
+
in_time_zone tz_us do
|
97
|
+
subject.tested_at.time_zone.should eq ActiveSupport::TimeZone[tz_us]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return correct time in other time zones" do
|
103
|
+
utc_time = Time.utc(2010, 1, 1)
|
104
|
+
us_time = utc_time.in_time_zone(tz_us)
|
105
|
+
|
106
|
+
in_time_zone tz_europe do
|
107
|
+
subject.tested_at = us_time
|
108
|
+
subject.tested_at.should eq utc_time
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should return correct times after save" do
|
113
|
+
utc_time = Time.now.utc
|
114
|
+
europe_time = utc_time.in_time_zone(tz_europe)
|
115
|
+
us_time = utc_time.in_time_zone(tz_us)
|
116
|
+
|
117
|
+
in_time_zone tz_europe do
|
118
|
+
subject.tested_at = europe_time
|
119
|
+
subject.save!
|
120
|
+
end
|
121
|
+
|
122
|
+
subject.reload
|
123
|
+
|
124
|
+
in_time_zone tz_us do
|
125
|
+
subject.tested_at.to_s.should eq us_time.to_s
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should store time in DB format" do
|
130
|
+
utc_time = Time.now.utc
|
131
|
+
europe_time = utc_time.in_time_zone(tz_europe)
|
132
|
+
|
133
|
+
in_time_zone tz_europe do
|
134
|
+
subject.tested_at = europe_time
|
135
|
+
subject.save!
|
136
|
+
end
|
137
|
+
|
138
|
+
subject.reload
|
139
|
+
subject.tested_at.to_s.should eq utc_time.to_s
|
140
|
+
|
141
|
+
in_time_zone tz_europe do
|
142
|
+
subject.tested_at.to_s.should eq europe_time.to_s
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should store time in DB format, raw check" do
|
147
|
+
in_time_zone tz_europe do
|
148
|
+
subject.tested_at = time_as_string
|
149
|
+
subject.save!
|
150
|
+
|
151
|
+
r = TestClass.table.find("test")
|
152
|
+
cell = r.columns["test_family:tested_at"]
|
153
|
+
cell.value.should eq MassiveRecord::ORM::Base.coder.dump(Time.zone.parse(time_as_string).utc)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|