active_harmony 1.0.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.
@@ -0,0 +1,44 @@
1
+ require "spec_helper"
2
+
3
+ module ActiveHarmony
4
+ describe ServiceManager do
5
+ before :each do
6
+ manager = ServiceManager.new
7
+ manager.instance_variable_set(:@services, {})
8
+ end
9
+
10
+ describe '#initialize' do
11
+ it 'should setup hash for known services' do
12
+ manager = ServiceManager.new
13
+ manager.instance_variable_get(:@services).should == {}
14
+ end
15
+ end
16
+
17
+ describe '#add_service_for_identifier' do
18
+ it 'should add service to services hash' do
19
+ service = Service.new
20
+ manager = ServiceManager.new
21
+ manager.add_service_for_identifier(service, :my_service)
22
+ manager.instance_variable_get(:@services).should == \
23
+ {:my_service => service}
24
+ end
25
+ end
26
+
27
+ describe '#service_with_identifier' do
28
+ it 'should return service by identifier' do
29
+ service = Service.new
30
+ manager = ServiceManager.new
31
+ manager.instance_variable_set(:@services,
32
+ {:my_service => service})
33
+ manager.service_with_identifier(:my_service).should == service
34
+ end
35
+
36
+ it 'should raise an exception when theres no such service' do
37
+ manager = ServiceManager.new
38
+ lambda {
39
+ manager.service_with_identifier(:awsum_service)
40
+ }.should raise_exception
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,313 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ module ActiveHarmony
6
+ describe Service do
7
+ before :each do
8
+ @service = Service.new
9
+ @base_url = "http://chunky.bacon"
10
+ @service.base_url = @base_url
11
+ end
12
+
13
+ ############################################################
14
+ # Initialization
15
+ describe "#initialize" do
16
+ it "should create new instance of Service::Rest" do
17
+ @service.should be_a(Service)
18
+ end
19
+ end
20
+
21
+ ############################################################
22
+ # URL and header configuration
23
+ describe "#base_url=" do
24
+ it "should set base url for the service" do
25
+ @service.base_url = @base_url
26
+ @service.base_url.should == @base_url
27
+ end
28
+ end
29
+
30
+ describe "#header=" do
31
+ it "should be empty hash as default" do
32
+ @service.header.should == {}
33
+ end
34
+
35
+ it "should set extra headers for the service" do
36
+ extra_header = {
37
+ "Header name" => "Header Value"
38
+ }
39
+ @service.header = extra_header
40
+ @service.header.should == extra_header
41
+ end
42
+ end
43
+
44
+ describe "#set_header" do
45
+ it "should set one header" do
46
+ @service.set_header("test_header", "bla")
47
+ @service.header["test_header"].should == "bla"
48
+ end
49
+ end
50
+
51
+ ##
52
+ # Generating URLs
53
+ describe "#generate_rest_url" do
54
+ it "should generate list url" do
55
+ @service.generate_rest_url(:list, :my_object).path.should == \
56
+ "#{@base_url}/my_objects"
57
+ end
58
+
59
+ it "should generate show url" do
60
+ @service.generate_rest_url(:show, :my_object, 123).path.should == \
61
+ "#{@base_url}/my_objects/123"
62
+ end
63
+
64
+ it "should generate update url" do
65
+ @service.generate_rest_url(:update, :my_object, 123).path.should == \
66
+ "#{@base_url}/my_objects/123"
67
+ end
68
+ end
69
+
70
+ describe "#generate_url" do
71
+ it "should generate url for path" do
72
+ @service.generate_url("rainbow").should == \
73
+ "#{@base_url}/rainbow"
74
+ end
75
+
76
+ it "should generate url for path with slash at beginning" do
77
+ @service.generate_url("/rainbow").should == \
78
+ "#{@base_url}/rainbow"
79
+ end
80
+ end
81
+
82
+ ##
83
+ # Retrieving data
84
+ describe "#retrieve" do
85
+ it "should retrieve data from a url" do
86
+ url = "http://chunky.bacon/foo.bar"
87
+ response = "Chunky Bacon !!!"
88
+ stub_request(:get, "http://chunky.bacon/foo.bar").to_return(:body => response)
89
+ @service.retrieve(url).should == response
90
+ end
91
+
92
+ it "should use header while making the request" do
93
+ url = "http://chunky.bacon/bar.foo"
94
+ stub_request(:get, url).
95
+ with(:headers => { 'Some-Header' => 'Some Value' }).
96
+ to_return(:body => "Success!")
97
+ @service.set_header 'Some-Header', 'Some Value'
98
+ @service.retrieve(url).should == "Success!"
99
+ end
100
+ end
101
+
102
+ describe "#list" do
103
+ it "should list objects" do
104
+ objects = <<-EOF
105
+ <?xml version="1.0" encoding="UTF-8"?>
106
+ <my_objects type="array">
107
+ <my_object>
108
+ <id type="integer">1</id>
109
+ <name>first</name>
110
+ </my_object>
111
+ <my_object>
112
+ <id type="integer">2</id>
113
+ <name>second</name>
114
+ </my_object>
115
+ </my_objects>
116
+ EOF
117
+ stub_request(:get, "http://chunky.bacon/my_objects").to_return(:body => objects)
118
+ response = @service.list(:my_object)
119
+ response.should == [
120
+ {"id" => 1, "name" => "first"},
121
+ {"id" => 2, "name" => "second"}
122
+ ]
123
+ end
124
+ end
125
+
126
+ describe "#show" do
127
+ it "should show an object" do
128
+ object = <<-EOF
129
+ <?xml version="1.0" encoding="UTF-8"?>
130
+ <my_object>
131
+ <id type="integer">1</id>
132
+ <name>first</name>
133
+ </my_object>
134
+ EOF
135
+ stub_request(:get, "http://chunky.bacon/my_objects/1").to_return(:body => object)
136
+ response = @service.show(:my_object, 1)
137
+ response.should == {"id" => 1, "name" => "first"}
138
+ end
139
+ end
140
+
141
+ describe "#update" do
142
+ it "should update object" do
143
+ response = <<-EOF
144
+ <?xml version="1.0" encoding="UTF-8"?>
145
+ <my_object>
146
+ <id type="integer">1</id>
147
+ <name>updated name</name>
148
+ </my_object>
149
+ EOF
150
+ changes = {'name' => 'updated name'}
151
+ expected_headers = {'Content-type' => 'application/xml'}
152
+ expected_data = '<?xml version="1.0" encoding="UTF-8"?>
153
+ <my-object>
154
+ <name>updated name</name>
155
+ </my-object>'
156
+ expected_url = 'http://chunky.bacon/my_objects/123'
157
+ stub_request(:put, expected_url).to_return(:body => response)
158
+ @service.update(:my_object, 123, changes)
159
+ request(:put, expected_url).with(:body => /<name>updated name<\/name>/).should have_been_made
160
+ # FIXME Add specs that checks for hash in response
161
+ end
162
+ end
163
+
164
+ describe "#create" do
165
+ it "should create object" do
166
+ response = <<-EOF
167
+ <?xml version="1.0" encoding="UTF-8"?>
168
+ <my_object>
169
+ <id type="integer">1</id>
170
+ <name>new name</name>
171
+ </my_object>
172
+ EOF
173
+ changes = {'name' => 'new name'}
174
+ expected_headers = {'Content-type' => 'application/xml'}
175
+ expected_url = 'http://chunky.bacon/my_objects'
176
+ stub_request(:post, expected_url).to_return(:body => response)
177
+ result = @service.create(:my_object, changes)
178
+ request(:post, expected_url).with(:body => /<name>new name<\/name>/).should have_been_made
179
+ result.should == {'id' => 1, 'name' => 'new name'}
180
+ end
181
+ end
182
+
183
+ describe "#set_contexts" do
184
+ it "should generate url with contexts in it" do
185
+ @service.set_contexts({
186
+ :first_context => 123,
187
+ :second_context => 456
188
+ })
189
+ url = @service.generate_rest_url(:list, :bacon)
190
+ url.path.should == "http://chunky.bacon/first_context/123/second_context/456/bacons"
191
+ end
192
+ end
193
+
194
+ describe "#clear_contexts" do
195
+ it "should reset contexts on a service" do
196
+ @service.set_contexts({
197
+ :first_context => 123,
198
+ :second_context => 456
199
+ })
200
+ url = @service.generate_rest_url(:list, :bacon)
201
+ url.path.should == "http://chunky.bacon/first_context/123/second_context/456/bacons"
202
+ @service.clear_contexts
203
+ url = @service.generate_rest_url(:list, :bacon)
204
+ url.path.should == "http://chunky.bacon/bacons"
205
+ end
206
+ end
207
+
208
+ context "with custom path" do
209
+ before :each do
210
+ @service.add_custom_url(:my_object, :list, "my_objects/all")
211
+ end
212
+
213
+ describe "#add_custom_url" do
214
+ it "should use custom path for specific object/action" do
215
+ @service.generate_rest_url(:list, :my_object).path.should == "http://chunky.bacon/my_objects/all"
216
+ end
217
+ end
218
+
219
+ describe "#custom_url_for" do
220
+ it "should find custom path" do
221
+ @service.custom_url_for(:my_object, :list).path.should == "http://chunky.bacon/my_objects/all"
222
+ end
223
+ end
224
+ end
225
+
226
+ context "with custom path and method" do
227
+ before :each do
228
+ @service.add_custom_url(:my_object, :update, "my_objects/update", :post)
229
+ end
230
+
231
+ it "should generate an url" do
232
+ url = @service.generate_rest_url(:update, :my_object, 1)
233
+ url.should be_a(ServiceUrl)
234
+ url.path.should == 'http://chunky.bacon/my_objects/update'
235
+ url.method.should == :post
236
+ end
237
+
238
+ it "should make a request" do
239
+ expected_url = 'http://chunky.bacon/my_objects/update'
240
+ stub_request(:post, expected_url)
241
+ @service.update(:my_object, 1, {})
242
+ request(:post, expected_url).should have_been_made
243
+ end
244
+ end
245
+
246
+ context "with custom root" do
247
+ before :each do
248
+ @service.root = "things/hidden/somewhere/my_objects"
249
+ end
250
+
251
+ describe "#list" do
252
+ it "should list" do
253
+ object = <<-EOF
254
+ <?xml version="1.0" encoding="UTF-8"?>
255
+ <things>
256
+ <hidden>
257
+ <somewhere>
258
+ <my_objects type="array">
259
+ <my_object>
260
+ <id type="integer">1</id>
261
+ <name>first</name>
262
+ </my_object>
263
+ <my_object>
264
+ <id type="integer">2</id>
265
+ <name>second</name>
266
+ </my_object>
267
+ </my_objects>
268
+ </somewhere>
269
+ </hidden>
270
+ </things>
271
+ EOF
272
+ stub_request(:get, "http://chunky.bacon/my_objects").to_return(:body => object)
273
+ response = @service.list(:my_object)
274
+ response.should == [
275
+ {"id" => 1, "name" => "first"},
276
+ {"id" => 2, "name" => "second"}
277
+ ]
278
+ end
279
+ end
280
+
281
+ describe "#show" do
282
+ it "should show" do
283
+ @service.root = "things/hidden/somewhere/my_object"
284
+ object = <<-EOF
285
+ <?xml version="1.0" encoding="UTF-8"?>
286
+ <things>
287
+ <hidden>
288
+ <somewhere>
289
+ <my_object>
290
+ <id type="integer">1</id>
291
+ <name>updated name</name>
292
+ </my_object>
293
+ </somewhere>
294
+ </hidden>
295
+ </things>
296
+ EOF
297
+ stub_request(:get, "http://chunky.bacon/my_objects/1").to_return(:body => object)
298
+ response = @service.show(:my_object, 1)
299
+ response.should == {"id" => 1, "name" => "updated name"}
300
+ end
301
+ end
302
+ end
303
+
304
+ context "with custom object name" do
305
+ describe "#add_object_name" do
306
+ it "should add object name" do
307
+ @service.add_object_name(:old_name, :show, 'new_name')
308
+ @service.object_name_for(:old_name, :show).should == 'new_name'
309
+ end
310
+ end
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,53 @@
1
+ require "spec_helper"
2
+
3
+ class MyClass
4
+ include Mongoid::Document
5
+ include ActiveHarmony::Synchronizable::Core
6
+ field :foo
7
+ end
8
+
9
+ module ActiveHarmony
10
+ module Synchronizable
11
+ describe Core do
12
+ describe "included" do
13
+ it 'should assign a new synchronizer' do
14
+ MyClass.synchronizer.should_not be_nil
15
+ MyClass.synchronizer.should be_a(ActiveHarmony::Synchronizer)
16
+ end
17
+
18
+ it 'should set synchronizers factory to self' do
19
+ MyClass.synchronizer.factory.should == MyClass
20
+ end
21
+ end
22
+
23
+ describe "#push" do
24
+ context "queued" do
25
+ it "should create queue item" do
26
+ my_object = MyClass.new
27
+ my_object.foo = "bar"
28
+ my_object.save
29
+ my_object.push
30
+ queue_item = ActiveHarmony::QueueItem.last
31
+ queue_item.kind.should == "push"
32
+ queue_item.state.should == "new"
33
+ queue_item.result.should == nil
34
+ queue_item.object_type.should == "MyClass"
35
+ queue_item.object_remote_id.should == nil
36
+ queue_item.object_local_id.to_s.should == my_object.id.to_s
37
+ end
38
+ end
39
+
40
+ context "instant" do
41
+ it "should trigger an instant push" do
42
+ my_object = MyClass.new
43
+ my_object.foo = "bar"
44
+ my_object.synchronizer.expects(:push_object).with(my_object)
45
+ my_object.push(true)
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ module ActiveHarmony
4
+ module Synchronizable
5
+ class MyModel; include ::Mongoid::Document; end
6
+
7
+ describe Mongoid do
8
+
9
+ before do
10
+ MyModel.send :include, ActiveHarmony::Synchronizable::Mongoid
11
+ @new_model = MyModel.new
12
+ end
13
+
14
+ it "should add _remote_id_field" do
15
+ @new_model._remote_id = 1
16
+ @new_model._remote_id.should == 1
17
+ end
18
+
19
+ it "should add _collection_order field" do
20
+ @new_model._collection_order = 1
21
+ @new_model._collection_order.should == 1
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ module ActiveHarmony
4
+ describe SynchronizerConfiguration do
5
+ before :each do
6
+ @config = SynchronizerConfiguration.new
7
+ end
8
+
9
+ describe '#push' do
10
+ it 'should add a push field to synchronizable fields' do
11
+ @config.push :chunky
12
+ @config.push :bacon
13
+ @config.instance_variable_get(:@synchronizable_fields).should == \
14
+ [{:type => SynchronizerConfiguration::TYPE_PUSH, :field => :chunky},
15
+ {:type => SynchronizerConfiguration::TYPE_PUSH, :field => :bacon}]
16
+ end
17
+ end
18
+
19
+ describe '#pull' do
20
+ it 'should add a pull field to synchronizable fields' do
21
+ @config.pull :chunky
22
+ @config.pull :bacon
23
+ @config.instance_variable_get(:@synchronizable_fields).should == \
24
+ [{:type => SynchronizerConfiguration::TYPE_PULL, :field => :chunky},
25
+ {:type => SynchronizerConfiguration::TYPE_PULL, :field => :bacon}]
26
+ end
27
+ end
28
+
29
+ describe '#synchronize' do
30
+ it 'should add field of certain type to synchronizable fields' do
31
+ @config.synchronize :chunky, :type => :chunky_type
32
+ @config.instance_variable_get(:@synchronizable_fields).should == \
33
+ [{:field => :chunky, :type => :chunky_type}]
34
+ end
35
+
36
+ it 'should add field with no type to synchronizable fields' do
37
+ @config.synchronize :chunky
38
+ @config.instance_variable_get(:@synchronizable_fields).should == \
39
+ [{:field => :chunky, :type => SynchronizerConfiguration::TYPE_ALL}]
40
+ end
41
+ end
42
+
43
+ describe '#synchronizable_for_push' do
44
+ it 'returns fields for push' do
45
+ @config.push :chunky
46
+ @config.push :bacon
47
+ @config.pull :meh
48
+ @config.synchronizable_for_push.should == [:chunky, :bacon]
49
+ end
50
+ end
51
+
52
+ describe '#synchronizable_for_pull' do
53
+ it 'returns fields for pull' do
54
+ @config.pull :chunky
55
+ @config.pull :bacon
56
+ @config.push :meh
57
+ @config.synchronizable_for_pull.should == [:chunky, :bacon]
58
+ end
59
+ end
60
+
61
+ describe '#synchronizable_for_types' do
62
+ it 'returns synchronizables for specified types' do
63
+ @config.synchronize :chunky, :type => :chunky_type
64
+ @config.synchronize :bacon, :type => :bacon_type
65
+ @config.synchronize :meh, :type => :meh_type
66
+ @config.synchronizable_for_types([:chunky_type, :meh_type]).should == \
67
+ [:chunky, :meh]
68
+ end
69
+ end
70
+ end
71
+ end