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.
- 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
|