rhosync 2.0.0.beta1

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.
Files changed (200) hide show
  1. data/CHANGELOG +5 -0
  2. data/LICENSE +674 -0
  3. data/README.md +26 -0
  4. data/Rakefile +109 -0
  5. data/bench/bench +6 -0
  6. data/bench/benchapp/Rakefile +14 -0
  7. data/bench/benchapp/application.rb +13 -0
  8. data/bench/benchapp/config.ru +32 -0
  9. data/bench/benchapp/settings/license.key +1 -0
  10. data/bench/benchapp/settings/settings.yml +18 -0
  11. data/bench/benchapp/sources/mock_adapter.rb +55 -0
  12. data/bench/benchapp/sources/queue_mock_adapter.rb +2 -0
  13. data/bench/benchapp/vendor/rhosync/lib/rhosync.rb +7 -0
  14. data/bench/lib/bench/cli.rb +16 -0
  15. data/bench/lib/bench/logging.rb +18 -0
  16. data/bench/lib/bench/mock_client.rb +41 -0
  17. data/bench/lib/bench/result.rb +50 -0
  18. data/bench/lib/bench/runner.rb +44 -0
  19. data/bench/lib/bench/session.rb +65 -0
  20. data/bench/lib/bench/statistics.rb +56 -0
  21. data/bench/lib/bench/test_data.rb +55 -0
  22. data/bench/lib/bench/timer.rb +10 -0
  23. data/bench/lib/bench/utils.rb +49 -0
  24. data/bench/lib/bench.rb +128 -0
  25. data/bench/lib/testdata/100-data.txt +148 -0
  26. data/bench/lib/testdata/5-data.txt +11 -0
  27. data/bench/scripts/cud_script.rb +77 -0
  28. data/bench/scripts/helpers.rb +101 -0
  29. data/bench/scripts/query_md_script.rb +46 -0
  30. data/bench/scripts/query_script.rb +46 -0
  31. data/bench/spec/bench_spec_helper.rb +65 -0
  32. data/bench/spec/logging_spec.rb +19 -0
  33. data/bench/spec/mock_adapter_spec.rb +61 -0
  34. data/bench/spec/mock_client_spec.rb +64 -0
  35. data/bench/spec/result_spec.rb +59 -0
  36. data/bench/spec/utils_spec.rb +35 -0
  37. data/bin/rhosync +34 -0
  38. data/doc/protocol.html +1901 -0
  39. data/doc/public/css/print.css +29 -0
  40. data/doc/public/css/screen.css +257 -0
  41. data/doc/public/css/style.css +20 -0
  42. data/examples/simple/application.rb +13 -0
  43. data/examples/simple/sources/sample_adapter.rb +5 -0
  44. data/examples/simple/sources/simple_adapter.rb +5 -0
  45. data/examples/simple/vendor/rhosync/lib/rhosync.rb +7 -0
  46. data/generators/rhosync.rb +98 -0
  47. data/generators/templates/application/Rakefile +19 -0
  48. data/generators/templates/application/application.rb +27 -0
  49. data/generators/templates/application/config.ru +33 -0
  50. data/generators/templates/application/settings/license.key +1 -0
  51. data/generators/templates/application/settings/settings.yml +14 -0
  52. data/generators/templates/source/source_adapter.rb +49 -0
  53. data/lib/rhosync/api/create_client.rb +3 -0
  54. data/lib/rhosync/api/create_user.rb +7 -0
  55. data/lib/rhosync/api/delete_client.rb +5 -0
  56. data/lib/rhosync/api/delete_user.rb +5 -0
  57. data/lib/rhosync/api/get_api_token.rb +7 -0
  58. data/lib/rhosync/api/get_client_params.rb +3 -0
  59. data/lib/rhosync/api/get_db_doc.rb +7 -0
  60. data/lib/rhosync/api/get_license_info.rb +7 -0
  61. data/lib/rhosync/api/get_source_params.rb +3 -0
  62. data/lib/rhosync/api/list_client_docs.rb +12 -0
  63. data/lib/rhosync/api/list_clients.rb +3 -0
  64. data/lib/rhosync/api/list_source_docs.rb +10 -0
  65. data/lib/rhosync/api/list_sources.rb +15 -0
  66. data/lib/rhosync/api/list_users.rb +3 -0
  67. data/lib/rhosync/api/ping.rb +7 -0
  68. data/lib/rhosync/api/push_deletes.rb +6 -0
  69. data/lib/rhosync/api/push_objects.rb +6 -0
  70. data/lib/rhosync/api/reset.rb +10 -0
  71. data/lib/rhosync/api/set_db_doc.rb +8 -0
  72. data/lib/rhosync/api/set_refresh_time.rb +8 -0
  73. data/lib/rhosync/api/update_user.rb +4 -0
  74. data/lib/rhosync/api/upload_file.rb +4 -0
  75. data/lib/rhosync/api_token.rb +19 -0
  76. data/lib/rhosync/app.rb +69 -0
  77. data/lib/rhosync/bulk_data/bulk_data.rb +75 -0
  78. data/lib/rhosync/bulk_data/syncdb.index.schema +3 -0
  79. data/lib/rhosync/bulk_data/syncdb.schema +37 -0
  80. data/lib/rhosync/bulk_data.rb +2 -0
  81. data/lib/rhosync/client.rb +74 -0
  82. data/lib/rhosync/client_sync.rb +296 -0
  83. data/lib/rhosync/console/app/helpers/auth_helper.rb +18 -0
  84. data/lib/rhosync/console/app/helpers/extensions.rb +19 -0
  85. data/lib/rhosync/console/app/helpers/helpers.rb +52 -0
  86. data/lib/rhosync/console/app/public/main.css +7 -0
  87. data/lib/rhosync/console/app/public/text.txt +0 -0
  88. data/lib/rhosync/console/app/routes/auth.rb +29 -0
  89. data/lib/rhosync/console/app/routes/client.rb +32 -0
  90. data/lib/rhosync/console/app/routes/docs.rb +84 -0
  91. data/lib/rhosync/console/app/routes/home.rb +22 -0
  92. data/lib/rhosync/console/app/routes/user.rb +63 -0
  93. data/lib/rhosync/console/app/views/client.erb +30 -0
  94. data/lib/rhosync/console/app/views/doc.erb +56 -0
  95. data/lib/rhosync/console/app/views/docs.erb +29 -0
  96. data/lib/rhosync/console/app/views/index.erb +50 -0
  97. data/lib/rhosync/console/app/views/layout.erb +12 -0
  98. data/lib/rhosync/console/app/views/newuser.erb +17 -0
  99. data/lib/rhosync/console/app/views/ping.erb +28 -0
  100. data/lib/rhosync/console/app/views/result.erb +11 -0
  101. data/lib/rhosync/console/app/views/user.erb +32 -0
  102. data/lib/rhosync/console/app/views/users.erb +14 -0
  103. data/lib/rhosync/console/rhosync_api.rb +102 -0
  104. data/lib/rhosync/console/server.rb +27 -0
  105. data/lib/rhosync/credential.rb +9 -0
  106. data/lib/rhosync/document.rb +43 -0
  107. data/lib/rhosync/indifferent_access.rb +132 -0
  108. data/lib/rhosync/jobs/bulk_data_job.rb +104 -0
  109. data/lib/rhosync/jobs/ping_job.rb +19 -0
  110. data/lib/rhosync/jobs/source_job.rb +16 -0
  111. data/lib/rhosync/license.rb +79 -0
  112. data/lib/rhosync/lock_ops.rb +11 -0
  113. data/lib/rhosync/model.rb +410 -0
  114. data/lib/rhosync/ping/blackberry.rb +55 -0
  115. data/lib/rhosync/ping/iphone.rb +44 -0
  116. data/lib/rhosync/ping.rb +2 -0
  117. data/lib/rhosync/read_state.rb +27 -0
  118. data/lib/rhosync/server/views/index.erb +12 -0
  119. data/lib/rhosync/server.rb +242 -0
  120. data/lib/rhosync/source.rb +112 -0
  121. data/lib/rhosync/source_adapter.rb +95 -0
  122. data/lib/rhosync/source_sync.rb +245 -0
  123. data/lib/rhosync/store.rb +199 -0
  124. data/lib/rhosync/tasks.rb +151 -0
  125. data/lib/rhosync/user.rb +83 -0
  126. data/lib/rhosync/version.rb +3 -0
  127. data/lib/rhosync.rb +251 -0
  128. data/spec/api/api_helper.rb +44 -0
  129. data/spec/api/create_client_spec.rb +13 -0
  130. data/spec/api/create_user_spec.rb +16 -0
  131. data/spec/api/delete_client_spec.rb +13 -0
  132. data/spec/api/delete_user_spec.rb +18 -0
  133. data/spec/api/get_api_token_spec.rb +25 -0
  134. data/spec/api/get_client_params_spec.rb +18 -0
  135. data/spec/api/get_db_doc_spec.rb +21 -0
  136. data/spec/api/get_license_info_spec.rb +16 -0
  137. data/spec/api/get_source_params_spec.rb +26 -0
  138. data/spec/api/list_client_docs_spec.rb +33 -0
  139. data/spec/api/list_clients_spec.rb +23 -0
  140. data/spec/api/list_source_docs_spec.rb +26 -0
  141. data/spec/api/list_sources_spec.rb +27 -0
  142. data/spec/api/list_users_spec.rb +21 -0
  143. data/spec/api/ping_spec.rb +24 -0
  144. data/spec/api/push_deletes_spec.rb +16 -0
  145. data/spec/api/push_objects_spec.rb +27 -0
  146. data/spec/api/reset_spec.rb +22 -0
  147. data/spec/api/set_db_doc_spec.rb +20 -0
  148. data/spec/api/set_refresh_time_spec.rb +43 -0
  149. data/spec/api/update_user_spec.rb +31 -0
  150. data/spec/api/upload_file_spec.rb +26 -0
  151. data/spec/api_token_spec.rb +13 -0
  152. data/spec/app_spec.rb +20 -0
  153. data/spec/apps/rhotestapp/Rakefile +1 -0
  154. data/spec/apps/rhotestapp/application.rb +16 -0
  155. data/spec/apps/rhotestapp/config.ru +1 -0
  156. data/spec/apps/rhotestapp/settings/apple_fake_cert.pem +1 -0
  157. data/spec/apps/rhotestapp/settings/license.key +1 -0
  158. data/spec/apps/rhotestapp/settings/settings.yml +23 -0
  159. data/spec/apps/rhotestapp/sources/base_adapter.rb +9 -0
  160. data/spec/apps/rhotestapp/sources/sample_adapter.rb +66 -0
  161. data/spec/apps/rhotestapp/sources/simple_adapter.rb +39 -0
  162. data/spec/apps/rhotestapp/sources/sub_adapter.rb +7 -0
  163. data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem/mygem.rb +8 -0
  164. data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem.rb +1 -0
  165. data/spec/bulk_data/bulk_data_spec.rb +79 -0
  166. data/spec/client_spec.rb +58 -0
  167. data/spec/client_sync_spec.rb +377 -0
  168. data/spec/doc/base.html +72 -0
  169. data/spec/doc/doc_spec.rb +303 -0
  170. data/spec/doc/footer.html +4 -0
  171. data/spec/doc/header.html +30 -0
  172. data/spec/document_spec.rb +27 -0
  173. data/spec/generator/generator_spec.rb +53 -0
  174. data/spec/generator/generator_spec_helper.rb +8 -0
  175. data/spec/jobs/bulk_data_job_spec.rb +76 -0
  176. data/spec/jobs/ping_job_spec.rb +26 -0
  177. data/spec/jobs/source_job_spec.rb +25 -0
  178. data/spec/license_spec.rb +48 -0
  179. data/spec/model_spec.rb +269 -0
  180. data/spec/perf/bulk_data_perf_spec.rb +33 -0
  181. data/spec/perf/perf_spec_helper.rb +51 -0
  182. data/spec/perf/store_perf_spec.rb +28 -0
  183. data/spec/ping/blackberry_spec.rb +62 -0
  184. data/spec/ping/iphone_spec.rb +50 -0
  185. data/spec/read_state_spec.rb +25 -0
  186. data/spec/rhosync_spec.rb +43 -0
  187. data/spec/server/server_spec.rb +341 -0
  188. data/spec/source_adapter_spec.rb +114 -0
  189. data/spec/source_spec.rb +77 -0
  190. data/spec/source_sync_spec.rb +248 -0
  191. data/spec/spec_helper.rb +240 -0
  192. data/spec/store_spec.rb +149 -0
  193. data/spec/sync_states_spec.rb +101 -0
  194. data/spec/testdata/1000-data.txt +1414 -0
  195. data/spec/testdata/compressed/compress-data.txt +1 -0
  196. data/spec/testdata/upload1.txt +1 -0
  197. data/spec/testdata/upload2.txt +1 -0
  198. data/spec/user_spec.rb +79 -0
  199. data/tasks/redis.rake +134 -0
  200. metadata +545 -0
@@ -0,0 +1,269 @@
1
+ # Taken from http://github.com/voloko/redis-model
2
+ require File.join(File.dirname(__FILE__),'spec_helper')
3
+
4
+ describe Rhosync::Model do
5
+
6
+ context "DSL" do
7
+ class TestDSL < Rhosync::Model
8
+ field :foo
9
+ list :bar
10
+ set :sloppy
11
+ end
12
+
13
+ before(:each) do
14
+ @x = TestDSL.with_key(1)
15
+ end
16
+
17
+ it "should define rw accessors for field" do
18
+ @x.should respond_to(:foo)
19
+ @x.should respond_to(:foo=)
20
+ end
21
+
22
+ it "should define r accessor for list" do
23
+ @x.should respond_to(:bar)
24
+ end
25
+
26
+ it "should define r accessor for set" do
27
+ @x.should respond_to(:sloppy)
28
+ end
29
+
30
+ it "should raise error on invalid type" do
31
+ lambda do
32
+ class TestInvalidType < Rhosync::Model
33
+ field :invalid, :invalid_type
34
+ end
35
+ end.should raise_error(ArgumentError, 'Unknown type invalid_type for field invalid')
36
+ end
37
+ end
38
+
39
+ context "field type cast" do
40
+ class TestType < Rhosync::Model
41
+ field :foo_string, :string
42
+ field :foo_json, :json
43
+ field :foo_date, :datetime
44
+ field :foo_int, :int
45
+ field :foo_float, :float
46
+
47
+ list :list_date, :datetime
48
+ set :set_date, :datetime
49
+ end
50
+
51
+ class TestValidateType < Rhosync::Model
52
+ field :v_field, :string
53
+ validates_presence_of :v_field
54
+ end
55
+
56
+ class TestLoadType < Rhosync::Model
57
+ field :something, :string
58
+ attr_accessor :foo
59
+ end
60
+
61
+ before(:each) do
62
+ @xRedisMock = Spec::Mocks::Mock.new
63
+ @yRedisMock = Spec::Mocks::Mock.new
64
+ @x = TestType.with_key(1)
65
+ @y = TestType.with_key(1)
66
+ @x.stub!(:redis).and_return(@xRedisMock)
67
+ @y.stub!(:redis).and_return(@yRedisMock)
68
+ end
69
+
70
+ it "should create with string id" do
71
+ @x = TestType.create(:id => 'test')
72
+ @x.id.should == 'test'
73
+ end
74
+
75
+ it "should create with auto-increment id" do
76
+ @x = TestType.create
77
+ @x1 = TestType.create
78
+ @x1.id.should == @x.id + 1
79
+ end
80
+
81
+ it "should raise ArgumentError on create with duplicate id" do
82
+ @x = TestType.create(:id => 'test1')
83
+ lambda { TestType.create(:id => 'test1') }.should
84
+ raise_error(ArgumentError, "Record already exists for 'test1'")
85
+ end
86
+
87
+ it "should validate_presence_of v_field" do
88
+ lambda { TestValidateType.create(:id => 'test2') }.should
89
+ raise_error(ArgumentError, "Missing required field 'v_field'")
90
+ end
91
+
92
+ it "should load with attributes set" do
93
+ TestLoadType.create(:id => 'test2')
94
+ @x = TestLoadType.load('test2',{:foo => 'bar'})
95
+ @x.foo.should == 'bar'
96
+ end
97
+
98
+ it "should save string as is" do
99
+ @xRedisMock.should_receive(:[]=).with('test_type:1:foo_string', 'xxx')
100
+ @yRedisMock.should_receive(:[]).with('test_type:1:foo_string').and_return('xxx')
101
+ @x.foo_string = 'xxx'
102
+ @y.foo_string.should be_instance_of(String)
103
+ end
104
+
105
+ it "should marshal integer fields" do
106
+ @xRedisMock.should_receive(:[]=).with('test_type:1:foo_int', '12')
107
+ @yRedisMock.should_receive(:[]).with('test_type:1:foo_int').and_return('12')
108
+ @x.foo_int = 12
109
+ @y.foo_int.should be_kind_of(Integer)
110
+ @y.foo_int.should == 12
111
+ end
112
+
113
+ it "should marshal float fields" do
114
+ @xRedisMock.should_receive(:[]=).with('test_type:1:foo_float', '12.1')
115
+ @yRedisMock.should_receive(:[]).with('test_type:1:foo_float').and_return('12.1')
116
+ @x.foo_float = 12.1
117
+ @y.foo_float.should be_kind_of(Float)
118
+ @y.foo_float.should == 12.1
119
+ end
120
+
121
+ it "should marshal datetime fields" do
122
+ time = DateTime.now
123
+ str = time.strftime('%FT%T%z')
124
+ @xRedisMock.should_receive(:[]=).with('test_type:1:foo_date', str)
125
+ @yRedisMock.should_receive(:[]).with('test_type:1:foo_date').and_return(str)
126
+ @x.foo_date = time
127
+ @y.foo_date.should be_kind_of(DateTime)
128
+ @y.foo_date.should.to_s == time.to_s
129
+ end
130
+
131
+ it "should marshal json structs" do
132
+ data = {'foo' => 'bar', 'x' => 2}
133
+ str = JSON.dump(data)
134
+ @xRedisMock.should_receive(:[]=).with('test_type:1:foo_json', str)
135
+ @yRedisMock.should_receive(:[]).with('test_type:1:foo_json').and_return(str)
136
+ @x.foo_json = data
137
+ @y.foo_json.should be_kind_of(Hash)
138
+ @y.foo_json.should.inspect == data.inspect
139
+ end
140
+
141
+ it "should return nil for empty fields" do
142
+ @xRedisMock.should_receive(:[]).with('test_type:1:foo_date').and_return(nil)
143
+ @x.foo_date.should be_nil
144
+ end
145
+
146
+ it "should marshal list values" do
147
+ data = DateTime.now
148
+ str = data.strftime('%FT%T%z')
149
+
150
+ @xRedisMock.should_receive('rpush').with('test_type:1:list_date', str)
151
+ @xRedisMock.should_receive('lset').with('test_type:1:list_date', 1, str)
152
+ @xRedisMock.should_receive('exists').with('test_type:1:list_date', str)
153
+ @xRedisMock.should_receive('lrem').with('test_type:1:list_date', 0, str)
154
+ @xRedisMock.should_receive('lpush').with('test_type:1:list_date', str)
155
+ @xRedisMock.should_receive('lrange').with('test_type:1:list_date', 0, 1).and_return([str])
156
+ @xRedisMock.should_receive('rpop').with('test_type:1:list_date').and_return(str)
157
+ @xRedisMock.should_receive('lpop').with('test_type:1:list_date').and_return(str)
158
+ @xRedisMock.should_receive('lindex').with('test_type:1:list_date', 0).and_return(str)
159
+ @x.list_date << data
160
+ @x.list_date[1] = data
161
+ @x.list_date.include?(data)
162
+ @x.list_date.remove(0, data)
163
+ @x.list_date.push_head(data)
164
+ @x.list_date[0].should be_kind_of(DateTime)
165
+ @x.list_date[0, 1][0].should be_kind_of(DateTime)
166
+ @x.list_date.pop_tail.should be_kind_of(DateTime)
167
+ @x.list_date.pop_head.should be_kind_of(DateTime)
168
+ end
169
+
170
+ it "should marshal set values" do
171
+ data = DateTime.now
172
+ str = data.strftime('%FT%T%z')
173
+
174
+ @xRedisMock.should_receive('sadd').with('test_type:1:set_date', str)
175
+ @xRedisMock.should_receive('srem').with('test_type:1:set_date', str)
176
+ @xRedisMock.should_receive('sismember').with('test_type:1:set_date', str)
177
+ @xRedisMock.should_receive('smembers').with('test_type:1:set_date').and_return([str])
178
+ @xRedisMock.should_receive('sinter').with('test_type:1:set_date', 'x').and_return([str])
179
+ @xRedisMock.should_receive('sunion').with('test_type:1:set_date', 'x').and_return([str])
180
+ @xRedisMock.should_receive('sdiff').with('test_type:1:set_date', 'x', 'y').and_return([str])
181
+ @x.set_date << data
182
+ @x.set_date.delete(data)
183
+ @x.set_date.include?(data)
184
+ @x.set_date.members[0].should be_kind_of(DateTime)
185
+ @x.set_date.intersect('x')[0].should be_kind_of(DateTime)
186
+ @x.set_date.union('x')[0].should be_kind_of(DateTime)
187
+ @x.set_date.diff('x', 'y')[0].should be_kind_of(DateTime)
188
+ end
189
+
190
+ end
191
+
192
+ context "increment/decrement" do
193
+ class TestIncrements < Rhosync::Model
194
+ field :foo, :integer
195
+ field :bar, :string
196
+ field :baz, :float
197
+ end
198
+
199
+ before do
200
+ @redisMock = Spec::Mocks::Mock.new
201
+ @x = TestIncrements.with_key(1)
202
+ @x.stub!(:redis).and_return(@redisMock)
203
+ end
204
+
205
+ it "should send INCR when #increment! is called on an integer" do
206
+ @redisMock.should_receive(:incr).with("test_increments:1:foo", 1)
207
+ @x.increment!(:foo)
208
+ end
209
+
210
+ it "should send DECR when #decrement! is called on an integer" do
211
+ @redisMock.should_receive(:decr).with("test_increments:1:foo", 1)
212
+ @x.decrement!(:foo)
213
+ end
214
+
215
+ it "should raise an ArgumentError when called on non-integers" do
216
+ [:bar, :baz].each do |f|
217
+ lambda{@x.increment!(f)}.should raise_error(ArgumentError)
218
+ lambda{@x.decrement!(f)}.should raise_error(ArgumentError)
219
+ end
220
+ end
221
+ end
222
+
223
+ context "redis commands" do
224
+ class TestCommands < Rhosync::Model
225
+ field :foo
226
+ list :bar
227
+ set :sloppy
228
+ end
229
+
230
+ before(:each) do
231
+ @redisMock = Spec::Mocks::Mock.new
232
+ @x = TestCommands.with_key(1)
233
+ @x.stub!(:redis).and_return(@redisMock)
234
+ end
235
+
236
+ it "should send GET on field read" do
237
+ @redisMock.should_receive(:[]).with('test_commands:1:foo')
238
+ @x.foo
239
+ end
240
+
241
+ it "should send SET on field write" do
242
+ @redisMock.should_receive(:[]=).with('test_commands:1:foo', 'bar')
243
+ @x.foo = 'bar'
244
+ end
245
+
246
+ it "should send RPUSH on list <<" do
247
+ @redisMock.should_receive(:rpush).with('test_commands:1:bar', 'bar')
248
+ @x.bar << 'bar'
249
+ end
250
+
251
+ it "should send SADD on set <<" do
252
+ @redisMock.should_receive(:sadd).with('test_commands:1:sloppy', 'bar')
253
+ @x.sloppy << 'bar'
254
+ end
255
+
256
+ it "should delete separate fields" do
257
+ @redisMock.should_receive(:del).with('test_commands:1:foo')
258
+ @x.delete :foo
259
+ end
260
+
261
+ it "should delete all field" do
262
+ @redisMock.should_receive(:del).with('test_commands:1:foo')
263
+ @redisMock.should_receive(:del).with('test_commands:1:rho__id')
264
+ @redisMock.should_receive(:del).with('test_commands:1:bar')
265
+ @redisMock.should_receive(:del).with('test_commands:1:sloppy')
266
+ @x.delete
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,33 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+ require File.join(File.dirname(__FILE__),'perf_spec_helper')
3
+
4
+ describe "BulkData Performance" do
5
+ it_should_behave_like "SourceAdapterHelper"
6
+ it_should_behave_like "PerfSpecHelper"
7
+
8
+ before(:each) do
9
+ basedir = File.join(File.dirname(__FILE__),'..','apps','rhotestapp')
10
+ Rhosync.bootstrap(basedir) do |rhosync|
11
+ rhosync.vendor_directory = File.join(basedir,'..','vendor')
12
+ end
13
+ end
14
+
15
+ after(:each) do
16
+ delete_data_directory
17
+ end
18
+
19
+ it "should generate sqlite bulk data for 1000 objects (6000 attributes)" do
20
+ start = start_timer
21
+ @data = get_test_data(1000)
22
+ start = lap_timer('generate data',start)
23
+ set_state('test_db_storage' => @data)
24
+ start = lap_timer('set_state masterdoc',start)
25
+ data = BulkData.create(:name => bulk_data_docname(@a.id,@u.id),
26
+ :state => :inprogress,
27
+ :app_id => @a.id,
28
+ :user_id => @u.id,
29
+ :sources => [@s_fields[:name]])
30
+ BulkDataJob.perform("data_name" => data.name)
31
+ lap_timer('BulkDataJob.perform duration',start)
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ require 'faker'
2
+
3
+ describe "PerfSpecHelper", :shared => true do
4
+
5
+ def get_test_data(num=1000)
6
+ file = File.join("spec","testdata","#{num}-data.txt")
7
+ data = nil
8
+ if File.exists?(file)
9
+ data = open(file, 'r') {|f| Marshal.load(f)}
10
+ else
11
+ data = generate_fake_data(num)
12
+ f = File.new(file, 'w')
13
+ f.write Marshal.dump(data)
14
+ f.close
15
+ end
16
+ data
17
+ end
18
+
19
+ private
20
+
21
+ PREFIX = ["Account", "Administrative", "Advertising", "Assistant", "Banking", "Business Systems",
22
+ "Computer", "Distribution", "IT", "Electronics", "Environmental", "Financial", "General", "Head",
23
+ "Laboratory", "Maintenance", "Medical", "Production", "Quality Assurance", "Software", "Technical",
24
+ "Chief", "Senior"] unless defined? PREFIX
25
+ SUFFIX = ["Clerk", "Analyst", "Manager", "Supervisor", "Plant Manager", "Mechanic", "Technician", "Engineer",
26
+ "Director", "Superintendent", "Specialist", "Technologist", "Estimator", "Scientist", "Foreman", "Nurse",
27
+ "Worker", "Helper", "Intern", "Sales", "Mechanic", "Planner", "Recruiter", "Officer", "Superintendent",
28
+ "Vice President", "Buyer", "Production Supervisor", "Chef", "Accountant", "Executive"] unless defined? SUFFIX
29
+
30
+ def title
31
+ prefix = PREFIX[rand(PREFIX.length)]
32
+ suffix = SUFFIX[rand(SUFFIX.length)]
33
+
34
+ "#{prefix} #{suffix}"
35
+ end
36
+
37
+ def generate_fake_data(num=1000)
38
+ res = {}
39
+ num.times do |n|
40
+ res[n.to_s] = {
41
+ "FirstName" => Faker::Name.first_name,
42
+ "LastName" => Faker::Name.last_name,
43
+ "Email" => Faker::Internet.free_email,
44
+ "Company" => Faker::Company.name,
45
+ "JobTitle" => title,
46
+ "Phone1" => Faker::PhoneNumber.phone_number
47
+ }
48
+ end
49
+ res
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+ require File.join(File.dirname(__FILE__),'perf_spec_helper')
3
+
4
+ describe "Rhosync Performance" do
5
+ it_should_behave_like "SourceAdapterHelper"
6
+ it_should_behave_like "PerfSpecHelper"
7
+
8
+ it "should process get/put for 1000 records (6000 elements)" do
9
+ @data = get_test_data(1000)
10
+ start = start_timer
11
+ Store.put_data('mdoc',@data).should == true
12
+ start = lap_timer('put_data duration',start)
13
+ Store.get_data('mdoc').should == @data
14
+ lap_timer('get_data duration',start)
15
+ end
16
+
17
+ it "should process single attribute update 1000-record doc" do
18
+ @data = get_test_data(1000)
19
+ @data1 = get_test_data(1000)
20
+ @data1['950']['Phone1'] = 'This is changed'
21
+ expected = {'950' => {'Phone1' => 'This is changed'}}
22
+ Store.put_data('mdoc',@data).should == true
23
+ Store.put_data('cdoc',@data1).should == true
24
+ start = start_timer
25
+ Store.get_diff_data('mdoc','cdoc').should == [expected,1]
26
+ lap_timer('get_diff_data duration', start)
27
+ end
28
+ end
@@ -0,0 +1,62 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe "Ping Blackberry" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ before do
8
+ @params = {"user_id" => @u.id, "api_token" => @api_token,
9
+ "sources" => [@s.name], "message" => 'hello world',
10
+ "vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3',
11
+ "device_pin" => @c.device_pin, "device_port" => @c.device_port}
12
+ post = mock('post')
13
+ post.stub!(:new).and_return(post)
14
+ post.stub!(:body=)
15
+ Net::HTTP::Post.stub!(:new).and_return(post)
16
+
17
+ @http = mock('http')
18
+ @http.stub!(:request)
19
+ @http.stub!(:start).and_yield(@http)
20
+ Net::HTTP.stub!(:new).and_return(@http)
21
+ end
22
+
23
+ it "should ping blackberry" do
24
+ Blackberry.ping(@params)
25
+ end
26
+
27
+ it "should ping blackberry with connection error" do
28
+ error = 'Connection refused'
29
+ @http.stub!(:request).and_return { raise SocketError.new(error) }
30
+ Blackberry.should_receive(:log).once.with("Error while sending ping: #{error}")
31
+ lambda { Blackberry.ping(@params) }.should raise_error(SocketError,error)
32
+ end
33
+
34
+ it "should compute pap_message" do
35
+ expected = <<PAP
36
+ --asdlfkjiurwghasf
37
+ Content-Type: application/xml; charset=UTF-8
38
+
39
+ <?xml version="1.0"?>
40
+ <!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.0//EN"
41
+ "http://www.wapforum.org/DTD/pap_2.0.dtd"
42
+ [<?wap-pap-ver supported-versions="2.0"?>]>
43
+ <pap>
44
+ <push-message push-id="pushID:RAND_ID" ppg-notify-requested-to="http://localhost:7778">
45
+
46
+ <address address-value="WAPPUSH=0%3A100/TYPE=USER@rim.net"/>
47
+ <quality-of-service delivery-method="preferconfirmed"/>
48
+ </push-message>
49
+ </pap>
50
+ --asdlfkjiurwghasf
51
+ Content-Type: text/plain
52
+
53
+ do_sync=SampleAdapter
54
+ show_popup=hello world
55
+ vibrate=5
56
+
57
+ --asdlfkjiurwghasf--
58
+ PAP
59
+ actual = Blackberry.pap_message(@params).gsub!(/pushID\:\d+/,'pushID:RAND_ID')
60
+ actual.gsub!(/\r|\n|\s/,"").should == expected.gsub!(/\r|\n|\s/,"")
61
+ end
62
+ end
@@ -0,0 +1,50 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe "Ping Iphone" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ before do
8
+ @params = {"user_id" => @u.id, "api_token" => @api_token,
9
+ "sources" => [@s.name], "message" => 'hello world',
10
+ "vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3',
11
+ "device_pin" => @c.device_pin, "device_port" => @c.device_port}
12
+ ssl_ctx = mock("ssl_ctx")
13
+ ssl_ctx.stub!(:key=).and_return('key')
14
+ ssl_ctx.stub!(:cert=).and_return('cert')
15
+ OpenSSL::SSL::SSLContext.stub!(:new).and_return(ssl_ctx)
16
+ OpenSSL::PKey::RSA.stub!(:new)
17
+ OpenSSL::X509::Certificate.stub!(:new)
18
+
19
+ tcp_socket = mock("tcp_socket")
20
+ tcp_socket.stub!(:close)
21
+ TCPSocket.stub!(:new).and_return(tcp_socket)
22
+
23
+ @ssl_socket = mock("ssl_socket")
24
+ @ssl_socket.stub!(:sync=)
25
+ @ssl_socket.stub!(:connect)
26
+ @ssl_socket.stub!(:write)
27
+ @ssl_socket.stub!(:close)
28
+ OpenSSL::SSL::SSLSocket.stub!(:new).and_return(@ssl_socket)
29
+ end
30
+
31
+ # TODO: This should really test SSLSocket.write
32
+ it "should ping iphone" do
33
+ Iphone.ping(@params)
34
+ end
35
+
36
+ it "should compute apn_message" do
37
+ expected = <<-eos
38
+ \000\000 \253\315\000g{"aps":{"vibrate":"5","badge":5,"sound":"hello.mp3","alert":"hello world"},"do_sync":["SampleAdapter"]}
39
+ eos
40
+ Iphone.apn_message(@params).should == expected.strip!
41
+ end
42
+
43
+ it "should raise SocketError if socket fails" do
44
+ error = 'socket error'
45
+ @ssl_socket.stub!(:write).and_return { raise SocketError.new(error) }
46
+ Iphone.should_receive(:log).once.with("Error while sending ping: #{error}")
47
+ lambda { Iphone.ping(@params) }.should raise_error(SocketError,error)
48
+ end
49
+
50
+ end
@@ -0,0 +1,25 @@
1
+ require File.join(File.dirname(__FILE__),'spec_helper')
2
+
3
+ describe "ReadState" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ it "should create refresh with correct id" do
8
+ @r.id.should == "#{@a_fields[:name]}:#{@u_fields[:login]}:#{@s_fields[:name]}"
9
+ end
10
+
11
+ it "should create refresh with default fields" do
12
+ @r.refresh_time.should <= Time.now.to_i
13
+ end
14
+
15
+ it "should load refresh with params" do
16
+ @r1 = ReadState.load(:app_id => @a_fields[:name],
17
+ :user_id => @u_fields[:login],:source_name => @s_fields[:name])
18
+ @r1.refresh_time.should <= Time.now.to_i
19
+ end
20
+
21
+ it "should delete read_state from db" do
22
+ ReadState.delete(@a_fields[:name])
23
+ Store.db.keys("read_state*").should == []
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(__FILE__),'spec_helper')
2
+
3
+ describe "Rhosync" do
4
+ it_should_behave_like "RhosyncHelper"
5
+ it_should_behave_like "TestappHelper"
6
+
7
+ it "should bootstrap Rhosync with block" do
8
+ Rhosync.bootstrap(get_testapp_path) do |rhosync|
9
+ rhosync.vendor_directory = 'foo'
10
+ end
11
+ path = get_testapp_path
12
+ File.expand_path(Rhosync.base_directory).should == path
13
+ File.expand_path(Rhosync.app_directory).should == path
14
+ File.expand_path(Rhosync.data_directory).should == File.join(path,'data')
15
+ Rhosync.vendor_directory.should == 'foo'
16
+ Rhosync.blackberry_bulk_sync.should == false
17
+ Rhosync.environment.should == :development
18
+ App.is_exist?(@test_app_name).should be_true
19
+ end
20
+
21
+ it "should bootstrap Rhosync with RHO_ENV provided" do
22
+ ENV['RHO_ENV'] = 'production'
23
+ Rhosync.bootstrap(get_testapp_path)
24
+ Rhosync.environment.should == :production
25
+ ENV.delete('RHO_ENV')
26
+ end
27
+
28
+ it "should bootstrap with existing app" do
29
+ app = App.create(:name => @test_app_name)
30
+ App.should_receive(:load).once.with(@test_app_name).and_return(app)
31
+ Rhosync.bootstrap(get_testapp_path)
32
+ end
33
+
34
+ it "should bootstrap app with no sources" do
35
+ app = App.create(:name => @test_app_name)
36
+ Rhosync.stub!(:get_config).and_return(
37
+ { Rhosync.environment.to_sym => { :licensefile => 'settings/license.key' } }
38
+ )
39
+ App.should_receive(:load).twice.with(@test_app_name).and_return(app)
40
+ Rhosync.bootstrap(get_testapp_path)
41
+ App.load(@test_app_name).sources.members.should == []
42
+ end
43
+ end