func GetProductionMTAContainer() (mtacontainer.MTAContainer, mtacontainer.Scheduler) { var passphrase = GetPassphraseFromArgOrTerminal() var mailGunConfig = mailgunprovider.BitLabConfig(passphrase) var amazonConfig = amazonsesprovider.BitLabConfig(passphrase) var sendgridConfig = sendgridprovider.BitLabConfig(passphrase) providers := make([]mtacontainer.MTAProvider, 3) providers[0] = mailgunprovider.New(utilities.GetLogger("MailGun"), mailGunConfig, mtacontainer.NewThressHoldFailureStrategy(ERROR_THRESHOLD)) providers[1] = amazonsesprovider.New(utilities.GetLogger("amazonSES"), amazonConfig, mtacontainer.NewThressHoldFailureStrategy(ERROR_THRESHOLD)) providers[2] = sendgridprovider.New(utilities.GetLogger("SendGrid"), sendgridConfig, mtacontainer.NewThressHoldFailureStrategy(ERROR_THRESHOLD)) var scheduler mtacontainer.Scheduler = mtacontainer.NewRoundRobinScheduler(providers) return mtacontainer.New(scheduler), scheduler }
// // An MTA Provider is expected to report EK_FATAL // right before it shuts down. // // Unit under test: Any MTAProvider // // func Test_check_fatal_event_on_shutdown(t *testing.T) { c := make(chan int) events := make([]mtacontainer.Event, 0) provider := loopbackprovider.New(utilities.GetLogger("Loop"), NewMockFailureStrategy()) go func() { for { select { case e := <-provider.GetEvent(): events = append(events, e) case <-c: return } } }() provider.Stop() if len(events) == 0 { t.Error("Expected at least one event EK_FATAL event...") } c <- 0 foundFatal := false for i := range events { if events[i].GetKind() == mtacontainer.EK_FATAL { foundFatal = true } } if foundFatal == false { t.Error("Expected one fatal event") } }
// ------------------------------------------ // // // End 2 End test of the MTAContainer with Failure strategy // and RoundRobinSchedule. // // func TestEnd2End(t *testing.T) { // mg := mailgunprovider.New(utilities.GetLogger("MG"),mailgunprovider.BitLabConfig("09fe27"),NewMockFailureStrategy()); // az := amazonsesprovider.New(utilities.GetLogger("MG"),amazonsesprovider.BitLabConfig("09fe27"),NewMockFailureStrategy()); // sg := sendgridprovider.New(utilities.GetLogger("MG"),sendgridprovider.BitLabConfig("09fe27"),NewMockFailureStrategy()); var provider = loopbackprovider.New(utilities.GetLogger("loop1"), mtacontainer.NewThressHoldFailureStrategy(12)) scheduler := mtacontainer.NewRoundRobinScheduler([]mtacontainer.MTAProvider{provider}) container := mtacontainer.New(scheduler) mail1 := FreshTestMail(provider, "*****@*****.**") mail2 := FreshTestMail(provider, "*****@*****.**") mail3 := FreshTestMail(provider, "*****@*****.**") container.GetOutgoing() <- mail1 container.GetOutgoing() <- mail2 container.GetOutgoing() <- mail3 go func() { <-container.GetIncoming() }() i := 0 for { select { case e := <-container.GetEvent(): log.Println("Reading event from container: " + e.GetError().Error()) if i == 2 { return } i = i + 1 } } }
func NewReceiveBackend(store JSonStore) *ReceiveBackEnd { var res *ReceiveBackEnd = new(ReceiveBackEnd) res.store = store res.incoming = make(chan model.Email) res.events = make(chan mtacontainer.Event) res.cmd = make(chan int) res.log = utilities.GetLogger("[Backend Server]", os.Stdout) go res.ListenForClientApi() return res }
func main() { if len(os.Args) < 3 { println("manual_test <to address> <key>") return } to := os.Args[1] key := os.Args[2] mailgunMTAProvider := mailgunprovider.New(utilities.GetLogger("MailGun"), mailgunprovider.BitLabConfig(key), test.NewMockFailureStrategy()) test.ManuallyVerifyEmailSend(mailgunMTAProvider, to) }
func main() { if len(os.Args) < 3 { println("manual_test <to address> <key>") return } to := os.Args[1] key := os.Args[2] config := sendgridprovider.BitLabConfig(key) sendgridMTAProvider := sendgridprovider.New(utilities.GetLogger("SendGrid"), config, test.NewMockFailureStrategy()) test.ManuallyVerifyEmailSend(sendgridMTAProvider, to) }
func Test_one_failover(t *testing.T) { loop1 := loopbackprovider.New(utilities.GetLogger("loop1"), new(FailImmediatelyFailureStrategy)) loop2 := loopbackprovider.New(utilities.GetLogger("loop2"), NewMockFailureStrategy()) scheduler := mtacontainer.NewRoundRobinScheduler([]mtacontainer.MTAProvider{loop1, loop2}) container := mtacontainer.New(scheduler) mail := FreshTestMail(loop1, "*****@*****.**") go func() { container.GetOutgoing() <- mail for { select { case evt := <-container.GetEvent(): log.Println(evt.GetError().Error()) } } }() // the round robin scheduler will schedule {loop1} which fails immediately // we expect to see {mail} emerge on the {GetIncoming} channel of {loop2} // because it has been RESUBMITTET to {loop2} by the fail over mechanism in // the MTAContainer. mailPrime, ok := <-loop2.GetIncoming() if ok == false { t.Error("loop2 incoming failed to provide emai.") } if mailPrime != mail { t.Error("Wrong mail") } }
// -------------------------------------------------------- // // Creates a Server for the website ClientApi // // // // -------------------------------------------------------- func New(docRoot string, port int) *ClientAPI { var result = new(ClientAPI) result.docRoot = docRoot result.events = make(chan mtacontainer.Event) result.port = port result.log = utilities.GetLogger("[client api] ", os.Stdout) result.validSessions = make(map[string]string) versionStr, versionStrErr := ioutil.ReadFile(result.docRoot + "/version.txt") result.pendingMessages = make(map[string][]string) if versionStrErr != nil { result.versionStr = "No Version" result.log.Println(versionStrErr.Error()) } else { result.versionStr = string(versionStr) } go result.serve() go result.listenMta() return result }
func Test_all_failover(t *testing.T) { loop1 := loopbackprovider.New(utilities.GetLogger("loop1"), new(FailImmediatelyFailureStrategy)) scheduler := mtacontainer.NewRoundRobinScheduler([]mtacontainer.MTAProvider{loop1}) container := mtacontainer.New(scheduler) go func() { mail := FreshTestMail(loop1, "*****@*****.**") container.GetOutgoing() <- mail for { select { case evt := <-container.GetEvent(): log.Println(evt.GetError().Error()) } } }() }
func TestLoopBack(t *testing.T) { loop1 := loopbackprovider.New(utilities.GetLogger("loop1"), mtacontainer.NewThressHoldFailureStrategy(1)) mail := test.FreshTestMail(loop1, "test") c := make(chan int) go func() { for { select { case <-loop1.GetEvent(): case <-c: } } }() loop1.GetOutgoing() <- mail <-loop1.GetIncoming() }
func main() { // // say hello // utilities.PrintGreeting(os.Stdout) // // Initialize logger for stdout for this mtaserver. // log := utilities.GetLogger("mtaserver") log.Print("Initial logger created, hi Log ") // // Start Container (ask for passphrase if necessary) // var container, _ = GetProductionMTAContainer() //var container, scheduler = GetLoopBackContainer(); // // Print Events that occurs until GOOD_BYE. // for { e := <-container.GetEvent() log.Println(e.GetError()) if e.GetKind() == mtacontainer.EK_GOOD_BYE { break } if e.GetKind() == mtacontainer.EK_INFORM_USER { postUserMessageWithClientAPI(e.GetError().Error(), e.GetPayload().(string)) } } return }
func GetLoopBackContainer() (mtacontainer.MTAContainer, mtacontainer.Scheduler) { var provider = loopbackprovider.New(utilities.GetLogger("LoopBack"), mtacontainer.NewThressHoldFailureStrategy(ERROR_THRESHOLD)) var scheduler = mtacontainer.NewRoundRobinScheduler([]mtacontainer.MTAProvider{provider}) return mtacontainer.New(scheduler), scheduler }
// // Public constructor for creating a DefaultMTAContainer. // func New(scheduler Scheduler) MTAContainer { if scheduler == nil { return nil } var result = new(DefaultMTAContainer) result.providers = scheduler.GetProviders() result.incoming = make(chan model.Email) result.outgoing = make(chan model.Email) result.events = make(chan Event) result.log = utilities.GetLogger("MTAContainer") result.scheduler = scheduler // Aggregate all provider incoming and event channels to those of the MTAContainer for p := range result.providers { var pp MTAProvider = result.providers[p] // incoming go func() { for { var in = pp.GetIncoming() var email, ok = <-in // suppose an MTA some day delivers an email it happens here if ok == false { result.log.Println("Incoming was closed.") } result.incoming <- email } }() // // Manage MTAProviders // go func() { for { var evt = pp.GetEvent() var event, ok = <-evt if ok == false { result.log.Println("Event channel was closed. Terminating event listener.") return } // // Fail over // if event.GetKind() == EK_RESUBMIT { mail, ok := event.GetPayload().(model.Email) if ok { result.outgoing <- mail } } // // Remove dead service from schedule // if event.GetKind() == EK_FATAL { provider, ok := event.GetPayload().(MTAProvider) if ok { result.scheduler.RemoveProviderFromService(provider) if len(result.scheduler.GetProviders()) < 1 { result.log.Println("No MTA Providers left we shutdown.") result.Stop() result.events <- NewEvent(EK_GOOD_BYE, errors.New("Container shuts down")) return } } } result.events <- event } }() } // upon receiving an e-mail to send, schedule and dispatch go func() { for { var email = <-result.outgoing provider := result.scheduler.Schedule() if provider == nil { result.log.Println("Scheduler gave nil Provider") n := len(result.outgoing) for j := 0; j < n; j++ { result.events <- NewEvent(EK_INFORM_USER, errors.New("No MTAs availble email not sent: "+ email.GetHeader(model.EML_HDR_SUBJECT)), email.GetSessionId()) } return // no more MTAs } result.log.Println("Scheduling mail for sending on " + provider.GetName()) provider.GetOutgoing() <- email } }() go result.forwardIncomingMailToBackend() go result.listenForSendBackEnd() return result }