active_remote 1.2.1
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/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +7 -0
- data/LICENSE +22 -0
- data/README.md +86 -0
- data/Rakefile +21 -0
- data/active_remote.gemspec +35 -0
- data/lib/active_remote.rb +15 -0
- data/lib/active_remote/association.rb +152 -0
- data/lib/active_remote/attributes.rb +29 -0
- data/lib/active_remote/base.rb +49 -0
- data/lib/active_remote/bulk.rb +143 -0
- data/lib/active_remote/dirty.rb +70 -0
- data/lib/active_remote/dsl.rb +141 -0
- data/lib/active_remote/errors.rb +24 -0
- data/lib/active_remote/persistence.rb +226 -0
- data/lib/active_remote/rpc.rb +71 -0
- data/lib/active_remote/search.rb +131 -0
- data/lib/active_remote/serialization.rb +40 -0
- data/lib/active_remote/serializers/json.rb +18 -0
- data/lib/active_remote/serializers/protobuf.rb +100 -0
- data/lib/active_remote/version.rb +3 -0
- data/lib/core_ext/date.rb +7 -0
- data/lib/core_ext/date_time.rb +7 -0
- data/lib/core_ext/integer.rb +19 -0
- data/lib/protobuf_extensions/base_field.rb +18 -0
- data/spec/core_ext/date_time_spec.rb +10 -0
- data/spec/lib/active_remote/association_spec.rb +80 -0
- data/spec/lib/active_remote/base_spec.rb +10 -0
- data/spec/lib/active_remote/bulk_spec.rb +74 -0
- data/spec/lib/active_remote/dsl_spec.rb +73 -0
- data/spec/lib/active_remote/persistence_spec.rb +266 -0
- data/spec/lib/active_remote/rpc_spec.rb +94 -0
- data/spec/lib/active_remote/search_spec.rb +98 -0
- data/spec/lib/active_remote/serialization_spec.rb +57 -0
- data/spec/lib/active_remote/serializers/json_spec.rb +32 -0
- data/spec/lib/active_remote/serializers/protobuf_spec.rb +95 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/definitions/author.proto +29 -0
- data/spec/support/definitions/post.proto +33 -0
- data/spec/support/definitions/support/protobuf/category.proto +29 -0
- data/spec/support/definitions/support/protobuf/error.proto +6 -0
- data/spec/support/definitions/tag.proto +29 -0
- data/spec/support/helpers.rb +37 -0
- data/spec/support/models.rb +5 -0
- data/spec/support/models/author.rb +14 -0
- data/spec/support/models/category.rb +14 -0
- data/spec/support/models/message_with_options.rb +11 -0
- data/spec/support/models/post.rb +16 -0
- data/spec/support/models/tag.rb +12 -0
- data/spec/support/protobuf.rb +4 -0
- data/spec/support/protobuf/author.pb.rb +54 -0
- data/spec/support/protobuf/category.pb.rb +54 -0
- data/spec/support/protobuf/error.pb.rb +21 -0
- data/spec/support/protobuf/post.pb.rb +58 -0
- data/spec/support/protobuf/tag.pb.rb +54 -0
- metadata +284 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRemote::Bulk do
|
4
|
+
let(:records) { double(:records, :to_hash => {}) }
|
5
|
+
let(:serialized_records) { double(:serialized_records) }
|
6
|
+
|
7
|
+
describe ".create_all" do
|
8
|
+
before {
|
9
|
+
Tag.stub(:parse_records).and_return(records)
|
10
|
+
Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
|
11
|
+
}
|
12
|
+
|
13
|
+
it "creates remote records" do
|
14
|
+
Tag.any_instance.should_receive(:execute).with(:create_all, records)
|
15
|
+
Tag.create_all(records)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".delete_all" do
|
20
|
+
before {
|
21
|
+
Tag.stub(:parse_records).and_return(records)
|
22
|
+
Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
|
23
|
+
}
|
24
|
+
|
25
|
+
it "deletes remote records" do
|
26
|
+
Tag.any_instance.should_receive(:execute).with(:delete_all, records)
|
27
|
+
Tag.delete_all(records)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe ".destroy_all" do
|
32
|
+
before {
|
33
|
+
Tag.stub(:parse_records).and_return(records)
|
34
|
+
Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
|
35
|
+
}
|
36
|
+
|
37
|
+
it "destroys remote records" do
|
38
|
+
Tag.any_instance.should_receive(:execute).with(:destroy_all, records)
|
39
|
+
Tag.destroy_all(records)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe ".parse_records" do
|
44
|
+
let(:records) { [ Hash.new ] }
|
45
|
+
|
46
|
+
it "preps records to be built into a bulk request" do
|
47
|
+
parsed_records = { :records => records }
|
48
|
+
Tag.parse_records(records).should eq parsed_records
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when given a bulk message" do
|
52
|
+
let(:records) { [ tag.to_hash ] }
|
53
|
+
let(:tag) { Generic::Remote::Tag.new }
|
54
|
+
let(:tags) { Generic::Remote::Tags.new(:records => [ tag ]) }
|
55
|
+
|
56
|
+
it "preps records to be built into a bulk request" do
|
57
|
+
parsed_records = { :records => records }
|
58
|
+
Tag.parse_records(tags).should eq parsed_records
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe ".update_all" do
|
64
|
+
before {
|
65
|
+
Tag.stub(:parse_records).and_return(records)
|
66
|
+
Tag.any_instance.stub(:serialize_records).and_return(serialized_records)
|
67
|
+
}
|
68
|
+
|
69
|
+
it "updates remote records" do
|
70
|
+
Tag.any_instance.should_receive(:execute).with(:update_all, records)
|
71
|
+
Tag.update_all(records)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# For testing the DSL methods
|
4
|
+
module Another
|
5
|
+
class TagService < Protobuf::Rpc::Service
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe ActiveRemote::DSL do
|
10
|
+
before { reset_dsl_variables(Tag) }
|
11
|
+
after { Tag.service_class Generic::Remote::TagService }
|
12
|
+
|
13
|
+
describe ".attr_publishable" do
|
14
|
+
after { reset_publishable_attributes(Tag) }
|
15
|
+
|
16
|
+
it "appends given attributes to @publishable_attributes" do
|
17
|
+
Tag.attr_publishable :guid
|
18
|
+
Tag.attr_publishable :name
|
19
|
+
|
20
|
+
Tag.publishable_attributes.should =~ [ :guid, :name ]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".auto_paging_size" do
|
25
|
+
context "when given a value" do
|
26
|
+
it "sets @auto_paging_size to the value" do
|
27
|
+
Tag.auto_paging_size 100
|
28
|
+
Tag.auto_paging_size.should eq 100
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe ".namespace" do
|
34
|
+
context "when given a value" do
|
35
|
+
it "sets @namespace to the value" do
|
36
|
+
Tag.namespace :foo
|
37
|
+
Tag.namespace.should eq :foo
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe ".service_class" do
|
43
|
+
context "when nil" do
|
44
|
+
it "determines the service class" do
|
45
|
+
Tag.namespace :another
|
46
|
+
|
47
|
+
Tag.service_class.should eq Another::TagService
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when given a value" do
|
52
|
+
it "sets @service_class to the value" do
|
53
|
+
Tag.service_class Generic::Remote::TagService
|
54
|
+
Tag.service_class.should eq Generic::Remote::TagService
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe ".service_name" do
|
60
|
+
context "when nil" do
|
61
|
+
it "determines the service name" do
|
62
|
+
Tag.service_name.should eq :tag_service
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "when given a value" do
|
67
|
+
it "sets @service_name to the value" do
|
68
|
+
Tag.service_name :foo
|
69
|
+
Tag.service_name.should eq :foo
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRemote::Persistence do
|
4
|
+
subject { Tag.new }
|
5
|
+
|
6
|
+
before { Tag.any_instance.stub(:last_response).and_return(HashWithIndifferentAccess.new) }
|
7
|
+
|
8
|
+
describe ".create" do
|
9
|
+
before { Tag.any_instance.stub(:execute) }
|
10
|
+
after { Tag.any_instance.unstub(:execute) }
|
11
|
+
|
12
|
+
it "initializes and saves a new record" do
|
13
|
+
Tag.any_instance.should_receive(:save)
|
14
|
+
Tag.create(:name => 'foo')
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns a new record" do
|
18
|
+
value = Tag.create(:name => 'foo')
|
19
|
+
value.should be_a(Tag)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe ".create!" do
|
24
|
+
before { Tag.any_instance.stub(:execute) }
|
25
|
+
after { Tag.any_instance.unstub(:execute) }
|
26
|
+
|
27
|
+
it "initializes and saves a new record" do
|
28
|
+
Tag.any_instance.should_receive(:save!)
|
29
|
+
Tag.create!(:name => 'foo')
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when the record has errors" do
|
33
|
+
before { Tag.any_instance.stub(:save!).and_raise(ActiveRemote::ActiveRemoteError) }
|
34
|
+
|
35
|
+
it "raises an exception" do
|
36
|
+
expect { Tag.create!(:name => 'foo') }.to raise_error(ActiveRemote::ActiveRemoteError)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#delete" do
|
42
|
+
before { subject.stub(:execute) }
|
43
|
+
after { subject.unstub(:execute) }
|
44
|
+
|
45
|
+
it "deletes a remote record" do
|
46
|
+
subject.should_receive(:execute).with(:delete, subject.attributes.slice("guid"))
|
47
|
+
subject.delete
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when the record doesn't have errors" do
|
51
|
+
it "freezes the record" do
|
52
|
+
subject.delete
|
53
|
+
subject.frozen?.should be_true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#delete!" do
|
59
|
+
before { subject.stub(:execute) }
|
60
|
+
after { subject.unstub(:execute) }
|
61
|
+
|
62
|
+
it "deletes a remote record" do
|
63
|
+
subject.should_receive(:execute).with(:delete, subject.attributes.slice("guid"))
|
64
|
+
subject.delete!
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when an error occurs" do
|
68
|
+
before { subject.stub(:execute).and_raise(ActiveRemote::ActiveRemoteError) }
|
69
|
+
|
70
|
+
it "raises an exception" do
|
71
|
+
expect { subject.delete! }.to raise_error(ActiveRemote::ActiveRemoteError)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#destroy" do
|
77
|
+
before { subject.stub(:execute) }
|
78
|
+
after { subject.unstub(:execute) }
|
79
|
+
|
80
|
+
it "destroys a remote record" do
|
81
|
+
subject.should_receive(:execute).with(:destroy, subject.attributes.slice("guid"))
|
82
|
+
subject.destroy
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when the record doesn't have errors" do
|
86
|
+
it "freezes the record" do
|
87
|
+
subject.destroy
|
88
|
+
subject.frozen?.should be_true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#destroy!" do
|
94
|
+
before { subject.stub(:execute) }
|
95
|
+
after { subject.unstub(:execute) }
|
96
|
+
|
97
|
+
it "destroys a remote record" do
|
98
|
+
subject.should_receive(:execute).with(:destroy, subject.attributes.slice("guid"))
|
99
|
+
subject.destroy!
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when an error occurs" do
|
103
|
+
before { subject.stub(:execute).and_raise(ActiveRemote::ActiveRemoteError) }
|
104
|
+
|
105
|
+
it "raises an exception" do
|
106
|
+
expect { subject.destroy! }.to raise_error(ActiveRemote::ActiveRemoteError)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#has_errors?" do
|
112
|
+
context "when errors are not present" do
|
113
|
+
before { subject.errors.clear }
|
114
|
+
|
115
|
+
its(:has_errors?) { should be_false }
|
116
|
+
end
|
117
|
+
|
118
|
+
context "when errors are present" do
|
119
|
+
before { subject.errors[:base] << "Boom!" }
|
120
|
+
|
121
|
+
its(:has_errors?) { should be_true }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#new_record?" do
|
126
|
+
context "when the record is persisted" do
|
127
|
+
subject { Tag.new(:guid => 'foo') }
|
128
|
+
|
129
|
+
its(:new_record?) { should be_false }
|
130
|
+
end
|
131
|
+
|
132
|
+
context "when the record is not persisted" do
|
133
|
+
subject { Tag.new }
|
134
|
+
|
135
|
+
its(:new_record?) { should be_true }
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "#persisted?" do
|
140
|
+
context "when the record has a guid" do
|
141
|
+
subject { Tag.new(:guid => 'foo') }
|
142
|
+
|
143
|
+
its(:persisted?) { should be_true }
|
144
|
+
end
|
145
|
+
|
146
|
+
context "when the record does not have a guid" do
|
147
|
+
subject { Tag.new }
|
148
|
+
|
149
|
+
its(:persisted?) { should be_false }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "#save" do
|
154
|
+
before { subject.stub(:execute) }
|
155
|
+
after { subject.unstub(:execute) }
|
156
|
+
|
157
|
+
it "runs callbacks" do
|
158
|
+
subject.should_receive(:run_callbacks).with(:save)
|
159
|
+
subject.save
|
160
|
+
end
|
161
|
+
|
162
|
+
context "when the record is new" do
|
163
|
+
subject { Tag.new }
|
164
|
+
|
165
|
+
it "creates the record" do
|
166
|
+
expected_attributes = subject.attributes.reject { |key, value| key == "guid" }
|
167
|
+
subject.should_receive(:execute).with(:create, expected_attributes)
|
168
|
+
subject.save
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "when the record is not new" do
|
173
|
+
let(:attributes) { { 'guid' => 'foo' } }
|
174
|
+
|
175
|
+
subject { Tag.new(attributes) }
|
176
|
+
|
177
|
+
it "updates the record" do
|
178
|
+
subject.should_receive(:execute).with(:update, attributes)
|
179
|
+
subject.save
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "when the record is saved" do
|
184
|
+
before { subject.errors.clear }
|
185
|
+
|
186
|
+
it "returns true" do
|
187
|
+
subject.save.should be_true
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "when the record is not saved" do
|
192
|
+
before { subject.errors[:base] << "Boom!" }
|
193
|
+
|
194
|
+
it "returns false" do
|
195
|
+
subject.save.should be_false
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "#save!" do
|
201
|
+
before { subject.stub(:execute) }
|
202
|
+
after { subject.unstub(:execute) }
|
203
|
+
|
204
|
+
context "when the record is saved" do
|
205
|
+
it "returns true" do
|
206
|
+
subject.stub(:save).and_return(true)
|
207
|
+
subject.save!.should be_true
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context "when the record is not saved" do
|
212
|
+
it "raises an exception" do
|
213
|
+
subject.stub(:save).and_return(false)
|
214
|
+
expect { subject.save! }.to raise_error(ActiveRemote::RemoteRecordNotSaved)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "#success?" do
|
220
|
+
context "when errors are present" do
|
221
|
+
before { subject.errors[:base] << "Boom!" }
|
222
|
+
|
223
|
+
its(:success?) { should be_false }
|
224
|
+
end
|
225
|
+
|
226
|
+
context "when errors are not present" do
|
227
|
+
before { subject.errors.clear }
|
228
|
+
|
229
|
+
its(:success?) { should be_true }
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "#update_attributes" do
|
234
|
+
let(:attributes) { HashWithIndifferentAccess.new(:name => 'bar') }
|
235
|
+
|
236
|
+
before { subject.stub(:save) }
|
237
|
+
after { subject.unstub(:save) }
|
238
|
+
|
239
|
+
it "assigns new attributes" do
|
240
|
+
subject.should_receive(:assign_attributes).with(attributes)
|
241
|
+
subject.update_attributes(attributes)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "saves the record" do
|
245
|
+
subject.should_receive(:save)
|
246
|
+
subject.update_attributes(attributes)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe "#update_attributes!" do
|
251
|
+
let(:attributes) { HashWithIndifferentAccess.new(:name => 'bar') }
|
252
|
+
|
253
|
+
before { subject.stub(:save!) }
|
254
|
+
after { subject.unstub(:save!) }
|
255
|
+
|
256
|
+
it "assigns new attributes" do
|
257
|
+
subject.should_receive(:assign_attributes).with(attributes)
|
258
|
+
subject.update_attributes!(attributes)
|
259
|
+
end
|
260
|
+
|
261
|
+
it "saves! the record" do
|
262
|
+
subject.should_receive(:save!)
|
263
|
+
subject.update_attributes!(attributes)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveRemote::RPC do
|
4
|
+
subject { Tag.new }
|
5
|
+
|
6
|
+
describe ".remote_call" do
|
7
|
+
let(:args) { double(:args) }
|
8
|
+
let(:response) { double(:response) }
|
9
|
+
|
10
|
+
before { Tag.any_instance.stub(:execute) }
|
11
|
+
|
12
|
+
it "calls the given RPC method" do
|
13
|
+
Tag.any_instance.should_receive(:execute).with(:remote_method, args)
|
14
|
+
Tag.remote_call(:remote_method, args)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns the response" do
|
18
|
+
Tag.any_instance.stub(:last_response).and_return(response)
|
19
|
+
Tag.remote_call(:remote_method, args).should eq response
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe ".request" do
|
24
|
+
let(:attributes) { Hash.new }
|
25
|
+
let(:message) { double(:message) }
|
26
|
+
|
27
|
+
it "builds an RPC request" do
|
28
|
+
Tag.should_receive(:build_message).with(Generic::Remote::Tag, attributes)
|
29
|
+
Tag.request(:create, attributes)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe ".request_type" do
|
34
|
+
it "fetches the request type for the given RPC method" do
|
35
|
+
Tag.request_type(:search).should eq Generic::Remote::TagRequest
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#execute" do
|
40
|
+
let(:request) { double(:request) }
|
41
|
+
|
42
|
+
it "calls the given RPC method" do
|
43
|
+
mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
|
44
|
+
subject.execute(:create, request)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "sets the last request" do
|
48
|
+
mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
|
49
|
+
|
50
|
+
subject.execute(:create, request)
|
51
|
+
subject.last_request.should eq(request)
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when request args is a hash" do
|
55
|
+
let(:args){ Hash.new }
|
56
|
+
let(:request) { double(:request) }
|
57
|
+
|
58
|
+
before {
|
59
|
+
subject.stub(:request).and_return(request)
|
60
|
+
mock_remote_service(Tag.service_class, :create, :response => double(:to_hash => {}))
|
61
|
+
}
|
62
|
+
|
63
|
+
it "creates a request" do
|
64
|
+
subject.should_receive(:request).with(:create, args)
|
65
|
+
subject.execute(:create, args)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when a request succeeds" do
|
70
|
+
let(:success_response) { double(:status => 'success', :awesome_town => true, :to_hash => {}) }
|
71
|
+
|
72
|
+
before {
|
73
|
+
mock_remote_service(Tag.service_class, :create, :response => success_response)
|
74
|
+
}
|
75
|
+
|
76
|
+
it "sets the last response" do
|
77
|
+
subject.execute(:create, request)
|
78
|
+
subject.last_response.should eq(success_response)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when a request fails" do
|
83
|
+
let(:error_response) { double(:error, :message => "Boom goes the dynamite!") }
|
84
|
+
|
85
|
+
before {
|
86
|
+
mock_remote_service(Tag.service_class, :create, :error => error_response)
|
87
|
+
}
|
88
|
+
|
89
|
+
it "raises an exception" do
|
90
|
+
expect { subject.execute(:create, request) }.to raise_error(ActiveRemote::ActiveRemoteError)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|