active_remote 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.gitignore +10 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +22 -0
  6. data/README.md +86 -0
  7. data/Rakefile +21 -0
  8. data/active_remote.gemspec +35 -0
  9. data/lib/active_remote.rb +15 -0
  10. data/lib/active_remote/association.rb +152 -0
  11. data/lib/active_remote/attributes.rb +29 -0
  12. data/lib/active_remote/base.rb +49 -0
  13. data/lib/active_remote/bulk.rb +143 -0
  14. data/lib/active_remote/dirty.rb +70 -0
  15. data/lib/active_remote/dsl.rb +141 -0
  16. data/lib/active_remote/errors.rb +24 -0
  17. data/lib/active_remote/persistence.rb +226 -0
  18. data/lib/active_remote/rpc.rb +71 -0
  19. data/lib/active_remote/search.rb +131 -0
  20. data/lib/active_remote/serialization.rb +40 -0
  21. data/lib/active_remote/serializers/json.rb +18 -0
  22. data/lib/active_remote/serializers/protobuf.rb +100 -0
  23. data/lib/active_remote/version.rb +3 -0
  24. data/lib/core_ext/date.rb +7 -0
  25. data/lib/core_ext/date_time.rb +7 -0
  26. data/lib/core_ext/integer.rb +19 -0
  27. data/lib/protobuf_extensions/base_field.rb +18 -0
  28. data/spec/core_ext/date_time_spec.rb +10 -0
  29. data/spec/lib/active_remote/association_spec.rb +80 -0
  30. data/spec/lib/active_remote/base_spec.rb +10 -0
  31. data/spec/lib/active_remote/bulk_spec.rb +74 -0
  32. data/spec/lib/active_remote/dsl_spec.rb +73 -0
  33. data/spec/lib/active_remote/persistence_spec.rb +266 -0
  34. data/spec/lib/active_remote/rpc_spec.rb +94 -0
  35. data/spec/lib/active_remote/search_spec.rb +98 -0
  36. data/spec/lib/active_remote/serialization_spec.rb +57 -0
  37. data/spec/lib/active_remote/serializers/json_spec.rb +32 -0
  38. data/spec/lib/active_remote/serializers/protobuf_spec.rb +95 -0
  39. data/spec/spec_helper.rb +17 -0
  40. data/spec/support/definitions/author.proto +29 -0
  41. data/spec/support/definitions/post.proto +33 -0
  42. data/spec/support/definitions/support/protobuf/category.proto +29 -0
  43. data/spec/support/definitions/support/protobuf/error.proto +6 -0
  44. data/spec/support/definitions/tag.proto +29 -0
  45. data/spec/support/helpers.rb +37 -0
  46. data/spec/support/models.rb +5 -0
  47. data/spec/support/models/author.rb +14 -0
  48. data/spec/support/models/category.rb +14 -0
  49. data/spec/support/models/message_with_options.rb +11 -0
  50. data/spec/support/models/post.rb +16 -0
  51. data/spec/support/models/tag.rb +12 -0
  52. data/spec/support/protobuf.rb +4 -0
  53. data/spec/support/protobuf/author.pb.rb +54 -0
  54. data/spec/support/protobuf/category.pb.rb +54 -0
  55. data/spec/support/protobuf/error.pb.rb +21 -0
  56. data/spec/support/protobuf/post.pb.rb +58 -0
  57. data/spec/support/protobuf/tag.pb.rb +54 -0
  58. metadata +284 -0
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRemote::Base do
4
+ describe "#initialize" do
5
+ it "runs callbacks" do
6
+ described_class.any_instance.should_receive(:run_callbacks).with(:initialize)
7
+ described_class.new
8
+ end
9
+ end
10
+ end
@@ -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