carterdte_smtp_filter 0.0.3

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.
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1" ?>
2
+ <RESULTADO_ENVIO>
3
+ <IDENTIFICACION>
4
+ <RUTEMISOR>81137900-K</RUTEMISOR>
5
+ <RUTENVIA>11862736-9</RUTENVIA>
6
+ <TRACKID>1031250770</TRACKID>
7
+ <TMSTRECEPCION>09/05/2015 12:18:50</TMSTRECEPCION>
8
+ <ESTADO>EPR - Envio Procesado</ESTADO>
9
+ </IDENTIFICACION>
10
+ <ESTADISTICA>
11
+ <SUBTOTAL>
12
+ <TIPODOC>33</TIPODOC>
13
+ <INFORMADO>1</INFORMADO>
14
+ <ACEPTA>1</ACEPTA>
15
+ </SUBTOTAL>
16
+ </ESTADISTICA>
17
+ </RESULTADO_ENVIO>
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ class TestApiClient < Minitest::Test
4
+
5
+
6
+ def setup
7
+ CarterdteSmtpFilter::Config.parse("./test/fixtures/config.yml")
8
+ @api_host = CarterdteSmtpFilter::Config::api_host
9
+ @api_url = "http://#{@api_host}"
10
+ stub_request(:any, /#{@api_host}/).to_rack(FakeApi)
11
+ end
12
+
13
+ def test_push_should_return_false_if_message_is_not_json
14
+ response = CarterdteSmtpFilter::ApiClient.push "hola"
15
+ assert(!response, "Failure message.")
16
+ end
17
+
18
+ def test_check_fake_api_response
19
+ user = CarterdteSmtpFilter::Config::api_user.gsub(/@/,"%40")
20
+ response = RestClient.get "http://#{user}:#{CarterdteSmtpFilter::Config::api_password}@#{@api_host}/api/v1/"
21
+ assert_equal("{api_version: 1}", response)
22
+ end
23
+
24
+ def test_post_should_workout_unauthorized
25
+ response = CarterdteSmtpFilter::ApiClient.post({url: "#{@api_url}/api/v1/denied" })
26
+ assert(!response, "Failure message.")
27
+ end
28
+
29
+ def test_post_should_workout_application_error
30
+ response = CarterdteSmtpFilter::ApiClient.post({url: "#{@api_url}/api/v1/app_error" })
31
+ assert(!response, "Failure message.")
32
+ end
33
+
34
+ def test_post_should_return_json
35
+ hash = {dte_type: 33, msg_type: "envio"}
36
+ json = JSON.generate hash
37
+ response = CarterdteSmtpFilter::ApiClient.post({payload: json})
38
+ new_hash = JSON.parse response
39
+ assert_equal("123456", new_hash["id"])
40
+ assert_equal(hash[:dte_type], new_hash["dte_type"])
41
+ end
42
+
43
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class TestConfig < Minitest::Test
4
+
5
+ def test_should_raise_not_file_if_file_not_exists
6
+ assert_raises(Errno::ENOENT) { CarterdteSmtpFilter::Config.parse("/tmp/file") }
7
+ end
8
+
9
+ def test_should_return_config_values
10
+ CarterdteSmtpFilter::Config.parse("./test/fixtures/config.yml")
11
+ assert_equal("127.0.0.1", CarterdteSmtpFilter::Config::bind_address)
12
+ assert_equal("127.0.0.1", CarterdteSmtpFilter::Config::return_host)
13
+ assert_equal("30025", CarterdteSmtpFilter::Config::return_port)
14
+ assert_equal("pbruna@example.com", CarterdteSmtpFilter::Config::api_user)
15
+ assert_equal("123456", CarterdteSmtpFilter::Config::api_password)
16
+ assert_equal("api.dte.zboxapp.com", CarterdteSmtpFilter::Config::api_host)
17
+ assert_equal("./test/tmp/carterdte_smtp_filter.log", CarterdteSmtpFilter::Config::log_file)
18
+ end
19
+
20
+ end
data/test/test_dte.rb ADDED
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+ class TestDte < Minitest::Test
4
+
5
+ def setup
6
+ @resultado = File.open("./test/fixtures/acuse.xml", "rb")
7
+ @envio = File.open("./test/fixtures/envio_dte_33.xml", "rb")
8
+ @dte_resultado = CarterdteSmtpFilter::Dte.new @resultado
9
+ @dte_envio = CarterdteSmtpFilter::Dte.new @envio
10
+ end
11
+
12
+ def teardown
13
+
14
+ end
15
+
16
+ def test_should_only_parse_valid_dtes
17
+ file = File.open("./test/fixtures/invalid_dte.xml", "rb")
18
+ dte = CarterdteSmtpFilter::Dte.new file
19
+ assert(!dte.valid?, "Should be false")
20
+ assert(@dte_resultado.valid?, "Failure message.")
21
+ assert(@dte_envio.valid?, "Failure message.")
22
+ end
23
+
24
+ def test_root_should_return_the_root_element
25
+ assert_equal("Resultado", @dte_resultado.root_name)
26
+ assert_equal("SetDTE", @dte_envio.root_name)
27
+ end
28
+
29
+ def test_return_msg_type
30
+ assert_equal("respuesta", @dte_resultado.msg_type)
31
+ assert_equal("envio", @dte_envio.msg_type)
32
+ end
33
+
34
+ def test_return_setdte_id
35
+ assert_equal("SETDTE94528000X33X7597817X94141763", @dte_resultado.setdte_id)
36
+ assert_equal("SETDTE96529310X33X3152118X94141243", @dte_envio.setdte_id)
37
+ end
38
+
39
+ def test_rut_emisor
40
+ assert_equal("94528000-K", @dte_resultado.rut_emisor)
41
+ assert_equal("96529310-8", @dte_envio.rut_emisor)
42
+ end
43
+
44
+ def test_rut_receptor
45
+ assert_equal("81537600-5", @dte_resultado.rut_receptor)
46
+ assert_equal("81201000-K", @dte_envio.rut_receptor)
47
+ end
48
+
49
+ def test_dte_type
50
+ assert_equal("33", @dte_resultado.dte_type)
51
+ assert_equal("33", @dte_envio.dte_type)
52
+ end
53
+
54
+ def test_dte_fecha_emision
55
+ date_envio = Time.parse("2015-05-09T11:10:10").to_date
56
+ date_resultado = Time.parse("2015-05-09T12:30:11").to_date
57
+ assert_equal(date_resultado, @dte_resultado.fecha_emision)
58
+ assert_equal(date_envio, @dte_envio.fecha_emision)
59
+ end
60
+
61
+ def test_dte_fecha_recepcion
62
+ date_resultado = Time.parse("2015-05-09T12:30:11").to_date
63
+ assert_equal(date_resultado, @dte_resultado.fecha_recepcion)
64
+ assert_equal(nil, @dte_envio.fecha_recepcion)
65
+ end
66
+
67
+ def test_return_empty_json_if_no_valid
68
+ file = File.open("./test/fixtures/invalid_dte.xml", "rb")
69
+ dte = CarterdteSmtpFilter::Dte.new file
70
+ json = JSON.parse dte.to_json
71
+ assert_equal({}, json)
72
+ end
73
+
74
+ def test_return_json_object
75
+ json = JSON.parse @dte_resultado.to_json
76
+ assert_equal("81537600-5", json["rut_receptor"])
77
+ end
78
+
79
+ end
@@ -0,0 +1,277 @@
1
+ require "carterdte_smtp_filter"
2
+ require 'pp'
3
+ require 'time'
4
+ require 'date'
5
+
6
+ require 'minitest/autorun'
7
+ require 'minitest/reporters' # requires the gem
8
+ require 'webmock/minitest'
9
+
10
+ require 'fake_api'
11
+
12
+ Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new # spec-like progress
13
+
14
+ # Only log Celluloid errors
15
+ #Celluloid.logger.level = Logger::ERROR
16
+
17
+
18
+ #CarterDteSmtp::Config.parse("./test/fixtures/config.yml")
19
+
20
+ def check_imap()
21
+ require "mail"
22
+ Mail.defaults do
23
+ retriever_method :imap, address: "localhost", port: 143, user_name: "carterdte", password: "123456"
24
+ end
25
+
26
+ emails = Mail.find keys: ['NOT', 'SEEN']
27
+ emails.first
28
+
29
+ end
30
+
31
+ class Enviacorreo
32
+ attr_accessor :to, :from, :body, :subject, :attachment_path, :server, :port
33
+
34
+ def initialize(to: "carterdte@example.com", from: "dte@itlinux.cl", body: "Cuerpo correo", subject: "DTE", attachment_path: false, server: "localhost", port: 2025)
35
+ @to = to
36
+ @from = from
37
+ @body = body
38
+ @subject = subject
39
+ @attachment_path = attachment_path
40
+ @server = server
41
+ @port = port
42
+ end
43
+
44
+ def send
45
+ message.deliver!
46
+ end
47
+
48
+ def message
49
+ smtp_conn = smtp_options
50
+ Mail.defaults do
51
+ delivery_method :smtp_connection, { :connection => smtp_conn.start }
52
+ end
53
+ mail = Mail.new(
54
+ from: @from,
55
+ to: @to,
56
+ subject: @subject,
57
+ body: @body
58
+ )
59
+ mail.add_file @attachment_path if @attachment_path
60
+ mail
61
+ end
62
+
63
+ def smtp_options
64
+ smtp = Net::SMTP.new(@server, @port)
65
+ smtp.read_timeout = 2
66
+ smtp.open_timeout = 2
67
+ smtp
68
+ end
69
+
70
+ end
71
+
72
+ class ReturnSmtp < MidiSmtpServer::Smtpd
73
+
74
+ attr_accessor :mail
75
+
76
+ def start
77
+ @logger = Logger.new('/dev/null')
78
+ @port = CarterdteSmtpFilter::Config::return_port
79
+ @host = CarterdteSmtpFilter::Config::return_host
80
+ super
81
+ end
82
+
83
+ def on_message_data_event(ctx)
84
+ File.open("./test/tmp/returnmail", "w") {|file| file.write ctx[:message][:data]}
85
+ end
86
+
87
+ def process_line(line)
88
+ # check wether in data or command mode
89
+ if Thread.current[:cmd_sequence] != :CMD_DATA
90
+
91
+ # Handle specific messages from the client
92
+ case line
93
+
94
+ when (/^(HELO|EHLO)(\s+.*)?$/i)
95
+ # HELO/EHLO
96
+ # 250 Requested mail action okay, completed
97
+ # 421 <domain> Service not available, closing transmission channel
98
+ # 500 Syntax error, command unrecognised
99
+ # 501 Syntax error in parameters or arguments
100
+ # 504 Command parameter not implemented
101
+ # 521 <domain> does not accept mail [rfc1846]
102
+ # ---------
103
+ # check valid command sequence
104
+ raise Smtpd503Exception if Thread.current[:cmd_sequence] != :CMD_HELO
105
+ # handle command
106
+ @cmd_data = line.gsub(/^(HELO|EHLO)\ /i, '').strip
107
+ # call event to handle data
108
+ on_helo_event(Thread.current[:ctx], @cmd_data)
109
+ # if no error raised, append to message hash
110
+ Thread.current[:ctx][:server][:helo] = @cmd_data
111
+ # set sequence state as RSET
112
+ Thread.current[:cmd_sequence] = :CMD_RSET
113
+ # reply ok
114
+ return "250 OK"
115
+
116
+ when (/^NOOP\s*$/i)
117
+ # NOOP
118
+ # 250 Requested mail action okay, completed
119
+ # 421 <domain> Service not available, closing transmission channel
120
+ # 500 Syntax error, command unrecognised
121
+ return "250 OK"
122
+
123
+ when (/^RSET\s*$/i)
124
+ # RSET
125
+ # 250 Requested mail action okay, completed
126
+ # 421 <domain> Service not available, closing transmission channel
127
+ # 500 Syntax error, command unrecognised
128
+ # 501 Syntax error in parameters or arguments
129
+ # ---------
130
+ # check valid command sequence
131
+ raise Smtpd503Exception if Thread.current[:cmd_sequence] == :CMD_HELO
132
+ # handle command
133
+ reset_ctx
134
+ return "250 OK"
135
+
136
+ when (/^QUIT\s*$/i)
137
+ # QUIT
138
+ # 221 <domain> Service closing transmission channel
139
+ # 500 Syntax error, command unrecognised
140
+ Thread.current[:cmd_sequence] = :CMD_QUIT
141
+ return ""
142
+
143
+ when (/^MAIL FROM\:/i)
144
+ # MAIL
145
+ # 250 Requested mail action okay, completed
146
+ # 421 <domain> Service not available, closing transmission channel
147
+ # 451 Requested action aborted: local error in processing
148
+ # 452 Requested action not taken: insufficient system storage
149
+ # 500 Syntax error, command unrecognised
150
+ # 501 Syntax error in parameters or arguments
151
+ # 552 Requested mail action aborted: exceeded storage allocation
152
+ # ---------
153
+ # check valid command sequence
154
+ raise Smtpd503Exception if Thread.current[:cmd_sequence] != :CMD_RSET
155
+ # handle command
156
+ @cmd_data = line.gsub(/^MAIL FROM\:/i, '').strip
157
+ # call event to handle data
158
+ if return_value = on_mail_from_event(Thread.current[:ctx], @cmd_data)
159
+ # overwrite data with returned value
160
+ @cmd_data = return_value
161
+ end
162
+ # if no error raised, append to message hash
163
+ Thread.current[:ctx][:envelope][:from] = @cmd_data
164
+ # set sequence state
165
+ Thread.current[:cmd_sequence] = :CMD_MAIL
166
+ # reply ok
167
+ return "250 OK"
168
+
169
+ when (/^RCPT TO\:/i)
170
+ # RCPT
171
+ # 250 Requested mail action okay, completed
172
+ # 251 User not local; will forward to <forward-path>
173
+ # 421 <domain> Service not available, closing transmission channel
174
+ # 450 Requested mail action not taken: mailbox unavailable
175
+ # 451 Requested action aborted: local error in processing
176
+ # 452 Requested action not taken: insufficient system storage
177
+ # 500 Syntax error, command unrecognised
178
+ # 501 Syntax error in parameters or arguments
179
+ # 503 Bad sequence of commands
180
+ # 521 <domain> does not accept mail [rfc1846]
181
+ # 550 Requested action not taken: mailbox unavailable
182
+ # 551 User not local; please try <forward-path>
183
+ # 552 Requested mail action aborted: exceeded storage allocation
184
+ # 553 Requested action not taken: mailbox name not allowed
185
+ # ---------
186
+ # check valid command sequence
187
+ raise Smtpd503Exception if ![ :CMD_MAIL, :CMD_RCPT ].include?(Thread.current[:cmd_sequence])
188
+ # handle command
189
+ @cmd_data = line.gsub(/^RCPT TO\:/i, '').strip
190
+ # call event to handle data
191
+ if return_value = on_rcpt_to_event(Thread.current[:ctx], @cmd_data)
192
+ # overwrite data with returned value
193
+ @cmd_data = return_value
194
+ end
195
+ # if no error raised, append to message hash
196
+ Thread.current[:ctx][:envelope][:to] << @cmd_data
197
+ # set sequence state
198
+ Thread.current[:cmd_sequence] = :CMD_RCPT
199
+ # reply ok
200
+ return "250 OK"
201
+
202
+ when (/^DATA\s*$/i)
203
+ # DATA
204
+ # 354 Start mail input; end with <CRLF>.<CRLF>
205
+ # 250 Requested mail action okay, completed
206
+ # 421 <domain> Service not available, closing transmission channel received data
207
+ # 451 Requested action aborted: local error in processing
208
+ # 452 Requested action not taken: insufficient system storage
209
+ # 500 Syntax error, command unrecognised
210
+ # 501 Syntax error in parameters or arguments
211
+ # 503 Bad sequence of commands
212
+ # 552 Requested mail action aborted: exceeded storage allocation
213
+ # 554 Transaction failed
214
+ # ---------
215
+ # check valid command sequence
216
+ raise Smtpd503Exception if Thread.current[:cmd_sequence] != :CMD_RCPT
217
+ # handle command
218
+ # set sequence state
219
+ Thread.current[:cmd_sequence] = :CMD_DATA
220
+ # reply ok / proceed with message data
221
+ return "354 Enter message, ending with \".\" on a line by itself"
222
+
223
+ else
224
+ # If we somehow get to this point then
225
+ # we have encountered an error
226
+ raise Smtpd500Exception
227
+
228
+ end
229
+
230
+ else
231
+ # If we are in data mode and the entire message consists
232
+ # solely of a period on a line by itself then we
233
+ # are being told to exit data mode
234
+ if (line.chomp =~ /^\.$/)
235
+ # append last chars to message data
236
+ Thread.current[:ctx][:message][:data] += line
237
+ # remove ending line .
238
+ Thread.current[:ctx][:message][:data].gsub!(/\r\n\Z/, '').gsub!(/\.\Z/, '')
239
+ # save delivered time
240
+ Thread.current[:ctx][:message][:delivered] = Time.now.utc
241
+ # save bytesize of message data
242
+ Thread.current[:ctx][:message][:bytesize] = Thread.current[:ctx][:message][:data].bytesize
243
+ # call event
244
+ begin
245
+ on_message_data_event(Thread.current[:ctx])
246
+ array = (0..9).to_a + ("A".."F").to_a
247
+ return "250 2.0.0 Ok: queued as #{array.sample(11).join("")}"
248
+
249
+ # test for SmtpdException
250
+ rescue SmtpdException
251
+ # just re-raise exception set by app
252
+ raise
253
+
254
+ # test all other Exceptions
255
+ rescue Exception => e
256
+ # send correct aborted message to smtp dialog
257
+ raise Smtpd451Exception.new("#{e}")
258
+
259
+ ensure
260
+ # always start with empty values after finishing incoming message
261
+ # and rset command sequence
262
+ reset_ctx
263
+ end
264
+
265
+ else
266
+ # If we are in date mode then we need to add
267
+ # the new data to the message
268
+ Thread.current[:ctx][:message][:data] += line
269
+ return ""
270
+ # command sequence state will stay on :CMD_DATA
271
+
272
+ end
273
+
274
+ end
275
+ end
276
+
277
+ end
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ class TestMessage < Minitest::Test
4
+
5
+ def setup
6
+ CarterdteSmtpFilter::Config.parse("./test/fixtures/config.yml")
7
+ @server = CarterdteSmtpFilter::SmtpServer.new()
8
+ @server.start
9
+ @return_stmp = ReturnSmtp.new()
10
+ @return_stmp.start
11
+ end
12
+
13
+ def teardown
14
+ @server.shutdown
15
+ sleep 2 unless @server.connections == 0
16
+ @server.stop
17
+ @return_stmp.shutdown
18
+ @return_stmp.stop
19
+ end
20
+
21
+ def test_message_should_save_server_response_when_returning_email
22
+ raw_mail = File.open("./test/fixtures/mail.tmp", "rb").read
23
+ message = CarterdteSmtpFilter::Message.new raw_mail
24
+ response = message.return_email
25
+ assert(Net::SMTP::Response == message.response.class, "Response should be a SMTP Response")
26
+ end
27
+
28
+ def test_message_should_save_server_queueid_response_if_any
29
+ raw_mail = File.open("./test/fixtures/mail_with_dte.eml", "rb").read
30
+ message = CarterdteSmtpFilter::Message.new raw_mail
31
+ message.process
32
+ assert_equal(message.response.string.split(/\s+/).last, message.qid)
33
+ end
34
+
35
+ def test_message_to_json_should_return_json_object_with_message_metada
36
+ message = CarterdteSmtpFilter::Message.new File.open("./test/fixtures/mail_with_dte.eml", "rb").read
37
+ assert(JSON.parse(message.to_json), "No JSON")
38
+ json = JSON.parse(message.to_json)
39
+ assert_equal(message.email.to, json["to"])
40
+ assert_equal(message.email.from, json["from"])
41
+ assert_equal(message.email.date.to_s, json["date"])
42
+ assert_equal("96529310-8", json["dte"]["rut_emisor"])
43
+ end
44
+
45
+ def test_extract_dte_should_return_false_if_no_attachments
46
+ message = CarterdteSmtpFilter::Message.new File.open("./test/fixtures/mail.tmp", "rb").read
47
+ assert(!message.extract_dte, "Failure message.")
48
+ end
49
+
50
+ def test_extract_dte_should_return_false_if_no_dte_attachments
51
+ message = CarterdteSmtpFilter::Message.new File.open("./test/fixtures/email_with_attachment_no_dte.eml", "rb").read
52
+ assert(!message.extract_dte, "Failure message.")
53
+ end
54
+
55
+ def test_extract_dte_should_return_mail_part_with_xml_file
56
+ message = CarterdteSmtpFilter::Message.new File.open("./test/fixtures/mail_with_multiple_attachments.eml", "rb").read
57
+ assert(message.dte, "Failure message.")
58
+ end
59
+
60
+
61
+ def test_message_dte_should_be_a_dte_object
62
+ message = CarterdteSmtpFilter::Message.new File.open("./test/fixtures/mail_with_dte.eml", "rb").read
63
+ assert_equal(CarterdteSmtpFilter::Dte, message.dte.class)
64
+ end
65
+
66
+
67
+ end