fakeas "github.com/cloudfoundry/bosh-agent/agent/applier/applyspec/fakes" boshassert "github.com/cloudfoundry/bosh-agent/assert" fakejobsuper "github.com/cloudfoundry/bosh-agent/jobsupervisor/fakes" boshntp "github.com/cloudfoundry/bosh-agent/platform/ntp" fakentp "github.com/cloudfoundry/bosh-agent/platform/ntp/fakes" boshvitals "github.com/cloudfoundry/bosh-agent/platform/vitals" fakevitals "github.com/cloudfoundry/bosh-agent/platform/vitals/fakes" boshsettings "github.com/cloudfoundry/bosh-agent/settings" fakesettings "github.com/cloudfoundry/bosh-agent/settings/fakes" ) var _ = Describe("GetState", func() { var ( settingsService *fakesettings.FakeSettingsService specService *fakeas.FakeV1Service jobSupervisor *fakejobsuper.FakeJobSupervisor vitalsService *fakevitals.FakeService action GetStateAction ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() vitalsService = fakevitals.NewFakeService() ntpService := &fakentp.FakeService{ GetOffsetNTPOffset: boshntp.NTPInfo{ Offset: "0.34958", Timestamp: "12 Oct 17:37:58", }, }
boshassert "github.com/cloudfoundry/bosh-agent/internal/github.com/cloudfoundry/bosh-utils/assert" boshjobsuper "github.com/cloudfoundry/bosh-agent/jobsupervisor" fakejobsuper "github.com/cloudfoundry/bosh-agent/jobsupervisor/fakes" boshntp "github.com/cloudfoundry/bosh-agent/platform/ntp" fakentp "github.com/cloudfoundry/bosh-agent/platform/ntp/fakes" boshvitals "github.com/cloudfoundry/bosh-agent/platform/vitals" fakevitals "github.com/cloudfoundry/bosh-agent/platform/vitals/fakes" boshsettings "github.com/cloudfoundry/bosh-agent/settings" fakesettings "github.com/cloudfoundry/bosh-agent/settings/fakes" ) var _ = Describe("GetState", func() { var ( settingsService *fakesettings.FakeSettingsService specService *fakeas.FakeV1Service jobSupervisor *fakejobsuper.FakeJobSupervisor vitalsService *fakevitals.FakeService action GetStateAction ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() vitalsService = fakevitals.NewFakeService() ntpService := &fakentp.FakeService{ GetOffsetNTPOffset: boshntp.Info{ Offset: "0.34958", Timestamp: "12 Oct 17:37:58", }, }
fakeas "github.com/cloudfoundry/bosh-agent/agent/applier/applyspec/fakes" boshscript "github.com/cloudfoundry/bosh-agent/agent/script" boshdrain "github.com/cloudfoundry/bosh-agent/agent/script/drain" fakedrain "github.com/cloudfoundry/bosh-agent/agent/script/drain/fakes" fakescript "github.com/cloudfoundry/bosh-agent/agent/script/fakes" fakejobsuper "github.com/cloudfoundry/bosh-agent/jobsupervisor/fakes" fakenotif "github.com/cloudfoundry/bosh-agent/notification/fakes" boshlog "github.com/cloudfoundry/bosh-utils/logger" ) var _ = Describe("DrainAction", func() { var ( notifier *fakenotif.FakeNotifier specService *fakeas.FakeV1Service jobScriptProvider *fakescript.FakeJobScriptProvider fakeScripts map[string]*fakedrain.FakeScript jobSupervisor *fakejobsuper.FakeJobSupervisor action DrainAction logger boshlog.Logger ) BeforeEach(func() { fakeScripts = make(map[string]*fakedrain.FakeScript) logger = boshlog.NewLogger(boshlog.LevelNone) notifier = fakenotif.NewFakeNotifier() specService = fakeas.NewFakeV1Service() jobScriptProvider = &fakescript.FakeJobScriptProvider{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() action = NewDrain(notifier, specService, jobScriptProvider, jobSupervisor, logger) })
func init() { Describe("concreteApplier", func() { var ( jobApplier *fakejobs.FakeApplier packageApplier *fakepackages.FakeApplier logRotateDelegate *FakeLogRotateDelegate jobSupervisor *fakejobsuper.FakeJobSupervisor applier Applier ) BeforeEach(func() { jobApplier = fakejobs.NewFakeApplier() packageApplier = fakepackages.NewFakeApplier() logRotateDelegate = &FakeLogRotateDelegate{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() applier = NewConcreteApplier( jobApplier, packageApplier, logRotateDelegate, jobSupervisor, boshdirs.NewProvider("/fake-base-dir"), ) }) Describe("Prepare", func() { It("prepares each jobs", func() { job := buildJob() err := applier.Prepare( &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.PreparedJobs).To(Equal([]models.Job{job})) }) It("returns error when preparing jobs fails", func() { job := buildJob() jobApplier.PrepareError = errors.New("fake-prepare-job-error") err := applier.Prepare( &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-prepare-job-error")) }) It("prepares each packages", func() { pkg1 := buildPackage() pkg2 := buildPackage() err := applier.Prepare( &fakeas.FakeApplySpec{PackageResults: []models.Package{pkg1, pkg2}}, ) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.PreparedPackages).To(Equal([]models.Package{pkg1, pkg2})) }) It("returns error when preparing packages fails", func() { pkg := buildPackage() packageApplier.PrepareError = errors.New("fake-prepare-package-error") err := applier.Prepare( &fakeas.FakeApplySpec{PackageResults: []models.Package{pkg}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-prepare-package-error")) }) }) Describe("Configure jobs", func() { It("reloads job supervisor", func() { job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"} job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"} jobs := []models.Job{job1, job2} err := applier.ConfigureJobs(&fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.Reloaded).To(BeTrue()) }) It("configures jobs", func() { job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"} job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"} jobs := []models.Job{job1, job2} err := applier.ConfigureJobs(&fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.ConfiguredJobs).To(ConsistOf(job1, job2)) }) }) Describe("Apply", func() { It("removes all jobs from job supervisor", func() { err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{}) Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.RemovedAllJobs).To(BeTrue()) }) It("removes all previous jobs from job supervisor before starting to apply jobs", func() { // force remove all error jobSupervisor.RemovedAllJobsErr = errors.New("fake-remove-all-jobs-error") job := buildJob() applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) // check that jobs were not applied before removing all other jobs Expect(jobApplier.AppliedJobs).To(Equal([]models.Job{})) }) It("returns error if removing all jobs from job supervisor fails", func() { jobSupervisor.RemovedAllJobsErr = errors.New("fake-remove-all-jobs-error") err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-remove-all-jobs-error")) }) It("apply applies jobs", func() { job := buildJob() err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.AppliedJobs).To(Equal([]models.Job{job})) }) It("apply errs when applying jobs errs", func() { job := buildJob() jobApplier.ApplyError = errors.New("fake-apply-job-error") err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: []models.Job{job}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-job-error")) }) It("asked jobApplier to keep only the jobs in the desired and current specs", func() { currentJob := buildJob() desiredJob := buildJob() err := applier.Apply( &fakeas.FakeApplySpec{JobResults: []models.Job{currentJob}}, &fakeas.FakeApplySpec{JobResults: []models.Job{desiredJob}}, ) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.KeepOnlyJobs).To(Equal([]models.Job{currentJob, desiredJob})) }) It("returns error when jobApplier fails to keep only the jobs in the desired and current specs", func() { jobApplier.KeepOnlyErr = errors.New("fake-keep-only-error") currentJob := buildJob() desiredJob := buildJob() err := applier.Apply( &fakeas.FakeApplySpec{JobResults: []models.Job{currentJob}}, &fakeas.FakeApplySpec{JobResults: []models.Job{desiredJob}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-error")) }) It("apply applies packages", func() { pkg1 := buildPackage() pkg2 := buildPackage() err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{PackageResults: []models.Package{pkg1, pkg2}}, ) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.AppliedPackages).To(Equal([]models.Package{pkg1, pkg2})) }) It("apply errs when applying packages errs", func() { pkg := buildPackage() packageApplier.ApplyError = errors.New("fake-apply-package-error") err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{PackageResults: []models.Package{pkg}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-package-error")) }) It("asked packageApplier to keep only the packages in the desired and current specs", func() { currentPkg := buildPackage() desiredPkg := buildPackage() err := applier.Apply( &fakeas.FakeApplySpec{PackageResults: []models.Package{currentPkg}}, &fakeas.FakeApplySpec{PackageResults: []models.Package{desiredPkg}}, ) Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.KeptOnlyPackages).To(Equal([]models.Package{currentPkg, desiredPkg})) }) It("returns error when packageApplier fails to keep only the packages in the desired and current specs", func() { packageApplier.KeepOnlyErr = errors.New("fake-keep-only-error") currentPkg := buildPackage() desiredPkg := buildPackage() err := applier.Apply( &fakeas.FakeApplySpec{PackageResults: []models.Package{currentPkg}}, &fakeas.FakeApplySpec{PackageResults: []models.Package{desiredPkg}}, ) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-error")) }) It("apply does not configure jobs", func() { job1 := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"} job2 := models.Job{Name: "fake-job-name-2", Version: "fake-version-name-2"} jobs := []models.Job{job1, job2} err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.ConfiguredJobs).To(BeEmpty()) Expect(jobSupervisor.Reloaded).To(BeTrue()) }) It("apply errs if monitor fails reload", func() { jobs := []models.Job{} jobSupervisor.ReloadErr = errors.New("error reloading monit") err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("error reloading monit")) }) It("apply sets up logrotation", func() { err := applier.Apply( &fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{MaxLogFileSizeResult: "fake-size"}, ) Expect(err).ToNot(HaveOccurred()) assert.Equal(GinkgoT(), logRotateDelegate.SetupLogrotateArgs, SetupLogrotateArgs{ GroupName: boshsettings.VCAPUsername, BasePath: "/fake-base-dir", Size: "fake-size", }) }) It("apply errs if setup logrotate fails", func() { logRotateDelegate.SetupLogrotateErr = errors.New("fake-set-up-logrotate-error") err := applier.Apply(&fakeas.FakeApplySpec{}, &fakeas.FakeApplySpec{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-set-up-logrotate-error")) }) }) }) }
func init() { Describe("Agent", func() { var ( logger boshlog.Logger handler *fakembus.FakeHandler platform *fakeplatform.FakePlatform actionDispatcher *fakeagent.FakeActionDispatcher jobSupervisor *fakejobsuper.FakeJobSupervisor specService *fakeas.FakeV1Service syslogServer *fakesyslog.FakeServer settingsService *fakesettings.FakeSettingsService uuidGenerator *fakeuuid.FakeGenerator timeService *fakeclock.FakeClock agent Agent ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelNone) handler = &fakembus.FakeHandler{} platform = fakeplatform.NewFakePlatform() actionDispatcher = &fakeagent.FakeActionDispatcher{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() syslogServer = &fakesyslog.FakeServer{} settingsService = &fakesettings.FakeSettingsService{} uuidGenerator = &fakeuuid.FakeGenerator{} timeService = fakeclock.NewFakeClock(time.Now()) agent = New( logger, handler, platform, actionDispatcher, jobSupervisor, specService, syslogServer, 5*time.Millisecond, settingsService, uuidGenerator, timeService, ) }) Describe("Run", func() { It("lets dispatcher handle requests arriving via handler", func() { err := agent.Run() Expect(err).ToNot(HaveOccurred()) expectedResp := boshhandler.NewValueResponse("pong") actionDispatcher.DispatchResp = expectedResp req := boshhandler.NewRequest("fake-reply", "fake-action", []byte("fake-payload")) resp := handler.RunFunc(req) Expect(actionDispatcher.DispatchReq).To(Equal(req)) Expect(resp).To(Equal(expectedResp)) }) It("resumes persistent actions *before* dispatching new requests", func() { resumedBeforeStartingToDispatch := false handler.RunCallBack = func() { resumedBeforeStartingToDispatch = actionDispatcher.ResumedPreviouslyDispatchedTasks } err := agent.Run() Expect(err).ToNot(HaveOccurred()) Expect(resumedBeforeStartingToDispatch).To(BeTrue()) }) Context("when heartbeats can be sent", func() { BeforeEach(func() { handler.KeepOnRunning() }) BeforeEach(func() { jobName := "fake-job" nodeID := "node-id" jobIndex := 1 specService.Spec = boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{Name: &jobName}, Index: &jobIndex, NodeID: nodeID, } jobSupervisor.StatusStatus = "fake-state" platform.FakeVitalsService.GetVitals = boshvitals.Vitals{ Load: []string{"a", "b", "c"}, } }) expectedJobName := "fake-job" expectedJobIndex := 1 expectedNodeID := "node-id" expectedHb := Heartbeat{ Job: &expectedJobName, Index: &expectedJobIndex, JobState: "fake-state", NodeID: expectedNodeID, Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, } It("sends initial heartbeat", func() { // Configure periodic heartbeat every 5 hours // so that we are sure that we will not receive it agent = New( logger, handler, platform, actionDispatcher, jobSupervisor, specService, syslogServer, 5*time.Hour, settingsService, uuidGenerator, timeService, ) // Immediately exit after sending initial heartbeat handler.SendErr = errors.New("stop") err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(handler.SendInputs()).To(Equal([]fakembus.SendInput{ { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, })) }) It("sends periodic heartbeats", func() { sentRequests := 0 handler.SendCallback = func(_ fakembus.SendInput) { sentRequests++ if sentRequests == 3 { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(handler.SendInputs()).To(Equal([]fakembus.SendInput{ { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, { Target: boshhandler.HealthMonitor, Topic: boshhandler.Heartbeat, Message: expectedHb, }, })) }) }) Context("when the agent fails to get job spec for a heartbeat", func() { BeforeEach(func() { specService.GetErr = errors.New("fake-spec-service-error") handler.KeepOnRunning() }) It("returns the error", func() { err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-spec-service-error")) }) }) Context("when the agent fails to get vitals for a heartbeat", func() { BeforeEach(func() { platform.FakeVitalsService.GetErr = errors.New("fake-vitals-service-error") handler.KeepOnRunning() }) It("returns the error", func() { err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-vitals-service-error")) }) }) It("sends job monitoring alerts to health manager", func() { handler.KeepOnRunning() monitAlert := boshalert.MonitAlert{ ID: "fake-monit-alert", Service: "fake-service", Event: "fake-event", Action: "fake-action", Date: "Sun, 22 May 2011 20:07:41 +0500", Description: "fake-description", } jobSupervisor.JobFailureAlert = &monitAlert // Fail the first time handler.Send is called for an alert (ignore heartbeats) handler.SendCallback = func(input fakembus.SendInput) { if input.Topic == boshhandler.Alert { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) expectedAlert := boshalert.Alert{ ID: "fake-monit-alert", Severity: boshalert.SeverityDefault, Title: "fake-service - fake-event - fake-action", Summary: "fake-description", CreatedAt: int64(1306076861), } Expect(handler.SendInputs()).To(ContainElement(fakembus.SendInput{ Target: boshhandler.HealthMonitor, Topic: boshhandler.Alert, Message: expectedAlert, })) }) It("sends ssh alerts to health manager", func() { handler.KeepOnRunning() syslogMsg := boshsyslog.Msg{Content: "disconnected by user"} syslogServer.StartFirstSyslogMsg = &syslogMsg uuidGenerator.GeneratedUUID = "fake-uuid" // Fail the first time handler.Send is called for an alert (ignore heartbeats) handler.SendCallback = func(input fakembus.SendInput) { if input.Topic == boshhandler.Alert { handler.SendErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) expectedAlert := boshalert.Alert{ ID: "fake-uuid", Severity: boshalert.SeverityWarning, Title: "SSH Logout", Summary: "disconnected by user", CreatedAt: timeService.Now().Unix(), } Expect(handler.SendInputs()).To(ContainElement(fakembus.SendInput{ Target: boshhandler.HealthMonitor, Topic: boshhandler.Alert, Message: expectedAlert, })) }) }) }) }
func init() { Describe("DrainAction", func() { var ( notifier *fakenotif.FakeNotifier specService *fakeas.FakeV1Service drainScriptProvider *fakedrain.FakeDrainScriptProvider jobSupervisor *fakejobsuper.FakeJobSupervisor action DrainAction ) BeforeEach(func() { notifier = fakenotif.NewFakeNotifier() specService = fakeas.NewFakeV1Service() drainScriptProvider = fakedrain.NewFakeDrainScriptProvider() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() action = NewDrain(notifier, specService, drainScriptProvider, jobSupervisor) }) BeforeEach(func() { drainScriptProvider.NewDrainScriptDrainScript.ExistsBool = true }) It("is asynchronous", func() { Expect(action.IsAsynchronous()).To(BeTrue()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) Context("when drain update is requested", func() { act := func() (int, error) { return action.Run(DrainTypeUpdate, boshas.V1ApplySpec{}) } Context("when current agent has a job spec template", func() { var currentSpec boshas.V1ApplySpec BeforeEach(func() { currentSpec = boshas.V1ApplySpec{} currentSpec.JobSpec.Template = "foo" specService.Spec = currentSpec }) It("unmonitors services so that drain scripts can kill processes on their own", func() { value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(jobSupervisor.Unmonitored).To(BeTrue()) }) Context("when unmonitoring services succeeds", func() { It("does not notify of job shutdown", func() { value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(notifier.NotifiedShutdown).To(BeFalse()) }) Context("when new apply spec is provided", func() { newSpec := boshas.V1ApplySpec{ PackageSpecs: map[string]boshas.PackageSpec{ "foo": boshas.PackageSpec{ Name: "foo", Sha1: "foo-sha1-new", }, }, } Context("when drain script exists", func() { It("runs drain script with job_shutdown param", func() { value, err := action.Run(DrainTypeUpdate, newSpec) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo")) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue()) params := drainScriptProvider.NewDrainScriptDrainScript.RunParams Expect(params).To(Equal(boshdrain.NewUpdateDrainParams(currentSpec, newSpec))) }) Context("when drain script runs and errs", func() { It("returns error", func() { drainScriptProvider.NewDrainScriptDrainScript.RunError = errors.New("fake-drain-run-error") value, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-drain-run-error")) Expect(value).To(Equal(0)) }) }) }) Context("when drain script does not exist", func() { It("returns 0", func() { drainScriptProvider.NewDrainScriptDrainScript.ExistsBool = false value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(0)) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeFalse()) }) }) }) Context("when apply spec is not provided", func() { It("returns error", func() { value, err := action.Run(DrainTypeUpdate) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Drain update requires new spec")) Expect(value).To(Equal(0)) }) }) }) Context("when unmonitoring services fails", func() { It("returns error", func() { jobSupervisor.UnmonitorErr = errors.New("fake-unmonitor-error") value, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-unmonitor-error")) Expect(value).To(Equal(0)) }) }) }) Context("when current agent spec does not have a job spec template", func() { It("returns 0 and does not run drain script", func() { specService.Spec = boshas.V1ApplySpec{} value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(0)) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeFalse()) }) }) }) Context("when drain shutdown is requested", func() { act := func() (int, error) { return action.Run(DrainTypeShutdown) } Context("when current agent has a job spec template", func() { var currentSpec boshas.V1ApplySpec BeforeEach(func() { currentSpec = boshas.V1ApplySpec{} currentSpec.JobSpec.Template = "foo" specService.Spec = currentSpec }) It("unmonitors services so that drain scripts can kill processes on their own", func() { value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(jobSupervisor.Unmonitored).To(BeTrue()) }) Context("when unmonitoring services succeeds", func() { It("notifies that job is about to shutdown", func() { value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(notifier.NotifiedShutdown).To(BeTrue()) }) Context("when job shutdown notification succeeds", func() { Context("when drain script exists", func() { It("runs drain script with job_shutdown param passing no apply spec", func() { value, err := action.Run(DrainTypeShutdown) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo")) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue()) params := drainScriptProvider.NewDrainScriptDrainScript.RunParams Expect(params).To(Equal(boshdrain.NewShutdownDrainParams(currentSpec, nil))) }) It("runs drain script with job_shutdown param passing in first apply spec", func() { newSpec := boshas.V1ApplySpec{} newSpec.JobSpec.Template = "fake-updated-template" value, err := action.Run(DrainTypeShutdown, newSpec) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo")) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue()) params := drainScriptProvider.NewDrainScriptDrainScript.RunParams Expect(params).To(Equal(boshdrain.NewShutdownDrainParams(currentSpec, &newSpec))) }) Context("when drain script runs and errs", func() { It("returns error", func() { drainScriptProvider.NewDrainScriptDrainScript.RunError = errors.New("fake-drain-run-error") value, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-drain-run-error")) Expect(value).To(Equal(0)) }) }) }) Context("when drain script does not exist", func() { It("returns 0", func() { drainScriptProvider.NewDrainScriptDrainScript.ExistsBool = false value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(0)) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeFalse()) }) }) }) Context("when job shutdown notification fails", func() { It("returns error if job shutdown notifications errs", func() { notifier.NotifyShutdownErr = errors.New("fake-shutdown-error") value, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-shutdown-error")) Expect(value).To(Equal(0)) }) }) }) Context("when unmonitoring services fails", func() { It("returns error", func() { jobSupervisor.UnmonitorErr = errors.New("fake-unmonitor-error") value, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-unmonitor-error")) Expect(value).To(Equal(0)) }) }) }) Context("when current agent spec does not have a job spec template", func() { It("returns 0 and does not run drain script", func() { specService.Spec = boshas.V1ApplySpec{} value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(0)) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeFalse()) }) }) }) Context("when drain status is requested", func() { act := func() (int, error) { return action.Run(DrainTypeStatus) } Context("when current agent has a job spec template", func() { var currentSpec boshas.V1ApplySpec BeforeEach(func() { currentSpec = boshas.V1ApplySpec{} currentSpec.JobSpec.Template = "foo" specService.Spec = currentSpec }) It("unmonitors services so that drain scripts can kill processes on their own", func() { value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(jobSupervisor.Unmonitored).To(BeTrue()) }) It("does not notify of job shutdown", func() { value, err := act() Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(notifier.NotifiedShutdown).To(BeFalse()) }) Context("when unmonitoring services succeeds", func() { Context("when drain script exists", func() { It("runs drain script with job_check_status param passing no apply spec", func() { value, err := action.Run(DrainTypeStatus) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo")) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue()) params := drainScriptProvider.NewDrainScriptDrainScript.RunParams Expect(params).To(Equal(boshdrain.NewStatusDrainParams(currentSpec, nil))) }) It("runs drain script with job_check_status param passing in first apply spec", func() { newSpec := boshas.V1ApplySpec{} newSpec.JobSpec.Template = "fake-updated-template" value, err := action.Run(DrainTypeStatus, newSpec) Expect(err).ToNot(HaveOccurred()) Expect(value).To(Equal(1)) Expect(drainScriptProvider.NewDrainScriptTemplateName).To(Equal("foo")) Expect(drainScriptProvider.NewDrainScriptDrainScript.DidRun).To(BeTrue()) params := drainScriptProvider.NewDrainScriptDrainScript.RunParams Expect(params).To(Equal(boshdrain.NewStatusDrainParams(currentSpec, &newSpec))) }) Context("when drain script runs and errs", func() { It("returns error if drain script errs", func() { drainScriptProvider.NewDrainScriptDrainScript.RunError = errors.New("fake-drain-run-error") value, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-drain-run-error")) Expect(value).To(Equal(0)) }) }) }) Context("when drain script does not exist", func() { It("returns error because drain status must be called after starting draining", func() { drainScriptProvider.NewDrainScriptDrainScript.ExistsBool = false value, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Check Status on Drain action requires a valid drain script")) Expect(value).To(Equal(0)) }) }) }) Context("when unmonitoring services fails", func() { It("returns error if unmonitoring services errs", func() { jobSupervisor.UnmonitorErr = errors.New("fake-unmonitor-error") value, err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-unmonitor-error")) Expect(value).To(Equal(0)) }) }) }) Context("when current agent spec does not have a job spec template", func() { It("returns error because drain status should only be called after starting draining", func() { specService.Spec = boshas.V1ApplySpec{} value, err := action.Run(DrainTypeStatus) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Check Status on Drain action requires job spec")) Expect(value).To(Equal(0)) }) }) }) }) }