local sent = {} local from = "luasock@tecgraf.puc-rio.br" local server = "mail.tecgraf.puc-rio.br" local rcpt = "luasock@tecgraf.puc-rio.br" local parse = {} local name = "/var/spool/mail/luasock" local t = _time() local err function mysetglobal (varname, oldvalue, newvalue) print("changing " .. varname) %rawset(%globals(), varname, newvalue) end function mygetglobal (varname, newvalue) print("checking " .. varname) return %rawget(%globals(), varname) end settagmethod(tag(nil), "setglobal", mysetglobal) settagmethod(tag(nil), "getglobal", mygetglobal) assert(dofile("../lua/smtp.lua")) assert(dofile("../lua/cl-compat.lua")) local total = function() local t = 0 for i = 1, getn(%sent) do t = t + %sent[i].count end return t end local similar = function(s1, s2) return strlower(gsub(s1, "%s", "")) == strlower(gsub(s2, "%s", "")) end function parse.headers(headers_s) local headers = {} headers_s = "\n" .. headers_s .. "$$$:\n" local i, j = 1, 1 local name, value, _ while 1 do j = strfind(headers_s, "\n%S-:", i+1) if not j then break end _, _, name, value = strfind(strsub(headers_s, i+1, j-1), "(%S-): (.*)") value = gsub(value, "\r\n", "\n") value = gsub(value, "\n%s*", " ") name = strlower(name) if headers[name] then headers[name] = headers[name] .. ", " .. value else headers[name] = value end i, j = j, i end headers["$$$"] = nil return headers end function parse.message(message_s) message_s = gsub(message_s, "^.-\n", "") local _, headers_s, body _, _, headers_s, body = strfind(message_s, "^(.-\n)\n(.*)") headers_s = headers_s or "" body = body or "" return { headers = %parse.headers(headers_s), body = body } end function parse.mbox(mbox_s) local mbox = {} mbox_s = "\n" .. mbox_s .. "\nFrom " local i, j = 1, 1 while 1 do j = strfind(mbox_s, "\nFrom ", i + 1) if not j then break end tinsert(mbox, %parse.message(strsub(mbox_s, i + 1, j - 1))) i, j = j, i end return mbox end local readfile = function(name) local f = readfrom(name) if not f then return nil end local s = read("*a") readfrom() return s end local capture = function(cmd) readfrom("| " .. cmd) local s = read("*a") readfrom() return s end local fail = function(s) s = s or "failed!" print(s) exit() end local empty = function() local f = openfile(%name, "w") closefile(f) end local get = function() return %readfile(%name) end local list = function() return %capture("ls -l " .. %name) end local check_headers = function(sent, got) sent = sent or {} got = got or {} for i,v in sent do if not %similar(v, got[i]) then %fail("header " .. v .. "failed!") end end end local check_body = function(sent, got) sent = sent or "" got = got or "" if not %similar(sent, got) then %fail("bodies differ!") end end local check = function(sent, m) write("checking ", m.headers.title, ": ") for i = 1, getn(sent) do local s = sent[i] if s.title == m.headers.title and s.count > 0 then %check_headers(s.headers, m.headers) %check_body(s.body, m.body) s.count = s.count - 1 print("ok") return end end %fail("not found") end local insert = function(sent, message) if type(message.rcpt) == "table" then message.count = getn(message.rcpt) else message.count = 1 end message.headers = message.headers or {} message.headers.title = message.title tinsert(sent, message) end local mark = function() local time = _time() return { time = time } end local wait = function(sentinel, n) local to write("waiting for ", n, " messages: ") while 1 do local mbox = %parse.mbox(%get()) if n == getn(mbox) then break end if _time() - sentinel.time > 50 then to = 1 break end _sleep(1) write(".") flush(_STDOUT) end if to then %fail("timeout") else print("ok") end end local stuffed_body = [[ This message body needs to be stuffed because it has a dot . by itself on a line. Otherwise the mailer would think that the dot . is the end of the message and the remaining will cause a lot of trouble. ]] insert(sent, { from = from, rcpt = { "luasock2@tecgraf.puc-rio.br", "luasock", "luasock1" }, body = "multiple rcpt body", title = "multiple rcpt", }) insert(sent, { from = from, rcpt = { "luasock2@tecgraf.puc-rio.br", "luasock", "luasock1" }, headers = { header1 = "header 1", header2 = "header 2", header3 = "header 3", header4 = "header 4", header5 = "header 5", header6 = "header 6", }, body = stuffed_body, title = "complex message", }) insert(sent, { from = from, rcpt = rcpt, server = server, body = "simple message body", title = "simple message" }) insert(sent, { from = from, rcpt = rcpt, server = server, body = stuffed_body, title = "stuffed message body" }) insert(sent, { from = from, rcpt = rcpt, headers = { header1 = "header 1", header2 = "header 2", header3 = "header 3", header4 = "header 4", header5 = "header 5", header6 = "header 6", }, title = "multiple headers" }) insert(sent, { from = from, rcpt = rcpt, title = "minimum message" }) write("testing host not found: ") local c, e = connect("wrong.host", 25) local err = SMTP.mail{ from = from, rcpt = rcpt, server = "wrong.host" } if e ~= err then fail("wrong error message") else print("ok") end write("testing invalid from: ") local err = SMTP.mail{ from = ' " " (( _ * ', rcpt = rcpt, } if not err then fail("wrong error message") else print(err) end write("testing no rcpt: ") local err = SMTP.mail{ from = from, } if not err then fail("wrong error message") else print(err) end write("clearing mailbox: ") empty() print("ok") write("sending messages: ") for i = 1, getn(sent) do err = SMTP.mail(sent[i]) if err then fail(err) end write("+") flush(_STDOUT) end print("ok") wait(mark(), total()) write("parsing mailbox: ") local mbox = parse.mbox(get()) print(getn(mbox) .. " messages found!") for i = 1, getn(mbox) do check(sent, mbox[i]) end print("passed all tests") print(format("done in %.2fs", _time() - t))