ohm 0.1.5 → 1.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ohm/version.rb DELETED
@@ -1,5 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module Ohm
4
- VERSION = "0.1.5"
5
- end
@@ -1,101 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
5
- prepare.clear
6
-
7
- test "connects lazily" do
8
- Ohm.connect(:port => 9876)
9
-
10
- begin
11
- Ohm.redis.get "foo"
12
- rescue => e
13
- assert Errno::ECONNREFUSED == e.class
14
- end
15
- end
16
-
17
- test "provides a separate connection for each thread" do
18
- assert Ohm.redis == Ohm.redis
19
-
20
- conn1, conn2 = nil
21
-
22
- threads = []
23
-
24
- threads << Thread.new do
25
- conn1 = Ohm.redis
26
- end
27
-
28
- threads << Thread.new do
29
- conn2 = Ohm.redis
30
- end
31
-
32
- threads.each { |t| t.join }
33
-
34
- assert conn1 != conn2
35
- end
36
-
37
- test "supports connecting by URL" do
38
- Ohm.connect(:url => "redis://localhost:9876")
39
-
40
- begin
41
- Ohm.redis.get "foo"
42
- rescue => e
43
- assert Errno::ECONNREFUSED == e.class
44
- end
45
- end
46
-
47
- test "Model.db is the same as Ohm.redis by default" do
48
- class U < Ohm::Model
49
- end
50
-
51
- assert_equal U.db.object_id, Ohm.redis.object_id
52
- end
53
-
54
- test "provides a unique Model.db connection in one thread" do
55
- class U < Ohm::Model
56
- end
57
-
58
- U.connect(db: 9876)
59
-
60
- r1 = U.db
61
- r2 = U.db
62
-
63
- assert_equal r1.object_id, r2.object_id
64
- end
65
-
66
- test "provides distinct Model.db connections per thread" do
67
- class U < Ohm::Model
68
- end
69
-
70
- U.connect(db: 9876)
71
-
72
- r1 = nil
73
- r2 = nil
74
-
75
- Thread.new { r1 = U.db }.join
76
- Thread.new { r2 = U.db }.join
77
-
78
- assert r1.object_id != r2.object_id
79
- end
80
-
81
- test "busts threaded cache when doing Model.connect" do
82
- class U < Ohm::Model
83
- end
84
-
85
- U.connect(db: 9876)
86
- r1 = U.db
87
-
88
- U.connect(db: 9876)
89
- r2 = U.db
90
-
91
- assert r1.object_id != r2.object_id
92
- end
93
-
94
- test "disallows the non-thread safe writing of Model.db" do
95
- class U < Ohm::Model
96
- end
97
-
98
- assert_raise NoMethodError do
99
- U.db = Redis.connect
100
- end
101
- end
data/test/errors_test.rb DELETED
@@ -1,120 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
5
- class User < Ohm::Model
6
- attribute :name
7
- attribute :account
8
-
9
- def validate
10
- assert_present :name
11
- assert_present :account
12
- assert false, :terrible_error
13
- end
14
- end
15
-
16
- setup do
17
- @model = User.new(:account => "")
18
- @model.valid?
19
- end
20
-
21
- test "raise an error if the errors are not handled" do
22
- begin
23
- @model.errors.present do |e|
24
- e.on :terrible_error do
25
- end
26
- end
27
- rescue => e
28
- assert e.class == Ohm::Validations::Presenter::UnhandledErrors
29
- end
30
- end
31
-
32
- test "evaluate blocks when errors match" do
33
- values = []
34
-
35
- @model.errors.present do |e|
36
- e.on [:name, :not_present] do
37
- values << 1
38
- end
39
-
40
- e.on [:account, :not_present] do
41
- values << 2
42
- end
43
-
44
- e.on :terrible_error do
45
- values << 3
46
- end
47
- end
48
-
49
- assert [1, 2, 3] == values
50
- end
51
-
52
- test "accept case-like matches for an error" do
53
- values = []
54
-
55
- @model.errors.present do |e|
56
- e.on Array do
57
- values << 1
58
- end
59
-
60
- e.on :terrible_error do
61
- values << 3
62
- end
63
- end
64
-
65
- assert [1, 3] == values
66
- end
67
-
68
- test "accept multiple matches for an error" do
69
- values = @model.errors.present do |e|
70
- e.on [:name, :not_present], "A"
71
- e.on [:account, :not_present] do
72
- "B"
73
- end
74
- e.on :terrible_error, "C"
75
- end
76
-
77
- assert %w{A B C} == values
78
- end
79
-
80
- class MyPresenter < Ohm::Validations::Presenter
81
- def on(*args)
82
- super(*args) do
83
- yield.downcase
84
- end
85
- end
86
- end
87
-
88
- test "take a custom presenter" do
89
- values = @model.errors.present(MyPresenter) do |e|
90
- e.on([:name, :not_present]) { "A" }
91
- e.on([:account, :not_present]) { "B" }
92
- e.on(:terrible_error) { "C" }
93
- end
94
-
95
- assert %w{a b c} == values
96
- end
97
-
98
- test "raise an error if neither a message nor a block are supplied" do
99
- begin
100
- Ohm::Validations::Presenter.new([:custom]).present do |e|
101
- e.on(:custom)
102
- end
103
- rescue => e
104
- assert e.class == ArgumentError
105
- end
106
- end
107
-
108
- test "not raise an error if the message passed is nil" do
109
- values = Ohm::Validations::Presenter.new([:custom]).present do |e|
110
- e.on(:custom, nil)
111
- end
112
-
113
- assert [nil] == values
114
-
115
- Ohm::Validations::Presenter.new([:custom]).present do |e|
116
- e.on(:custom, nil) do
117
- raise "Should not call block"
118
- end
119
- end
120
- end
data/test/indices_test.rb DELETED
@@ -1,213 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
5
- class User < Ohm::Model
6
- attribute :email
7
- attribute :update
8
- attribute :activation_code
9
- attribute :sandunga
10
-
11
- index :email
12
- index :email_provider
13
- index :working_days
14
- index :update
15
- index :activation_code
16
-
17
- def email_provider
18
- email.split("@").last
19
- end
20
-
21
- def working_days
22
- @working_days ||= []
23
- end
24
-
25
- def write
26
- self.activation_code ||= "user:#{id}"
27
- super
28
- end
29
- end
30
-
31
- setup do
32
- @user1 = User.create(:email => "foo", :activation_code => "bar", :update => "baz")
33
- @user2 = User.create(:email => "bar")
34
- @user3 = User.create(:email => "baz qux")
35
- end
36
-
37
- test "be able to find by the given attribute" do
38
- assert @user1 == User.find(:email => "foo").first
39
- end
40
-
41
- test "raise an error if the parameter supplied is not a hash" do
42
- begin
43
- User.find(1)
44
- rescue => ex
45
- ensure
46
- assert ex.kind_of?(ArgumentError)
47
- assert ex.message == "You need to supply a hash with filters. If you want to find by ID, use User[id] instead."
48
- end
49
- end
50
-
51
- test "avoid intersections with the all collection" do
52
- assert "User:email:#{Ohm::Model.encode "foo"}" == User.find(:email => "foo").key.to_s
53
-
54
- assert "~:User:email:Zm9v+User:activation_code:" ==
55
- User.find(:email => "foo").find(:activation_code => "").key.to_s
56
-
57
- assert "~:User:email:Zm9v+User:activation_code:YmFy+User:update:YmF6" ==
58
- result = User.find(:email => "foo").find(:activation_code => "bar").find(:update => "baz").key.to_s
59
- end
60
-
61
- test "use a special namespace for set operations" do
62
- assert User.find(:email => "foo", :activation_code => "bar").key.to_s.match(/^~:/)
63
-
64
- assert Ohm.redis.keys("~:*").size > 0
65
- end
66
-
67
- test "allow multiple chained finds" do
68
- assert 1 == User.find(:email => "foo").find(:activation_code => "bar").find(:update => "baz").size
69
- end
70
-
71
- test "raise if the field is not indexed" do
72
- assert_raise(Ohm::Model::IndexNotFound) do
73
- User.find(:sandunga => "foo")
74
- end
75
- end
76
-
77
- test "return nil if no results are found" do
78
- assert User.find(:email => "foobar").empty?
79
- assert nil == User.find(:email => "foobar").first
80
- end
81
-
82
- test "update indices when changing attribute values" do
83
- @user1.email = "baz"
84
- @user1.save
85
-
86
- assert [] == User.find(:email => "foo").all
87
- assert [@user1] == User.find(:email => "baz").all
88
- end
89
-
90
- test "remove from the index after deleting" do
91
- @user2.delete
92
-
93
- assert [] == User.find(:email => "bar").all
94
- end
95
-
96
- test "work with attributes that contain spaces" do
97
- assert [@user3] == User.find(:email => "baz qux").all
98
- end
99
-
100
- # Indexing arbitrary attributes
101
- setup do
102
- @user1 = User.create(:email => "foo@gmail.com")
103
- @user2 = User.create(:email => "bar@gmail.com")
104
- @user3 = User.create(:email => "bazqux@yahoo.com")
105
- end
106
-
107
- test "allow indexing by an arbitrary attribute" do
108
- assert [@user1, @user2] == User.find(:email_provider => "gmail.com").to_a.sort_by { |u| u.id }
109
- assert [@user3] == User.find(:email_provider => "yahoo.com").all
110
- end
111
-
112
- test "allow indexing by an attribute that is lazily set" do
113
- assert [@user1] == User.find(:activation_code => "user:1").to_a
114
- end
115
-
116
- # Indexing enumerables
117
- setup do
118
- @user1 = User.create(:email => "foo@gmail.com")
119
- @user2 = User.create(:email => "bar@gmail.com")
120
-
121
- @user1.working_days << "Mon"
122
- @user1.working_days << "Tue"
123
- @user2.working_days << "Mon"
124
- @user2.working_days << "Wed"
125
-
126
- @user1.save
127
- @user2.save
128
- end
129
-
130
- test "index each item" do
131
- assert [@user1, @user2] == User.find(:working_days => "Mon").to_a.sort_by { |u| u.id }
132
- end
133
-
134
- # TODO If we deal with Ohm collections, the updates are atomic but the reindexing never happens.
135
- # One solution may be to reindex after inserts or deletes in collection.
136
- test "remove the indices when the object changes" do
137
- @user2.working_days.delete "Mon"
138
- @user2.save
139
- assert [@user1] == User.find(:working_days => "Mon").all
140
- end
141
-
142
- # Intersection and difference
143
- class Event < Ohm::Model
144
- attr_writer :days
145
-
146
- attribute :timeline
147
- index :timeline
148
- index :days
149
-
150
- def days
151
- @days ||= []
152
- end
153
- end
154
-
155
- setup do
156
- @event1 = Event.create(:timeline => 1).update(:days => [1, 2])
157
- @event2 = Event.create(:timeline => 1).update(:days => [2, 3])
158
- @event3 = Event.create(:timeline => 2).update(:days => [3, 4])
159
- @event4 = Event.create(:timeline => 2).update(:days => [1, 3])
160
- end
161
-
162
- test "intersect multiple sets of results" do
163
- assert [@event1] == Event.find(:days => [1, 2]).all
164
- assert [@event1] == Event.find(:timeline => 1, :days => [1, 2]).all
165
- assert [@event1] == Event.find(:timeline => 1).find(:days => [1, 2]).all
166
- end
167
-
168
- test "compute the difference between sets" do
169
- assert [@event2] == Event.find(:timeline => 1).except(:days => 1).all
170
- end
171
-
172
- test "raise if the argument is not an index" do
173
- assert_raise(Ohm::Model::IndexNotFound) do
174
- Event.find(:timeline => 1).except(:not_an_index => 1)
175
- end
176
- end
177
-
178
- test "work with strings that generate a new line when encoded" do
179
- user = User.create(:email => "foo@bar", :update => "CORRECTED - UPDATE 2-Suspected US missile strike kills 5 in Pakistan")
180
- assert [user] == User.find(:update => "CORRECTED - UPDATE 2-Suspected US missile strike kills 5 in Pakistan").all
181
- end
182
-
183
- # New indices
184
- test "populate a new index when the model is saved" do
185
- class Event < Ohm::Model
186
- attribute :name
187
- end
188
-
189
- foo = Event.create(:name => "Foo")
190
-
191
- assert_raise(Ohm::Model::IndexNotFound) { Event.find(:name => "Foo") }
192
-
193
- class Event < Ohm::Model
194
- index :name
195
- end
196
-
197
- # Find works correctly once the index is added.
198
- Event.find(:name => "Foo")
199
-
200
- # The index was added after foo was created.
201
- assert Event.find(:name => "Foo").empty?
202
-
203
- bar = Event.create(:name => "Bar")
204
-
205
- # Bar was indexed properly.
206
- assert bar == Event.find(:name => "Bar").first
207
-
208
- # Saving all the objects populates the indices.
209
- Event.all.each { |e| e.save }
210
-
211
- # Now foo is indexed.
212
- assert foo == Event.find(:name => "Foo").first
213
- end
data/test/mutex_test.rb DELETED
@@ -1,84 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
5
- class Person < Ohm::Model
6
- attribute :name
7
- end
8
-
9
- setup do
10
- @p1 = Person.create :name => "Albert"
11
- @p2 = Person[1]
12
- end
13
-
14
- test "prevent other instances of the same object from grabing a locked record" do
15
- t1 = t2 = nil
16
- p1 = Thread.new do
17
- @p1.mutex do
18
- sleep 0.01
19
- t1 = Time.now
20
- end
21
- end
22
-
23
- p2 = Thread.new do
24
- sleep 0.01
25
- @p2.mutex do
26
- t2 = Time.now
27
- end
28
- end
29
-
30
- p1.join
31
- p2.join
32
- assert t2 > t1
33
- end
34
-
35
- test "allow an instance to lock a record if the previous lock is expired" do
36
- @p1.send(:lock!)
37
- @p2.mutex do
38
- assert true
39
- end
40
- end
41
-
42
- test "work if two clients are fighting for the lock" do
43
- @p1.send(:lock!)
44
- @p3 = Person[1]
45
- @p4 = Person[1]
46
-
47
- p1 = Thread.new { @p1.mutex {} }
48
- p2 = Thread.new { @p2.mutex {} }
49
- p3 = Thread.new { @p3.mutex {} }
50
- p4 = Thread.new { @p4.mutex {} }
51
- p1.join
52
- p2.join
53
- p3.join
54
- p4.join
55
- end
56
-
57
- test "yield the right result after a lock fight" do
58
- class Candidate < Ohm::Model
59
- attribute :name
60
- counter :votes
61
- end
62
-
63
- @candidate = Candidate.create :name => "Foo"
64
- @candidate.send(:lock!)
65
-
66
- threads = []
67
-
68
- n = 3
69
- m = 2
70
-
71
- n.times do
72
- threads << Thread.new do
73
- m.times do
74
- @candidate.mutex do
75
- sleep 0.01
76
- @candidate.incr(:votes)
77
- end
78
- end
79
- end
80
- end
81
-
82
- threads.each { |t| t.join }
83
- assert n * m == @candidate.votes
84
- end