| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 | 
							- package guerrilla
 
- import (
 
- 	"bufio"
 
- 	"errors"
 
- 	"fmt"
 
- 	"github.com/flashmob/go-guerrilla/backends"
 
- 	"github.com/flashmob/go-guerrilla/log"
 
- 	"github.com/flashmob/go-guerrilla/mail"
 
- 	"github.com/flashmob/go-guerrilla/response"
 
- 	"io/ioutil"
 
- 	"net"
 
- 	"os"
 
- 	"strings"
 
- 	"testing"
 
- 	"time"
 
- )
 
- // Test Starting smtp without setting up logger / backend
 
- func TestSMTP(t *testing.T) {
 
- 	done := make(chan bool)
 
- 	go func() {
 
- 		select {
 
- 		case <-time.After(time.Second * 40):
 
- 			t.Error("timeout")
 
- 			return
 
- 		case <-done:
 
- 			return
 
- 		}
 
- 	}()
 
- 	d := Daemon{}
 
- 	err := d.Start()
 
- 	if err != nil {
 
- 		t.Error(err)
 
- 	}
 
- 	// it should set to stderr automatically
 
- 	if d.Config.LogFile != log.OutputStderr.String() {
 
- 		t.Error("smtp.config.LogFile is not", log.OutputStderr.String())
 
- 	}
 
- 	if len(d.Config.AllowedHosts) == 0 {
 
- 		t.Error("smtp.config.AllowedHosts len should be 1, not 0", d.Config.AllowedHosts)
 
- 	}
 
- 	if d.Config.LogLevel != "debug" {
 
- 		t.Error("smtp.config.LogLevel expected'debug', it is", d.Config.LogLevel)
 
- 	}
 
- 	if len(d.Config.Servers) != 1 {
 
- 		t.Error("len(smtp.config.Servers) should be 1, got", len(d.Config.Servers))
 
- 	}
 
- 	time.Sleep(time.Second * 2)
 
- 	d.Shutdown()
 
- 	done <- true
 
- }
 
- // Suppressing log output
 
- func TestSMTPNoLog(t *testing.T) {
 
- 	// configure a default server with no log output
 
- 	cfg := &AppConfig{LogFile: log.OutputOff.String()}
 
- 	d := Daemon{Config: cfg}
 
- 	err := d.Start()
 
- 	if err != nil {
 
- 		t.Error(err)
 
- 	}
 
- 	time.Sleep(time.Second * 2)
 
- 	d.Shutdown()
 
- }
 
- // our custom server
 
- func TestSMTPCustomServer(t *testing.T) {
 
- 	cfg := &AppConfig{LogFile: log.OutputOff.String()}
 
- 	sc := ServerConfig{
 
- 		ListenInterface: "127.0.0.1:2526",
 
- 		IsEnabled:       true,
 
- 	}
 
- 	cfg.Servers = append(cfg.Servers, sc)
 
- 	d := Daemon{Config: cfg}
 
- 	err := d.Start()
 
- 	if err != nil {
 
- 		t.Error("start error", err)
 
- 	} else {
 
- 		time.Sleep(time.Second * 2)
 
- 		d.Shutdown()
 
- 	}
 
- }
 
- // with a backend config
 
- func TestSMTPCustomBackend(t *testing.T) {
 
- 	cfg := &AppConfig{LogFile: log.OutputOff.String()}
 
- 	sc := ServerConfig{
 
- 		ListenInterface: "127.0.0.1:2526",
 
- 		IsEnabled:       true,
 
- 	}
 
- 	cfg.Servers = append(cfg.Servers, sc)
 
- 	bcfg := backends.BackendConfig{
 
- 		"save_workers_size":  3,
 
- 		"save_process":       "HeadersParser|Header|Hasher|Debugger",
 
- 		"log_received_mails": true,
 
- 		"primary_mail_host":  "example.com",
 
- 	}
 
- 	cfg.BackendConfig = bcfg
 
- 	d := Daemon{Config: cfg}
 
- 	err := d.Start()
 
- 	if err != nil {
 
- 		t.Error("start error", err)
 
- 	} else {
 
- 		time.Sleep(time.Second * 2)
 
- 		d.Shutdown()
 
- 	}
 
- }
 
- // with a config from a json file
 
- func TestSMTPLoadFile(t *testing.T) {
 
- 	json := `{
 
-     "log_file" : "./tests/testlog",
 
-     "log_level" : "debug",
 
-     "pid_file" : "tests/go-guerrilla.pid",
 
-     "allowed_hosts": ["spam4.me","grr.la"],
 
-     "backend_config" :
 
-         {
 
-             "log_received_mails" : true,
 
-             "save_process": "HeadersParser|Header|Hasher|Debugger",
 
-             "save_workers_size":  3
 
-         },
 
-     "servers" : [
 
-         {
 
-             "is_enabled" : true,
 
-             "host_name":"mail.guerrillamail.com",
 
-             "max_size": 100017,
 
-             "timeout":160,
 
-             "listen_interface":"127.0.0.1:2526",
 
-             "max_clients": 2,
 
- 			"tls" : {
 
- 				"private_key_file":"config_test.go",
 
-             	"public_key_file":"config_test.go",
 
- 				"start_tls_on":false,
 
-             	"tls_always_on":false
 
- 			}
 
-         }
 
-     ]
 
- }
 
- 	`
 
- 	json2 := `{
 
-     "log_file" : "./tests/testlog2",
 
-     "log_level" : "debug",
 
-     "pid_file" : "tests/go-guerrilla2.pid",
 
-     "allowed_hosts": ["spam4.me","grr.la"],
 
-     "backend_config" :
 
-         {
 
-             "log_received_mails" : true,
 
-             "save_process": "HeadersParser|Header|Hasher|Debugger",
 
-             "save_workers_size":  3
 
-         },
 
-     "servers" : [
 
-         {
 
-             "is_enabled" : true,
 
-             "host_name":"mail.guerrillamail.com",
 
-             "max_size": 100017,
 
-             "timeout":160,
 
-             "listen_interface":"127.0.0.1:2526",
 
-             "max_clients": 2,
 
- 			"tls" : {
 
-  				"private_key_file":"config_test.go",
 
- 				"public_key_file":"config_test.go",
 
- 				"start_tls_on":false,
 
-             	"tls_always_on":false
 
- 			}
 
-         }
 
-     ]
 
- }
 
- 	`
 
- 	err := ioutil.WriteFile("goguerrilla.conf.api", []byte(json), 0644)
 
- 	if err != nil {
 
- 		t.Error("could not write guerrilla.conf.api", err)
 
- 		return
 
- 	}
 
- 	d := Daemon{}
 
- 	_, err = d.LoadConfig("goguerrilla.conf.api")
 
- 	if err != nil {
 
- 		t.Error("ReadConfig error", err)
 
- 		return
 
- 	}
 
- 	err = d.Start()
 
- 	if err != nil {
 
- 		t.Error("start error", err)
 
- 		return
 
- 	} else {
 
- 		time.Sleep(time.Second * 2)
 
- 		if d.Config.LogFile != "./tests/testlog" {
 
- 			t.Error("d.Config.LogFile != \"./tests/testlog\"")
 
- 		}
 
- 		if d.Config.PidFile != "tests/go-guerrilla.pid" {
 
- 			t.Error("d.Config.LogFile != tests/go-guerrilla.pid")
 
- 		}
 
- 		err := ioutil.WriteFile("goguerrilla.conf.api", []byte(json2), 0644)
 
- 		if err != nil {
 
- 			t.Error("could not write guerrilla.conf.api", err)
 
- 			return
 
- 		}
 
- 		d.ReloadConfigFile("goguerrilla.conf.api")
 
- 		if d.Config.LogFile != "./tests/testlog2" {
 
- 			t.Error("d.Config.LogFile != \"./tests/testlog\"")
 
- 		}
 
- 		if d.Config.PidFile != "tests/go-guerrilla2.pid" {
 
- 			t.Error("d.Config.LogFile != \"go-guerrilla.pid\"")
 
- 		}
 
- 		d.Shutdown()
 
- 	}
 
- }
 
- func TestReopenLog(t *testing.T) {
 
- 	os.Truncate("test/testlog", 0)
 
- 	cfg := &AppConfig{LogFile: "tests/testlog"}
 
- 	sc := ServerConfig{
 
- 		ListenInterface: "127.0.0.1:2526",
 
- 		IsEnabled:       true,
 
- 	}
 
- 	cfg.Servers = append(cfg.Servers, sc)
 
- 	d := Daemon{Config: cfg}
 
- 	err := d.Start()
 
- 	if err != nil {
 
- 		t.Error("start error", err)
 
- 	} else {
 
- 		d.ReopenLogs()
 
- 		time.Sleep(time.Second * 2)
 
- 		d.Shutdown()
 
- 	}
 
- 	b, err := ioutil.ReadFile("tests/testlog")
 
- 	if err != nil {
 
- 		t.Error("could not read logfile")
 
- 		return
 
- 	}
 
- 	if strings.Index(string(b), "re-opened log file") < 0 {
 
- 		t.Error("Server log did not re-opened, expecting \"re-opened log file\"")
 
- 	}
 
- 	if strings.Index(string(b), "re-opened main log file") < 0 {
 
- 		t.Error("Main log did not re-opened, expecting \"re-opened main log file\"")
 
- 	}
 
- }
 
- func TestSetConfig(t *testing.T) {
 
- 	os.Truncate("test/testlog", 0)
 
- 	cfg := AppConfig{LogFile: "tests/testlog"}
 
- 	sc := ServerConfig{
 
- 		ListenInterface: "127.0.0.1:2526",
 
- 		IsEnabled:       true,
 
- 	}
 
- 	cfg.Servers = append(cfg.Servers, sc)
 
- 	d := Daemon{Config: &cfg}
 
- 	// lets add a new server
 
- 	sc.ListenInterface = "127.0.0.1:2527"
 
- 	cfg.Servers = append(cfg.Servers, sc)
 
- 	err := d.SetConfig(cfg)
 
- 	if err != nil {
 
- 		t.Error("SetConfig returned an error:", err)
 
- 		return
 
- 	}
 
- 	err = d.Start()
 
- 	if err != nil {
 
- 		t.Error("start error", err)
 
- 	} else {
 
- 		time.Sleep(time.Second * 2)
 
- 		d.Shutdown()
 
- 	}
 
- 	b, err := ioutil.ReadFile("tests/testlog")
 
- 	if err != nil {
 
- 		t.Error("could not read logfile")
 
- 		return
 
- 	}
 
- 	//fmt.Println(string(b))
 
- 	// has 127.0.0.1:2527 started?
 
- 	if strings.Index(string(b), "127.0.0.1:2527") < 0 {
 
- 		t.Error("expecting 127.0.0.1:2527 to start")
 
- 	}
 
- }
 
- func TestSetConfigError(t *testing.T) {
 
- 	os.Truncate("tests/testlog", 0)
 
- 	cfg := AppConfig{LogFile: "tests/testlog"}
 
- 	sc := ServerConfig{
 
- 		ListenInterface: "127.0.0.1:2526",
 
- 		IsEnabled:       true,
 
- 	}
 
- 	cfg.Servers = append(cfg.Servers, sc)
 
- 	d := Daemon{Config: &cfg}
 
- 	// lets add a new server with bad TLS
 
- 	sc.ListenInterface = "127.0.0.1:2527"
 
- 	sc.TLS.StartTLSOn = true
 
- 	sc.TLS.PublicKeyFile = "tests/testlog"  // totally wrong :->
 
- 	sc.TLS.PrivateKeyFile = "tests/testlog" // totally wrong :->
 
- 	cfg.Servers = append(cfg.Servers, sc)
 
- 	err := d.SetConfig(cfg)
 
- 	if err == nil {
 
- 		t.Error("SetConfig should have returned an error compalning about bad tls settings")
 
- 		return
 
- 	}
 
- }
 
- var funkyLogger = func() backends.Decorator {
 
- 	backends.Svc.AddInitializer(
 
- 		backends.InitializeWith(
 
- 			func(backendConfig backends.BackendConfig) error {
 
- 				backends.Log().Info("Funky logger is up & down to funk!")
 
- 				return nil
 
- 			}),
 
- 	)
 
- 	backends.Svc.AddShutdowner(
 
- 		backends.ShutdownWith(
 
- 			func() error {
 
- 				backends.Log().Info("The funk has been stopped!")
 
- 				return nil
 
- 			}),
 
- 	)
 
- 	return func(p backends.Processor) backends.Processor {
 
- 		return backends.ProcessWith(
 
- 			func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
 
- 				if task == backends.TaskValidateRcpt {
 
- 					// log the last recipient appended to e.Rcpt
 
- 					backends.Log().Infof(
 
- 						"another funky recipient [%s]",
 
- 						e.RcptTo[len(e.RcptTo)-1])
 
- 					// if valid then forward call to the next processor in the chain
 
- 					return p.Process(e, task)
 
- 					// if invalid, return a backend result
 
- 					//return backends.NewResult(response.Canned.FailRcptCmd), nil
 
- 				} else if task == backends.TaskSaveMail {
 
- 					backends.Log().Info("Another funky email!")
 
- 				}
 
- 				return p.Process(e, task)
 
- 			})
 
- 	}
 
- }
 
- // How about a custom processor?
 
- func TestSetAddProcessor(t *testing.T) {
 
- 	os.Truncate("tests/testlog", 0)
 
- 	cfg := &AppConfig{
 
- 		LogFile:      "tests/testlog",
 
- 		AllowedHosts: []string{"grr.la"},
 
- 		BackendConfig: backends.BackendConfig{
 
- 			"save_process":     "HeadersParser|Debugger|FunkyLogger",
 
- 			"validate_process": "FunkyLogger",
 
- 		},
 
- 	}
 
- 	d := Daemon{Config: cfg}
 
- 	d.AddProcessor("FunkyLogger", funkyLogger)
 
- 	d.Start()
 
- 	// lets have a talk with the server
 
- 	talkToServer("127.0.0.1:2525")
 
- 	d.Shutdown()
 
- 	b, err := ioutil.ReadFile("tests/testlog")
 
- 	if err != nil {
 
- 		t.Error("could not read logfile")
 
- 		return
 
- 	}
 
- 	// lets check for fingerprints
 
- 	if strings.Index(string(b), "another funky recipient") < 0 {
 
- 		t.Error("did not log: another funky recipient")
 
- 	}
 
- 	if strings.Index(string(b), "Another funky email!") < 0 {
 
- 		t.Error("Did not log: Another funky email!")
 
- 	}
 
- 	if strings.Index(string(b), "Funky logger is up & down to funk") < 0 {
 
- 		t.Error("Did not log: Funky logger is up & down to funk")
 
- 	}
 
- 	if strings.Index(string(b), "The funk has been stopped!") < 0 {
 
- 		t.Error("Did not log:The funk has been stopped!")
 
- 	}
 
- }
 
- func talkToServer(address string) {
 
- 	conn, err := net.Dial("tcp", address)
 
- 	if err != nil {
 
- 		return
 
- 	}
 
- 	in := bufio.NewReader(conn)
 
- 	str, err := in.ReadString('\n')
 
- 	fmt.Fprint(conn, "HELO maildiranasaurustester\r\n")
 
- 	str, err = in.ReadString('\n')
 
- 	fmt.Fprint(conn, "MAIL FROM:<[email protected]>r\r\n")
 
- 	str, err = in.ReadString('\n')
 
- 	fmt.Fprint(conn, "RCPT TO:[email protected]\r\n")
 
- 	str, err = in.ReadString('\n')
 
- 	fmt.Fprint(conn, "DATA\r\n")
 
- 	str, err = in.ReadString('\n')
 
- 	fmt.Fprint(conn, "Subject: Test subject\r\n")
 
- 	fmt.Fprint(conn, "\r\n")
 
- 	fmt.Fprint(conn, "A an email body\r\n")
 
- 	fmt.Fprint(conn, ".\r\n")
 
- 	str, err = in.ReadString('\n')
 
- 	_ = str
 
- }
 
- // Test hot config reload
 
- // Here we forgot to add FunkyLogger so backend will fail to init
 
- func TestReloadConfig(t *testing.T) {
 
- 	os.Truncate("tests/testlog", 0)
 
- 	d := Daemon{}
 
- 	d.Start()
 
- 	defer d.Shutdown()
 
- 	cfg := AppConfig{
 
- 		LogFile:      "tests/testlog",
 
- 		AllowedHosts: []string{"grr.la"},
 
- 		BackendConfig: backends.BackendConfig{
 
- 			"save_process":     "HeadersParser|Debugger|FunkyLogger",
 
- 			"validate_process": "FunkyLogger",
 
- 		},
 
- 	}
 
- 	// Look mom, reloading the config without shutting down!
 
- 	d.ReloadConfig(cfg)
 
- }
 
- func TestPubSubAPI(t *testing.T) {
 
- 	os.Truncate("tests/testlog", 0)
 
- 	d := Daemon{Config: &AppConfig{LogFile: "tests/testlog"}}
 
- 	d.Start()
 
- 	defer d.Shutdown()
 
- 	// new config
 
- 	cfg := AppConfig{
 
- 		PidFile:      "tests/pidfilex.pid",
 
- 		LogFile:      "tests/testlog",
 
- 		AllowedHosts: []string{"grr.la"},
 
- 		BackendConfig: backends.BackendConfig{
 
- 			"save_process":     "HeadersParser|Debugger|FunkyLogger",
 
- 			"validate_process": "FunkyLogger",
 
- 		},
 
- 	}
 
- 	var i = 0
 
- 	pidEvHandler := func(c *AppConfig) {
 
- 		i++
 
- 		if i > 1 {
 
- 			t.Error("number > 1, it means d.Unsubscribe didn't work")
 
- 		}
 
- 		d.Logger.Info("number", i)
 
- 	}
 
- 	d.Subscribe(EventConfigPidFile, pidEvHandler)
 
- 	d.ReloadConfig(cfg)
 
- 	d.Unsubscribe(EventConfigPidFile, pidEvHandler)
 
- 	cfg.PidFile = "tests/pidfile2.pid"
 
- 	d.Publish(EventConfigPidFile, &cfg)
 
- 	d.ReloadConfig(cfg)
 
- 	b, err := ioutil.ReadFile("tests/testlog")
 
- 	if err != nil {
 
- 		t.Error("could not read logfile")
 
- 		return
 
- 	}
 
- 	// lets interrogate the log
 
- 	if strings.Index(string(b), "number1") < 0 {
 
- 		t.Error("it lools like d.ReloadConfig(cfg) did not fire EventConfigPidFile, pidEvHandler not called")
 
- 	}
 
- }
 
- func TestAPILog(t *testing.T) {
 
- 	os.Truncate("tests/testlog", 0)
 
- 	d := Daemon{}
 
- 	l := d.Log()
 
- 	l.Info("logtest1") // to stderr
 
- 	if l.GetLevel() != log.InfoLevel.String() {
 
- 		t.Error("Log level does not eq info, it is ", l.GetLevel())
 
- 	}
 
- 	d.Logger = nil
 
- 	d.Config = &AppConfig{LogFile: "tests/testlog"}
 
- 	l = d.Log()
 
- 	l.Info("logtest1") // to tests/testlog
 
- 	//
 
- 	l = d.Log()
 
- 	if l.GetLogDest() != "tests/testlog" {
 
- 		t.Error("log dest is not tests/testlog, it was ", l.GetLogDest())
 
- 	}
 
- 	b, err := ioutil.ReadFile("tests/testlog")
 
- 	if err != nil {
 
- 		t.Error("could not read logfile")
 
- 		return
 
- 	}
 
- 	// lets interrogate the log
 
- 	if strings.Index(string(b), "logtest1") < 0 {
 
- 		t.Error("hai was not found in the log, it should have been in tests/testlog")
 
- 	}
 
- }
 
- // Test the allowed_hosts config option with a single entry of ".", which will allow all hosts.
 
- func TestSkipAllowsHost(t *testing.T) {
 
- 	d := Daemon{}
 
- 	defer d.Shutdown()
 
- 	// setting the allowed hosts to a single entry with a dot will let any host through
 
- 	d.Config = &AppConfig{AllowedHosts: []string{"."}, LogFile: "off"}
 
- 	d.Start()
 
- 	conn, err := net.Dial("tcp", d.Config.Servers[0].ListenInterface)
 
- 	if err != nil {
 
- 		t.Error(t)
 
- 		return
 
- 	}
 
- 	in := bufio.NewReader(conn)
 
- 	fmt.Fprint(conn, "HELO test\r\n")
 
- 	fmt.Fprint(conn, "RCPT TO: [email protected]\r\n")
 
- 	in.ReadString('\n')
 
- 	in.ReadString('\n')
 
- 	str, _ := in.ReadString('\n')
 
- 	if strings.Index(str, "250") != 0 {
 
- 		t.Error("expected 250 reply, got:", str)
 
- 	}
 
- }
 
- var customBackend2 = func() backends.Decorator {
 
- 	return func(p backends.Processor) backends.Processor {
 
- 		return backends.ProcessWith(
 
- 			func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
 
- 				if task == backends.TaskValidateRcpt {
 
- 					return p.Process(e, task)
 
- 				} else if task == backends.TaskSaveMail {
 
- 					backends.Log().Info("Another funky email!")
 
- 					err := errors.New("system shock")
 
- 					return backends.NewResult(response.Canned.FailReadErrorDataCmd, response.SP, err), err
 
- 				}
 
- 				return p.Process(e, task)
 
- 			})
 
- 	}
 
- }
 
- // Test a custom backend response
 
- func TestCustomBackendResult(t *testing.T) {
 
- 	os.Truncate("tests/testlog", 0)
 
- 	cfg := &AppConfig{
 
- 		LogFile:      "tests/testlog",
 
- 		AllowedHosts: []string{"grr.la"},
 
- 		BackendConfig: backends.BackendConfig{
 
- 			"save_process":     "HeadersParser|Debugger|Custom",
 
- 			"validate_process": "Custom",
 
- 		},
 
- 	}
 
- 	d := Daemon{Config: cfg}
 
- 	d.AddProcessor("Custom", customBackend2)
 
- 	if err := d.Start(); err != nil {
 
- 		t.Error(err)
 
- 	}
 
- 	// lets have a talk with the server
 
- 	talkToServer("127.0.0.1:2525")
 
- 	d.Shutdown()
 
- 	b, err := ioutil.ReadFile("tests/testlog")
 
- 	if err != nil {
 
- 		t.Error("could not read logfile")
 
- 		return
 
- 	}
 
- 	// lets check for fingerprints
 
- 	if strings.Index(string(b), "451 4.3.0 Error") < 0 {
 
- 		t.Error("did not log: 451 4.3.0 Error")
 
- 	}
 
- 	if strings.Index(string(b), "system shock") < 0 {
 
- 		t.Error("did not log: system shock")
 
- 	}
 
- }
 
 
  |