mirror of
https://github.com/gophish/gophish
synced 2024-11-14 00:07:19 +00:00
8162a80cb1
Adding the ability to cache campaigns on maillogs to greatly improve generation time (and, by extension, sending speed and memory usage).
337 lines
9.7 KiB
Go
337 lines
9.7 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
check "gopkg.in/check.v1"
|
|
)
|
|
|
|
func (s *ModelsSuite) TestGenerateSendDate(c *check.C) {
|
|
campaign := s.createCampaignDependencies(c)
|
|
// Test that if no launch date is provided, the campaign's creation date
|
|
// is used.
|
|
err := PostCampaign(&campaign, campaign.UserId)
|
|
c.Assert(err, check.Equals, nil)
|
|
c.Assert(campaign.LaunchDate, check.Equals, campaign.CreatedDate)
|
|
|
|
// For comparing the dates, we need to fetch the campaign again. This is
|
|
// to solve an issue where the campaign object right now has time down to
|
|
// the microsecond, while in MySQL it's rounded down to the second.
|
|
campaign, _ = GetCampaign(campaign.Id, campaign.UserId)
|
|
|
|
ms, err := GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
for _, m := range ms {
|
|
c.Assert(m.SendDate, check.Equals, campaign.CreatedDate)
|
|
}
|
|
|
|
// Test that if no send date is provided, all the emails are sent at the
|
|
// campaign's launch date
|
|
campaign = s.createCampaignDependencies(c)
|
|
campaign.LaunchDate = time.Now().UTC()
|
|
err = PostCampaign(&campaign, campaign.UserId)
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
campaign, _ = GetCampaign(campaign.Id, campaign.UserId)
|
|
|
|
ms, err = GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
for _, m := range ms {
|
|
c.Assert(m.SendDate, check.Equals, campaign.LaunchDate)
|
|
}
|
|
|
|
// Finally, test that if a send date is provided, the emails are staggered
|
|
// correctly.
|
|
campaign = s.createCampaignDependencies(c)
|
|
campaign.LaunchDate = time.Now().UTC()
|
|
campaign.SendByDate = campaign.LaunchDate.Add(2 * time.Minute)
|
|
err = PostCampaign(&campaign, campaign.UserId)
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
campaign, _ = GetCampaign(campaign.Id, campaign.UserId)
|
|
|
|
ms, err = GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
sendingOffset := 2 / float64(len(ms))
|
|
for i, m := range ms {
|
|
expectedOffset := int(sendingOffset * float64(i))
|
|
expectedDate := campaign.LaunchDate.Add(time.Duration(expectedOffset) * time.Minute)
|
|
c.Assert(m.SendDate, check.Equals, expectedDate)
|
|
}
|
|
}
|
|
|
|
func (s *ModelsSuite) TestCampaignDateValidation(c *check.C) {
|
|
campaign := s.createCampaignDependencies(c)
|
|
// If both are zero, then the campaign should start immediately with no
|
|
// send by date
|
|
err := campaign.Validate()
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
// If the launch date is specified, then the send date is optional
|
|
campaign = s.createCampaignDependencies(c)
|
|
campaign.LaunchDate = time.Now().UTC()
|
|
err = campaign.Validate()
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
// If the send date is greater than the launch date, then there's no
|
|
//problem
|
|
campaign = s.createCampaignDependencies(c)
|
|
campaign.LaunchDate = time.Now().UTC()
|
|
campaign.SendByDate = campaign.LaunchDate.Add(1 * time.Minute)
|
|
err = campaign.Validate()
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
// If the send date is less than the launch date, then there's an issue
|
|
campaign = s.createCampaignDependencies(c)
|
|
campaign.LaunchDate = time.Now().UTC()
|
|
campaign.SendByDate = campaign.LaunchDate.Add(-1 * time.Minute)
|
|
err = campaign.Validate()
|
|
c.Assert(err, check.Equals, ErrInvalidSendByDate)
|
|
}
|
|
|
|
func (s *ModelsSuite) TestLaunchCampaignMaillogStatus(c *check.C) {
|
|
// For the first test, ensure that campaigns created with the zero date
|
|
// (and therefore are set to launch immediately) have maillogs that are
|
|
// locked to prevent race conditions.
|
|
campaign := s.createCampaign(c)
|
|
ms, err := GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
for _, m := range ms {
|
|
c.Assert(m.Processing, check.Equals, true)
|
|
}
|
|
|
|
// Next, verify that campaigns scheduled in the future do not lock the
|
|
// maillogs so that they can be picked up by the background worker.
|
|
campaign = s.createCampaignDependencies(c)
|
|
campaign.Name = "New Campaign"
|
|
campaign.LaunchDate = time.Now().Add(1 * time.Hour)
|
|
c.Assert(PostCampaign(&campaign, campaign.UserId), check.Equals, nil)
|
|
ms, err = GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
for _, m := range ms {
|
|
c.Assert(m.Processing, check.Equals, false)
|
|
}
|
|
}
|
|
|
|
func (s *ModelsSuite) TestDeleteCampaignAlsoDeletesMailLogs(c *check.C) {
|
|
campaign := s.createCampaign(c)
|
|
ms, err := GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
c.Assert(len(ms), check.Equals, len(campaign.Results))
|
|
|
|
err = DeleteCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
ms, err = GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
c.Assert(len(ms), check.Equals, 0)
|
|
}
|
|
|
|
func (s *ModelsSuite) TestCompleteCampaignAlsoDeletesMailLogs(c *check.C) {
|
|
campaign := s.createCampaign(c)
|
|
ms, err := GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
c.Assert(len(ms), check.Equals, len(campaign.Results))
|
|
|
|
err = CompleteCampaign(campaign.Id, campaign.UserId)
|
|
c.Assert(err, check.Equals, nil)
|
|
|
|
ms, err = GetMailLogsByCampaign(campaign.Id)
|
|
c.Assert(err, check.Equals, nil)
|
|
c.Assert(len(ms), check.Equals, 0)
|
|
}
|
|
|
|
func (s *ModelsSuite) TestCampaignGetResults(c *check.C) {
|
|
campaign := s.createCampaign(c)
|
|
got, err := GetCampaign(campaign.Id, campaign.UserId)
|
|
c.Assert(err, check.Equals, nil)
|
|
c.Assert(len(campaign.Results), check.Equals, len(got.Results))
|
|
}
|
|
|
|
func setupCampaignDependencies(b *testing.B, size int) {
|
|
group := Group{Name: "Test Group"}
|
|
// Create a large group of 5000 members
|
|
for i := 0; i < size; i++ {
|
|
group.Targets = append(group.Targets, Target{BaseRecipient: BaseRecipient{Email: fmt.Sprintf("test%d@example.com", i), FirstName: "User", LastName: fmt.Sprintf("%d", i)}})
|
|
}
|
|
group.UserId = 1
|
|
err := PostGroup(&group)
|
|
if err != nil {
|
|
b.Fatalf("error posting group: %v", err)
|
|
}
|
|
|
|
// Add a template
|
|
template := Template{Name: "Test Template"}
|
|
template.Subject = "{{.RId}} - Subject"
|
|
template.Text = "{{.RId}} - Text"
|
|
template.HTML = "{{.RId}} - HTML"
|
|
template.UserId = 1
|
|
err = PostTemplate(&template)
|
|
if err != nil {
|
|
b.Fatalf("error posting template: %v", err)
|
|
}
|
|
|
|
// Add a landing page
|
|
p := Page{Name: "Test Page"}
|
|
p.HTML = "<html>Test</html>"
|
|
p.UserId = 1
|
|
err = PostPage(&p)
|
|
if err != nil {
|
|
b.Fatalf("error posting page: %v", err)
|
|
}
|
|
|
|
// Add a sending profile
|
|
smtp := SMTP{Name: "Test Page"}
|
|
smtp.UserId = 1
|
|
smtp.Host = "example.com"
|
|
smtp.FromAddress = "test@test.com"
|
|
err = PostSMTP(&smtp)
|
|
if err != nil {
|
|
b.Fatalf("error posting smtp: %v", err)
|
|
}
|
|
}
|
|
|
|
// setupCampaign sets up the campaign dependencies as well as posting the
|
|
// actual campaign
|
|
func setupCampaign(b *testing.B, size int) Campaign {
|
|
setupCampaignDependencies(b, size)
|
|
campaign := Campaign{Name: "Test campaign"}
|
|
campaign.UserId = 1
|
|
campaign.Template = Template{Name: "Test Template"}
|
|
campaign.Page = Page{Name: "Test Page"}
|
|
campaign.SMTP = SMTP{Name: "Test Page"}
|
|
campaign.Groups = []Group{Group{Name: "Test Group"}}
|
|
PostCampaign(&campaign, 1)
|
|
return campaign
|
|
}
|
|
|
|
func BenchmarkCampaign100(b *testing.B) {
|
|
setupBenchmark(b)
|
|
setupCampaignDependencies(b, 100)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
campaign := Campaign{Name: "Test campaign"}
|
|
campaign.UserId = 1
|
|
campaign.Template = Template{Name: "Test Template"}
|
|
campaign.Page = Page{Name: "Test Page"}
|
|
campaign.SMTP = SMTP{Name: "Test Page"}
|
|
campaign.Groups = []Group{Group{Name: "Test Group"}}
|
|
|
|
b.StartTimer()
|
|
err := PostCampaign(&campaign, 1)
|
|
if err != nil {
|
|
b.Fatalf("error posting campaign: %v", err)
|
|
}
|
|
b.StopTimer()
|
|
db.Delete(Result{})
|
|
db.Delete(MailLog{})
|
|
db.Delete(Campaign{})
|
|
}
|
|
tearDownBenchmark(b)
|
|
}
|
|
|
|
func BenchmarkCampaign1000(b *testing.B) {
|
|
setupBenchmark(b)
|
|
setupCampaignDependencies(b, 1000)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
campaign := Campaign{Name: "Test campaign"}
|
|
campaign.UserId = 1
|
|
campaign.Template = Template{Name: "Test Template"}
|
|
campaign.Page = Page{Name: "Test Page"}
|
|
campaign.SMTP = SMTP{Name: "Test Page"}
|
|
campaign.Groups = []Group{Group{Name: "Test Group"}}
|
|
|
|
b.StartTimer()
|
|
err := PostCampaign(&campaign, 1)
|
|
if err != nil {
|
|
b.Fatalf("error posting campaign: %v", err)
|
|
}
|
|
b.StopTimer()
|
|
db.Delete(Result{})
|
|
db.Delete(MailLog{})
|
|
db.Delete(Campaign{})
|
|
}
|
|
tearDownBenchmark(b)
|
|
}
|
|
|
|
func BenchmarkCampaign10000(b *testing.B) {
|
|
setupBenchmark(b)
|
|
setupCampaignDependencies(b, 10000)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
campaign := Campaign{Name: "Test campaign"}
|
|
campaign.UserId = 1
|
|
campaign.Template = Template{Name: "Test Template"}
|
|
campaign.Page = Page{Name: "Test Page"}
|
|
campaign.SMTP = SMTP{Name: "Test Page"}
|
|
campaign.Groups = []Group{Group{Name: "Test Group"}}
|
|
|
|
b.StartTimer()
|
|
err := PostCampaign(&campaign, 1)
|
|
if err != nil {
|
|
b.Fatalf("error posting campaign: %v", err)
|
|
}
|
|
b.StopTimer()
|
|
db.Delete(Result{})
|
|
db.Delete(MailLog{})
|
|
db.Delete(Campaign{})
|
|
}
|
|
tearDownBenchmark(b)
|
|
}
|
|
|
|
func BenchmarkGetCampaign100(b *testing.B) {
|
|
setupBenchmark(b)
|
|
campaign := setupCampaign(b, 100)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := GetCampaign(campaign.Id, campaign.UserId)
|
|
if err != nil {
|
|
b.Fatalf("error getting campaign: %v", err)
|
|
}
|
|
}
|
|
tearDownBenchmark(b)
|
|
}
|
|
|
|
func BenchmarkGetCampaign1000(b *testing.B) {
|
|
setupBenchmark(b)
|
|
campaign := setupCampaign(b, 1000)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := GetCampaign(campaign.Id, campaign.UserId)
|
|
if err != nil {
|
|
b.Fatalf("error getting campaign: %v", err)
|
|
}
|
|
}
|
|
tearDownBenchmark(b)
|
|
}
|
|
|
|
func BenchmarkGetCampaign5000(b *testing.B) {
|
|
setupBenchmark(b)
|
|
campaign := setupCampaign(b, 5000)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := GetCampaign(campaign.Id, campaign.UserId)
|
|
if err != nil {
|
|
b.Fatalf("error getting campaign: %v", err)
|
|
}
|
|
}
|
|
tearDownBenchmark(b)
|
|
}
|
|
|
|
func BenchmarkGetCampaign10000(b *testing.B) {
|
|
setupBenchmark(b)
|
|
campaign := setupCampaign(b, 10000)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := GetCampaign(campaign.Id, campaign.UserId)
|
|
if err != nil {
|
|
b.Fatalf("error getting campaign: %v", err)
|
|
}
|
|
}
|
|
tearDownBenchmark(b)
|
|
}
|