func processSchedule(name string, p Process) scheduler.Schedule { if p.Cron != nil { return scheduler.CRONSchedule(*p.Cron) } return nil }
func TestScheduleExpression(t *testing.T) { tests := []struct { schedule scheduler.Schedule expression string }{ {scheduler.CRONSchedule("0 12 * * ? *"), "cron(0 12 * * ? *)"}, {5 * time.Minute, "rate(5 minutes)"}, {1 * time.Minute, "rate(1 minute)"}, {24 * time.Hour, "rate(1440 minutes)"}, } for _, tt := range tests { expression := scheduleExpression(tt.schedule) assert.Equal(t, tt.expression, expression) } }
func TestEmpireTemplate(t *testing.T) { tests := []struct { file string app *scheduler.App }{ { "basic.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Env: map[string]string{ // These should get re-sorted in // alphabetical order. "C": "foo", "A": "foobar", "B": "bar", }, Processes: []*scheduler.Process{ { Type: "web", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/web"}, Exposure: &scheduler.Exposure{ Type: &scheduler.HTTPExposure{}, }, Labels: map[string]string{ "empire.app.process": "web", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Instances: 1, Nproc: 256, }, { Type: "worker", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/worker"}, Labels: map[string]string{ "empire.app.process": "worker", }, Env: map[string]string{ "FOO": "BAR", }, }, }, }, }, { "https.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Processes: []*scheduler.Process{ { Type: "web", Command: []string{"./bin/web"}, Exposure: &scheduler.Exposure{ Type: &scheduler.HTTPSExposure{ Cert: "arn:aws:iam::012345678901:server-certificate/AcmeIncDotCom", }, }, }, { Type: "api", Command: []string{"./bin/api"}, Exposure: &scheduler.Exposure{ Type: &scheduler.HTTPSExposure{ Cert: "AcmeIncDotCom", // Simple cert format. }, }, }, }, }, }, { "custom.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Env: map[string]string{ "ECS_TASK_DEFINITION": "custom", }, Processes: []*scheduler.Process{ { Type: "web", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/web"}, Env: map[string]string{ "B": "foo", "A": "foo", "FOO": "bar", }, Exposure: &scheduler.Exposure{ Type: &scheduler.HTTPExposure{}, }, Labels: map[string]string{ "empire.app.process": "web", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Instances: 1, Nproc: 256, }, { Type: "vacuum", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/vacuum"}, Schedule: scheduler.CRONSchedule("* * * * *"), Instances: 1, Labels: map[string]string{ "empire.app.process": "vacuum", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Nproc: 256, }, }, }, }, { "cron.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Processes: []*scheduler.Process{ { Type: "send-emails", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/send-emails"}, Schedule: scheduler.CRONSchedule("* * * * *"), Instances: 1, Labels: map[string]string{ "empire.app.process": "send-emails", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Nproc: 256, }, { Type: "vacuum", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/vacuum"}, Schedule: scheduler.CRONSchedule("* * * * *"), Instances: 0, Labels: map[string]string{ "empire.app.process": "vacuum", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Nproc: 256, }, }, }, }, } for _, tt := range tests { tmpl := newTemplate() tmpl.NoCompress = true buf := new(bytes.Buffer) filename := fmt.Sprintf("templates/%s", tt.file) err := tmpl.Execute(buf, tt.app) assert.NoError(t, err) expected, err := ioutil.ReadFile(filename) assert.NoError(t, err) assert.Equal(t, string(expected), buf.String()) ioutil.WriteFile(filename, buf.Bytes(), 0660) } }
func TestEmpireTemplate(t *testing.T) { tests := []struct { file string app *scheduler.App }{ { "basic.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Env: map[string]string{ // These should get re-sorted in // alphabetical order. "C": "foo", "A": "foobar", "B": "bar", }, Processes: []*scheduler.Process{ { Type: "web", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/web"}, Env: map[string]string{ "PORT": "8080", }, Exposure: &scheduler.Exposure{ Ports: []scheduler.Port{ { Host: 80, Container: 8080, Protocol: &scheduler.HTTP{}, }, }, }, Labels: map[string]string{ "empire.app.process": "web", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Instances: 1, Nproc: 256, }, { Type: "worker", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/worker"}, Labels: map[string]string{ "empire.app.process": "worker", }, Env: map[string]string{ "FOO": "BAR", }, }, }, }, }, { "basic-alb.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Env: map[string]string{ // These should get re-sorted in // alphabetical order. "C": "foo", "A": "foobar", "B": "bar", "LOAD_BALANCER_TYPE": "alb", }, Processes: []*scheduler.Process{ { Type: "web", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/web"}, Exposure: &scheduler.Exposure{ Ports: []scheduler.Port{ { Host: 80, Container: 8080, Protocol: &scheduler.HTTP{}, }, }, }, Labels: map[string]string{ "empire.app.process": "web", }, Env: map[string]string{ "PORT": "8080", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Instances: 1, Nproc: 256, }, { Type: "worker", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/worker"}, Labels: map[string]string{ "empire.app.process": "worker", }, Env: map[string]string{ "FOO": "BAR", }, }, }, }, }, { "https.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Processes: []*scheduler.Process{ { Type: "web", Command: []string{"./bin/web"}, Env: map[string]string{ "PORT": "8080", }, Exposure: &scheduler.Exposure{ Ports: []scheduler.Port{ { Host: 80, Container: 8080, Protocol: &scheduler.HTTP{}, }, { Host: 443, Container: 8080, Protocol: &scheduler.HTTPS{ Cert: "arn:aws:iam::012345678901:server-certificate/AcmeIncDotCom", }, }, }, }, }, { Type: "api", Command: []string{"./bin/api"}, Env: map[string]string{ "PORT": "8080", }, Exposure: &scheduler.Exposure{ Ports: []scheduler.Port{ { Host: 80, Container: 8080, Protocol: &scheduler.HTTP{}, }, { Host: 443, Container: 8080, Protocol: &scheduler.HTTPS{ Cert: "AcmeIncDotCom", // Simple cert format. }, }, }, }, }, }, }, }, { "https-alb.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Processes: []*scheduler.Process{ { Type: "web", Command: []string{"./bin/web"}, Labels: map[string]string{ "empire.app.process": "web", }, Env: map[string]string{ "PORT": "8080", "LOAD_BALANCER_TYPE": "alb", }, Exposure: &scheduler.Exposure{ Ports: []scheduler.Port{ { Host: 80, Container: 8080, Protocol: &scheduler.HTTP{}, }, { Host: 443, Container: 8080, Protocol: &scheduler.HTTPS{ Cert: "arn:aws:iam::012345678901:server-certificate/AcmeIncDotCom", }, }, }, }, }, { Type: "api", Command: []string{"./bin/api"}, Labels: map[string]string{ "empire.app.process": "api", }, Env: map[string]string{ "PORT": "8080", "EMPIRE_X_LOAD_BALANCER_TYPE": "alb", }, Exposure: &scheduler.Exposure{ Ports: []scheduler.Port{ { Host: 80, Container: 8080, Protocol: &scheduler.HTTP{}, }, { Host: 443, Container: 8080, Protocol: &scheduler.HTTPS{ Cert: "AcmeIncDotCom", // Simple cert format }, }, }, }, }, }, }, }, { "custom.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Env: map[string]string{ "ECS_TASK_DEFINITION": "custom", }, Processes: []*scheduler.Process{ { Type: "web", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/web"}, Env: map[string]string{ "B": "foo", "A": "foo", "FOO": "bar", "PORT": "8080", }, Exposure: &scheduler.Exposure{ Ports: []scheduler.Port{ { Host: 80, Container: 8080, Protocol: &scheduler.HTTP{}, }, }, }, Labels: map[string]string{ "empire.app.process": "web", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Instances: 1, Nproc: 256, }, { Type: "vacuum", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/vacuum"}, Schedule: scheduler.CRONSchedule("* * * * *"), Instances: 1, Labels: map[string]string{ "empire.app.process": "vacuum", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Nproc: 256, }, }, }, }, { "cron.json", &scheduler.App{ ID: "1234", Release: "v1", Name: "acme-inc", Processes: []*scheduler.Process{ { Type: "send-emails", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/send-emails"}, Schedule: scheduler.CRONSchedule("* * * * *"), Instances: 1, Labels: map[string]string{ "empire.app.process": "send-emails", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Nproc: 256, }, { Type: "vacuum", Image: image.Image{Repository: "remind101/acme-inc", Tag: "latest"}, Command: []string{"./bin/vacuum"}, Schedule: scheduler.CRONSchedule("* * * * *"), Instances: 0, Labels: map[string]string{ "empire.app.process": "vacuum", }, MemoryLimit: 128 * bytesize.MB, CPUShares: 256, Nproc: 256, }, }, }, }, } stackTags := []*cloudformation.Tag{ {Key: aws.String("environment"), Value: aws.String("test")}, } for _, tt := range tests { t.Run(tt.file, func(t *testing.T) { tmpl := newTemplate() tmpl.NoCompress = true buf := new(bytes.Buffer) filename := fmt.Sprintf("templates/%s", tt.file) data := &TemplateData{tt.app, stackTags} err := tmpl.Execute(buf, data) if assert.NoError(t, err) { expected, err := ioutil.ReadFile(filename) assert.NoError(t, err) if got, want := buf.String(), string(expected); got != want { ioutil.WriteFile(filename, buf.Bytes(), 0660) t.Errorf("expected generated template to match existing %s. Wrote to %s", tt.file, filename) } } }) } }
func TestEmpire_Deploy(t *testing.T) { e := empiretest.NewEmpire(t) s := new(mockScheduler) e.Scheduler = s user := &empire.User{Name: "ejholmes"} app, err := e.Create(context.Background(), empire.CreateOpts{ User: user, Name: "acme-inc", }) assert.NoError(t, err) img := image.Image{Repository: "remind101/acme-inc"} s.On("Submit", &scheduler.App{ ID: app.ID, Name: "acme-inc", Release: "v1", Env: map[string]string{ "EMPIRE_APPID": app.ID, "EMPIRE_APPNAME": "acme-inc", "EMPIRE_RELEASE": "v1", }, Labels: map[string]string{ "empire.app.name": "acme-inc", "empire.app.id": app.ID, "empire.app.release": "v1", }, Processes: []*scheduler.Process{ { Type: "scheduled", Image: img, Command: []string{"./bin/scheduled"}, Schedule: scheduler.CRONSchedule("* * * * * *"), Instances: 0, MemoryLimit: 536870912, CPUShares: 256, Nproc: 256, Env: map[string]string{ "EMPIRE_PROCESS": "scheduled", "EMPIRE_PROCESS_SCALE": "0", "SOURCE": "acme-inc.scheduled.v1", }, Labels: map[string]string{ "empire.app.process": "scheduled", }, }, { Type: "web", Image: img, Command: []string{"./bin/web"}, Exposure: &scheduler.Exposure{ Type: &scheduler.HTTPExposure{}, }, Instances: 1, MemoryLimit: 536870912, CPUShares: 256, Nproc: 256, Env: map[string]string{ "EMPIRE_PROCESS": "web", "EMPIRE_PROCESS_SCALE": "1", "SOURCE": "acme-inc.web.v1", }, Labels: map[string]string{ "empire.app.process": "web", }, }, { Type: "worker", Image: img, Command: []string{"./bin/worker"}, Instances: 0, MemoryLimit: 536870912, CPUShares: 256, Nproc: 256, Env: map[string]string{ "EMPIRE_PROCESS": "worker", "EMPIRE_PROCESS_SCALE": "0", "SOURCE": "acme-inc.worker.v1", }, Labels: map[string]string{ "empire.app.process": "worker", }, }, }, }).Return(nil) _, err = e.Deploy(context.Background(), empire.DeployOpts{ App: app, User: user, Output: empire.NewDeploymentStream(ioutil.Discard), Image: img, }) assert.NoError(t, err) s.AssertExpectations(t) }