rhoconnect 3.0.2 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -181,10 +181,23 @@ module Rhoconnect
181
181
 
182
182
  # Deletes all keys matching a given mask
183
183
  def flash_data(keymask)
184
- @@db.keys(keymask).each do |key|
185
- @@db.del(key)
184
+ if keymask[/[*\[\]?]/]
185
+ # If the keymask contains any pattern matching characters
186
+ # Use keys command to find all keys matching pattern (this is extremely expensive)
187
+ # Then delete matches
188
+ @@db.keys(keymask).each do |key|
189
+ @@db.del(key)
190
+ end
191
+ else
192
+ # The keymask doesn't contain pattern matching characters
193
+ # A delete call is all that is needed
194
+ @@db.del(keymask)
186
195
  end
187
196
  end
197
+
198
+ def exists?(key)
199
+ @@db.exists(key)
200
+ end
188
201
 
189
202
  # Returns array of keys matching a given keymask
190
203
  def get_keys(keymask)
@@ -210,19 +223,27 @@ module Rhoconnect
210
223
  ts = current_time+(Rhoconnect.lock_duration || timeout)+1
211
224
  loop do
212
225
  if not @@db.setnx(lock_key,ts)
213
- if raise_on_expire or Rhoconnect.raise_on_expired_lock
214
- if @@db.get(lock_key).to_i <= current_time
215
- # lock expired before operation which set it up completed
216
- # this process cannot continue without corrupting locked data
217
- raise StoreLockException, "Lock \"#{lock_key}\" expired before it was released"
218
- end
219
- else
220
- if @@db.get(lock_key).to_i <= current_time and
221
- @@db.getset(lock_key,ts).to_i <= current_time
222
- # previous lock expired and we replaced it with our own
223
- break
224
- end
225
- end
226
+ current_lock = @@db.get(lock_key)
227
+ # ensure lock wasn't released between the setnx and get calls
228
+ if current_lock
229
+ current_lock_timeout = current_lock.to_i
230
+ if raise_on_expire or Rhoconnect.raise_on_expired_lock
231
+ if current_lock_timeout <= current_time
232
+ # lock expired before operation which set it up completed
233
+ # this process cannot continue without corrupting locked data
234
+ raise StoreLockException, "Lock \"#{lock_key}\" expired before it was released"
235
+ end
236
+ else
237
+ if current_lock_timeout <= current_time and
238
+ @@db.getset(lock_key,ts).to_i <= current_time
239
+ # previous lock expired and we replaced it with our own
240
+ break
241
+ end
242
+ end
243
+ # lock was released between setnx and get - try to acquire it again
244
+ elsif @@db.setnx(lock_key,ts)
245
+ break
246
+ end
226
247
  sleep(1)
227
248
  current_time = Time.now.to_i
228
249
  else
@@ -1,3 +1,3 @@
1
1
  module Rhoconnect
2
- VERSION = '3.0.2'
2
+ VERSION = '3.0.3'
3
3
  end
data/rhoconnect.gemspec CHANGED
@@ -43,7 +43,7 @@ Gem::Specification.new do |s|
43
43
  s.add_dependency('rubyzip', '~> 0.9.4')
44
44
  s.add_dependency('uuidtools', '>= 2.1.1')
45
45
  s.add_dependency('redis', '>= 2.2.0')
46
- s.add_dependency('resque', '~> 1.18.0')
46
+ s.add_dependency('resque', '~> 1.19.0')
47
47
  s.add_dependency('rest-client', '~> 1.6.1')
48
48
  s.add_dependency('templater', '~> 1.0.0')
49
49
  end
@@ -231,25 +231,97 @@ describe "SourceSync" do
231
231
  verify_read_operation_with_error('query')
232
232
  end
233
233
 
234
+ it "should do query with exception raised and update refresh time only after retries limit is exceeded" do
235
+ @s.retry_limit = 1
236
+ msg = "Error during query"
237
+ set_test_data('test_db_storage',{},msg,"query error")
238
+ res = @ss.do_query
239
+ verify_result(@s.docname(:md) => {},
240
+ @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
241
+ # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
242
+ @s.read_state.retry_counter.should == 1
243
+ @s.read_state.refresh_time.should <= Time.now.to_i
244
+
245
+ # try once more and fail again
246
+ set_test_data('test_db_storage',{},msg,"query error")
247
+ res = @ss.do_query
248
+ verify_result(@s.docname(:md) => {},
249
+ @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
250
+
251
+ # 2) if retry_limit is set to N and number of retries exceeded it - update refresh_time
252
+ @s.read_state.retry_counter.should == 0
253
+ @s.read_state.refresh_time.should > Time.now.to_i
254
+ end
255
+
256
+ it "should do query with exception raised and restore state with succesfull retry" do
257
+ @s.retry_limit = 1
258
+ msg = "Error during query"
259
+ set_test_data('test_db_storage',{},msg,"query error")
260
+ res = @ss.do_query
261
+ verify_result(@s.docname(:md) => {},
262
+ @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
263
+ # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
264
+ @s.read_state.retry_counter.should == 1
265
+ @s.read_state.refresh_time.should <= Time.now.to_i
266
+
267
+ # try once more (with success)
268
+ expected = {'1'=>@product1,'2'=>@product2}
269
+ set_test_data('test_db_storage',expected)
270
+ @ss.do_query
271
+ verify_result(@s.docname(:md) => expected,
272
+ @s.docname(:errors) => {})
273
+ @s.read_state.retry_counter.should == 0
274
+ @s.read_state.refresh_time.should > Time.now.to_i
275
+ end
276
+
277
+ it "should reset the retry counter if prev_refresh_time was set more than poll_interval secs ago" do
278
+ @s.retry_limit = 3
279
+ @s.poll_interval = 2
280
+ msg = "Error during query"
281
+ set_test_data('test_db_storage',{},msg,"query error")
282
+ res = @ss.do_query
283
+ verify_result(@s.docname(:md) => {},
284
+ @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
285
+ # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
286
+ @s.read_state.retry_counter.should == 1
287
+ @s.read_state.refresh_time.should <= Time.now.to_i
288
+
289
+ # 2) Make another error - results are the same
290
+ set_test_data('test_db_storage',{},msg,"query error")
291
+ res = @ss.do_query
292
+ verify_result(@s.docname(:md) => {},
293
+ @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
294
+ @s.read_state.retry_counter.should == 2
295
+ @s.read_state.refresh_time.should <= Time.now.to_i
296
+
297
+ # wait until time interval exprires and prev_refresh_time is too old -
298
+ # this should reset the counter on next request with error
299
+ # and do not update refresh_time
300
+ sleep(3)
301
+ set_test_data('test_db_storage',{},msg,"query error")
302
+ res = @ss.do_query
303
+ verify_result(@s.docname(:md) => {},
304
+ @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
305
+ @s.read_state.retry_counter.should == 1
306
+ @s.read_state.refresh_time.should <= Time.now.to_i
307
+ end
308
+
234
309
  it "should do query with exception raised and update refresh time if retry_limit is 0" do
235
310
  @s.retry_limit = 0
236
311
  msg = "Error during query"
237
- @ss.should_receive(:log).with("SourceAdapter raised query exception: #{msg}")
238
- @ss.should_receive(:log).with(anything)
239
312
  set_test_data('test_db_storage',{},msg,"query error")
240
313
  res = @ss.do_query
241
314
  verify_result(@s.docname(:md) => {},
242
315
  @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
316
+ # if poll_interval is set to 0 - refresh time should be updated
243
317
  @s.read_state.retry_counter.should == 0
244
318
  @s.read_state.refresh_time.should > Time.now.to_i
245
319
  end
246
-
320
+
247
321
  it "should do query with exception raised and update refresh time if poll_interval == 0" do
248
322
  @s.retry_limit = 1
249
323
  @s.poll_interval = 0
250
324
  msg = "Error during query"
251
- @ss.should_receive(:log).with("SourceAdapter raised query exception: #{msg}")
252
- @ss.should_receive(:log).with(anything)
253
325
  set_test_data('test_db_storage',{},msg,"query error")
254
326
  prev_refresh_time = @s.read_state.refresh_time
255
327
  # make sure refresh time is expired
@@ -288,6 +360,7 @@ describe "SourceSync" do
288
360
  verify_result("source:#{test_app_name}:__shared__:#{@s_fields[:name]}:md" => expected)
289
361
  Store.db.keys("read_state:#{test_app_name}:__shared__*").sort.should ==
290
362
  [ "read_state:#{test_app_name}:__shared__:SampleAdapter:refresh_time",
363
+ "read_state:#{test_app_name}:__shared__:SampleAdapter:prev_refresh_time",
291
364
  "read_state:#{test_app_name}:__shared__:SampleAdapter:rho__id",
292
365
  "read_state:#{test_app_name}:__shared__:SampleAdapter:retry_counter"].sort
293
366
  end
data/spec/store_spec.rb CHANGED
@@ -164,6 +164,29 @@ describe "Store" do
164
164
  Store.flash_data(@s.docname(:md))
165
165
  Store.get_data(@s.docname(:md)).should == {}
166
166
  end
167
+
168
+ it "should flash_data for all keys matching pattern" do
169
+ keys = ['test_flash_data1','test_flash_data2']
170
+ keys.each {|key| Store.put_data(key,@data)}
171
+ Store.flash_data('test_flash_data*')
172
+ keys.each {|key| Store.get_data(key).should == {} }
173
+ end
174
+
175
+ it "should flash_data without calling KEYS when there aren't pattern matching characters in the provided keymask" do
176
+ key = 'test_flash_data'
177
+ Store.put_data(key,@data)
178
+ Store.db.should_not_receive(:keys)
179
+ Store.db.should_receive(:del).once.with(key).and_return(true)
180
+ Store.flash_data(key)
181
+ end
182
+
183
+ it "should flash_data and call KEYS when there are pattern matching characters in the provided keymask" do
184
+ keys = ['test_flash_data1','test_flash_data2']
185
+ keys.each {|key| Store.put_data(key,@data)}
186
+ Store.db.should_receive(:keys).exactly(1).times.with("test_flash_data*").and_return(keys)
187
+ Store.db.should_receive(:del).exactly(2).times.with(/^test_flash_data[12]$/).and_return(true)
188
+ Store.flash_data("test_flash_data*")
189
+ end
167
190
 
168
191
  it "should get_keys" do
169
192
  expected = ["doc1:1:1:1:source1", "doc1:1:1:1:source2"]
metadata CHANGED
@@ -1,190 +1,135 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rhoconnect
3
- version: !ruby/object:Gem::Version
4
- hash: 3
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.3
5
5
  prerelease:
6
- segments:
7
- - 3
8
- - 0
9
- - 2
10
- version: 3.0.2
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Rhomobile
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-10-05 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- type: :runtime
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
12
+ date: 2011-10-13 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &2160601560 !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
18
+ requirements:
26
19
  - - ~>
27
- - !ruby/object:Gem::Version
28
- hash: 15
29
- segments:
30
- - 1
31
- - 0
32
- version: "1.0"
33
- version_requirements: *id001
34
- name: bundler
35
- - !ruby/object:Gem::Dependency
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
36
22
  type: :runtime
37
23
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *2160601560
25
+ - !ruby/object:Gem::Dependency
26
+ name: sinatra
27
+ requirement: &2160591620 !ruby/object:Gem::Requirement
39
28
  none: false
40
- requirements:
29
+ requirements:
41
30
  - - ~>
42
- - !ruby/object:Gem::Version
43
- hash: 9
44
- segments:
45
- - 1
46
- - 3
47
- version: "1.3"
48
- version_requirements: *id002
49
- name: sinatra
50
- - !ruby/object:Gem::Dependency
31
+ - !ruby/object:Gem::Version
32
+ version: '1.3'
51
33
  type: :runtime
52
34
  prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *2160591620
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &2160590320 !ruby/object:Gem::Requirement
54
39
  none: false
55
- requirements:
56
- - - "="
57
- - !ruby/object:Gem::Version
58
- hash: 63
59
- segments:
60
- - 0
61
- - 9
62
- - 2
40
+ requirements:
41
+ - - =
42
+ - !ruby/object:Gem::Version
63
43
  version: 0.9.2
64
- version_requirements: *id003
65
- name: rake
66
- - !ruby/object:Gem::Dependency
67
44
  type: :runtime
68
45
  prerelease: false
69
- requirement: &id004 !ruby/object:Gem::Requirement
46
+ version_requirements: *2160590320
47
+ - !ruby/object:Gem::Dependency
48
+ name: json
49
+ requirement: &2160588440 !ruby/object:Gem::Requirement
70
50
  none: false
71
- requirements:
51
+ requirements:
72
52
  - - ~>
73
- - !ruby/object:Gem::Version
74
- hash: 3
75
- segments:
76
- - 1
77
- - 5
78
- - 0
53
+ - !ruby/object:Gem::Version
79
54
  version: 1.5.0
80
- version_requirements: *id004
81
- name: json
82
- - !ruby/object:Gem::Dependency
83
55
  type: :runtime
84
56
  prerelease: false
85
- requirement: &id005 !ruby/object:Gem::Requirement
57
+ version_requirements: *2160588440
58
+ - !ruby/object:Gem::Dependency
59
+ name: rubyzip
60
+ requirement: &2160586960 !ruby/object:Gem::Requirement
86
61
  none: false
87
- requirements:
62
+ requirements:
88
63
  - - ~>
89
- - !ruby/object:Gem::Version
90
- hash: 51
91
- segments:
92
- - 0
93
- - 9
94
- - 4
64
+ - !ruby/object:Gem::Version
95
65
  version: 0.9.4
96
- version_requirements: *id005
97
- name: rubyzip
98
- - !ruby/object:Gem::Dependency
99
66
  type: :runtime
100
67
  prerelease: false
101
- requirement: &id006 !ruby/object:Gem::Requirement
68
+ version_requirements: *2160586960
69
+ - !ruby/object:Gem::Dependency
70
+ name: uuidtools
71
+ requirement: &2160585460 !ruby/object:Gem::Requirement
102
72
  none: false
103
- requirements:
104
- - - ">="
105
- - !ruby/object:Gem::Version
106
- hash: 9
107
- segments:
108
- - 2
109
- - 1
110
- - 1
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
111
76
  version: 2.1.1
112
- version_requirements: *id006
113
- name: uuidtools
114
- - !ruby/object:Gem::Dependency
115
77
  type: :runtime
116
78
  prerelease: false
117
- requirement: &id007 !ruby/object:Gem::Requirement
79
+ version_requirements: *2160585460
80
+ - !ruby/object:Gem::Dependency
81
+ name: redis
82
+ requirement: &2160556320 !ruby/object:Gem::Requirement
118
83
  none: false
119
- requirements:
120
- - - ">="
121
- - !ruby/object:Gem::Version
122
- hash: 7
123
- segments:
124
- - 2
125
- - 2
126
- - 0
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
127
87
  version: 2.2.0
128
- version_requirements: *id007
129
- name: redis
130
- - !ruby/object:Gem::Dependency
131
88
  type: :runtime
132
89
  prerelease: false
133
- requirement: &id008 !ruby/object:Gem::Requirement
90
+ version_requirements: *2160556320
91
+ - !ruby/object:Gem::Dependency
92
+ name: resque
93
+ requirement: &2160555260 !ruby/object:Gem::Requirement
134
94
  none: false
135
- requirements:
95
+ requirements:
136
96
  - - ~>
137
- - !ruby/object:Gem::Version
138
- hash: 95
139
- segments:
140
- - 1
141
- - 18
142
- - 0
143
- version: 1.18.0
144
- version_requirements: *id008
145
- name: resque
146
- - !ruby/object:Gem::Dependency
97
+ - !ruby/object:Gem::Version
98
+ version: 1.19.0
147
99
  type: :runtime
148
100
  prerelease: false
149
- requirement: &id009 !ruby/object:Gem::Requirement
101
+ version_requirements: *2160555260
102
+ - !ruby/object:Gem::Dependency
103
+ name: rest-client
104
+ requirement: &2160553000 !ruby/object:Gem::Requirement
150
105
  none: false
151
- requirements:
106
+ requirements:
152
107
  - - ~>
153
- - !ruby/object:Gem::Version
154
- hash: 13
155
- segments:
156
- - 1
157
- - 6
158
- - 1
108
+ - !ruby/object:Gem::Version
159
109
  version: 1.6.1
160
- version_requirements: *id009
161
- name: rest-client
162
- - !ruby/object:Gem::Dependency
163
110
  type: :runtime
164
111
  prerelease: false
165
- requirement: &id010 !ruby/object:Gem::Requirement
112
+ version_requirements: *2160553000
113
+ - !ruby/object:Gem::Dependency
114
+ name: templater
115
+ requirement: &2160551640 !ruby/object:Gem::Requirement
166
116
  none: false
167
- requirements:
117
+ requirements:
168
118
  - - ~>
169
- - !ruby/object:Gem::Version
170
- hash: 23
171
- segments:
172
- - 1
173
- - 0
174
- - 0
119
+ - !ruby/object:Gem::Version
175
120
  version: 1.0.0
176
- version_requirements: *id010
177
- name: templater
121
+ type: :runtime
122
+ prerelease: false
123
+ version_requirements: *2160551640
178
124
  description: RhoConnect App Integration Server and related command-line utilities
179
125
  email: dev@rhomobile.com
180
- executables:
126
+ executables:
181
127
  - rhoconnect
182
128
  extensions: []
183
-
184
- extra_rdoc_files:
129
+ extra_rdoc_files:
185
130
  - LICENSE
186
131
  - README.md
187
- files:
132
+ files:
188
133
  - CHANGELOG.md
189
134
  - CREDITS
190
135
  - Gemfile
@@ -265,6 +210,7 @@ files:
265
210
  - doc/benchmarks.txt
266
211
  - doc/blob-sync.txt
267
212
  - doc/bulk-sync.txt
213
+ - doc/client-objc.txt
268
214
  - doc/client.txt
269
215
  - doc/command-line.txt
270
216
  - doc/contributing.txt
@@ -292,7 +238,6 @@ files:
292
238
  - doc/web-console.txt
293
239
  - examples/simple/application.rb
294
240
  - examples/simple/config.ru
295
- - examples/simple/dump.rdb
296
241
  - examples/simple/Rakefile
297
242
  - examples/simple/settings/license.key
298
243
  - examples/simple/settings/settings.yml
@@ -561,38 +506,32 @@ files:
561
506
  - bin/rhoconnect
562
507
  homepage: http://rhomobile.com/products/rhoconnect
563
508
  licenses: []
564
-
565
509
  post_install_message:
566
510
  rdoc_options: []
567
-
568
- require_paths:
511
+ require_paths:
569
512
  - lib
570
- required_ruby_version: !ruby/object:Gem::Requirement
513
+ required_ruby_version: !ruby/object:Gem::Requirement
571
514
  none: false
572
- requirements:
573
- - - ">="
574
- - !ruby/object:Gem::Version
575
- hash: 3
576
- segments:
515
+ requirements:
516
+ - - ! '>='
517
+ - !ruby/object:Gem::Version
518
+ version: '0'
519
+ segments:
577
520
  - 0
578
- version: "0"
579
- required_rubygems_version: !ruby/object:Gem::Requirement
521
+ hash: -2200436175486104004
522
+ required_rubygems_version: !ruby/object:Gem::Requirement
580
523
  none: false
581
- requirements:
582
- - - ">="
583
- - !ruby/object:Gem::Version
584
- hash: 3
585
- segments:
586
- - 0
587
- version: "0"
524
+ requirements:
525
+ - - ! '>='
526
+ - !ruby/object:Gem::Version
527
+ version: '0'
588
528
  requirements: []
589
-
590
529
  rubyforge_project:
591
530
  rubygems_version: 1.8.10
592
531
  signing_key:
593
532
  specification_version: 3
594
533
  summary: RhoConnect App Integration Server
595
- test_files:
534
+ test_files:
596
535
  - spec/api/admin/api_token_spec.rb
597
536
  - spec/api/admin/get_api_token_spec.rb
598
537
  - spec/api/admin/get_license_info_spec.rb
Binary file