api_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. package guerrilla
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "github.com/flashmob/go-guerrilla/backends"
  7. "github.com/flashmob/go-guerrilla/log"
  8. "github.com/flashmob/go-guerrilla/mail"
  9. "github.com/flashmob/go-guerrilla/response"
  10. "io/ioutil"
  11. "net"
  12. "os"
  13. "strings"
  14. "testing"
  15. "time"
  16. )
  17. // Test Starting smtp without setting up logger / backend
  18. func TestSMTP(t *testing.T) {
  19. done := make(chan bool)
  20. go func() {
  21. select {
  22. case <-time.After(time.Second * 40):
  23. t.Error("timeout")
  24. return
  25. case <-done:
  26. return
  27. }
  28. }()
  29. d := Daemon{}
  30. err := d.Start()
  31. if err != nil {
  32. t.Error(err)
  33. }
  34. // it should set to stderr automatically
  35. if d.Config.LogFile != log.OutputStderr.String() {
  36. t.Error("smtp.config.LogFile is not", log.OutputStderr.String())
  37. }
  38. if len(d.Config.AllowedHosts) == 0 {
  39. t.Error("smtp.config.AllowedHosts len should be 1, not 0", d.Config.AllowedHosts)
  40. }
  41. if d.Config.LogLevel != "debug" {
  42. t.Error("smtp.config.LogLevel expected'debug', it is", d.Config.LogLevel)
  43. }
  44. if len(d.Config.Servers) != 1 {
  45. t.Error("len(smtp.config.Servers) should be 1, got", len(d.Config.Servers))
  46. }
  47. time.Sleep(time.Second * 2)
  48. d.Shutdown()
  49. done <- true
  50. }
  51. // Suppressing log output
  52. func TestSMTPNoLog(t *testing.T) {
  53. // configure a default server with no log output
  54. cfg := &AppConfig{LogFile: log.OutputOff.String()}
  55. d := Daemon{Config: cfg}
  56. err := d.Start()
  57. if err != nil {
  58. t.Error(err)
  59. }
  60. time.Sleep(time.Second * 2)
  61. d.Shutdown()
  62. }
  63. // our custom server
  64. func TestSMTPCustomServer(t *testing.T) {
  65. cfg := &AppConfig{LogFile: log.OutputOff.String()}
  66. sc := ServerConfig{
  67. ListenInterface: "127.0.0.1:2526",
  68. IsEnabled: true,
  69. }
  70. cfg.Servers = append(cfg.Servers, sc)
  71. d := Daemon{Config: cfg}
  72. err := d.Start()
  73. if err != nil {
  74. t.Error("start error", err)
  75. } else {
  76. time.Sleep(time.Second * 2)
  77. d.Shutdown()
  78. }
  79. }
  80. // with a backend config
  81. func TestSMTPCustomBackend(t *testing.T) {
  82. cfg := &AppConfig{LogFile: log.OutputOff.String()}
  83. sc := ServerConfig{
  84. ListenInterface: "127.0.0.1:2526",
  85. IsEnabled: true,
  86. }
  87. cfg.Servers = append(cfg.Servers, sc)
  88. bcfg := backends.BackendConfig{
  89. "save_workers_size": 3,
  90. "save_process": "HeadersParser|Header|Hasher|Debugger",
  91. "log_received_mails": true,
  92. "primary_mail_host": "example.com",
  93. }
  94. cfg.BackendConfig = bcfg
  95. d := Daemon{Config: cfg}
  96. err := d.Start()
  97. if err != nil {
  98. t.Error("start error", err)
  99. } else {
  100. time.Sleep(time.Second * 2)
  101. d.Shutdown()
  102. }
  103. }
  104. // with a config from a json file
  105. func TestSMTPLoadFile(t *testing.T) {
  106. json := `{
  107. "log_file" : "./tests/testlog",
  108. "log_level" : "debug",
  109. "pid_file" : "tests/go-guerrilla.pid",
  110. "allowed_hosts": ["spam4.me","grr.la"],
  111. "backend_config" :
  112. {
  113. "log_received_mails" : true,
  114. "save_process": "HeadersParser|Header|Hasher|Debugger",
  115. "save_workers_size": 3
  116. },
  117. "servers" : [
  118. {
  119. "is_enabled" : true,
  120. "host_name":"mail.guerrillamail.com",
  121. "max_size": 100017,
  122. "timeout":160,
  123. "listen_interface":"127.0.0.1:2526",
  124. "max_clients": 2,
  125. "tls" : {
  126. "private_key_file":"config_test.go",
  127. "public_key_file":"config_test.go",
  128. "start_tls_on":false,
  129. "tls_always_on":false
  130. }
  131. }
  132. ]
  133. }
  134. `
  135. json2 := `{
  136. "log_file" : "./tests/testlog2",
  137. "log_level" : "debug",
  138. "pid_file" : "tests/go-guerrilla2.pid",
  139. "allowed_hosts": ["spam4.me","grr.la"],
  140. "backend_config" :
  141. {
  142. "log_received_mails" : true,
  143. "save_process": "HeadersParser|Header|Hasher|Debugger",
  144. "save_workers_size": 3
  145. },
  146. "servers" : [
  147. {
  148. "is_enabled" : true,
  149. "host_name":"mail.guerrillamail.com",
  150. "max_size": 100017,
  151. "timeout":160,
  152. "listen_interface":"127.0.0.1:2526",
  153. "max_clients": 2,
  154. "tls" : {
  155. "private_key_file":"config_test.go",
  156. "public_key_file":"config_test.go",
  157. "start_tls_on":false,
  158. "tls_always_on":false
  159. }
  160. }
  161. ]
  162. }
  163. `
  164. err := ioutil.WriteFile("goguerrilla.conf.api", []byte(json), 0644)
  165. if err != nil {
  166. t.Error("could not write guerrilla.conf.api", err)
  167. return
  168. }
  169. d := Daemon{}
  170. _, err = d.LoadConfig("goguerrilla.conf.api")
  171. if err != nil {
  172. t.Error("ReadConfig error", err)
  173. return
  174. }
  175. err = d.Start()
  176. if err != nil {
  177. t.Error("start error", err)
  178. return
  179. } else {
  180. time.Sleep(time.Second * 2)
  181. if d.Config.LogFile != "./tests/testlog" {
  182. t.Error("d.Config.LogFile != \"./tests/testlog\"")
  183. }
  184. if d.Config.PidFile != "tests/go-guerrilla.pid" {
  185. t.Error("d.Config.LogFile != tests/go-guerrilla.pid")
  186. }
  187. err := ioutil.WriteFile("goguerrilla.conf.api", []byte(json2), 0644)
  188. if err != nil {
  189. t.Error("could not write guerrilla.conf.api", err)
  190. return
  191. }
  192. if err = d.ReloadConfigFile("goguerrilla.conf.api"); err != nil {
  193. t.Error(err)
  194. }
  195. if d.Config.LogFile != "./tests/testlog2" {
  196. t.Error("d.Config.LogFile != \"./tests/testlog\"")
  197. }
  198. if d.Config.PidFile != "tests/go-guerrilla2.pid" {
  199. t.Error("d.Config.LogFile != \"go-guerrilla.pid\"")
  200. }
  201. d.Shutdown()
  202. }
  203. }
  204. // test re-opening the main log
  205. func TestReopenLog(t *testing.T) {
  206. if err := os.Truncate("tests/testlog", 0); err != nil {
  207. t.Error(err)
  208. }
  209. cfg := &AppConfig{LogFile: "tests/testlog"}
  210. sc := ServerConfig{
  211. ListenInterface: "127.0.0.1:2526",
  212. IsEnabled: true,
  213. }
  214. cfg.Servers = append(cfg.Servers, sc)
  215. d := Daemon{Config: cfg}
  216. err := d.Start()
  217. if err != nil {
  218. t.Error("start error", err)
  219. } else {
  220. if err = d.ReopenLogs(); err != nil {
  221. t.Error(err)
  222. }
  223. time.Sleep(time.Second * 2)
  224. d.Shutdown()
  225. }
  226. b, err := ioutil.ReadFile("tests/testlog")
  227. if err != nil {
  228. t.Error("could not read logfile")
  229. return
  230. }
  231. if !strings.Contains(string(b), "re-opened log file") {
  232. t.Error("Server log did not re-opened, expecting \"re-opened log file\"")
  233. }
  234. if !strings.Contains(string(b), "re-opened main log file") {
  235. t.Error("Main log did not re-opened, expecting \"re-opened main log file\"")
  236. }
  237. }
  238. const testServerLog = "tests/testlog-server.log"
  239. // test re-opening the individual server log
  240. func TestReopenServerLog(t *testing.T) {
  241. if err := os.Truncate("tests/testlog", 0); err != nil {
  242. t.Error(err)
  243. }
  244. defer func() {
  245. if _, err := os.Stat(testServerLog); err == nil {
  246. if err = os.Remove(testServerLog); err != nil {
  247. t.Error(err)
  248. }
  249. }
  250. }()
  251. cfg := &AppConfig{LogFile: "tests/testlog", LogLevel: log.DebugLevel.String(), AllowedHosts: []string{"grr.la"}}
  252. sc := ServerConfig{
  253. ListenInterface: "127.0.0.1:2526",
  254. IsEnabled: true,
  255. LogFile: testServerLog,
  256. }
  257. cfg.Servers = append(cfg.Servers, sc)
  258. d := Daemon{Config: cfg}
  259. err := d.Start()
  260. if err != nil {
  261. t.Error("start error", err)
  262. } else {
  263. if err := talkToServer("127.0.0.1:2526"); err != nil {
  264. t.Error(err)
  265. }
  266. if err = d.ReopenLogs(); err != nil {
  267. t.Error(err)
  268. }
  269. time.Sleep(time.Second * 2)
  270. if err := talkToServer("127.0.0.1:2526"); err != nil {
  271. t.Error(err)
  272. }
  273. d.Shutdown()
  274. }
  275. b, err := ioutil.ReadFile("tests/testlog")
  276. if err != nil {
  277. t.Error("could not read logfile")
  278. return
  279. }
  280. if !strings.Contains(string(b), "re-opened log file") {
  281. t.Error("Server log did not re-opened, expecting \"re-opened log file\"")
  282. }
  283. if !strings.Contains(string(b), "re-opened main log file") {
  284. t.Error("Main log did not re-opened, expecting \"re-opened main log file\"")
  285. }
  286. b, err = ioutil.ReadFile(testServerLog)
  287. if err != nil {
  288. t.Error("could not read logfile")
  289. return
  290. }
  291. if !strings.Contains(string(b), "Handle client") {
  292. t.Error("server log does not contain \"handle client\"")
  293. }
  294. }
  295. func TestSetConfig(t *testing.T) {
  296. if err := os.Truncate("tests/testlog", 0); err != nil {
  297. t.Error(err)
  298. }
  299. cfg := AppConfig{LogFile: "tests/testlog"}
  300. sc := ServerConfig{
  301. ListenInterface: "127.0.0.1:2526",
  302. IsEnabled: true,
  303. }
  304. cfg.Servers = append(cfg.Servers, sc)
  305. d := Daemon{Config: &cfg}
  306. // lets add a new server
  307. sc.ListenInterface = "127.0.0.1:2527"
  308. cfg.Servers = append(cfg.Servers, sc)
  309. err := d.SetConfig(cfg)
  310. if err != nil {
  311. t.Error("SetConfig returned an error:", err)
  312. return
  313. }
  314. err = d.Start()
  315. if err != nil {
  316. t.Error("start error", err)
  317. } else {
  318. time.Sleep(time.Second * 2)
  319. d.Shutdown()
  320. }
  321. b, err := ioutil.ReadFile("tests/testlog")
  322. if err != nil {
  323. t.Error("could not read logfile")
  324. return
  325. }
  326. //fmt.Println(string(b))
  327. // has 127.0.0.1:2527 started?
  328. if !strings.Contains(string(b), "127.0.0.1:2527") {
  329. t.Error("expecting 127.0.0.1:2527 to start")
  330. }
  331. }
  332. func TestSetConfigError(t *testing.T) {
  333. if err := os.Truncate("tests/testlog", 0); err != nil {
  334. t.Error(err)
  335. }
  336. cfg := AppConfig{LogFile: "tests/testlog"}
  337. sc := ServerConfig{
  338. ListenInterface: "127.0.0.1:2526",
  339. IsEnabled: true,
  340. }
  341. cfg.Servers = append(cfg.Servers, sc)
  342. d := Daemon{Config: &cfg}
  343. // lets add a new server with bad TLS
  344. sc.ListenInterface = "127.0.0.1:2527"
  345. sc.TLS.StartTLSOn = true
  346. sc.TLS.PublicKeyFile = "tests/testlog" // totally wrong :->
  347. sc.TLS.PrivateKeyFile = "tests/testlog" // totally wrong :->
  348. cfg.Servers = append(cfg.Servers, sc)
  349. err := d.SetConfig(cfg)
  350. if err == nil {
  351. t.Error("SetConfig should have returned an error compalning about bad tls settings")
  352. return
  353. }
  354. }
  355. var funkyLogger = func() backends.Decorator {
  356. backends.Svc.AddInitializer(
  357. backends.InitializeWith(
  358. func(backendConfig backends.BackendConfig) error {
  359. backends.Log().Info("Funky logger is up & down to funk!")
  360. return nil
  361. }),
  362. )
  363. backends.Svc.AddShutdowner(
  364. backends.ShutdownWith(
  365. func() error {
  366. backends.Log().Info("The funk has been stopped!")
  367. return nil
  368. }),
  369. )
  370. return func(p backends.Processor) backends.Processor {
  371. return backends.ProcessWith(
  372. func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
  373. if task == backends.TaskValidateRcpt {
  374. // log the last recipient appended to e.Rcpt
  375. backends.Log().Infof(
  376. "another funky recipient [%s]",
  377. e.RcptTo[len(e.RcptTo)-1])
  378. // if valid then forward call to the next processor in the chain
  379. return p.Process(e, task)
  380. // if invalid, return a backend result
  381. //return backends.NewResult(response.Canned.FailRcptCmd), nil
  382. } else if task == backends.TaskSaveMail {
  383. backends.Log().Info("Another funky email!")
  384. }
  385. return p.Process(e, task)
  386. })
  387. }
  388. }
  389. // How about a custom processor?
  390. func TestSetAddProcessor(t *testing.T) {
  391. if err := os.Truncate("tests/testlog", 0); err != nil {
  392. t.Error(err)
  393. }
  394. cfg := &AppConfig{
  395. LogFile: "tests/testlog",
  396. AllowedHosts: []string{"grr.la"},
  397. BackendConfig: backends.BackendConfig{
  398. "save_process": "HeadersParser|Debugger|FunkyLogger",
  399. "validate_process": "FunkyLogger",
  400. },
  401. }
  402. d := Daemon{Config: cfg}
  403. d.AddProcessor("FunkyLogger", funkyLogger)
  404. if err := d.Start(); err != nil {
  405. t.Error(err)
  406. }
  407. // lets have a talk with the server
  408. if err := talkToServer("127.0.0.1:2525"); err != nil {
  409. t.Error(err)
  410. }
  411. d.Shutdown()
  412. b, err := ioutil.ReadFile("tests/testlog")
  413. if err != nil {
  414. t.Error("could not read logfile")
  415. return
  416. }
  417. // lets check for fingerprints
  418. if !strings.Contains(string(b), "another funky recipient") {
  419. t.Error("did not log: another funky recipient")
  420. }
  421. if !strings.Contains(string(b), "Another funky email!") {
  422. t.Error("Did not log: Another funky email!")
  423. }
  424. if !strings.Contains(string(b), "Funky logger is up & down to funk") {
  425. t.Error("Did not log: Funky logger is up & down to funk")
  426. }
  427. if !strings.Contains(string(b), "The funk has been stopped!") {
  428. t.Error("Did not log:The funk has been stopped!")
  429. }
  430. }
  431. func talkToServer(address string) (err error) {
  432. conn, err := net.Dial("tcp", address)
  433. if err != nil {
  434. return
  435. }
  436. in := bufio.NewReader(conn)
  437. str, err := in.ReadString('\n')
  438. if err != nil {
  439. return err
  440. }
  441. _, err = fmt.Fprint(conn, "HELO maildiranasaurustester\r\n")
  442. if err != nil {
  443. return err
  444. }
  445. str, err = in.ReadString('\n')
  446. if err != nil {
  447. return err
  448. }
  449. _, err = fmt.Fprint(conn, "MAIL FROM:<[email protected]>r\r\n")
  450. if err != nil {
  451. return err
  452. }
  453. str, err = in.ReadString('\n')
  454. if err != nil {
  455. return err
  456. }
  457. _, err = fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n")
  458. if err != nil {
  459. return err
  460. }
  461. str, err = in.ReadString('\n')
  462. if err != nil {
  463. return err
  464. }
  465. _, err = fmt.Fprint(conn, "DATA\r\n")
  466. if err != nil {
  467. return err
  468. }
  469. str, err = in.ReadString('\n')
  470. if err != nil {
  471. return err
  472. }
  473. _, err = fmt.Fprint(conn, "Subject: Test subject\r\n")
  474. if err != nil {
  475. return err
  476. }
  477. _, err = fmt.Fprint(conn, "\r\n")
  478. if err != nil {
  479. return err
  480. }
  481. _, err = fmt.Fprint(conn, "A an email body\r\n")
  482. if err != nil {
  483. return err
  484. }
  485. _, err = fmt.Fprint(conn, ".\r\n")
  486. if err != nil {
  487. return err
  488. }
  489. str, err = in.ReadString('\n')
  490. if err != nil {
  491. return err
  492. }
  493. _ = str
  494. return nil
  495. }
  496. // Test hot config reload
  497. // Here we forgot to add FunkyLogger so backend will fail to init
  498. // it will log to stderr at the beginning, but then change to tests/testlog
  499. func TestReloadConfig(t *testing.T) {
  500. if err := os.Truncate("tests/testlog", 0); err != nil {
  501. t.Error(err)
  502. }
  503. d := Daemon{}
  504. if err := d.Start(); err != nil {
  505. t.Error(err)
  506. }
  507. defer d.Shutdown()
  508. cfg := AppConfig{
  509. LogFile: "tests/testlog",
  510. AllowedHosts: []string{"grr.la"},
  511. BackendConfig: backends.BackendConfig{
  512. "save_process": "HeadersParser|Debugger|FunkyLogger",
  513. "validate_process": "FunkyLogger",
  514. },
  515. }
  516. // Look mom, reloading the config without shutting down!
  517. if err := d.ReloadConfig(cfg); err != nil {
  518. t.Error(err)
  519. }
  520. }
  521. func TestPubSubAPI(t *testing.T) {
  522. if err := os.Truncate("tests/testlog", 0); err != nil {
  523. t.Error(err)
  524. }
  525. d := Daemon{Config: &AppConfig{LogFile: "tests/testlog"}}
  526. if err := d.Start(); err != nil {
  527. t.Error(err)
  528. }
  529. defer d.Shutdown()
  530. // new config
  531. cfg := AppConfig{
  532. PidFile: "tests/pidfilex.pid",
  533. LogFile: "tests/testlog",
  534. AllowedHosts: []string{"grr.la"},
  535. BackendConfig: backends.BackendConfig{
  536. "save_process": "HeadersParser|Debugger|FunkyLogger",
  537. "validate_process": "FunkyLogger",
  538. },
  539. }
  540. var i = 0
  541. pidEvHandler := func(c *AppConfig) {
  542. i++
  543. if i > 1 {
  544. t.Error("number > 1, it means d.Unsubscribe didn't work")
  545. }
  546. d.Logger.Info("number", i)
  547. }
  548. if err := d.Subscribe(EventConfigPidFile, pidEvHandler); err != nil {
  549. t.Error(err)
  550. }
  551. if err := d.ReloadConfig(cfg); err != nil {
  552. t.Error(err)
  553. }
  554. if err := d.Unsubscribe(EventConfigPidFile, pidEvHandler); err != nil {
  555. t.Error(err)
  556. }
  557. cfg.PidFile = "tests/pidfile2.pid"
  558. d.Publish(EventConfigPidFile, &cfg)
  559. if err := d.ReloadConfig(cfg); err != nil {
  560. t.Error(err)
  561. }
  562. b, err := ioutil.ReadFile("tests/testlog")
  563. if err != nil {
  564. t.Error("could not read logfile")
  565. return
  566. }
  567. // lets interrogate the log
  568. if !strings.Contains(string(b), "number1") {
  569. t.Error("it lools like d.ReloadConfig(cfg) did not fire EventConfigPidFile, pidEvHandler not called")
  570. }
  571. }
  572. func TestAPILog(t *testing.T) {
  573. if err := os.Truncate("tests/testlog", 0); err != nil {
  574. t.Error(err)
  575. }
  576. d := Daemon{}
  577. l := d.Log()
  578. l.Info("logtest1") // to stderr
  579. if l.GetLevel() != log.InfoLevel.String() {
  580. t.Error("Log level does not eq info, it is ", l.GetLevel())
  581. }
  582. d.Logger = nil
  583. d.Config = &AppConfig{LogFile: "tests/testlog"}
  584. l = d.Log()
  585. l.Info("logtest1") // to tests/testlog
  586. //
  587. l = d.Log()
  588. if l.GetLogDest() != "tests/testlog" {
  589. t.Error("log dest is not tests/testlog, it was ", l.GetLogDest())
  590. }
  591. b, err := ioutil.ReadFile("tests/testlog")
  592. if err != nil {
  593. t.Error("could not read logfile")
  594. return
  595. }
  596. // lets interrogate the log
  597. if !strings.Contains(string(b), "logtest1") {
  598. t.Error("hai was not found in the log, it should have been in tests/testlog")
  599. }
  600. }
  601. // Test the allowed_hosts config option with a single entry of ".", which will allow all hosts.
  602. func TestSkipAllowsHost(t *testing.T) {
  603. d := Daemon{}
  604. defer d.Shutdown()
  605. // setting the allowed hosts to a single entry with a dot will let any host through
  606. d.Config = &AppConfig{AllowedHosts: []string{"."}, LogFile: "off"}
  607. if err := d.Start(); err != nil {
  608. t.Error(err)
  609. }
  610. conn, err := net.Dial("tcp", d.Config.Servers[0].ListenInterface)
  611. if err != nil {
  612. t.Error(t)
  613. return
  614. }
  615. in := bufio.NewReader(conn)
  616. if _, err := fmt.Fprint(conn, "HELO test\r\n"); err != nil {
  617. t.Error(err)
  618. }
  619. if _, err := fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n"); err != nil {
  620. t.Error(err)
  621. }
  622. if _, err := in.ReadString('\n'); err != nil {
  623. t.Error(err)
  624. }
  625. if _, err := in.ReadString('\n'); err != nil {
  626. t.Error(err)
  627. }
  628. str, _ := in.ReadString('\n')
  629. if strings.Index(str, "250") != 0 {
  630. t.Error("expected 250 reply, got:", str)
  631. }
  632. }
  633. var customBackend2 = func() backends.Decorator {
  634. return func(p backends.Processor) backends.Processor {
  635. return backends.ProcessWith(
  636. func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
  637. if task == backends.TaskValidateRcpt {
  638. return p.Process(e, task)
  639. } else if task == backends.TaskSaveMail {
  640. backends.Log().Info("Another funky email!")
  641. err := errors.New("system shock")
  642. return backends.NewResult(response.Canned.FailReadErrorDataCmd, response.SP, err), err
  643. }
  644. return p.Process(e, task)
  645. })
  646. }
  647. }
  648. // Test a custom backend response
  649. func TestCustomBackendResult(t *testing.T) {
  650. if err := os.Truncate("tests/testlog", 0); err != nil {
  651. t.Error(err)
  652. }
  653. cfg := &AppConfig{
  654. LogFile: "tests/testlog",
  655. AllowedHosts: []string{"grr.la"},
  656. BackendConfig: backends.BackendConfig{
  657. "save_process": "HeadersParser|Debugger|Custom",
  658. "validate_process": "Custom",
  659. },
  660. }
  661. d := Daemon{Config: cfg}
  662. d.AddProcessor("Custom", customBackend2)
  663. if err := d.Start(); err != nil {
  664. t.Error(err)
  665. }
  666. // lets have a talk with the server
  667. if err := talkToServer("127.0.0.1:2525"); err != nil {
  668. t.Error(err)
  669. }
  670. d.Shutdown()
  671. b, err := ioutil.ReadFile("tests/testlog")
  672. if err != nil {
  673. t.Error("could not read logfile")
  674. return
  675. }
  676. // lets check for fingerprints
  677. if !strings.Contains(string(b), "451 4.3.0 Error") {
  678. t.Error("did not log: 451 4.3.0 Error")
  679. }
  680. if !strings.Contains(string(b), "system shock") {
  681. t.Error("did not log: system shock")
  682. }
  683. }