rhosync 2.1.0.beta.1 → 2.1.0.beta.2

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/CHANGELOG CHANGED
@@ -6,6 +6,14 @@
6
6
  * #5821277 - http stats by source not showing
7
7
  * #5899454 - move lock prefix to beginning so we don't return stats keys with it
8
8
  * #5822966 - bulk sync data file cannot handle space in the username
9
+ * #6450519 - blob sync resend_page doesn't send metadata
10
+ * #4646791 - cryptic error message if client exists, but source name is bogus
11
+ * #6827511 - fill in schema column in bulk sync file sources table
12
+ * #4490679 - support schema method in source adapter (runtime schema for bulk data)
13
+ * #6573429 - if schema changed in any adapter, invalidate bulk data file
14
+ * #7034095 - don't ping device if device_pin is empty or nil
15
+ * #7089047 - fixed application.rb template store_blob method
16
+ * #7055889 - fixed schema tables should have 'object' primary key
9
17
 
10
18
  ## 2.0.9
11
19
  * #5154725 - stats framework
data/Rakefile CHANGED
@@ -18,7 +18,6 @@ begin
18
18
  :jobs => 'spec/jobs/*_spec.rb',
19
19
  :stats => 'spec/stats/*_spec.rb',
20
20
  :ping => 'spec/ping/*_spec.rb',
21
- :doc => 'spec/doc/*_spec.rb',
22
21
  :generator => 'spec/generator/*_spec.rb',
23
22
  :bench => 'bench/spec/*_spec.rb'
24
23
  }
@@ -37,6 +36,12 @@ begin
37
36
  t.rcov_opts = ['--exclude', 'spec/*,gems/*,apps/*,bench/spec/*,json/*']
38
37
  end
39
38
 
39
+ desc "Run doc generator - dumps out doc/protocol.html"
40
+ Spec::Rake::SpecTask.new('doc') do |t|
41
+ t.spec_files = FileList['spec/doc/*_spec.rb']
42
+ t.rcov = false
43
+ end
44
+
40
45
  rescue LoadError => e
41
46
  puts "rspec / rcov not available. Install with: "
42
47
  puts "gem install rspec rcov\n\n"
@@ -55,7 +60,7 @@ begin
55
60
  gemspec.homepage = %q{http://rhomobile.com/products/rhosync}
56
61
  gemspec.authors = ["Rhomobile"]
57
62
  gemspec.email = %q{dev@rhomobile.com}
58
- gemspec.version = Rhosync::VERSION
63
+ gemspec.version = '2.1.0.beta.2'
59
64
  gemspec.files = FileList["[A-Z]*", "{bench,bin,generators,lib,spec,tasks}/**/*"]
60
65
 
61
66
  # TODO: Due to https://www.pivotaltracker.com/story/show/3417862, we can't use JSON 1.4.3
@@ -67,7 +72,7 @@ begin
67
72
  gemspec.add_dependency "redis", "~>2.0.0"
68
73
  gemspec.add_dependency "resque", ">=1.9.7"
69
74
  gemspec.add_dependency "rest-client", ">=1.4.2"
70
- gemspec.add_dependency "sinatra", "~>1.0"
75
+ gemspec.add_dependency "sinatra", "~>1.1"
71
76
  gemspec.add_dependency "templater", "~>1.0.0"
72
77
  gemspec.add_dependency "rake", ">=0.8.7"
73
78
  gemspec.add_development_dependency "jeweler", ">=1.4.0"
@@ -18,7 +18,7 @@ class Application < Rhosync::Base
18
18
  # Override this by creating a copy of the file somewhere
19
19
  # and returning the path to that file (then don't call super!):
20
20
  # i.e. /mnt/myimages/soccer.png
21
- def store_blob(blob)
21
+ def store_blob(obj,field_name,blob)
22
22
  super #=> returns blob[:tempfile]
23
23
  end
24
24
  end
@@ -18,7 +18,7 @@ class Application < Rhosync::Base
18
18
  # Override this by creating a copy of the file somewhere
19
19
  # and returning the path to that file (then don't call super!):
20
20
  # i.e. /mnt/myimages/soccer.png
21
- def store_blob(blob)
21
+ def store_blob(obj,field_name,blob)
22
22
  super #=> returns blob[:tempfile]
23
23
  end
24
24
  end
@@ -18,7 +18,7 @@ class Application < Rhosync::Base
18
18
  # Override this by creating a copy of the file somewhere
19
19
  # and returning the path to that file (then don't call super!):
20
20
  # i.e. /mnt/myimages/soccer.png
21
- def store_blob(blob)
21
+ def store_blob(object,field_name,blob)
22
22
  super #=> returns blob[:tempfile]
23
23
  end
24
24
  end
@@ -40,7 +40,7 @@ class <%=class_name%> < SourceAdapter
40
40
  # TODO: write some code here if applicable
41
41
  # be sure to have a hash key and value for "object"
42
42
  # for now, we'll say that its OK to not have a delete operation
43
- # raise "Please provide some code to delete a single object in the backend application using the hash values in name_value_list"
43
+ # raise "Please provide some code to delete a single object in the backend application using the object_id"
44
44
  end
45
45
 
46
46
  def logoff
@@ -60,12 +60,15 @@ module Rhosync
60
60
  end
61
61
 
62
62
  def update_clientdoc(sources)
63
+ # TODO: We need to store schema info and data info in bulk data
64
+ # source masterdoc and source schema might have changed!
63
65
  sources.each do |source|
64
66
  s = Source.load(source,{:app_id => app_id,:user_id => user_id})
65
67
  unless s.sync_type.to_sym == :bulk_sync_only
66
68
  self.source_name = source
67
69
  Store.clone(s.docname(:md_copy),self.docname(:cd))
68
70
  end
71
+ self.put_value(:schema_sha1,s.get_value(:schema_sha1))
69
72
  end
70
73
  end
71
74
 
@@ -12,22 +12,30 @@ module Rhosync
12
12
  end
13
13
 
14
14
  def receive_cud(cud_params={},query_params=nil)
15
- _process_blobs(cud_params)
16
- processed = 0
17
- ['create','update','delete'].each do |op|
18
- key,value = op,cud_params[op]
19
- processed += _receive_cud(key,value) if value
15
+ if @source.is_pass_through
16
+ @source_sync.pass_through_cud(cud_params,query_params) if value
17
+ else
18
+ _process_blobs(cud_params)
19
+ processed = 0
20
+ ['create','update','delete'].each do |op|
21
+ key,value = op,cud_params[op]
22
+ processed += _receive_cud(key,value) if value
23
+ end
24
+ @source_sync.process_cud(@client.id) if processed > 0
20
25
  end
21
- @source_sync.process_cud(@client.id) if processed > 0
22
26
  end
23
27
 
24
28
  def send_cud(token=nil,query_params=nil)
25
29
  res = []
26
- if not _ack_token(token)
30
+ if not _ack_token(token) and not @source.is_pass_through?
27
31
  res = resend_page(token)
28
32
  else
29
- @source_sync.process_query(query_params)
30
- res = send_new_page
33
+ query_result = @source_sync.process_query(query_params)
34
+ if @source.is_pass_through?
35
+ res = send_pass_through_data(query_result)
36
+ else
37
+ res = send_new_page
38
+ end
31
39
  end
32
40
  _format_result(res[0],res[1],res[2],res[3])
33
41
  end
@@ -53,39 +61,85 @@ module Rhosync
53
61
  end
54
62
 
55
63
  def send_new_page
64
+ token,progress_count,total_count,res = '',0,0,{}
65
+ if schema_changed?
66
+ _expire_bulk_data
67
+ token = compute_token(@client.docname(:page_token))
68
+ res = {'schema-changed' => 'true'}
69
+ else
70
+ compute_errors_page
71
+ res = build_page do |r|
72
+ progress_count,total_count,r['insert'] = compute_page
73
+ r['delete'] = compute_deleted_page
74
+ r['links'] = compute_links_page
75
+ r['metadata'] = compute_metadata
76
+ end
77
+ if res['insert'] or res['delete'] or res['links']
78
+ token = compute_token(@client.docname(:page_token))
79
+ else
80
+ _delete_errors_page
81
+ end
82
+ @client.put_data(:cd,res['insert'],true)
83
+ @client.delete_data(:cd,res['delete'])
84
+ end
85
+ [token,progress_count,total_count,res]
86
+ end
87
+
88
+ def send_pass_through_data(data)
89
+ data ||= {}
90
+ data.each_key do |object_id|
91
+ data[object_id].each { |attrib,value| data[object_id][attrib] = '' if value.nil? }
92
+ end
93
+ token = ''
56
94
  compute_errors_page
57
- token,progress_count,total_count = '',0,0
58
95
  res = build_page do |r|
59
- progress_count,total_count,r['insert'] = compute_page
60
- r['delete'] = compute_deleted_page
61
- r['links'] = compute_links_page
96
+ r['insert'] = data
62
97
  r['metadata'] = compute_metadata
63
98
  end
64
- if res['insert'] or res['delete'] or res['links']
99
+ if res['insert']
65
100
  token = compute_token(@client.docname(:page_token))
66
101
  else
67
102
  _delete_errors_page
68
103
  end
69
- @client.put_data(:cd,res['insert'],true)
70
- @client.delete_data(:cd,res['delete'])
71
- [token,progress_count,total_count,res]
104
+ [token,0,data.size,res]
72
105
  end
73
106
 
74
107
  # Resend token for a client, also sends exceptions
75
108
  def resend_page(token=nil)
76
- token,progress_count,total_count = '',0,0
77
- res = build_page do |r|
78
- r['insert'] = @client.get_data(:page)
79
- r['delete'] = @client.get_data(:delete_page)
80
- r['links'] = @client.get_data(:create_links_page)
81
- r['metadata'] = compute_metadata
82
- progress_count = @client.get_value(:cd_size).to_i
83
- total_count = @client.get_value(:total_count_page).to_i
109
+ token,progress_count,total_count,res = '',0,0,{}
110
+ schema_page = @client.get_value(:schema_page)
111
+ if schema_page
112
+ res = {'schema-changed' => 'true'}
113
+ else
114
+ res = build_page do |r|
115
+ r['insert'] = @client.get_data(:page)
116
+ r['delete'] = @client.get_data(:delete_page)
117
+ r['links'] = @client.get_data(:create_links_page)
118
+ r['metadata'] = @client.get_value(:metadata_page)
119
+ progress_count = @client.get_value(:cd_size).to_i
120
+ total_count = @client.get_value(:total_count_page).to_i
121
+ end
84
122
  end
85
123
  token = @client.get_value(:page_token)
86
124
  [token,progress_count,total_count,res]
87
125
  end
88
126
 
127
+ # Checks if schema changed
128
+ def schema_changed?
129
+ schema_sha1 = @source.get_value(:schema_sha1)
130
+
131
+ if @client.get_value(:schema_sha1).nil?
132
+ @client.put_value(:schema_sha1,schema_sha1)
133
+ return false
134
+ elsif @client.get_value(:schema_sha1) == schema_sha1
135
+ return false
136
+ end
137
+
138
+ @client.put_value(:schema_sha1,schema_sha1)
139
+ @client.put_value(:schema_page,schema_sha1)
140
+ true
141
+ end
142
+
89
143
  # Computes the metadata sha1 and returns metadata if client's sha1 doesn't
90
144
  # match source's sha1
91
145
  def compute_metadata
@@ -94,9 +148,11 @@ module Rhosync
94
148
  end
95
149
  return if @client.get_value(:metadata_sha1) == metadata_sha1
96
150
  @client.put_value(:metadata_sha1,metadata_sha1)
151
+ @client.put_value(:metadata_page,metadata)
97
152
  metadata
98
153
  end
99
154
 
155
+
100
156
  # Computes diffs between master doc and client doc, trims it to page size,
101
157
  # stores page, and returns page as hash
102
158
  def compute_page
@@ -215,6 +271,14 @@ module Rhosync
215
271
  end
216
272
 
217
273
  private
274
+
275
+ # expires the bulk data for the client
276
+ def _expire_bulk_data
277
+ [:user,:app].each do |partition|
278
+ Rhosync.expire_bulk_data(@client.user_id,partition)
279
+ end
280
+ end
281
+
218
282
  def _resend_search_result
219
283
  res = @client.get_data(:search_page)
220
284
  _format_search_result(res,res.size)
@@ -234,8 +298,8 @@ module Rhosync
234
298
  def _do_search(params={})
235
299
  # call source adapter search unless client is sending token for ack
236
300
  search_params = params[:search] if params
237
- @source_sync.search(@client.id,search_params) if params.nil? or !params[:token]
238
- res,diffsize = compute_search
301
+ res = @source_sync.search(@client.id,search_params) if params.nil? or !params[:token]
302
+ res,diffsize = @source.is_pass_through? ? [res,res.size] : compute_search
239
303
  formatted_res = _format_search_result(res,diffsize)
240
304
  @client.flash_data('search*') if diffsize == 0
241
305
  formatted_res
@@ -250,7 +314,6 @@ module Rhosync
250
314
  else
251
315
  search_token = @client.get_value(:search_token)
252
316
  search_token ||= ''
253
- #res,diffsize = compute_search
254
317
  return [] if res.empty?
255
318
  [ {'version'=>VERSION},
256
319
  {'token' => search_token},
@@ -285,6 +348,8 @@ module Rhosync
285
348
  if stored_token
286
349
  if token and stored_token == token
287
350
  @client.put_value(:page_token,nil)
351
+ @client.flash_data(:schema_page)
352
+ @client.flash_data(:metadata_page)
288
353
  @client.flash_data(:create_links_page)
289
354
  @client.flash_data(:page)
290
355
  @client.flash_data(:delete_page)
@@ -55,7 +55,7 @@ module Rhosync
55
55
  data = source.get_data(:md)
56
56
  counter = {}
57
57
  columns,qm = [],[]
58
- create_table = ["\"object\" varchar"]
58
+ create_table = ["\"object\" varchar(255) PRIMARY KEY"]
59
59
  schema = JSON.parse(source.schema)
60
60
 
61
61
  db.transaction do |database|
@@ -84,7 +84,7 @@ module Rhosync
84
84
  schema['index'].each do |key,value|
85
85
  val2 = ""
86
86
  value.split(',').each do |col|
87
- val2 += ',' if val2.length() > 0
87
+ val2 += ',' if val2.length > 0
88
88
  val2 += "\"#{col}\""
89
89
  end
90
90
 
@@ -95,7 +95,7 @@ module Rhosync
95
95
  schema['unique_index'].each do |key,value|
96
96
  val2 = ""
97
97
  value.split(',').each do |col|
98
- val2 += ',' if val2.length() > 0
98
+ val2 += ',' if val2.length > 0
99
99
  val2 += "\"#{col}\""
100
100
  end
101
101
 
@@ -117,12 +117,12 @@ module Rhosync
117
117
  def self.populate_sources_table(db,sources_refs)
118
118
  db.transaction do |database|
119
119
  database.prepare("insert into sources
120
- (source_id,name,sync_priority,partition,sync_type,source_attribs,metadata,blob_attribs,associations)
121
- values (?,?,?,?,?,?,?,?,?)") do |stmt|
120
+ (source_id,name,sync_priority,partition,sync_type,source_attribs,metadata,schema,blob_attribs,associations)
121
+ values (?,?,?,?,?,?,?,?,?,?)") do |stmt|
122
122
  sources_refs.each do |source_name,ref|
123
123
  s = ref[:source]
124
124
  stmt.execute(s.source_id,s.name,s.priority,s.partition_type,
125
- s.sync_type,refs_to_s(ref[:refs]),s.get_value(:metadata),s.blob_attribs,s.has_many)
125
+ s.sync_type,refs_to_s(ref[:refs]),s.get_value(:metadata),s.schema,s.blob_attribs,s.has_many)
126
126
  end
127
127
  end
128
128
  end
@@ -11,7 +11,7 @@ module Rhosync
11
11
  client = Client.load(client_id,{:source_name => '*'})
12
12
  params.merge!('device_port' => client.device_port,
13
13
  'device_pin' => client.device_pin)
14
- if client.device_type and client.device_type.size > 0
14
+ if client.device_type and client.device_type.size > 0 and client.device_pin and client.device_pin.size > 0
15
15
  klass = Object.const_get(camelize(client.device_type.downcase))
16
16
  klass.ping(params) if klass
17
17
  else
@@ -24,6 +24,7 @@ module Rhosync
24
24
  end
25
25
 
26
26
  def self.c2d_message(params)
27
+ params.reject! {|k,v| v.nil? || v.length == 0}
27
28
  data = {}
28
29
  data['registration_id'] = params['device_pin']
29
30
  data['collapse_key'] = (rand * 100000000).to_i.to_s
@@ -100,8 +100,11 @@ module Rhosync
100
100
  user = current_user
101
101
  if params[:source_name] and user
102
102
  @source = Source.load(params[:source_name],
103
- {:user_id => user.login,:app_id => APP_NAME})
103
+ {:user_id => user.login,:app_id => APP_NAME})
104
+ raise "ERROR: Source '#{params[:source_name]}' requested by client doesn't exist.\n" unless @source
105
+ @source
104
106
  else
107
+ log "ERROR: Can't load source, no source_name provided.\n"
105
108
  nil
106
109
  end
107
110
  end
@@ -15,7 +15,7 @@ module Rhosync
15
15
  field :queue,:string
16
16
  field :query_queue,:string
17
17
  field :cud_queue,:string
18
- field :schema, :string
18
+ field :pass_through,:string
19
19
  attr_accessor :app_id, :user_id
20
20
  validates_presence_of :name #, :source_id
21
21
 
@@ -100,6 +100,10 @@ module Rhosync
100
100
  @app ||= App.load(self.app_id)
101
101
  end
102
102
 
103
+ def schema
104
+ @schema ||= self.get_value(:schema)
105
+ end
106
+
103
107
  def read_state
104
108
  id = {:app_id => self.app_id,:user_id => user_by_partition,
105
109
  :source_name => self.name}
@@ -142,6 +146,10 @@ module Rhosync
142
146
  yield client_id,params if need_refresh
143
147
  end
144
148
 
149
+ def is_pass_through?
150
+ self.pass_through and self.pass_through == 'true'
151
+ end
152
+
145
153
  private
146
154
  def self.validate_attributes(params)
147
155
  raise ArgumentError.new('Missing required attribute user_id') unless params[:user_id]
@@ -62,7 +62,12 @@ module Rhosync
62
62
  @tmp_docname = @source.docname(:md) + get_random_uuid
63
63
  @stash_size = 0
64
64
  params ? self.query(params) : self.query
65
- self.sync
65
+ if @source.is_pass_through?
66
+ @result
67
+ else
68
+ self.sync
69
+ true
70
+ end
66
71
  end
67
72
 
68
73
  def stash_result
@@ -73,9 +78,7 @@ module Rhosync
73
78
  end
74
79
 
75
80
  def expire_bulk_data(partition = :user)
76
- name = BulkData.get_name(partition,current_user.login)
77
- data = BulkData.load(name)
78
- data.refresh_time = Time.now.to_i if data
81
+ Rhosync.expire_bulk_data(current_user.login,partition)
79
82
  end
80
83
 
81
84
  def create(name_value_list); end
@@ -22,6 +22,33 @@ module Rhosync
22
22
  _measure_and_process_cud('delete',client_id)
23
23
  end
24
24
 
25
+ # Pass through CUD to adapter, no data stored
26
+ def pass_through_cud(cud_params,query_params)
27
+ res,processed_objects = {},[]
28
+ begin
29
+ ['create','update','delete'].each do |op|
30
+ key,objects = op,cud_params[op]
31
+ objects.each do |key,value|
32
+ case op
33
+ when 'create'
34
+ @adapter.send(op.to_sym,value)
35
+ when 'update'
36
+ value['id'] = key
37
+ @adapter.send(op.to_sym,value)
38
+ when 'delete'
39
+ @adapter.send(op.to_sym,key)
40
+ end
41
+ process_objects << key
42
+ end if objects
43
+ end
44
+ rescue Exception => e
45
+ log "Error in #{op} pass through method: #{e.message}"
46
+ res['error'] = { 'operation' => op, 'message' => e.message }
47
+ end
48
+ res['processed'] = process_objects
49
+ res.to_json
50
+ end
51
+
25
52
  # Read Operation; params are query arguments
26
53
  def read(client_id=nil,params=nil)
27
54
  _read('query',client_id,params)
@@ -59,13 +86,15 @@ module Rhosync
59
86
  end
60
87
 
61
88
  def do_query(params=nil)
89
+ result = nil
62
90
  @source.if_need_refresh do
63
91
  Stats::Record.update("source:query:#{@source.name}") do
64
92
  return if _auth_op('login') == false
65
- self.read(nil,params)
93
+ result = self.read(nil,params)
66
94
  _auth_op('logoff')
67
95
  end
68
96
  end
97
+ result
69
98
  end
70
99
 
71
100
  # Enqueue a job for the source based on job type
@@ -210,12 +239,12 @@ module Rhosync
210
239
  end
211
240
 
212
241
  # Metadata Operation; source adapter returns json
213
- def _get_metadata
214
- if @adapter.respond_to?(:metadata)
215
- metadata = @adapter.metadata
216
- if metadata
217
- @source.put_value(:metadata,metadata)
218
- @source.put_value(:metadata_sha1,Digest::SHA1.hexdigest(metadata))
242
+ def _get_data(method)
243
+ if @adapter.respond_to?(method)
244
+ data = @adapter.send(method)
245
+ if data
246
+ @source.put_value(method,data)
247
+ @source.put_value("#{method}_sha1",Digest::SHA1.hexdigest(data))
219
248
  end
220
249
  end
221
250
  end
@@ -223,17 +252,20 @@ module Rhosync
223
252
  # Read Operation; params are query arguments
224
253
  def _read(operation,client_id,params=nil)
225
254
  errordoc = nil
255
+ result = nil
226
256
  begin
227
257
  if operation == 'search'
228
258
  client = Client.load(client_id,{:source_name => @source.name})
229
259
  errordoc = client.docname(:search_errors)
230
260
  compute_token(client.docname(:search_token))
231
- @adapter.search(params)
261
+ result = @adapter.search(params)
232
262
  @adapter.save(client.docname(:search))
233
263
  else
234
264
  errordoc = @source.docname(:errors)
235
- _get_metadata
236
- @adapter.do_query(params)
265
+ [:metadata,:schema].each do |method|
266
+ _get_data(method)
267
+ end
268
+ result = @adapter.do_query(params)
237
269
  end
238
270
  # operation,sync succeeded, remove errors
239
271
  Store.lock(errordoc) do
@@ -246,7 +278,7 @@ module Rhosync
246
278
  Store.put_data(errordoc,{"#{operation}-error"=>{'message'=>e.message}},true)
247
279
  end
248
280
  end
249
- true
281
+ result
250
282
  end
251
283
  end
252
284
  end
@@ -1,3 +1,3 @@
1
1
  module Rhosync
2
- VERSION = '2.1.0.beta.1'
3
- end
2
+ VERSION = '2.1.0'
3
+ end
data/lib/rhosync.rb CHANGED
@@ -91,7 +91,8 @@ module Rhosync
91
91
  end
92
92
  sources = config[:sources] || []
93
93
  sources.each do |source_name,fields|
94
- if Source.is_exist?(source_name)
94
+ check_for_schema_field!(fields)
95
+ if Source.is_exist?(source_name)
95
96
  s = Source.load(source_name,{:app_id => app.name,:user_id => '*'})
96
97
  s.update(fields)
97
98
  else
@@ -143,6 +144,13 @@ module Rhosync
143
144
  log "*"*60
144
145
  end
145
146
  end
147
+
148
+ def check_for_schema_field!(fields)
149
+ if fields['schema']
150
+ log "ERROR: 'schema' field in settings.yml is not supported anymore, please use source adapter schema method!"
151
+ exit(1)
152
+ end
153
+ end
146
154
 
147
155
  # Serializes oav to set element
148
156
  def setelement(obj,attrib,value)
@@ -200,6 +208,12 @@ module Rhosync
200
208
  log "*"*60
201
209
  end
202
210
  end
211
+
212
+ def expire_bulk_data(username, partition = :user)
213
+ name = BulkData.get_name(partition,username)
214
+ data = BulkData.load(name)
215
+ data.refresh_time = Time.now.to_i if data
216
+ end
203
217
 
204
218
  def unzip_file(file_dir,params)
205
219
  uploaded_file = File.join(file_dir, params[:filename])
@@ -22,7 +22,7 @@ describe "RhosyncApiGetSourceParams" do
22
22
  {"name"=>"queue", "value"=>nil, "type"=>"string"},
23
23
  {"name"=>"query_queue", "value"=>nil, "type"=>"string"},
24
24
  {"name"=>"cud_queue", "value"=>nil, "type"=>"string"},
25
- {"name"=>"schema", "value"=>nil, "type"=>"string"}]
25
+ {"name"=>"pass_through", "value"=>nil, "type"=>"string"}]
26
26
  end
27
27
 
28
28
  end
@@ -169,7 +169,7 @@ describe "RhosyncApi" do
169
169
  {"name"=>"queue", "value"=>nil, "type"=>"string"},
170
170
  {"name"=>"query_queue", "value"=>nil, "type"=>"string"},
171
171
  {"name"=>"cud_queue", "value"=>nil, "type"=>"string"},
172
- {"name"=>"schema", "value"=>nil, "type"=>"string"}]
172
+ {"name"=>"pass_through", "value"=>nil, "type"=>"string"}]
173
173
  end
174
174
 
175
175
  it "should list source attributes using rest call" do
@@ -9,18 +9,6 @@
9
9
  sync_type: 'incremental'
10
10
  belongs_to:
11
11
  - brand: 'SampleAdapter'
12
- schema:
13
- version: '1.0'
14
- property:
15
- name: 'string'
16
- brand: 'string'
17
- price: 'string'
18
- image_url_cropped: 'blob,overwrite'
19
- image_url: 'blob'
20
- index:
21
- by_name_brand: 'name,brand'
22
- unique_index:
23
- by_price: 'price'
24
12
 
25
13
  :development:
26
14
  :licensefile: settings/license.key
@@ -6,4 +6,23 @@ class FixedSchemaAdapter < SourceAdapter
6
6
  def query(params=nil)
7
7
  @result = Store.get_data('test_db_storage')
8
8
  end
9
+
10
+ def schema
11
+ {
12
+ 'version' => '1.0',
13
+ 'property' => {
14
+ 'name' => 'string',
15
+ 'brand' => 'string',
16
+ 'price' => 'string',
17
+ 'image_url_cropped' => 'blob,overwrite',
18
+ 'image_url' => 'blob'
19
+ },
20
+ 'index' => {
21
+ 'by_name_brand' => 'name,brand'
22
+ },
23
+ 'unique_index' => {
24
+ 'by_price' => 'price'
25
+ }
26
+ }.to_json
27
+ end
9
28
  end
data/spec/client_spec.rb CHANGED
@@ -61,6 +61,16 @@ describe "Client" do
61
61
  @s.docname(:md_copy) => @data)
62
62
  end
63
63
 
64
+ it "should update client schema_sha1" do
65
+ set_state(@s.docname(:md_copy) => @data,
66
+ @s.docname(:schema_sha1) => 'foobar',
67
+ @c.docname(:cd) => {'foo' => {'bar' => 'abc'}})
68
+ @c.update_clientdoc([@s_fields[:name]])
69
+ verify_result(@c.docname(:cd) => @data,
70
+ @s.docname(:md_copy) => @data,
71
+ @c.docname(:schema_sha1) => 'foobar')
72
+ end
73
+
64
74
  describe "Client Stats" do
65
75
 
66
76
  before(:each) do
@@ -35,6 +35,19 @@ describe "ClientSync" do
35
35
  @cs.client.docname(:cd) => data)
36
36
  end
37
37
 
38
+ it "should handle send cud if pass_through is set" do
39
+ data = {'1'=>@product1,'2'=>@product2}
40
+ expected = {'insert'=>data}
41
+ set_test_data('test_db_storage',data)
42
+ @s.pass_through = 'true'
43
+ @cs.send_cud.should == [{'version'=>ClientSync::VERSION},
44
+ {'token'=>@c.get_value(:page_token)},
45
+ {'count'=>data.size},{'progress_count'=>data.size},
46
+ {'total_count'=>data.size},expected]
47
+ verify_result(@cs.client.docname(:page) => {},
48
+ @cs.client.docname(:cd) => {})
49
+ end
50
+
38
51
  it "should return read errors in send cud" do
39
52
  msg = "Error during query"
40
53
  data = {'1'=>@product1,'2'=>@product2}
@@ -405,6 +418,113 @@ describe "ClientSync" do
405
418
  Store.get_data(@cs.client.docname(:page)).should == {}
406
419
  @c.get_value(:page_token).should be_nil
407
420
  end
421
+
422
+ it "should send metadata with page" do
423
+ expected = {'1'=>@product1}
424
+ set_state('test_db_storage' => expected)
425
+ metadata = "{\"foo\":\"bar\"}"
426
+ mock_metadata_method([SampleAdapter]) do
427
+ result = @cs.send_cud
428
+ token = @c.get_value(:page_token)
429
+ result.should == [{"version"=>ClientSync::VERSION},{"token"=>token},
430
+ {"count"=>1}, {"progress_count"=>0},{"total_count"=>1},
431
+ {'metadata'=>metadata,'insert'=>expected}]
432
+ @c.get_value(:metadata_page).should == metadata
433
+ end
434
+ end
435
+
436
+ it "should send metadata with resend page" do
437
+ expected = {'1'=>@product1}
438
+ set_state('test_db_storage' => expected)
439
+ mock_metadata_method([SampleAdapter]) do
440
+ result = @cs.send_cud
441
+ token = @c.get_value(:page_token)
442
+ @cs.send_cud.should == [{"version"=>ClientSync::VERSION},{"token"=>token},
443
+ {"count"=>1}, {"progress_count"=>0},{"total_count"=>1},
444
+ {'metadata'=>"{\"foo\":\"bar\"}",'insert'=>expected}]
445
+ end
446
+ end
447
+
448
+ it "should ack metadata page with ack token" do
449
+ expected = {'1'=>@product1}
450
+ set_state('test_db_storage' => expected)
451
+ mock_metadata_method([SampleAdapter]) do
452
+ result = @cs.send_cud
453
+ token = @c.get_value(:page_token)
454
+ @cs.send_cud(token).should == [{"version"=>ClientSync::VERSION},{"token"=>""},
455
+ {"count"=>0}, {"progress_count"=>1},{"total_count"=>1},{}]
456
+ @c.get_value(:metadata_page).should be_nil
457
+ end
458
+ end
459
+
460
+ it "shouldn't send schema-changed if client schema sha1 is nil" do
461
+ expected = {'1'=>@product1}
462
+ set_state('test_db_storage' => expected)
463
+ mock_schema_method([SampleAdapter]) do
464
+ result = @cs.send_cud
465
+ token = @c.get_value(:page_token)
466
+ result.should == [{"version"=>ClientSync::VERSION},{"token"=>token},
467
+ {"count"=>1}, {"progress_count"=>0},{"total_count"=>1},{'insert'=>expected}]
468
+ @c.get_value(:schema_sha1).should == '8c148c8c1a66c7baf685c07d58bea360da87981b'
469
+ end
470
+ end
471
+
472
+ it "should send schema-changed instead of page" do
473
+ mock_schema_method([SampleAdapter]) do
474
+ @c.put_value(:schema_sha1,'foo')
475
+ result = @cs.send_cud
476
+ token = @c.get_value(:page_token)
477
+ result.should == [{"version"=>ClientSync::VERSION},{"token"=>token},
478
+ {"count"=>0}, {"progress_count"=>0},{"total_count"=>0},{'schema-changed'=>'true'}]
479
+ @c.get_value(:schema_page).should == '8c148c8c1a66c7baf685c07d58bea360da87981b'
480
+ @c.get_value(:schema_sha1).should == '8c148c8c1a66c7baf685c07d58bea360da87981b'
481
+ end
482
+ end
483
+
484
+ it "should re-send schema-changed if no token sent" do
485
+ mock_schema_method([SampleAdapter]) do
486
+ @c.put_value(:schema_sha1,'foo')
487
+ result = @cs.send_cud
488
+ token = @c.get_value(:page_token)
489
+ @cs.send_cud.should == [{"version"=>ClientSync::VERSION},{"token"=>token},
490
+ {"count"=>0}, {"progress_count"=>0},{"total_count"=>0},{'schema-changed'=>'true'}]
491
+ @c.get_value(:schema_page).should == '8c148c8c1a66c7baf685c07d58bea360da87981b'
492
+ @c.get_value(:schema_sha1).should == '8c148c8c1a66c7baf685c07d58bea360da87981b'
493
+ end
494
+ end
495
+
496
+ it "should ack schema-changed with token" do
497
+ mock_schema_method([SampleAdapter]) do
498
+ @c.put_value(:schema_sha1,'foo')
499
+ result = @cs.send_cud
500
+ token = @c.get_value(:page_token)
501
+ @cs.send_cud(token).should == [{"version"=>ClientSync::VERSION},{"token"=>""},
502
+ {"count"=>0}, {"progress_count"=>0},{"total_count"=>0},{}]
503
+ @c.get_value(:schema_page).should be_nil
504
+ @c.get_value(:schema_sha1).should == '8c148c8c1a66c7baf685c07d58bea360da87981b'
505
+ end
506
+ end
507
+
508
+ it "should expire bulk data if schema changed" do
509
+ docname = bulk_data_docname(@a.id,@u.id)
510
+ data = BulkData.create(:name => docname,
511
+ :state => :inprogress,
512
+ :app_id => @a.id,
513
+ :user_id => @u.id,
514
+ :sources => [@s_fields[:name]])
515
+ data.refresh_time = Time.now.to_i + 600
516
+ mock_schema_method([SampleAdapter]) do
517
+ @c.put_value(:schema_sha1,'foo')
518
+ result = @cs.send_cud
519
+ token = @c.get_value(:page_token)
520
+ @cs.send_cud(token).should == [{"version"=>ClientSync::VERSION},{"token"=>""},
521
+ {"count"=>0}, {"progress_count"=>0},{"total_count"=>0},{}]
522
+ @c.get_value(:schema_page).should be_nil
523
+ @c.get_value(:schema_sha1).should == '8c148c8c1a66c7baf685c07d58bea360da87981b'
524
+ data = BulkData.load(docname)
525
+ data.refresh_time.should <= Time.now.to_i
526
+ end
527
+ end
408
528
  end
409
529
 
410
530
  describe "bulk data" do
@@ -451,7 +571,6 @@ describe "ClientSync" do
451
571
  :app_id => @a.id,
452
572
  :user_id => name,
453
573
  :sources => [@s_fields[:name]])
454
- puts "data: #{data.inspect}"
455
574
  BulkDataJob.perform("data_name" => bulk_data_docname(@a.id,name))
456
575
  data = BulkData.load(bulk_data_docname(@a.id,name))
457
576
  data.url.should match /a%20b/
@@ -76,6 +76,25 @@ describe "BulkDataJob" do
76
76
  end
77
77
  end
78
78
 
79
+ it "should create sqlite data with source schema" do
80
+ set_state('test_db_storage' => @data)
81
+ mock_schema_method([SampleAdapter]) do
82
+ docname = bulk_data_docname(@a.id,@u.id)
83
+ data = BulkData.create(:name => docname,
84
+ :state => :inprogress,
85
+ :app_id => @a.id,
86
+ :user_id => @u.id,
87
+ :sources => [@s_fields[:name]])
88
+ BulkDataJob.perform("data_name" => data.name)
89
+ data = BulkData.load(docname)
90
+ data.completed?.should == true
91
+ verify_result(@s.docname(:md) => @data,
92
+ @s.docname(:schema) => "{\"property\":{\"brand\":\"string\",\"name\":\"string\"},\"version\":\"1.0\"}",
93
+ @s.docname(:md_copy) => @data)
94
+ validate_db(data,@s.name => @data).should == true
95
+ end
96
+ end
97
+
79
98
  it "should raise exception if hsqldata fails" do
80
99
  data = BulkData.create(:name => bulk_data_docname(@a.id,@u.id),
81
100
  :state => :inprogress,
@@ -32,4 +32,14 @@ describe "PingJob" do
32
32
  lambda { PingJob.perform(params) }.should_not raise_error
33
33
  end
34
34
 
35
+ it "should skip ping for empty device_pin" do
36
+ params = {"user_id" => @u.id, "api_token" => @api_token,
37
+ "sources" => [@s.name], "message" => 'hello world',
38
+ "vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3'}
39
+ @c.device_type = 'blackberry'
40
+ @c.device_pin = nil
41
+ PingJob.should_receive(:log).once.with("Skipping ping for non-registered client_id '#{@c.id}'...")
42
+ lambda { PingJob.perform(params) }.should_not raise_error
43
+ end
44
+
35
45
  end
@@ -42,4 +42,14 @@ describe "Ping Android" do
42
42
  actual['collapse_key'] = "RAND_KEY" unless actual['collapse_key'].nil?
43
43
  actual.should == expected
44
44
  end
45
+
46
+ it "should trim empty or nil params from c2d_message" do
47
+ expected = {'registration_id' => @c.device_pin, 'collapse_key' => "RAND_KEY",
48
+ 'data.vibrate' => '5', 'data.do_sync' => '', 'data.sound' => "hello.mp3"}
49
+ params = {"device_pin" => @c.device_pin,
50
+ "sources" => [], "message" => '', "vibrate" => '5', "sound" => 'hello.mp3'}
51
+ actual = Android.c2d_message(params)
52
+ actual['collapse_key'] = "RAND_KEY" unless actual['collapse_key'].nil?
53
+ actual.should == expected
54
+ end
45
55
  end
data/spec/rhosync_spec.rb CHANGED
@@ -43,6 +43,18 @@ describe "Rhosync" do
43
43
  App.load(@test_app_name).sources.members.should == []
44
44
  end
45
45
 
46
+ it "should exit if schema config exists" do
47
+ config = Rhosync.get_config(get_testapp_path)
48
+ config[:sources]['FixedSchemaAdapter'].merge!(
49
+ 'schema' => {'property' => 'foo'}
50
+ )
51
+ Rhosync.stub!(:get_config).and_return(config)
52
+ Rhosync.should_receive(:log).once.with(
53
+ "ERROR: 'schema' field in settings.yml is not supported anymore, please use source adapter schema method!"
54
+ )
55
+ lambda { Rhosync.bootstrap(get_testapp_path) }.should raise_error(SystemExit)
56
+ end
57
+
46
58
  it "should add associations during bootstrap" do
47
59
  Rhosync.bootstrap(get_testapp_path)
48
60
  s = Source.load('SampleAdapter',{:app_id => @test_app_name,:user_id => '*'})
@@ -12,9 +12,7 @@ describe "Server" do
12
12
 
13
13
  include Rack::Test::Methods
14
14
  include Rhosync
15
-
16
- it_should_behave_like "DBObjectsHelper"
17
-
15
+
18
16
  before(:each) do
19
17
  require File.join(get_testapp_path,@test_app_name)
20
18
  Rhosync.bootstrap(get_testapp_path) do |rhosync|
@@ -28,6 +26,8 @@ describe "Server" do
28
26
  Rhosync::Server.use Rack::Static, :urls => ["/data"],
29
27
  :root => File.expand_path(File.join(File.dirname(__FILE__),'..','apps','rhotestapp'))
30
28
  end
29
+
30
+ it_should_behave_like "DBObjectsHelper"
31
31
 
32
32
  def app
33
33
  @app ||= Rhosync::Server.new
@@ -127,17 +127,7 @@ describe "Server" do
127
127
  @source_config = {
128
128
  "sources"=>
129
129
  {"FixedSchemaAdapter"=>
130
- {"schema"=>
131
- {"property"=>
132
- {"image_url_cropped"=>"blob,overwrite",
133
- "price"=>"string",
134
- "brand"=>"string",
135
- "name"=>"string",
136
- "image_url"=>"blob"},
137
- "unique_index"=>{"by_price"=>"price"},
138
- "version"=>"1.0",
139
- "index"=>{"by_name_brand"=>"name,brand"}},
140
- "poll_interval"=>300,
130
+ {"poll_interval"=>300,
141
131
  "sync_type"=>"incremental",
142
132
  "belongs_to"=>[{"brand"=>"SampleAdapter"}]},
143
133
  "SampleAdapter"=>{"poll_interval"=>300},
@@ -148,7 +138,7 @@ describe "Server" do
148
138
  it "should respond to clientcreate" do
149
139
  get "/application/clientcreate?device_type=blackberry"
150
140
  last_response.should be_ok
151
- last_response.content_type.should == 'application/json'
141
+ last_response.content_type.should =~ /application\/json/
152
142
  id = JSON.parse(last_response.body)['client']['client_id']
153
143
  id.length.should == 32
154
144
  JSON.parse(last_response.body).should ==
@@ -235,7 +225,7 @@ describe "Server" do
235
225
  set_test_data('test_db_storage',data)
236
226
  get "/application",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
237
227
  last_response.should be_ok
238
- last_response.content_type.should == 'application/json'
228
+ last_response.content_type.should =~ /application\/json/
239
229
  token = @c.get_value(:page_token)
240
230
  JSON.parse(last_response.body).should == [{"version"=>ClientSync::VERSION},{"token"=>token},
241
231
  {"count"=>2}, {"progress_count"=>0},{"total_count"=>2},{'insert'=>data}]
@@ -257,6 +247,12 @@ describe "Server" do
257
247
  {"count"=>0}, {"progress_count"=>2}, {"total_count"=>2},{}]
258
248
  end
259
249
 
250
+ it "should return error if source_name is unknown" do
251
+ get "/application",:client_id => @c.id,:source_name => 'Broken',:version => ClientSync::VERSION
252
+ last_response.status.should == 500
253
+ last_response.body.should == "ERROR: Source 'Broken' requested by client doesn't exist.\n"
254
+ end
255
+
260
256
  it "should get deletes json" do
261
257
  cs = ClientSync.new(@s,@c,1)
262
258
  data = {'1'=>@product1,'2'=>@product2}
@@ -286,7 +282,7 @@ describe "Server" do
286
282
  params = {:client_id => @c.id,:sources => sources,:search => {'name' => 'iPhone'},
287
283
  :version => ClientSync::VERSION}
288
284
  get "/application/search",params
289
- last_response.content_type.should == 'application/json'
285
+ last_response.content_type.should =~ /application\/json/
290
286
  token = @c.get_value(:search_token)
291
287
  JSON.parse(last_response.body).should == [[{'version'=>ClientSync::VERSION},{'token'=>token},
292
288
  {'source'=>sources[0][:name]},{'count'=>1},{'insert'=>{'1'=>@product1}}]]
@@ -72,6 +72,17 @@ describe "SourceSync" do
72
72
  end
73
73
  end
74
74
 
75
+ it "should process source adapter schema" do
76
+ mock_schema_method([SampleAdapter]) do
77
+ expected = {'1'=>@product1,'2'=>@product2}
78
+ set_state('test_db_storage' => expected)
79
+ @ss.process_query
80
+ verify_result(@s.docname(:md) => expected,
81
+ @s.docname(:schema) => "{\"property\":{\"brand\":\"string\",\"name\":\"string\"},\"version\":\"1.0\"}",
82
+ @s.docname(:schema_sha1) => "8c148c8c1a66c7baf685c07d58bea360da87981b")
83
+ end
84
+ end
85
+
75
86
  it "should process source adapter with stash" do
76
87
  expected = {'1'=>@product1,'2'=>@product2}
77
88
  set_state('test_db_storage' => expected)
@@ -94,6 +105,16 @@ describe "SourceSync" do
94
105
  end
95
106
  end
96
107
 
108
+ it "should process source adapter with pass_through set" do
109
+ expected = {'1'=>@product1,'2'=>@product2}
110
+ set_state('test_db_storage' => expected)
111
+ @s.pass_through = 'true'
112
+ @ss.process_query.should == expected
113
+ verify_result(@s.docname(:md) => {},
114
+ @s.docname(:md_size) => nil)
115
+ @s.pass_through = nil
116
+ end
117
+
97
118
  describe "create" do
98
119
  it "should do create where adapter.create returns nil" do
99
120
  set_state(@c.docname(:create) => {'2'=>@product2})
@@ -219,7 +240,7 @@ describe "SourceSync" do
219
240
  verify_result(@s.docname(:md) => expected,
220
241
  @s.docname(:errors) => {})
221
242
  else
222
- @ss.search(@c.id).should == true
243
+ @ss.search(@c.id).should == expected
223
244
  verify_result(@c.docname(:search) => expected,
224
245
  @c.docname(:search_errors) => {})
225
246
  end
@@ -230,11 +251,11 @@ describe "SourceSync" do
230
251
  @ss.should_receive(:log).with("SourceAdapter raised #{operation} exception: #{msg}")
231
252
  set_test_data('test_db_storage',{},msg,"#{operation} error")
232
253
  if operation == 'query'
233
- @ss.read.should == true
254
+ @ss.read.should be_nil
234
255
  verify_result(@s.docname(:md) => {},
235
256
  @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
236
257
  else
237
- @ss.search(@c.id).should == true
258
+ @ss.search(@c.id).should be_nil
238
259
  verify_result(@c.docname(:search) => {},
239
260
  @c.docname(:search_errors) => {'search-error'=>{'message'=>msg}})
240
261
  end
data/spec/spec_helper.rb CHANGED
@@ -115,7 +115,7 @@ module TestHelpers
115
115
 
116
116
  def validate_db_by_name(db,s,data)
117
117
  db.execute("select source_id,name,sync_priority,partition,
118
- sync_type,source_attribs,metadata,blob_attribs,associations
118
+ sync_type,source_attribs,metadata,schema,blob_attribs,associations
119
119
  from sources where name='#{s.name}'").each do |row|
120
120
  return false if row[0].to_s != s.source_id.to_s
121
121
  return false if row[1] != s.name
@@ -124,8 +124,9 @@ module TestHelpers
124
124
  return false if row[4] != s.sync_type.to_s
125
125
  return false if row[5] != (s.schema ? "" : get_attrib_counter(data))
126
126
  return false if row[6] != s.get_value(:metadata)
127
- return false if row[7] != s.blob_attribs
128
- return false if row[8] != s.has_many
127
+ return false if row[7] != s.schema
128
+ return false if row[8] != s.blob_attribs
129
+ return false if row[9] != s.has_many
129
130
  end
130
131
 
131
132
  data = json_clone(data)
@@ -174,6 +175,24 @@ module TestHelpers
174
175
  end
175
176
  end
176
177
 
178
+ def mock_schema_method(adapters, &block)
179
+ adapters.each do |klass|
180
+ klass.class_eval 'def schema
181
+ {
182
+ "property" => {
183
+ "name" => "string",
184
+ "brand" => "string"
185
+ },
186
+ "version" => "1.0"
187
+ }.to_json
188
+ end'
189
+ end
190
+ yield
191
+ adapters.each do |klass|
192
+ klass.class_eval "def schema; end"
193
+ end
194
+ end
195
+
177
196
  def unzip_file(file,file_dir)
178
197
  Zip::ZipFile.open(file) do |zip_file|
179
198
  zip_file.each do |f|
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhosync
3
3
  version: !ruby/object:Gem::Version
4
- hash: 62196465
4
+ hash: 62196471
5
5
  prerelease: true
6
6
  segments:
7
7
  - 2
8
8
  - 1
9
9
  - 0
10
10
  - beta
11
- - 1
12
- version: 2.1.0.beta.1
11
+ - 2
12
+ version: 2.1.0.beta.2
13
13
  platform: ruby
14
14
  authors:
15
15
  - Rhomobile
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2010-11-07 00:00:00 -07:00
20
+ date: 2010-12-07 00:00:00 -08:00
21
21
  default_executable: rhosync
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -156,11 +156,11 @@ dependencies:
156
156
  requirements:
157
157
  - - ~>
158
158
  - !ruby/object:Gem::Version
159
- hash: 15
159
+ hash: 13
160
160
  segments:
161
161
  - 1
162
- - 0
163
- version: "1.0"
162
+ - 1
163
+ version: "1.1"
164
164
  type: :runtime
165
165
  version_requirements: *id009
166
166
  - !ruby/object:Gem::Dependency
@@ -551,8 +551,8 @@ homepage: http://rhomobile.com/products/rhosync
551
551
  licenses: []
552
552
 
553
553
  post_install_message:
554
- rdoc_options:
555
- - --charset=UTF-8
554
+ rdoc_options: []
555
+
556
556
  require_paths:
557
557
  - lib
558
558
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -583,6 +583,9 @@ signing_key:
583
583
  specification_version: 3
584
584
  summary: RhoSync Synchronization Framework
585
585
  test_files:
586
+ - examples/simple/application.rb
587
+ - examples/simple/sources/sample_adapter.rb
588
+ - examples/simple/sources/simple_adapter.rb
586
589
  - spec/api/api_helper.rb
587
590
  - spec/api/create_client_spec.rb
588
591
  - spec/api/create_user_spec.rb
@@ -616,8 +619,8 @@ test_files:
616
619
  - spec/apps/rhotestapp/sources/sample_adapter.rb
617
620
  - spec/apps/rhotestapp/sources/simple_adapter.rb
618
621
  - spec/apps/rhotestapp/sources/sub_adapter.rb
619
- - spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem/mygem.rb
620
622
  - spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem.rb
623
+ - spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem/mygem.rb
621
624
  - spec/bulk_data/bulk_data_spec.rb
622
625
  - spec/client_spec.rb
623
626
  - spec/client_sync_spec.rb
@@ -649,6 +652,3 @@ test_files:
649
652
  - spec/sync_states_spec.rb
650
653
  - spec/test_methods_spec.rb
651
654
  - spec/user_spec.rb
652
- - examples/simple/application.rb
653
- - examples/simple/sources/sample_adapter.rb
654
- - examples/simple/sources/simple_adapter.rb