openc_bot 0.0.11

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.travis.yml +8 -0
  4. data/CHANGELOG.md +2 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +253 -0
  8. data/Rakefile +14 -0
  9. data/bin/openc_bot +13 -0
  10. data/create_bot.sh +30 -0
  11. data/create_company_bot.sh +16 -0
  12. data/create_simple_licence_bot.sh +31 -0
  13. data/db/.gitkeep +0 -0
  14. data/examples/basic/.gitignore +3 -0
  15. data/examples/basic/Gemfile +7 -0
  16. data/examples/basic/config.yml +21 -0
  17. data/examples/basic/lib/basic.rb +88 -0
  18. data/examples/basic_with_proxy/Gemfile +7 -0
  19. data/examples/basic_with_proxy/config.yml +21 -0
  20. data/examples/basic_with_proxy/lib/basic_with_proxy.rb +103 -0
  21. data/examples/bot_with_simple_iterator/Gemfile +6 -0
  22. data/examples/bot_with_simple_iterator/config.yml +21 -0
  23. data/examples/bot_with_simple_iterator/lib/bot_with_simple_iterator.rb +112 -0
  24. data/examples/company_fetchers/basic.rb +49 -0
  25. data/lib/monkey_patches/mechanize.rb +53 -0
  26. data/lib/openc_bot.rb +89 -0
  27. data/lib/openc_bot/bot_data_validator.rb +18 -0
  28. data/lib/openc_bot/company_fetcher_bot.rb +40 -0
  29. data/lib/openc_bot/exceptions.rb +17 -0
  30. data/lib/openc_bot/helpers/_csv.rb +10 -0
  31. data/lib/openc_bot/helpers/alpha_search.rb +73 -0
  32. data/lib/openc_bot/helpers/dates.rb +33 -0
  33. data/lib/openc_bot/helpers/html.rb +8 -0
  34. data/lib/openc_bot/helpers/incremental_search.rb +106 -0
  35. data/lib/openc_bot/helpers/register_methods.rb +205 -0
  36. data/lib/openc_bot/helpers/text.rb +18 -0
  37. data/lib/openc_bot/incrementers.rb +2 -0
  38. data/lib/openc_bot/incrementers/base.rb +214 -0
  39. data/lib/openc_bot/incrementers/common.rb +47 -0
  40. data/lib/openc_bot/tasks.rb +385 -0
  41. data/lib/openc_bot/templates/README.md +35 -0
  42. data/lib/openc_bot/templates/bin/export_data +28 -0
  43. data/lib/openc_bot/templates/bin/fetch_data +23 -0
  44. data/lib/openc_bot/templates/bin/verify_data +1 -0
  45. data/lib/openc_bot/templates/config.yml +21 -0
  46. data/lib/openc_bot/templates/lib/bot.rb +43 -0
  47. data/lib/openc_bot/templates/lib/company_fetcher_bot.rb +95 -0
  48. data/lib/openc_bot/templates/lib/simple_bot.rb +67 -0
  49. data/lib/openc_bot/templates/spec/bot_spec.rb +11 -0
  50. data/lib/openc_bot/templates/spec/simple_bot_spec.rb +11 -0
  51. data/lib/openc_bot/templates/spec/spec_helper.rb +13 -0
  52. data/lib/openc_bot/version.rb +3 -0
  53. data/lib/simple_openc_bot.rb +289 -0
  54. data/openc_bot.gemspec +35 -0
  55. data/schemas/company-schema.json +112 -0
  56. data/schemas/includes/address.json +23 -0
  57. data/schemas/includes/base-statement.json +27 -0
  58. data/schemas/includes/company.json +14 -0
  59. data/schemas/includes/filing.json +20 -0
  60. data/schemas/includes/license-data.json +27 -0
  61. data/schemas/includes/officer.json +14 -0
  62. data/schemas/includes/previous_name.json +11 -0
  63. data/schemas/includes/share-parcel-data.json +67 -0
  64. data/schemas/includes/share-parcel.json +60 -0
  65. data/schemas/includes/subsidiary-relationship-data.json +52 -0
  66. data/schemas/includes/total-shares.json +10 -0
  67. data/schemas/licence-schema.json +21 -0
  68. data/schemas/share-parcel-schema.json +21 -0
  69. data/schemas/subsidiary-relationship-schema.json +19 -0
  70. data/spec/dummy_classes/foo_bot.rb +4 -0
  71. data/spec/lib/bot_data_validator_spec.rb +69 -0
  72. data/spec/lib/company_fetcher_bot_spec.rb +93 -0
  73. data/spec/lib/exceptions_spec.rb +25 -0
  74. data/spec/lib/helpers/alpha_search_spec.rb +173 -0
  75. data/spec/lib/helpers/dates_spec.rb +65 -0
  76. data/spec/lib/helpers/incremental_search_spec.rb +471 -0
  77. data/spec/lib/helpers/register_methods_spec.rb +558 -0
  78. data/spec/lib/helpers/text_spec.rb +50 -0
  79. data/spec/lib/openc_bot/db/.gitkeep +0 -0
  80. data/spec/lib/openc_bot/incrementers/common_spec.rb +83 -0
  81. data/spec/lib/openc_bot_spec.rb +116 -0
  82. data/spec/schemas/company-schema_spec.rb +676 -0
  83. data/spec/simple_openc_bot_spec.rb +302 -0
  84. data/spec/spec_helper.rb +19 -0
  85. metadata +300 -0
@@ -0,0 +1,558 @@
1
+ # encoding: UTF-8
2
+ require_relative '../../spec_helper'
3
+ require 'openc_bot'
4
+ require 'openc_bot/helpers/register_methods'
5
+
6
+ module ModuleThatIncludesRegisterMethods
7
+ extend OpencBot
8
+ extend OpencBot::Helpers::RegisterMethods
9
+ PRIMARY_KEY_NAME = :custom_uid
10
+ SCHEMA_NAME = 'company-schema'
11
+ end
12
+
13
+ module ModuleWithNoCustomPrimaryKey
14
+ extend OpencBot
15
+ extend OpencBot::Helpers::RegisterMethods
16
+ end
17
+
18
+ describe 'a module that includes RegisterMethods' do
19
+
20
+ before do
21
+ ModuleThatIncludesRegisterMethods.stub(:sqlite_magic_connection).
22
+ and_return(test_database_connection)
23
+ end
24
+
25
+ after do
26
+ remove_test_database
27
+ end
28
+
29
+ describe "#datum_exists?" do
30
+ before do
31
+ ModuleThatIncludesRegisterMethods.stub(:select).and_return([])
32
+
33
+ end
34
+
35
+ it "should select_data from database" do
36
+ expected_sql_query = "ocdata.custom_uid FROM ocdata WHERE custom_uid = ? LIMIT 1"
37
+ ModuleThatIncludesRegisterMethods.should_receive(:select).with(expected_sql_query, '4567').and_return([])
38
+ ModuleThatIncludesRegisterMethods.datum_exists?('4567')
39
+ end
40
+
41
+ it "should return true if result returned" do
42
+ ModuleThatIncludesRegisterMethods.stub(:select).and_return([{'custom_uid' => '4567'}])
43
+
44
+ ModuleThatIncludesRegisterMethods.datum_exists?('4567').should be_true
45
+ end
46
+
47
+ it "should return false if result returned" do
48
+ ModuleThatIncludesRegisterMethods.datum_exists?('4567').should be_false
49
+ end
50
+ end
51
+
52
+ describe "#export_data" do
53
+ before do
54
+ ModuleThatIncludesRegisterMethods.stub(:select).and_return([])
55
+
56
+ end
57
+
58
+ it "should select_data from database" do
59
+ expected_sql_query = "ocdata.* from ocdata"
60
+ ModuleThatIncludesRegisterMethods.should_receive(:select).with(expected_sql_query).and_return([])
61
+ ModuleThatIncludesRegisterMethods.export_data
62
+ end
63
+
64
+ it "should yield rows that have been passed to post_process" do
65
+ datum = {'food' => 'tofu'}
66
+ ModuleThatIncludesRegisterMethods.stub(:select).and_return([datum])
67
+ ModuleThatIncludesRegisterMethods.should_receive(:post_process).with(datum, true).and_return(datum)
68
+ ModuleThatIncludesRegisterMethods.export_data{|x|}
69
+ end
70
+ end
71
+
72
+
73
+ describe '#primary_key_name' do
74
+ it 'should return :uid if PRIMARY_KEY_NAME not set' do
75
+ ModuleWithNoCustomPrimaryKey.send(:primary_key_name).should == :uid
76
+ end
77
+
78
+ it 'should return value if PRIMARY_KEY_NAME set' do
79
+ ModuleThatIncludesRegisterMethods.send(:primary_key_name).should == :custom_uid
80
+ end
81
+ end
82
+
83
+ describe "#use_alpha_search" do
84
+ context 'and no USE_ALPHA_SEARCH constant' do
85
+ it "should not return true" do
86
+ ModuleThatIncludesRegisterMethods.use_alpha_search.should_not be_true
87
+ end
88
+ end
89
+
90
+ context 'and USE_ALPHA_SEARCH constant set' do
91
+ it "should return USE_ALPHA_SEARCH" do
92
+ stub_const("ModuleThatIncludesRegisterMethods::USE_ALPHA_SEARCH", true)
93
+ ModuleThatIncludesRegisterMethods.use_alpha_search.should be_true
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "#schema_name" do
99
+ context 'and no SCHEMA_NAME constant' do
100
+ it "should return nil" do
101
+ ModuleWithNoCustomPrimaryKey.schema_name.should be_nil
102
+ end
103
+ end
104
+
105
+ context 'and SCHEMA_NAME constant set' do
106
+ it "should return SCHEMA_NAME" do
107
+ ModuleThatIncludesRegisterMethods.schema_name.should == 'company-schema'
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "#update_data" do
113
+ before do
114
+ ModuleThatIncludesRegisterMethods.stub(:fetch_data_via_incremental_search)
115
+ ModuleThatIncludesRegisterMethods.stub(:update_stale)
116
+ end
117
+
118
+ it "should get new records via incremental search" do
119
+ ModuleThatIncludesRegisterMethods.should_not_receive(:fetch_data_via_alpha_search)
120
+ ModuleThatIncludesRegisterMethods.should_receive(:fetch_data_via_incremental_search)
121
+ ModuleThatIncludesRegisterMethods.update_data
122
+ end
123
+
124
+ it "should get new records via alpha search if use_alpha_search" do
125
+ ModuleThatIncludesRegisterMethods.should_receive(:use_alpha_search).and_return(true)
126
+ ModuleThatIncludesRegisterMethods.should_not_receive(:fetch_data_via_incremental_search)
127
+ ModuleThatIncludesRegisterMethods.should_receive(:fetch_data_via_alpha_search)
128
+ ModuleThatIncludesRegisterMethods.update_data
129
+ end
130
+
131
+ it "should update stale records" do
132
+ ModuleThatIncludesRegisterMethods.should_receive(:update_stale)
133
+ ModuleThatIncludesRegisterMethods.update_data
134
+ end
135
+
136
+ it "should save run report" do
137
+ ModuleThatIncludesRegisterMethods.should_receive(:save_run_report).with(:status => 'success')
138
+ ModuleThatIncludesRegisterMethods.update_data
139
+ end
140
+
141
+ it "should not raise error if passed options" do
142
+ lambda { ModuleThatIncludesRegisterMethods.update_data }.should_not raise_error
143
+ end
144
+ end
145
+
146
+ describe "#update_stale" do
147
+ it "should get uids of stale entries" do
148
+ ModuleThatIncludesRegisterMethods.should_receive(:stale_entry_uids)
149
+ ModuleThatIncludesRegisterMethods.update_stale
150
+ end
151
+
152
+ it "should update_datum for each entry yielded by stale_entries" do
153
+ ModuleThatIncludesRegisterMethods.stub(:stale_entry_uids).and_yield('234').and_yield('666').and_yield('876')
154
+ ModuleThatIncludesRegisterMethods.should_receive(:update_datum).with('234')
155
+ ModuleThatIncludesRegisterMethods.should_receive(:update_datum).with('666')
156
+ ModuleThatIncludesRegisterMethods.should_receive(:update_datum).with('876')
157
+ ModuleThatIncludesRegisterMethods.update_stale
158
+ end
159
+
160
+ context "and limit passed in" do
161
+ it "should pass on limit to #stale_entries" do
162
+ ModuleThatIncludesRegisterMethods.should_receive(:stale_entry_uids).with(42)
163
+ ModuleThatIncludesRegisterMethods.update_stale(42)
164
+ end
165
+ end
166
+ end
167
+
168
+ describe "#stale_entry_uids" do
169
+ before do
170
+ ModuleThatIncludesRegisterMethods.save_data([:custom_uid], :custom_uid => '99999')
171
+ ModuleThatIncludesRegisterMethods.save_data([:custom_uid], :custom_uid => 'A094567')
172
+ end
173
+
174
+ it "should get entries which have not been retrieved or are more than 1 month old" do
175
+ ModuleThatIncludesRegisterMethods.save_data([:custom_uid], :custom_uid => '5234888', :retrieved_at => (Date.today-40).to_time)
176
+ ModuleThatIncludesRegisterMethods.save_data([:custom_uid], :custom_uid => '9234567', :retrieved_at => (Date.today-2).to_time)
177
+
178
+ expect {|b| ModuleThatIncludesRegisterMethods.stale_entry_uids(&b)}.to yield_successive_args('99999', 'A094567', '5234888')
179
+ end
180
+
181
+ context "and no retrieved_at column" do
182
+ it "should not raise error" do
183
+ lambda { ModuleThatIncludesRegisterMethods.stale_entry_uids {} }.should_not raise_error
184
+ end
185
+
186
+ it "should create retrieved_at column" do
187
+ ModuleThatIncludesRegisterMethods.stale_entry_uids {}
188
+ ModuleThatIncludesRegisterMethods.select('* from ocdata').first.keys.should include('retrieved_at')
189
+ end
190
+
191
+ it "should retry" do
192
+ expect {|b| ModuleThatIncludesRegisterMethods.stale_entry_uids(&b)}.to yield_successive_args('99999','A094567')
193
+ end
194
+ end
195
+ end
196
+
197
+ describe '#prepare_and_save_data' do
198
+ before do
199
+ @params = {:name => 'Foo Inc', :custom_uid => '12345', :foo => ['bar','baz'], :foo2 => {:bar => 'baz'}}
200
+ end
201
+
202
+ it "should insert_or_update data using primary_key" do
203
+ ModuleThatIncludesRegisterMethods.should_receive(:insert_or_update).with([:custom_uid], anything)
204
+ ModuleThatIncludesRegisterMethods.prepare_and_save_data(@params)
205
+ end
206
+
207
+ it "should save basic data" do
208
+ ModuleThatIncludesRegisterMethods.should_receive(:insert_or_update).with(anything, hash_including(:name => 'Foo Inc', :custom_uid => '12345'))
209
+ ModuleThatIncludesRegisterMethods.prepare_and_save_data(@params)
210
+ end
211
+
212
+ it "should convert arrays and hashes to json" do
213
+ ModuleThatIncludesRegisterMethods.should_receive(:insert_or_update).with(anything, hash_including(:foo => ['bar','baz'].to_json, :foo2 => {:bar => 'baz'}.to_json))
214
+ ModuleThatIncludesRegisterMethods.prepare_and_save_data(@params)
215
+ end
216
+
217
+ it "should convert time and datetimes to iso601 version" do
218
+ some_date = Date.parse('2012-04-23')
219
+ some_time = Time.now
220
+ ModuleThatIncludesRegisterMethods.should_receive(:insert_or_update).with(anything, hash_including(:some_date => some_date.iso8601, :some_time => some_time.iso8601))
221
+ ModuleThatIncludesRegisterMethods.prepare_and_save_data(@params.merge(:some_date => some_date, :some_time => some_time))
222
+ end
223
+
224
+ it "should not change original params" do
225
+ dup_params = Marshal.load( Marshal.dump(@params) )
226
+ ModuleThatIncludesRegisterMethods.prepare_and_save_data(@params)
227
+ @params.should == dup_params
228
+ end
229
+
230
+ it "should return true" do
231
+ ModuleThatIncludesRegisterMethods.prepare_and_save_data(@params).should be_true
232
+ end
233
+ end
234
+
235
+
236
+ describe "#update_datum for uid" do
237
+ before do
238
+ @dummy_time = Time.now
239
+ @uid = '23456'
240
+ Time.stub(:now).and_return(@dummy_time)
241
+ @fetch_datum_response = 'some really useful data'
242
+ # @processed_data = ModuleThatIncludesRegisterMethods.process_datum(@fetch_datum_response)
243
+ @processed_data = {:foo => 'bar'}
244
+ ModuleThatIncludesRegisterMethods.stub(:fetch_datum).and_return(@fetch_datum_response)
245
+ ModuleThatIncludesRegisterMethods.stub(:process_datum).and_return(@processed_data)
246
+ @processed_data_with_retrieved_at_and_uid = @processed_data.merge(:custom_uid => @uid, :retrieved_at => @dummy_time)
247
+ ModuleThatIncludesRegisterMethods.stub(:save_data)
248
+ ModuleThatIncludesRegisterMethods.stub(:validate_datum).and_return([])
249
+ end
250
+
251
+ it "should fetch_datum for company number" do
252
+ ModuleThatIncludesRegisterMethods.should_receive(:fetch_datum).with(@uid).and_return(@fetch_datum_response)
253
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
254
+ end
255
+
256
+ context "and nothing returned from fetch_datum" do
257
+ before do
258
+ ModuleThatIncludesRegisterMethods.stub(:fetch_datum) # => nil
259
+ end
260
+
261
+ it "should not process_datum" do
262
+ ModuleThatIncludesRegisterMethods.should_not_receive(:process_datum)
263
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
264
+ end
265
+
266
+ it "should not save data" do
267
+ ModuleThatIncludesRegisterMethods.should_not_receive(:save_data)
268
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
269
+ end
270
+
271
+ it "should return nil" do
272
+ ModuleThatIncludesRegisterMethods.update_datum(@uid).should be_nil
273
+ end
274
+
275
+ end
276
+
277
+ context 'and data returned from fetch_datum' do
278
+ it "should process_datum returned from fetching" do
279
+ ModuleThatIncludesRegisterMethods.should_receive(:process_datum).with(@fetch_datum_response)
280
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
281
+ end
282
+
283
+ it "should validate processed data" do
284
+ ModuleThatIncludesRegisterMethods.should_receive(:validate_datum).with(hash_including(@processed_data_with_retrieved_at_and_uid)).and_call_original
285
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
286
+ end
287
+
288
+ it "should prepare processed data for saving including timestamp" do
289
+ ModuleThatIncludesRegisterMethods.should_receive(:prepare_for_saving).with(hash_including(@processed_data_with_retrieved_at_and_uid)).and_call_original
290
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
291
+ end
292
+
293
+ it "should include data in data to be prepared for saving" do
294
+ ModuleThatIncludesRegisterMethods.should_receive(:prepare_for_saving).with(hash_including(:data => @fetch_datum_response)).and_call_original
295
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
296
+ end
297
+
298
+ it "should use supplied retrieved_at in preference to default" do
299
+ different_time = (Date.today-3).iso8601
300
+ ModuleThatIncludesRegisterMethods.stub(:process_datum).
301
+ and_return(@processed_data.merge(:retrieved_at => different_time))
302
+ ModuleThatIncludesRegisterMethods.should_receive(:prepare_for_saving).
303
+ with(hash_including(:retrieved_at => different_time)).and_call_original
304
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
305
+ end
306
+
307
+ it "should save prepared_data" do
308
+ ModuleThatIncludesRegisterMethods.stub(:prepare_for_saving).and_return({:foo => 'some prepared data'})
309
+
310
+ ModuleThatIncludesRegisterMethods.should_receive(:insert_or_update).with([:custom_uid], hash_including(:foo => 'some prepared data'))
311
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
312
+ end
313
+
314
+ it "should return data including uid" do
315
+ ModuleThatIncludesRegisterMethods.update_datum(@uid).should == @processed_data_with_retrieved_at_and_uid
316
+ end
317
+
318
+ it "should not output jsonified processed data by default" do
319
+ ModuleThatIncludesRegisterMethods.should_not_receive(:puts).with(@processed_data_with_retrieved_at_and_uid.to_json)
320
+ ModuleThatIncludesRegisterMethods.update_datum(@uid)
321
+ end
322
+
323
+ it "should output jsonified processed data to STDOUT if passed true as second argument" do
324
+ expected_output = @processed_data_with_retrieved_at_and_uid.
325
+ merge(:retrieved_at => @processed_data_with_retrieved_at_and_uid[:retrieved_at].iso8601)
326
+ # json output is in different, unknown order, so we test output like this
327
+ ModuleThatIncludesRegisterMethods.should_receive(:puts) { |output| json_hash = JSON.parse(output); json_hash == expected_output }
328
+ ModuleThatIncludesRegisterMethods.update_datum(@uid, true)
329
+ end
330
+
331
+
332
+ context "and exception raised" do
333
+ before do
334
+ ModuleThatIncludesRegisterMethods.stub(:process_datum).and_raise('something went wrong')
335
+ end
336
+
337
+ it "should output error message if true passes as second argument" do
338
+ ModuleThatIncludesRegisterMethods.should_receive(:puts).with(/error.+went wrong/m)
339
+ ModuleThatIncludesRegisterMethods.update_datum(@uid, true)
340
+ end
341
+
342
+ it "should return nil if true not passed as second argument" do
343
+ ModuleThatIncludesRegisterMethods.update_datum(@uid).should be_nil
344
+ end
345
+
346
+ it "should output error message if true not passed as second argument" do
347
+ ModuleThatIncludesRegisterMethods.should_not_receive(:puts).with(/error/)
348
+ ModuleThatIncludesRegisterMethods.update_datum(@uid).should be_nil
349
+ end
350
+ end
351
+ end
352
+ end
353
+
354
+ describe '#registry_url for uid' do
355
+ it 'should get computed_registry_url' do
356
+ ModuleThatIncludesRegisterMethods.should_receive(:computed_registry_url).with('338811').and_return('http://some.url')
357
+ ModuleThatIncludesRegisterMethods.registry_url('338811').should == 'http://some.url'
358
+ end
359
+
360
+ context "and computed_registry_url returns nil" do
361
+ it 'should get registry_url_from_db' do
362
+ ModuleThatIncludesRegisterMethods.stub(:computed_registry_url)
363
+ ModuleThatIncludesRegisterMethods.should_receive(:registry_url_from_db).with('338811').and_return('http://another.url')
364
+ ModuleThatIncludesRegisterMethods.registry_url('338811').should == 'http://another.url'
365
+ end
366
+ end
367
+ end
368
+
369
+ describe "#fetch_registry_page for company_number" do
370
+ before do
371
+ @dummy_client = double('http_client', :get_content => nil)
372
+ ModuleThatIncludesRegisterMethods.stub(:_client).and_return(@dummy_client)
373
+ ModuleThatIncludesRegisterMethods.stub(:registry_url).and_return('http://some.registry.url')
374
+ end
375
+
376
+ it "should GET registry_page for registry_url for company_number" do
377
+ ModuleThatIncludesRegisterMethods.should_receive(:registry_url).
378
+ with('76543').and_return('http://some.registry.url')
379
+ @dummy_client.should_receive(:get_content).with('http://some.registry.url')
380
+ ModuleThatIncludesRegisterMethods.fetch_registry_page('76543')
381
+ end
382
+
383
+ it "should return result of GETing registry_page" do
384
+ @dummy_client.stub(:get_content).and_return(:registry_page_html)
385
+ ModuleThatIncludesRegisterMethods.fetch_registry_page('76543').should == :registry_page_html
386
+ end
387
+ end
388
+
389
+ describe "#validate_datum" do
390
+ before do
391
+ @valid_params = {:name => 'Foo Inc', :company_number => '12345', :jurisdiction_code => 'ie'}
392
+ end
393
+
394
+ it "should check json version of datum against given schema" do
395
+ JSON::Validator.should_receive(:fully_validate).with(File.expand_path("../../../../schemas/company-schema.json", __FILE__), @valid_params.to_json, anything)
396
+ ModuleThatIncludesRegisterMethods.validate_datum(@valid_params)
397
+ end
398
+
399
+ context "and datum is valid" do
400
+ it "should return empty array" do
401
+ ModuleThatIncludesRegisterMethods.validate_datum(@valid_params).should == []
402
+ end
403
+ end
404
+
405
+ context "and datum is not valid" do
406
+ it "should return errors" do
407
+ result = ModuleThatIncludesRegisterMethods.validate_datum({:name => 'Foo Inc', :jurisdiction_code => 'ie'})
408
+ result.should be_kind_of Array
409
+ result.size.should == 1
410
+ result.first[:failed_attribute].should == "Required"
411
+ result.first[:message].should match 'company_number'
412
+ end
413
+ end
414
+ end
415
+
416
+ describe "save_entity" do
417
+ before do
418
+ @params = {:name => 'Foo Inc', :custom_uid => '12345', :data => {:foo => 'bar'}}
419
+ end
420
+
421
+ it "should validate entity data" do
422
+ ModuleThatIncludesRegisterMethods.should_receive(:validate_datum).with(@params.except(:data)).and_return([])
423
+ ModuleThatIncludesRegisterMethods.save_entity(@params)
424
+ end
425
+
426
+ context "and entity_data is valid (excluding :data)" do
427
+ before do
428
+ ModuleThatIncludesRegisterMethods.stub(:validate_datum).and_return([])
429
+ end
430
+
431
+ it "should prepare and save data" do
432
+ ModuleThatIncludesRegisterMethods.should_receive(:prepare_and_save_data).with(@params)
433
+ ModuleThatIncludesRegisterMethods.save_entity(@params)
434
+ end
435
+
436
+ it "should return true" do
437
+ ModuleThatIncludesRegisterMethods.save_entity(@params).should be_true
438
+ end
439
+ end
440
+
441
+ context "and entity_data is not valid" do
442
+ before do
443
+ ModuleThatIncludesRegisterMethods.stub(:validate_datum).and_return([{:message=>'Not valid'}])
444
+ end
445
+
446
+ it "should not prepare and save data" do
447
+ ModuleThatIncludesRegisterMethods.should_not_receive(:prepare_and_save_data)
448
+ ModuleThatIncludesRegisterMethods.save_entity(@params)
449
+ end
450
+
451
+ it "should not return true" do
452
+ ModuleThatIncludesRegisterMethods.save_entity(@params).should_not be_true
453
+ end
454
+ end
455
+ end
456
+
457
+ describe "save_entity!" do
458
+ before do
459
+ @params = {:name => 'Foo Inc', :custom_uid => '12345', :data => {:foo => 'bar'}}
460
+ end
461
+
462
+ it "should validate entity data (excluding :data)" do
463
+ ModuleThatIncludesRegisterMethods.should_receive(:validate_datum).with(@params.except(:data)).and_return([])
464
+ ModuleThatIncludesRegisterMethods.save_entity!(@params)
465
+ end
466
+
467
+ context "and entity_data is valid" do
468
+ before do
469
+ ModuleThatIncludesRegisterMethods.stub(:validate_datum).and_return([])
470
+ end
471
+
472
+ it "should prepare and save data" do
473
+ ModuleThatIncludesRegisterMethods.should_receive(:prepare_and_save_data).with(@params)
474
+ ModuleThatIncludesRegisterMethods.save_entity!(@params)
475
+ end
476
+
477
+ it "should return true" do
478
+ ModuleThatIncludesRegisterMethods.save_entity!(@params).should be_true
479
+ end
480
+ end
481
+
482
+ context "and entity_data is not valid" do
483
+ before do
484
+ ModuleThatIncludesRegisterMethods.stub(:validate_datum).and_return([{:message=>'Not valid'}])
485
+ end
486
+
487
+ it "should not prepare and save data" do
488
+ ModuleThatIncludesRegisterMethods.should_not_receive(:prepare_and_save_data)
489
+ lambda {ModuleThatIncludesRegisterMethods.save_entity!(@params)}
490
+ end
491
+
492
+ it "should raise exception" do
493
+ lambda {ModuleThatIncludesRegisterMethods.save_entity!(@params)}.should raise_error(OpencBot::RecordInvalid)
494
+ end
495
+ end
496
+ end
497
+
498
+ describe '#post_process' do
499
+ before do
500
+ @unprocessed_data = { :name => 'Foo Corp',
501
+ :company_number => '12345',
502
+ :serialised_field_1 => "[\"foo\",\"bar\"]",
503
+ :serialised_field_2 => "[{\"position\":\"gestor\",\"name\":\"JOSE MANUEL REYES R.\",\"other_attributes\":{\"foo\":\"bar\"}}]",
504
+ :serialised_field_3 => "{\"foo\":\"bar\"}",
505
+ :serialised_field_4 => "[]",
506
+ :serialised_field_5 => "{}",
507
+ :serialised_field_6 => nil,
508
+ }
509
+ end
510
+
511
+ context 'in general' do
512
+ before do
513
+ @processed_data = ModuleThatIncludesRegisterMethods.post_process(@unprocessed_data)
514
+ end
515
+
516
+ it 'should include non-serialised fields' do
517
+ @processed_data[:name].should == @unprocessed_data[:name]
518
+ @processed_data[:company_number].should == @unprocessed_data[:company_number]
519
+ end
520
+
521
+ it 'should deserialize fields' do
522
+ @processed_data[:serialised_field_1].should == ['foo','bar']
523
+ @processed_data[:serialised_field_3].should == {'foo' => 'bar'}
524
+ @processed_data[:serialised_field_4].should == []
525
+ @processed_data[:serialised_field_5].should == {}
526
+ end
527
+
528
+ it 'should deserialize nested fields correctly' do
529
+ @processed_data[:serialised_field_2].first[:position].should == "gestor"
530
+ @processed_data[:serialised_field_2].first[:other_attributes][:foo].should == "bar"
531
+ end
532
+
533
+ it 'should not do anything with null value' do
534
+ @processed_data[:serialised_field_6].should be_nil
535
+ @processed_data.has_key?(:serialised_field_6).should be_true
536
+ end
537
+ end
538
+
539
+ context 'with `skip_nulls` argument as true' do
540
+ before do
541
+ @processed_data = ModuleThatIncludesRegisterMethods.post_process(@unprocessed_data, true)
542
+ end
543
+
544
+ it 'should remove value from result' do
545
+ @processed_data.has_key?(:serialised_field_6).should be_false
546
+ end
547
+ end
548
+
549
+
550
+ context "and there is generic :data field" do
551
+ it "should not include it" do
552
+ ModuleThatIncludesRegisterMethods.post_process(@unprocessed_data.merge(:data => 'something else'))[:data].should be_nil
553
+ ModuleThatIncludesRegisterMethods.post_process(@unprocessed_data.merge(:data => "{\"bar\":\"baz\"}"))[:data].should be_nil
554
+ end
555
+ end
556
+ end
557
+
558
+ end