test_machine_shop 0.0.4

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 (73) hide show
  1. checksums.yaml +7 -0
  2. data/.idea/.name +1 -0
  3. data/.idea/.rakeTasks +7 -0
  4. data/.idea/compiler.xml +23 -0
  5. data/.idea/copyright/profiles_settings.xml +5 -0
  6. data/.idea/encodings.xml +5 -0
  7. data/.idea/inspectionProfiles/Project_Default.xml +7 -0
  8. data/.idea/inspectionProfiles/profiles_settings.xml +7 -0
  9. data/.idea/machineshop.iml +194 -0
  10. data/.idea/misc.xml +5 -0
  11. data/.idea/modules.xml +9 -0
  12. data/.idea/scopes/scope_settings.xml +5 -0
  13. data/.idea/vcs.xml +7 -0
  14. data/.idea/workspace.xml +722 -0
  15. data/Gemfile +9 -0
  16. data/LICENSE +22 -0
  17. data/README.md +977 -0
  18. data/Rakefile +8 -0
  19. data/doc.txt +50 -0
  20. data/lib/machineshop.rb +475 -0
  21. data/lib/machineshop/api_operations/create.rb +17 -0
  22. data/lib/machineshop/api_operations/delete.rb +11 -0
  23. data/lib/machineshop/api_operations/list.rb +16 -0
  24. data/lib/machineshop/api_operations/update.rb +11 -0
  25. data/lib/machineshop/api_resource.rb +35 -0
  26. data/lib/machineshop/configuration.rb +14 -0
  27. data/lib/machineshop/customer.rb +15 -0
  28. data/lib/machineshop/data_source_types.rb +28 -0
  29. data/lib/machineshop/data_sources.rb +35 -0
  30. data/lib/machineshop/database.rb +59 -0
  31. data/lib/machineshop/device.rb +30 -0
  32. data/lib/machineshop/device_instance.rb +30 -0
  33. data/lib/machineshop/end_points.rb +30 -0
  34. data/lib/machineshop/errors/api_connection_error.rb +4 -0
  35. data/lib/machineshop/errors/api_error.rb +4 -0
  36. data/lib/machineshop/errors/authentication_error.rb +4 -0
  37. data/lib/machineshop/errors/database_error.rb +5 -0
  38. data/lib/machineshop/errors/invalid_request_error.rb +10 -0
  39. data/lib/machineshop/errors/machineshop_error.rb +20 -0
  40. data/lib/machineshop/errors/schema_error.rb +5 -0
  41. data/lib/machineshop/json.rb +21 -0
  42. data/lib/machineshop/machineshop_cache.rb +49 -0
  43. data/lib/machineshop/machineshop_object.rb +165 -0
  44. data/lib/machineshop/mapping.rb +34 -0
  45. data/lib/machineshop/meter.rb +12 -0
  46. data/lib/machineshop/models/api_endpoint.rb +8 -0
  47. data/lib/machineshop/models/api_request.rb +28 -0
  48. data/lib/machineshop/models/schema.rb +184 -0
  49. data/lib/machineshop/report.rb +11 -0
  50. data/lib/machineshop/rule.rb +42 -0
  51. data/lib/machineshop/user.rb +43 -0
  52. data/lib/machineshop/users.rb +43 -0
  53. data/lib/machineshop/util.rb +193 -0
  54. data/lib/machineshop/utility.rb +30 -0
  55. data/lib/machineshop/version.rb +3 -0
  56. data/machineshop.gemspec +35 -0
  57. data/spec/lib/api_calls_spec.rb +628 -0
  58. data/spec/lib/custom_endpoint_test.rb +78 -0
  59. data/spec/lib/customer_spec.rb +87 -0
  60. data/spec/lib/data_source.rb +138 -0
  61. data/spec/lib/data_source_type_spec.rb +77 -0
  62. data/spec/lib/database_spec.rb +45 -0
  63. data/spec/lib/device_instances.rb +73 -0
  64. data/spec/lib/device_spec.rb +172 -0
  65. data/spec/lib/endpoint_spec.rb +37 -0
  66. data/spec/lib/geocode_spec +45 -0
  67. data/spec/lib/mapping_spec.rb +68 -0
  68. data/spec/lib/meter_spec.rb +49 -0
  69. data/spec/lib/report_spec.rb +52 -0
  70. data/spec/lib/rule_spec.rb +130 -0
  71. data/spec/lib/user_spec.rb +58 -0
  72. data/spec/spec_helper.rb +12 -0
  73. metadata +235 -0
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new
6
+
7
+ task :default => :spec
8
+ task :test => :spec
data/doc.txt ADDED
@@ -0,0 +1,50 @@
1
+ #response from authenticate
2
+
3
+ {:_id=>"52160c8e981800aaef000001",
4
+ :authentication_token=>"2jzZmcHWLZyghsxcB16E",
5
+ :company_name=>"CSR",
6
+ :current_sign_in_at=>"2014-03-21T09:32:13Z",
7
+ :current_sign_in_ip=>"202.51.76.235",
8
+ :email=>"admin@csr.com",
9
+ :first_name=>"CSR",
10
+ :keychain=>{},
11
+ :last_name=>"Admin",
12
+ :last_sign_in_at=>"2014-03-21T09:11:08Z",
13
+ :last_sign_in_ip=>"202.51.76.235",
14
+ :logo_url=>nil,
15
+ :notification_method=>"sms",
16
+ :phone_number=>"+1 (123) 456-7890",
17
+ :role=>"admin",
18
+ :sign_in_count=>7910,
19
+ :tag_ids=>[],
20
+ :http_code=>200}
21
+
22
+
23
+
24
+ #user object
25
+
26
+ {
27
+ "id": "52160c8e981800aaef000001",
28
+ "_id": "52160c8e981800aaef000001",
29
+ "authentication_token": "2jzZmcHWLZyghsxcB16E",
30
+ "company_name": "CSR",
31
+ "current_sign_in_at": "2014-03-21T09:30:42Z",
32
+ "current_sign_in_ip": "202.51.76.235",
33
+ "email": "admin@csr.com",
34
+ "first_name": "CSR",
35
+ "keychain": {},
36
+ "last_name": "Admin",
37
+ "last_sign_in_at": "2014-03-21T09:32:13Z",
38
+ "last_sign_in_ip": "202.51.76.235",
39
+ "logo_url": null,
40
+ "notification_method": "sms",
41
+ "phone_number": "+1 (123) 456-7890",
42
+ "role": "admin",
43
+ "sign_in_count": 7912,
44
+ "tag_ids": [
45
+
46
+ ],
47
+ "http_code": 200
48
+ }
49
+
50
+
@@ -0,0 +1,475 @@
1
+ require "machineshop/version"
2
+
3
+ # require 'awesome_print'
4
+ # require 'will_paginate'
5
+
6
+ require 'cgi'
7
+ require 'set'
8
+ require 'openssl'
9
+ require 'rest_client'
10
+ require "base64"
11
+ require "addressable/uri"
12
+ require 'multi_json'
13
+
14
+ #configurations
15
+ require 'machineshop/configuration'
16
+ #database
17
+ require 'machineshop/database'
18
+
19
+ # API operations
20
+ require 'machineshop/api_operations/create'
21
+ require 'machineshop/api_operations/delete'
22
+ require 'machineshop/api_operations/list'
23
+ require 'machineshop/api_operations/update'
24
+
25
+ # Resources
26
+
27
+ require 'machineshop/machineshop_object'
28
+ require 'machineshop/api_resource'
29
+ require 'machineshop/device_instance'
30
+ require 'machineshop/device'
31
+ require 'machineshop/machineshop_object'
32
+ require 'machineshop/mapping'
33
+ require 'machineshop/meter'
34
+ require 'machineshop/report'
35
+ require 'machineshop/customer'
36
+ require 'machineshop/rule'
37
+ # require 'machineshop/user'
38
+ require 'machineshop/users'
39
+ require 'machineshop/utility'
40
+ require 'machineshop/json'
41
+ require 'machineshop/util'
42
+ require 'machineshop/end_points'
43
+
44
+ require 'machineshop/data_sources'
45
+ require 'machineshop/data_source_types'
46
+
47
+ # Errors
48
+ require 'machineshop/errors/machineshop_error'
49
+ require 'machineshop/errors/api_error'
50
+ require 'machineshop/errors/invalid_request_error'
51
+ require 'machineshop/errors/authentication_error'
52
+ require 'machineshop/errors/api_connection_error'
53
+
54
+ #Models
55
+ require 'machineshop/models/api_request'
56
+ require 'machineshop/models/api_endpoint'
57
+
58
+
59
+ module MachineShop
60
+ class << self
61
+ # @@api_base_url = 'http://api.machineshop.io/api/v0'
62
+ @@api_base_url = 'http://stage.services.machineshop.io/api/v0'
63
+
64
+ #configs starts
65
+ attr_writer :configuration
66
+
67
+ def configuration
68
+ @configuration ||= Configuration.new
69
+ end
70
+
71
+ def configure
72
+ yield(configuration)
73
+ end
74
+
75
+ #reset the config object
76
+ def reset
77
+ Configuration.new
78
+ end
79
+
80
+ #configs ends
81
+
82
+ def api_base_url=(api_base_url)
83
+ @@api_base_url = api_base_url
84
+ end
85
+
86
+ def api_base_url
87
+ @@api_base_url
88
+ end
89
+
90
+ #For Custom endpoints
91
+ def get(name, auth_token, *params)
92
+ url = Util.valid_endpoint(name,auth_token,:get, params)
93
+ platform_request(url, auth_token, nil, :get)
94
+ end
95
+
96
+ def post(name,auth_token, body_hash)
97
+ url = Util.valid_endpoint(name,auth_token,:post,[])
98
+ platform_request(url, auth_token,body_hash,:post)
99
+ end
100
+
101
+ def put(name,auth_token,*params,body_hash)
102
+ url = Util.valid_endpoint(name,auth_token,:put,params)
103
+ platform_request(url, auth_token,body_hash,:put)
104
+ end
105
+
106
+ def delete(name,auth_token,*params)
107
+ url = Util.valid_endpoint(name,auth_token,:delete,params)
108
+ platform_request(url, auth_token, nil ,:delete)
109
+ end
110
+
111
+ #Call for the predefined request
112
+ def gem_get(url, auth_token, body_hash=nil)
113
+ platform_request(url, auth_token, body_hash)
114
+ end
115
+
116
+ def gem_post(url, auth_token, body_hash)
117
+ platform_request(url, auth_token, body_hash, :post)
118
+ end
119
+
120
+ def gem_delete(url, auth_token, body_hash)
121
+ platform_request(url, auth_token, body_hash, :delete)
122
+ end
123
+
124
+ def gem_put(url, auth_token, body_hash)
125
+ platform_request(url, auth_token, body_hash, :put)
126
+ end
127
+
128
+ def headers(auth_token)
129
+ header ={:content_type => :json,
130
+ :accept => :json}
131
+ header.merge!({ authorization: "Basic " + Base64.encode64(auth_token + ':X') }) if auth_token
132
+ header
133
+ end
134
+
135
+ def platform_request(url, auth_token, body_hash=nil, http_verb=:get )
136
+ rbody=nil
137
+ cachedContent = :true
138
+ # ApiRequest.cache(url,MachineShop.configuration.expiry_time)
139
+ if http_verb==:get
140
+
141
+ if Util.db_connected?
142
+ xpired=true
143
+
144
+ ApiRequest.cache(url, auth_token, MachineShop.configuration.expiry_time) do
145
+ xpired=false
146
+ puts "Not expired , calling from local "
147
+ rbody = get_from_cache(url,body_hash,auth_token)
148
+ rcode="200"
149
+ end
150
+ end
151
+
152
+ end
153
+ if (rbody.nil? || rbody.empty?)
154
+ cachedContent=:false
155
+ opts = nil
156
+ api_uri = api_base_url + url
157
+ headers = self.headers(auth_token)
158
+ if http_verb == :get
159
+ if (body_hash && !body_hash.empty?)
160
+ uri = Addressable::URI.new
161
+ uri.query_values = body_hash
162
+ api_uri += "?" + uri.query
163
+ end
164
+
165
+ opts = {
166
+ :method => :get,
167
+ :url => api_uri,
168
+ :headers => headers,
169
+ :open_timeout => 30,
170
+ :timeout => 80
171
+ }
172
+
173
+ else
174
+ opts = {
175
+ :method => http_verb,
176
+ :url => api_uri,
177
+ :headers => headers,
178
+ :open_timeout => 30,
179
+ :payload => MachineShop::JSON.dump(body_hash),
180
+ :timeout => 80
181
+ }
182
+
183
+ end
184
+
185
+ puts "request params: #{opts} "
186
+
187
+ begin
188
+ response = execute_request(opts)
189
+
190
+ rescue SocketError => e
191
+ self.handle_restclient_error(e)
192
+ rescue NoMethodError => e
193
+ # Work around RestClient bug
194
+ if e.message =~ /\WRequestFailed\W/
195
+ e = APIConnectionError.new('Unexpected HTTP response code')
196
+ self.handle_restclient_error(e)
197
+ else
198
+ raise
199
+ end
200
+ rescue RestClient::ExceptionWithResponse => e
201
+ if rcode = e.http_code and rbody = e.http_body
202
+ self.handle_api_error(rcode, rbody)
203
+ else
204
+ self.handle_restclient_error(e)
205
+ end
206
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
207
+ self.handle_restclient_error(e)
208
+ end
209
+
210
+ rbody = response.body
211
+ # puts rbody
212
+ rcode = response.code
213
+ end
214
+
215
+ begin
216
+ # Would use :symbolize_names => true, but apparently there is
217
+ # some library out there that makes symbolize_names not work.
218
+ resp = MachineShop::JSON.load(rbody)
219
+ resp ||= {}
220
+ resp = Util.symbolize_names(resp)
221
+
222
+ save_into_cache(url,resp,auth_token) if (http_verb == :get && cachedContent==:false)
223
+
224
+ resp.merge!({:http_code => rcode}) if resp.is_a?(Hash)
225
+ return resp
226
+ rescue MultiJson::DecodeError
227
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
228
+ end
229
+
230
+ end
231
+
232
+
233
+ def execute_request(opts)
234
+ RestClient::Request.execute(opts)
235
+ end
236
+
237
+ def handle_api_error(rcode, rbody)
238
+ begin
239
+ error_obj = MachineShop::JSON.load(rbody)
240
+ error_obj = Util.symbolize_names(error_obj)
241
+ error = error_obj[:error] or raise MachineShopError.new # escape from parsing
242
+ rescue MultiJson::DecodeError, MachineShopError
243
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
244
+ end
245
+
246
+ case rcode
247
+ when 400, 404 then
248
+ raise invalid_request_error(error, rcode, rbody, error_obj)
249
+ when 401
250
+ raise authentication_error(error, rcode, rbody, error_obj)
251
+ when 402
252
+ # TODO Come up with errors
253
+ else
254
+ raise api_error(error, rcode, rbody, error_obj)
255
+ end
256
+ end
257
+
258
+ def invalid_request_error(error, rcode, rbody, error_obj)
259
+ InvalidRequestError.new(error, error, rcode, rbody, error_obj)
260
+ end
261
+
262
+ def authentication_error(error, rcode, rbody, error_obj)
263
+ AuthenticationError.new(error, rcode, rbody, error_obj)
264
+ end
265
+
266
+ def api_error(error, rcode, rbody, error_obj)
267
+ APIError.new(error, rcode, rbody, error_obj)
268
+ end
269
+
270
+ def handle_restclient_error(e)
271
+ case e
272
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
273
+ message = "Could not connect to MachineShop (#{@@api_base_url}). Please check your internet connection and try again. If this problem persists, you should check MachineShop's service status."
274
+ when RestClient::SSLCertificateNotVerified
275
+ message = "Could not verify MachineShops's SSL certificate. Please make sure that your network is not intercepting certificates."
276
+ when SocketError
277
+ message = "Unexpected error communicating when trying to connect to MachineShop (#{@@api_base_url}). HINT: You may be seeing this message because your DNS is not working."
278
+ else
279
+ message = "Unexpected error communicating with MachineShop"
280
+ end
281
+ message += "\n\n(Network error: #{e.message})"
282
+ # puts "error message string : #{message}"
283
+ raise APIConnectionError.new(message)
284
+ end
285
+
286
+
287
+ # Check if the class with the variable exists
288
+ def class_exists?(class_name)
289
+ klass = class_name.constantize
290
+ return klass.is_a?(Class)
291
+ rescue NameError =>e
292
+ return false
293
+ end
294
+
295
+
296
+ def save_into_cache(url, data,auth_token)
297
+ id,klass= Util.get_klass_from_url(url)
298
+ if !TABLE_NAME_BLACKLIST.include?(klass)
299
+ if Util.db_connected?
300
+
301
+ klass = klass.capitalize+"Cache"
302
+ puts "creating dynamic class #{klass}"
303
+
304
+
305
+ modelClass ||= (Object.const_set klass, Class.new(ActiveRecord::Base))
306
+ modelClass.inheritance_column = :_type_disabled
307
+ #Because 'type' is reserved for storing the class in case of inheritance and our array has "TYPE" key
308
+
309
+ if ActiveRecord::Base.connection.table_exists? CGI.escape(klass.pluralize.underscore)
310
+
311
+ #delete all the previous records
312
+
313
+ modelClass.delete_all
314
+ puts "db table #{klass.pluralize.underscore} exists"
315
+ if data.class ==Hash
316
+
317
+ findId = data[:_id] || data["_id"]
318
+ @activeObject = modelClass.new
319
+ # @activeObject = modelClass.find_by(_id: findId) || modelClass.new
320
+ data.each do |k,v|
321
+
322
+ val=nil
323
+
324
+ if v.class==Array
325
+ val = v.to_json
326
+ elsif v.class==Hash
327
+ val = v.to_json
328
+ else
329
+ val=v
330
+ end
331
+ if @activeObject.has_attribute?(k)
332
+ @activeObject.send("#{k}=",val)
333
+ end
334
+ @activeObject.save
335
+ end
336
+
337
+
338
+ else
339
+ data.each do |data_arr|
340
+
341
+ if data_arr
342
+
343
+ if data_arr.first.class==String && data_arr.class==Array
344
+ @activeObject = modelClass.find_by(rule_condition: data_arr.select{|k| k.include?("rule_condition")}) || modelClass.new
345
+ data_arr.each do |k|
346
+
347
+ if k.include?("rule_condition")
348
+ @activeObject.rule_condition = k
349
+ else
350
+ @activeObject.rule_description=k
351
+ end
352
+ end
353
+
354
+
355
+ else
356
+ if data_arr.class!=String
357
+ findId = data_arr[:_id] || data_arr["_id"]
358
+ @activeObject = modelClass.find_by(_id: findId) || modelClass.new
359
+ data_arr.each do |k,v|
360
+
361
+ val=nil
362
+
363
+ if v.class==Array
364
+ val = v.to_json
365
+ elsif v.class==Hash
366
+ val = v.to_json
367
+ else
368
+ val=v
369
+ end
370
+ #check if the database has the particular field to store
371
+ if @activeObject.has_attribute?(k)
372
+ @activeObject.send("#{k}=",val)
373
+ end
374
+ end
375
+ end
376
+ end
377
+ end
378
+ @activeObject.send("auth_token=",auth_token)
379
+ @activeObject.save
380
+ end
381
+ end
382
+
383
+ end #if ActiveRecord ends
384
+
385
+ end #if db_connected ends
386
+ end #if !TABLE_NAME_BLACKLIST.include? ends
387
+ end
388
+
389
+
390
+ def get_from_cache(url, body_hash,auth_token)
391
+ result =Array.new
392
+ id,klass= Util.get_klass_from_url(url)
393
+ if !TABLE_NAME_BLACKLIST.include?(klass)
394
+ if Util.db_connected?
395
+
396
+ klass = klass.capitalize+"Cache"
397
+
398
+ modelClass = Object.const_set klass, Class.new(ActiveRecord::Base)
399
+ modelClass.inheritance_column = :_type_disabled
400
+
401
+ data_exist=false
402
+ if ActiveRecord::Base.connection.table_exists? CGI.escape(klass.pluralize.underscore)
403
+ puts "db:table #{klass.pluralize} exists"
404
+ resp= nil
405
+ if id
406
+ resp = modelClass.find_by(_id: id, auth_token: auth_token)
407
+ data_exist=true if resp
408
+ else
409
+ # pagination = body_hash.select{|k| k==:per_page || k==:page} if body_hash
410
+ resp = modelClass.where(parse_query_string(body_hash,auth_token))
411
+ data_exist = true if resp.exists?
412
+ end
413
+
414
+ if data_exist
415
+ if(klass.include?("rule_condition"))
416
+ resp.each do |rTemp|
417
+ temp = Array.new
418
+ temp.push rTemp["rule_description"]
419
+ temp.push rTemp["rule_condition"]
420
+ result << temp
421
+ end
422
+ result = result.to_json(:except=>[:id]) if result
423
+ else
424
+ result = resp.to_json(:except=>[:id]) if resp
425
+ end
426
+
427
+ end
428
+ end
429
+ end
430
+ end
431
+ return result
432
+ end
433
+
434
+ TABLE_NAME_BLACKLIST = ["user","routes"]
435
+ QUERY_STRING_BLACKLIST = [
436
+ 'page',
437
+ 'per_page'
438
+ ]
439
+
440
+ def parse_query_string(query_params,auth_token)
441
+
442
+ search_parms = {}
443
+ if query_params
444
+ params = Hash[query_params.map{ |k, v| [k.to_s, v] }]
445
+ operators = ["gt", "gte", "lt", "lte"]
446
+
447
+ xs = params.reject { |k,_| QUERY_STRING_BLACKLIST.include?(k) }
448
+ xs.each do |key,value|
449
+ tokens = key.split('_')
450
+ if tokens.nil? || tokens.length == 1
451
+ search_parms[key] = value
452
+ else
453
+ token_length = tokens[tokens.length-1].length-1
454
+ if operators.include?(tokens[tokens.length-1])
455
+ operator = "$" + tokens[tokens.length-1]
456
+ new_key = key[0,key.length-token_length-2].to_sym
457
+ search_parms[new_key] = { operator => value }
458
+ elsif tokens[tokens.length-1] == "between" && value.split("_").length > 1
459
+ new_key = key[0,key.length-token_length-2].to_sym
460
+ vals = value.split("_")
461
+ search_parms[new_key] = {"$gte" => vals[0], "$lte" => vals[1]}
462
+ else
463
+ search_parms[key] = value
464
+ end
465
+ end
466
+ end
467
+ end
468
+ #append auth_token = auth_token part as well
469
+ search_parms['auth_token']=auth_token
470
+ search_parms
471
+ end
472
+
473
+
474
+ end
475
+ end