wicoris-postman 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ require 'spec_helper'
2
+
3
+ module Wicoris::Postman
4
+ describe Copier do
5
+ let(:job) { double('job') }
6
+ let(:copier) { Copier.new(job, {}) }
7
+
8
+ describe '#run' do
9
+
10
+ before do
11
+ job.stub(:letter).and_return('/tmp/foo.pdf')
12
+ copier.stub(:destination).and_return('/export')
13
+ end
14
+
15
+ context 'without noop' do
16
+ let(:copier) { Copier.new(job, {}) }
17
+
18
+ it 'copies the letter to destination' do
19
+ copier.should_receive(:source).and_return('/chunky.pdf')
20
+ copier.should_receive(:destination).and_return('/bacon.pdf')
21
+ FileUtils.should_receive(:cp).
22
+ with('/chunky.pdf', '/bacon.pdf', :noop => false)
23
+ copier.run
24
+ end
25
+ end
26
+
27
+ context 'with noop' do
28
+ let(:copier) { Copier.new(job, :noop => true) }
29
+
30
+ it 'does not copy the letter to destination' do
31
+ FileUtils.should_receive(:cp).
32
+ with('/tmp/foo.pdf', '/export', :noop => true)
33
+ copier.run
34
+ end
35
+ end
36
+ end
37
+
38
+ describe '#source' do
39
+ it 'returns the letter' do
40
+ job.should_receive(:letter).and_return('/chunky/bacon.pdf')
41
+ expect(copier.send(:source)).to eq '/chunky/bacon.pdf'
42
+ end
43
+ end
44
+
45
+ describe '#fingerprint' do
46
+ it 'returns the first 4 bytes of the source hexdigest' do
47
+ copier.should_receive(:source).and_return('/chunky/bacon.pdf')
48
+ File.should_receive(:read).with('/chunky/bacon.pdf').
49
+ and_return('content')
50
+ Digest::MD5.should_receive(:hexdigest).with('content').
51
+ and_return('cafebabedeadbeef')
52
+ expect(copier.send(:fingerprint)).to eq 'cafe'
53
+ end
54
+ end
55
+
56
+ describe '#destination' do
57
+ it 'returns full path from output filename' do
58
+ copier.should_receive(:outdir).and_return('/chunky')
59
+ copier.should_receive(:filename).and_return('bacon.pdf')
60
+ expect(copier.send(:destination)).to eq '/chunky/bacon.pdf'
61
+ end
62
+ end
63
+
64
+ describe '#outdir' do
65
+ let(:copier) { Copier.new(job, {:outdir => '/chunky'}) }
66
+
67
+ before do
68
+ [:exists?, :directory?, :writable?].each do |method|
69
+ File.stub(method).and_return(true)
70
+ end
71
+ end
72
+
73
+ it 'returns the output dir' do
74
+ expect(copier.send(:outdir)).to eq '/chunky'
75
+ end
76
+
77
+ it 'raises when directory does not exist' do
78
+ File.should_receive(:exists?).and_return(false)
79
+ expect { copier.send(:outdir) }.to raise_error(
80
+ %r{output directory does not exist: /chunky}i)
81
+ end
82
+
83
+ it 'raises when not a directory' do
84
+ File.should_receive(:directory?).and_return(false)
85
+ expect { copier.send(:outdir) }.to raise_error(
86
+ %r{output directory is no directory: '/chunky'}i)
87
+ end
88
+
89
+ it 'raises when not writable' do
90
+ File.should_receive(:writable?).and_return(false)
91
+ expect { copier.send(:outdir) }.to raise_error(
92
+ %r{output directory not writable: '/chunky'}i)
93
+ end
94
+
95
+ context 'without outdir' do
96
+ let(:copier) { Copier.new(job, {:outdir => nil}) }
97
+
98
+ it 'raises an error' do
99
+ expect { copier.send(:outdir) }.to raise_error(
100
+ %r{No output directory given}i)
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '#filename' do
106
+ it 'returns a filename based on its components and suffix' do
107
+ copier.stub(:filename_components).
108
+ and_return %w(chunky bacon 42)
109
+ copier.stub(:suffix).and_return('.foo')
110
+ expect(copier.send(:filename)).to eq 'chunky_bacon_42.foo'
111
+ end
112
+
113
+ it 'raises on missing filename component' do
114
+ copier.stub(:filename_components).
115
+ and_return ['chunky', nil, 'bacon']
116
+ expect{ copier.send(:filename) }.to raise_error(
117
+ /missing patient demographics/i)
118
+ end
119
+
120
+ it 'raises on empty filename component' do
121
+ copier.stub(:filename_components).
122
+ and_return ['chunky', '', 'bacon']
123
+ expect{ copier.send(:filename) }.to raise_error(
124
+ /missing patient demographics/i)
125
+ end
126
+ end
127
+
128
+ describe '#filename_components' do
129
+ it 'orders the components by most relevant patient demographics' do
130
+ job.should_receive(:patient_first_name).and_return('Chuck')
131
+ job.should_receive(:patient_last_name).and_return('Norris')
132
+ job.should_receive(:patient_date_of_birth).and_return('1940-03-10')
133
+ copier.should_receive(:fingerprint).and_return('abcd')
134
+ expect(copier.send(:filename_components)).to eq(
135
+ %w(Norris Chuck 1940-03-10 abcd))
136
+ end
137
+ end
138
+
139
+ describe '#suffix' do
140
+ it 'returns the filename suffix' do
141
+ expect(copier.send(:suffix)).to eq '.pdf'
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ module Wicoris::Postman
4
+ describe FaxMachine do
5
+ let(:job) { double('job') }
6
+ let(:fax) { FaxMachine.new(job) }
7
+
8
+ before do
9
+ fax.stub(:system)
10
+ end
11
+
12
+ describe '#run' do
13
+ let(:logger) { double('logger') }
14
+
15
+ it 'faxes the document' do
16
+ fax.stub(:command).and_return('chunky bacon')
17
+ fax.should_receive(:system).with('chunky bacon')
18
+ fax.run
19
+ end
20
+
21
+ context 'with noop' do
22
+ let(:fax) { FaxMachine.new(job, :noop => true) }
23
+
24
+ it 'does not fax the job' do
25
+ fax.stub(:command).and_return('chunky bacon')
26
+ fax.should_not_receive(:system)
27
+ fax.run
28
+ end
29
+ end
30
+ end
31
+
32
+ describe '#command' do
33
+ it 'should return the command-line for sending a fax' do
34
+ fax.stub(:validated_phone).and_return('042')
35
+ job.stub(:letter).and_return('/tmp/foo.pdf')
36
+ expect(fax.send(:command)).to eq(
37
+ "lp -d Fax -o phone=042 '/tmp/foo.pdf'")
38
+ end
39
+ end
40
+
41
+ describe '#phone' do
42
+ it 'adds the dial-out prefix' do
43
+ job.stub(:phone).and_return('0123456789')
44
+ expect(fax.validated_phone).to eq '00123456789'
45
+ end
46
+
47
+ it 'removes all whitespaces and dashes from the number' do
48
+ job.stub(:phone).and_return("\t012-345 6789 \n")
49
+ expect(fax.validated_phone).to eq '00123456789'
50
+ end
51
+
52
+ it 'raises when phone is missing' do
53
+ job.stub(:phone).and_return(nil)
54
+ expect{ fax.validated_phone }.to raise_error ArgumentError
55
+ end
56
+
57
+ it 'raises when one leading zero is missing' do
58
+ job.stub(:phone).and_return('1234567890')
59
+ expect{ fax.validated_phone }.to raise_error ArgumentError
60
+ end
61
+
62
+ it 'raises when begins with more then one zero' do
63
+ job.stub(:phone).and_return('00123456789')
64
+ expect{ fax.validated_phone }.to raise_error ArgumentError
65
+ end
66
+
67
+ it 'raises when shorter then 9 digits' do
68
+ job.stub(:phone).and_return('01234567')
69
+ expect{ fax.validated_phone }.to raise_error ArgumentError
70
+ end
71
+
72
+ it 'raises when number contains invalid chars' do
73
+ job.stub(:phone).and_return('01234hello')
74
+ expect{ fax.validated_phone }.to raise_error ArgumentError
75
+ end
76
+
77
+ it 'includes the phone number in the exception' do
78
+ job.stub(:phone).and_return('42')
79
+ expect{ fax.validated_phone }.to raise_error /42/
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ module Wicoris::Postman
4
+ describe Job do
5
+ let(:job) { Job.new('example.json') }
6
+
7
+ before do
8
+ FileUtils.stub(:rm)
9
+ end
10
+
11
+ describe '#json' do
12
+ it 'parses and returns the JSON file' do
13
+ job.should_receive(:json_file_content).and_return('content')
14
+ JSON.should_receive(:parse).with('content').once.and_return('json')
15
+ 2.times { expect(job.send(:json)).to eq 'json' }
16
+ end
17
+ end
18
+
19
+ describe '#json_file_content' do
20
+ it 'returns the file content' do
21
+ File.should_receive(:read).with('example.json').and_return('content')
22
+ expect(job.send(:json_file_content)).to eq 'content'
23
+ end
24
+
25
+ it 'converts Mac Roman encoding to UTF-8' do
26
+ File.stub(:read).and_return("Schl\237ter")
27
+ expect(job.send(:json_file_content)).to eq 'Schlüter'
28
+ end
29
+ end
30
+
31
+ describe '#letter' do
32
+ before do
33
+ File.stub(:exists?).and_return(true)
34
+ end
35
+
36
+ it 'returns the letter path' do
37
+ job.stub(:json).and_return('file' => '/tmp/foo.pdf')
38
+ expect(job.letter).to eq '/tmp/foo.pdf'
39
+ end
40
+
41
+ it 'raises when letter is missing' do
42
+ File.should_receive(:exists?).and_return(false)
43
+ job.stub(:file).and_return('chunky')
44
+ expect {
45
+ job.send(:letter)
46
+ }.to raise_error /letter does not exist.*chunky/i
47
+ end
48
+ end
49
+
50
+ describe '#method_missing' do
51
+ context 'with existing JSON attribute' do
52
+ it 'returns it' do
53
+ job.stub(:json).and_return('chunky' => 'bacon')
54
+ expect(job.chunky).to eq 'bacon'
55
+ end
56
+ end
57
+
58
+ context 'without matching JSON attribute' do
59
+ it 'returns it' do
60
+ job.stub(:json).and_return({})
61
+ expect {
62
+ job.chunky
63
+ }.to raise_error /undefined method/i
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#process' do
69
+ context 'when fax' do
70
+ it 'faxes the letter' do
71
+ job.should_receive(:json).and_return('type' => 'fax')
72
+ fax_machine = double('fax_machine')
73
+ FaxMachine.should_receive(:new).with(job, {}).and_return(fax_machine)
74
+ fax_machine.should_receive(:run).ordered
75
+ job.process
76
+ end
77
+ end
78
+
79
+ context 'when copy' do
80
+ it 'copies the letter' do
81
+ job.should_receive(:json).and_return('type' => 'copy')
82
+ copier = double('copier')
83
+ Copier.should_receive(:new).with(job, {}).and_return(copier)
84
+ copier.should_receive(:run).ordered
85
+ job.process
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#patient_first_name' do
91
+ it 'returns the patients first name' do
92
+ job.stub(:json).and_return('patient_first_name' => 'Chuck')
93
+ expect(job.patient_first_name).to eq 'Chuck'
94
+ end
95
+ end
96
+
97
+ describe '#patient_last_name' do
98
+ it 'returns the patients last name' do
99
+ job.stub(:json).and_return('patient_last_name' => 'Norris')
100
+ expect(job.patient_last_name).to eq 'Norris'
101
+ end
102
+ end
103
+
104
+ describe '#patient_date_of_birth' do
105
+ it 'returns the patients date of birth' do
106
+ job.stub(:json).and_return('patient_date_of_birth' => '1940-03-10')
107
+ expect(job.patient_date_of_birth).to eq '1940-03-10'
108
+ end
109
+ end
110
+
111
+ describe '#clear!' do
112
+ before do
113
+ job.stub(:json).and_return('')
114
+ end
115
+
116
+ it 'deletes the json file' do
117
+ FileUtils.should_receive(:rm).with('example.json', :noop => false)
118
+ job.clear!
119
+ end
120
+
121
+ context 'with noop' do
122
+ let(:job) { Job.new('example.json', :noop => true) }
123
+
124
+ it 'does not delete the json file' do
125
+ FileUtils.should_receive(:rm).with('example.json', :noop => true)
126
+ job.clear!
127
+ end
128
+ end
129
+
130
+ context 'without parsable JSON' do
131
+ let(:logger) { double('logger', :warn => true) }
132
+
133
+ before do
134
+ job.stub(:json).
135
+ and_return { raise JSON::ParserError, 'Shitty JSON' }
136
+ job.stub(:logger).and_return(logger)
137
+ end
138
+
139
+ it 'does not delete the JSON file' do
140
+ FileUtils.should_not_receive(:rm)
141
+ job.clear!
142
+ end
143
+
144
+ it 'logs a warning' do
145
+ logger.should_receive(:warn).with({
146
+ :message => 'Refused to delete non-JSON file.',
147
+ :json_file => 'example.json'
148
+ })
149
+ job.clear!
150
+ end
151
+ end
152
+ end
153
+
154
+ describe '#to_hash' do
155
+ let(:job) { Job.new('example.json') }
156
+
157
+ context 'with parsable JSON' do
158
+ before do
159
+ job.stub(:json).and_return({'chunky' => 'bacon'})
160
+ end
161
+
162
+ it 'includes all JSON attributes' do
163
+ expect(job.to_hash['chunky']).to eq 'bacon'
164
+ end
165
+
166
+ it 'includes the JSON filename' do
167
+ expect(job.to_hash['json_file']).to eq 'example.json'
168
+ end
169
+ end
170
+
171
+ context 'with unparsable JSON' do
172
+ before do
173
+ job.stub(:json).and_return { raise JSON::ParserError, 'Shitty JSON' }
174
+ end
175
+
176
+ it 'includes only the JSON filename' do
177
+ expect(job.to_hash).to eq({'json_file' => 'example.json'})
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module Wicoris::Postman
4
+ describe Logger do
5
+ let(:logger) { Logger.new }
6
+
7
+ describe '#info' do
8
+ it 'only accepts one argument' do
9
+ expect {
10
+ logger.info('hey', :explosion => true)
11
+ }.to raise_error
12
+ #}.to raise_error ArgumentError
13
+ end
14
+ end
15
+
16
+ describe '#error' do
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ module Wicoris::Postman
4
+ describe Postman do
5
+ let(:postman) { Postman.new }
6
+
7
+ describe '#run' do
8
+ let(:job) { double('job') }
9
+
10
+ it 'processes each job' do
11
+ postman.should_receive(:jobs).
12
+ and_return [job, job]
13
+ job.should_receive(:process).twice
14
+ job.should_receive(:clear!).twice
15
+ postman.run
16
+ end
17
+
18
+ it 'clears failed jobs too' do
19
+ postman.stub(:jobs).and_return [job]
20
+ job.stub(:process)
21
+ job.should_receive(:clear!)
22
+ postman.run
23
+ end
24
+
25
+ context 'when job raises an error' do
26
+ it 'rescues failed jobs' do
27
+ postman.stub(:jobs).and_return [job, job]
28
+ job.should_receive(:process).twice.and_return { raise 'BOOOM!' }
29
+ job.stub(:clear!)
30
+ postman.run
31
+ end
32
+
33
+ it 'clears failed jobs too' do
34
+ postman.stub(:jobs).and_return [job]
35
+ job.stub(:process).and_return { raise 'BOOOM!' }
36
+ job.should_receive(:clear!)
37
+ postman.run
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#jobs' do
43
+ let(:postman) { Postman.new(:chunky => 'bacon') }
44
+
45
+ it 'initializes jobs by json files' do
46
+ job = double('job')
47
+ postman.should_receive(:json_files).
48
+ and_return ['example.json', 'example.json']
49
+ Job.should_receive(:new).
50
+ with('example.json', {:chunky => 'bacon'}).twice.and_return(job)
51
+ expect(postman.send(:jobs)).to eq [job, job]
52
+ end
53
+ end
54
+
55
+ describe '#json_files' do
56
+ it 'returns a list of all json files within the jobdir' do
57
+ postman.should_receive(:jobdir).and_return('jobdir')
58
+ Dir.should_receive(:glob).with('jobdir/*.JSON', File::FNM_CASEFOLD).
59
+ and_return('some files')
60
+ expect(postman.send(:json_files)).to eq 'some files'
61
+ end
62
+ end
63
+
64
+ describe '#jobdir' do
65
+ let(:postman) { Postman.new(:jobdir => '/chunky') }
66
+
67
+ it 'returns the jobdir from config' do
68
+ expect(postman.send(:jobdir)).to eq '/chunky'
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wicoris/postman/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wicoris-postman"
8
+ spec.version = Wicoris::Postman::VERSION
9
+ spec.authors = ["Björn Albers"]
10
+ spec.email = ["bjoernalbers@googlemail.com"]
11
+ spec.description = %q{Deliver letters from WiCoRIS}
12
+ spec.summary = "#{spec.name}-#{spec.version}"
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "json_pure", "~> 1.8"
22
+ spec.add_dependency "cabin", "~> 0.6"
23
+ spec.add_dependency "mixlib-cli", "~> 1.4"
24
+ spec.add_dependency "mixlib-config", "~> 2.1"
25
+ spec.add_dependency "jlo", "~> 0.3"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.3"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "aruba", "~> 0.5"
30
+ spec.add_development_dependency "aruba-doubles", "~> 1.2"
31
+ end