ncs_mdes_warehouse 0.0.2 → 0.1.0

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 (34) hide show
  1. data/CHANGELOG.md +16 -0
  2. data/generated_models/ncs_navigator/warehouse/models/two_point_zero/env_equipment_prob_log.rb +1 -1
  3. data/generated_models/ncs_navigator/warehouse/models/two_point_zero/incident.rb +6 -6
  4. data/generated_models/ncs_navigator/warehouse/models/two_point_zero/participant_rvis.rb +1 -1
  5. data/generated_models/ncs_navigator/warehouse/models/two_point_zero/sample_shipping.rb +1 -1
  6. data/lib/ncs_navigator/warehouse.rb +4 -0
  7. data/lib/ncs_navigator/warehouse/cli.rb +31 -1
  8. data/lib/ncs_navigator/warehouse/configuration.rb +49 -9
  9. data/lib/ncs_navigator/warehouse/database_initializer.rb +62 -4
  10. data/lib/ncs_navigator/warehouse/models.rb +3 -0
  11. data/lib/ncs_navigator/warehouse/postgresql.rb +7 -0
  12. data/lib/ncs_navigator/warehouse/postgresql/pgpass.rb +79 -0
  13. data/lib/ncs_navigator/warehouse/table_modeler/mdes_ext.rb +9 -0
  14. data/lib/ncs_navigator/warehouse/table_modeler/model_template.rb.erb +1 -1
  15. data/lib/ncs_navigator/warehouse/transform_load.rb +55 -0
  16. data/lib/ncs_navigator/warehouse/transform_status.rb +63 -0
  17. data/lib/ncs_navigator/warehouse/transformers.rb +0 -1
  18. data/lib/ncs_navigator/warehouse/transformers/database.rb +91 -85
  19. data/lib/ncs_navigator/warehouse/transformers/enum_transformer.rb +26 -8
  20. data/lib/ncs_navigator/warehouse/transformers/vdr_xml.rb +1 -1
  21. data/lib/ncs_navigator/warehouse/transformers/vdr_xml/reader.rb +11 -4
  22. data/lib/ncs_navigator/warehouse/version.rb +1 -1
  23. data/spec/bcdatabase/test_sqlite.yml +4 -0
  24. data/spec/ncs_navigator/warehouse/configuration_spec.rb +42 -0
  25. data/spec/ncs_navigator/warehouse/postgresql/pgpass_spec.rb +187 -0
  26. data/spec/ncs_navigator/warehouse/table_modeler_spec.rb +15 -1
  27. data/spec/ncs_navigator/warehouse/transform_load_spec.rb +152 -0
  28. data/spec/ncs_navigator/warehouse/transformers/database_spec.rb +24 -28
  29. data/spec/ncs_navigator/warehouse/transformers/enum_transformer_spec.rb +16 -10
  30. data/spec/ncs_navigator/warehouse/transformers/vdr_xml/made_up_vdr_xml.xml +4 -4
  31. data/spec/ncs_navigator/warehouse/transformers/vdr_xml/reader_spec.rb +8 -3
  32. data/spec/spec_helper.rb +1 -1
  33. metadata +44 -37
  34. data/lib/ncs_navigator/warehouse/transformers/transform_status.rb +0 -23
@@ -9,7 +9,7 @@ module NcsNavigator::Warehouse::Transformers
9
9
  # @return [#transform] a transformer that loads the MDES data in
10
10
  # the specified VDR XML file.
11
11
  def from_file(config, filename) # <- TODO better solution
12
- EnumTransformer.new(Reader.new(config, filename))
12
+ EnumTransformer.new(config, Reader.new(config, filename))
13
13
  end
14
14
 
15
15
  ##
@@ -46,8 +46,9 @@ class NcsNavigator::Warehouse::Transformers::VdrXml
46
46
  @start = Time.now
47
47
 
48
48
  Nokogiri::XML::Reader(@io).each do |node|
49
- # 1 is an open element, 15 is a close
50
- next unless [1, 15].include?(node.node_type)
49
+ element_types = [:TYPE_ELEMENT, :TYPE_END_ELEMENT].
50
+ collect { |c| Nokogiri::XML::Reader.const_get(c) }
51
+ next unless element_types.include?(node.node_type)
51
52
  encounter_node(node, node.node_type == 1, &block)
52
53
  end
53
54
 
@@ -77,8 +78,14 @@ class NcsNavigator::Warehouse::Transformers::VdrXml
77
78
  # node is the start tag of a table variable
78
79
  var = node.local_name.to_sym
79
80
  val = node.inner_xml.strip
80
- node.read # skip contents (read as 'var' above)
81
- node.read # skip close tag
81
+
82
+ unless node.self_closing?
83
+ # Skip to closing tag
84
+ n = node.read
85
+ until n.node_type == Nokogiri::XML::Reader::TYPE_END_ELEMENT
86
+ n = node.read
87
+ end
88
+ end
82
89
 
83
90
  unless should_filter_out(@current_model_class, var, val)
84
91
  @current_parameter_values[var] = val
@@ -1,5 +1,5 @@
1
1
  module NcsNavigator
2
2
  module Warehouse
3
- VERSION = '0.0.2'
3
+ VERSION = '0.1.0'
4
4
  end
5
5
  end
@@ -3,3 +3,7 @@ defaults:
3
3
  datamapper_adapter: sqlite
4
4
  people_pro:
5
5
  database: people_pro.sqlite3
6
+ mdes_warehouse_reporting:
7
+ database: wh_reporting.sqlite3
8
+ mdes_warehouse_working:
9
+ database: wh_working.sqlite3
@@ -328,6 +328,48 @@ module NcsNavigator::Warehouse
328
328
  end
329
329
  end
330
330
 
331
+ describe '#pg_bin_path' do
332
+ it 'defaults to nil' do
333
+ config.pg_bin_path.should be_nil
334
+ end
335
+
336
+ describe 'when set' do
337
+ before do
338
+ config.pg_bin_path = '/Library/PostgreSQL/9.0/bin'
339
+ end
340
+
341
+ it 'is retrievable' do
342
+ config.pg_bin_path.to_s.should == '/Library/PostgreSQL/9.0/bin'
343
+ end
344
+
345
+ it 'becomes a Pathname' do
346
+ config.pg_bin_path.should be_a Pathname
347
+ end
348
+ end
349
+ end
350
+
351
+ describe '#pg_bin' do
352
+ describe 'with no path' do
353
+ before do
354
+ config.pg_bin_path = nil
355
+ end
356
+
357
+ it 'prepends nothing' do
358
+ config.pg_bin('pg_dumpall').to_s.should == 'pg_dumpall'
359
+ end
360
+ end
361
+
362
+ describe 'with a path' do
363
+ before do
364
+ config.pg_bin_path = '/home/me/bin'
365
+ end
366
+
367
+ it 'prepends the path' do
368
+ config.pg_bin('pg_dumpall').to_s.should == '/home/me/bin/pg_dumpall'
369
+ end
370
+ end
371
+ end
372
+
331
373
  describe '.from_file' do
332
374
  let(:filename) { tmpdir + 'test.rb' }
333
375
  subject { Configuration.from_file(filename) }
@@ -0,0 +1,187 @@
1
+ require File.expand_path('../../../../spec_helper', __FILE__)
2
+
3
+ module NcsNavigator::Warehouse::PostgreSQL
4
+ describe Pgpass do
5
+ let(:home) { tmpdir('home') }
6
+ let(:file) { home + '.pgpass' }
7
+
8
+ before do
9
+ @original_home, ENV['HOME'] = ENV['HOME'], home
10
+ end
11
+
12
+ after do
13
+ ENV['HOME'] = @original_home
14
+ end
15
+
16
+ describe '#file' do
17
+ it 'defaults to $HOME/.pgpass' do
18
+ Pgpass.new.file.should == file
19
+ end
20
+ end
21
+
22
+ describe '.line' do
23
+ subject { Pgpass.line entry }
24
+ let(:entry) {
25
+ {
26
+ 'username' => 'warehouse',
27
+ 'password' => 'volt',
28
+ 'database' => 'ignored'
29
+ }
30
+ }
31
+
32
+ it 'includes defaults for host and port if not set' do
33
+ subject.should == %w(localhost 5432 * warehouse volt)
34
+ end
35
+
36
+ it 'uses an explicit host if available' do
37
+ entry['host'] = 'ncs_db'
38
+ subject.should == %w(ncs_db 5432 * warehouse volt)
39
+ end
40
+
41
+ it 'uses an explicit port if available' do
42
+ entry['port'] = 5439
43
+ subject.should == %w(localhost 5439 * warehouse volt)
44
+ end
45
+
46
+ it 'fails without a username' do
47
+ entry.delete 'username'
48
+ lambda { subject }.should raise_error(/No username in configuration/)
49
+ end
50
+
51
+ it 'fails without a password' do
52
+ entry.delete 'password'
53
+ lambda { subject }.should raise_error(/No password in configuration/)
54
+ end
55
+ end
56
+
57
+ describe '#update' do
58
+ subject { Pgpass.new }
59
+ let(:entry) {
60
+ {
61
+ 'username' => 'mw',
62
+ 'password' => 'fishes',
63
+ 'host' => 'ncsdb',
64
+ 'port' => 5500,
65
+ 'database' => 'mw_r'
66
+ }
67
+ }
68
+ let(:lines) {
69
+ file.readlines.collect { |l| l.chomp.split ':' }
70
+ }
71
+ let(:expected_line) { "ncsdb:5500:*:mw:fishes\n" }
72
+
73
+ describe 'when the file exists' do
74
+ describe 'and the same line exists' do
75
+ before do
76
+ file.open('w') do |f|
77
+ f.puts 'somewhere:5400:*:aguy:five'
78
+ f.puts 'ncsdb:5500:*:mw:fishes'
79
+ f.puts 'somewhere:5400:*:someoneelse:yet'
80
+ end
81
+
82
+ subject.update(entry)
83
+ end
84
+
85
+ it 'does nothing' do
86
+ lines.collect { |l| l[3] }.should == %w(aguy mw someoneelse)
87
+ end
88
+ end
89
+
90
+ describe 'and a similar line with a different password exists' do
91
+ before do
92
+ file.open('w') do |f|
93
+ f.puts 'somewhere:5400:*:aguy:five'
94
+ f.puts 'ncsdb:5500:*:mw:shark'
95
+ f.puts 'ncsdb:5500:*:someoneelse:fred'
96
+ f.puts 'somewhere:5400:*:someoneelse:yet'
97
+ end
98
+
99
+ subject.update(entry)
100
+ end
101
+
102
+ it 'updates the password' do
103
+ file.readlines[1].should == expected_line
104
+ end
105
+
106
+ it 'leaves other entries alone' do
107
+ lines.collect { |l| l[4] }.should == %w(five fishes fred yet)
108
+ end
109
+ end
110
+
111
+ describe 'and no similar entry exists' do
112
+ before do
113
+ file.open('w') do |f|
114
+ f.puts 'somewhere:5400:*:aguy:five'
115
+ f.puts 'ncsdb:5500:*:someoneelse:fred'
116
+ f.puts 'somewhere:5400:*:someoneelse:yet'
117
+ end
118
+
119
+ subject.update(entry)
120
+ end
121
+
122
+ it 'adds the entry' do
123
+ file.readlines.last.should == expected_line
124
+ end
125
+
126
+ it 'leaves the other entries alone' do
127
+ lines.collect { |l| l[0] }.should == %w(somewhere ncsdb somewhere ncsdb)
128
+ end
129
+ end
130
+ end
131
+
132
+ describe 'when the file does not exist' do
133
+ before do
134
+ file.exist?.should be_false
135
+
136
+ subject.update(entry)
137
+ end
138
+
139
+ it 'creates the file' do
140
+ file.exist?.should be_true
141
+ end
142
+
143
+ it 'sets the permissions to user-rw only' do
144
+ `ls -al '#{file}'`.should =~ /^-rw------/
145
+ end
146
+
147
+ it 'adds the appropriate entry' do
148
+ file.readlines.should == [expected_line]
149
+ end
150
+ end
151
+
152
+ describe 'when the directory does not exist' do
153
+ before do
154
+ home.rmdir
155
+ end
156
+
157
+ it 'fails' do
158
+ lambda { subject.update(entry) }.should(
159
+ raise_error %r{Cannot create #{home}/.pgpass})
160
+ end
161
+ end
162
+
163
+ describe 'when the directory is not writable' do
164
+ before do
165
+ home.chmod(0500)
166
+ end
167
+
168
+ it 'fails' do
169
+ lambda { subject.update(entry) }.should(
170
+ raise_error %r{Cannot create #{home}/.pgpass})
171
+ end
172
+ end
173
+
174
+ describe 'when the file exists but is not writable' do
175
+ before do
176
+ file.open('w') { |f| }
177
+ file.chmod(0500)
178
+ end
179
+
180
+ it 'fails' do
181
+ lambda { subject.update(entry) }.should(
182
+ raise_error %r{Cannot update #{home}/.pgpass})
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
@@ -449,8 +449,10 @@ end
449
449
  end
450
450
  end
451
451
 
452
+ let(:child_variable_name) { 'some_tree_id' }
453
+
452
454
  before do
453
- table.variables << NcsNavigator::Mdes::Variable.new('some_tree_id').tap do |v|
455
+ table.variables << NcsNavigator::Mdes::Variable.new(child_variable_name).tap do |v|
454
456
  v.table_reference = parent_table
455
457
  v.type = NcsNavigator::Mdes::VariableType.new('foreignKeyRequiredType').tap do |vt|
456
458
  vt.base_type = :string
@@ -502,6 +504,18 @@ end
502
504
 
503
505
  instance.should_not be_valid
504
506
  end
507
+
508
+ describe 'when the child key does not have the "_id" suffix' do
509
+ let(:child_variable_name) { 'some_tree' }
510
+
511
+ it 'has an object reference accessor' do
512
+ model_class.instance_methods.collect(&:to_s).should include('some_tree_record')
513
+ end
514
+
515
+ it 'does not have a suffixed ID attribute' do
516
+ model_class.instance_methods.collect(&:to_s).should_not include('some_tree_id')
517
+ end
518
+ end
505
519
  end
506
520
  end
507
521
 
@@ -0,0 +1,152 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ module NcsNavigator::Warehouse
4
+ describe TransformLoad, :modifies_warehouse_state do
5
+ let(:config) { base_config }
6
+ let(:loader) { TransformLoad.new(config) }
7
+
8
+ def base_config
9
+ Configuration.new.tap do |c|
10
+ c.bcdatabase_group = :test_sqlite
11
+ c.log_file = tmpdir + "#{File.basename(__FILE__)}.log"
12
+ c.output_level = :quiet
13
+ end
14
+ end
15
+
16
+ before(:all) do
17
+ # Not config due to RSpec #500
18
+ DatabaseInitializer.new(base_config).tap do |dbi|
19
+ dbi.set_up_repository(:both)
20
+ end
21
+ TransformError.auto_migrate!(:mdes_warehouse_working)
22
+ TransformStatus.auto_migrate!(:mdes_warehouse_working)
23
+ end
24
+
25
+ describe '#run' do
26
+ it 'runs the transformers in the order specified' do
27
+ order = []
28
+ config.add_transformer(BlockTransformer.new { |s| order << 'B' })
29
+ config.add_transformer(BlockTransformer.new { |s| order << 'T' })
30
+ config.add_transformer(BlockTransformer.new { |s| order << 'w' })
31
+
32
+ loader.run
33
+
34
+ order.should == %w(B T w)
35
+ end
36
+
37
+ it 'passes a separate instance of TransformStatus to each transformer' do
38
+ statuses = []
39
+ config.add_transformer(BlockTransformer.new { |s| statuses << s })
40
+ config.add_transformer(BlockTransformer.new { |s| statuses << s })
41
+
42
+ loader.run
43
+
44
+ statuses.first.should_not be statuses.last
45
+ end
46
+
47
+ describe 'a created status' do
48
+ let(:statuses) { [] }
49
+ let(:status) { statuses.first }
50
+ let(:transformer) { BlockTransformer.new { |s| statuses << s } }
51
+
52
+ before do
53
+ config.add_transformer(transformer)
54
+ end
55
+
56
+ it 'uses the name provided by the transformer, if any' do
57
+ def transformer.name; 'provided'; end
58
+
59
+ loader.run
60
+
61
+ status.name.should == 'provided'
62
+ end
63
+
64
+ it 'uses the class name of the transformer otherwise' do
65
+ loader.run
66
+
67
+ status.name.should == 'BlockTransformer'
68
+ end
69
+
70
+ it 'sets the start and end times' do
71
+ Time.should_receive(:now).and_return(Time.iso8601('2001-01-12T08:00:00'))
72
+ Time.stub!(:now).and_return(Time.iso8601('2001-01-12T09:06:30'))
73
+
74
+ loader.run
75
+
76
+ status.start_time.hour.should == 8
77
+ status.end_time.hour.should == 9
78
+ end
79
+
80
+ it 'sets the position' do
81
+ loader.run
82
+ status.position.should == 0
83
+ end
84
+ end
85
+
86
+ it 'returns true if none of the transformers report an error' do
87
+ config.add_transformer(BlockTransformer.new { |s| })
88
+ loader.run.should be_true
89
+ end
90
+
91
+ describe 'with a reported error' do
92
+ let(:runs) { [] }
93
+
94
+ before do
95
+ config.add_transformer(BlockTransformer.new { |s| runs << 'A' })
96
+ config.add_transformer(BlockTransformer.new { |s|
97
+ runs << 'B'
98
+ s.unsuccessful_record(nil, 'fail')
99
+ })
100
+ config.add_transformer(BlockTransformer.new { |s| runs << 'C3' })
101
+ @result = loader.run
102
+ end
103
+
104
+ it 'still runs all the transformers' do
105
+ runs.should == %w(A B C3)
106
+ end
107
+
108
+ it 'returns false' do
109
+ @result.should == false
110
+ end
111
+ end
112
+
113
+ describe 'with a failure' do
114
+ let(:runs) { [] }
115
+
116
+ before do
117
+ config.add_transformer(BlockTransformer.new { |s| runs << 'A' })
118
+ config.add_transformer(BlockTransformer.new { |s|
119
+ runs << 'B'
120
+ fail 'No thanks.'
121
+ })
122
+ config.add_transformer(BlockTransformer.new { |s| runs << 'C3' })
123
+ @result = loader.run
124
+ end
125
+
126
+ it 'still runs all the transformers' do
127
+ runs.should == %w(A B C3)
128
+ end
129
+
130
+ it 'returns false' do
131
+ @result.should == false
132
+ end
133
+ end
134
+
135
+ describe 'sending e-mail' do
136
+ it 'sends on success'
137
+
138
+ it 'sends on failure'
139
+ end
140
+ end
141
+
142
+ class ::BlockTransformer
143
+ def initialize(&block)
144
+ @block = block
145
+ end
146
+
147
+ def transform(status)
148
+ @block.call(status)
149
+ end
150
+ end
151
+ end
152
+ end