func init() { Describe("Stop", func() { var ( jobSupervisor *fakejobsuper.FakeJobSupervisor action StopAction ) BeforeEach(func() { jobSupervisor = fakejobsuper.NewFakeJobSupervisor() action = NewStop(jobSupervisor) }) It("is asynchronous", func() { Expect(action.IsAsynchronous()).To(BeTrue()) }) It("is not persistent", func() { Expect(action.IsPersistent()).To(BeFalse()) }) It("returns stopped", func() { stopped, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(stopped).To(Equal("stopped")) }) It("stops job supervisor services", func() { _, err := action.Run() Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.Stopped).To(BeTrue()) }) }) }
func TestHandlerProviderGetReturnsConcreteProvider(t *testing.T) { platform := fakeplatform.NewFakePlatform() blobstore := fakeblob.NewFakeBlobstore() jobSupervisor := fakejobsuper.NewFakeJobSupervisor() expectedPackageApplier := pa.NewConcretePackageApplier( bc.NewFileBundleCollection("/fake-base-dir/data", "/fake-base-dir", "packages", platform.GetFs()), blobstore, platform.GetCompressor(), ) expectedJobApplier := ja.NewRenderedJobApplier( bc.NewFileBundleCollection("/fake-base-dir/data", "/fake-base-dir", "jobs", platform.GetFs()), blobstore, platform.GetCompressor(), jobSupervisor, ) dirProvider := boshdirs.NewDirectoriesProvider("/fake-base-dir") expectedApplier := NewConcreteApplier( expectedJobApplier, expectedPackageApplier, platform, jobSupervisor, dirProvider, ) provider := NewApplierProvider(platform, blobstore, jobSupervisor, dirProvider) applier := provider.Get() assert.Equal(t, expectedApplier, applier) }
func buildFactory() ( deps concreteFactoryDependencies, factory Factory) { deps.settings = &fakesettings.FakeSettingsService{} deps.platform = fakeplatform.NewFakePlatform() deps.blobstore = &fakeblobstore.FakeBlobstore{} deps.taskService = &faketask.FakeService{} deps.notifier = fakenotif.NewFakeNotifier() deps.applier = fakeappl.NewFakeApplier() deps.compiler = fakecomp.NewFakeCompiler() deps.jobSupervisor = fakejobsuper.NewFakeJobSupervisor() deps.specService = fakeas.NewFakeV1Service() deps.drainScriptProvider = boshdrain.NewConcreteDrainScriptProvider(nil, nil, deps.platform.GetDirProvider()) factory = NewFactory( deps.settings, deps.platform, deps.blobstore, deps.taskService, deps.notifier, deps.applier, deps.compiler, deps.jobSupervisor, deps.specService, deps.drainScriptProvider, ) return }
func buildAgent() (deps agentDeps, agent Agent) { deps = agentDeps{ logger: boshlog.NewLogger(boshlog.LEVEL_NONE), handler: &fakembus.FakeHandler{}, platform: fakeplatform.NewFakePlatform(), actionDispatcher: &FakeActionDispatcher{}, alertBuilder: fakealert.NewFakeAlertBuilder(), jobSupervisor: fakejobsup.NewFakeJobSupervisor(), } agent = New(deps.logger, deps.handler, deps.platform, deps.actionDispatcher, deps.alertBuilder, deps.jobSupervisor, 5*time.Millisecond) return }
func buildApplier() ( *fakeja.FakeJobApplier, *fakepa.FakePackageApplier, *FakeLogRotateDelegate, *fakejobsuper.FakeJobSupervisor, Applier, ) { jobApplier := fakeja.NewFakeJobApplier() packageApplier := fakepa.NewFakePackageApplier() platform := &FakeLogRotateDelegate{} jobSupervisor := fakejobsuper.NewFakeJobSupervisor() applier := NewConcreteApplier(jobApplier, packageApplier, platform, jobSupervisor, boshdirs.NewDirectoriesProvider("/fake-base-dir")) return jobApplier, packageApplier, platform, jobSupervisor, applier }
func buildJobApplier() ( jobsBc *fakebc.FakeBundleCollection, blobstore *fakeblob.FakeBlobstore, compressor *fakecmd.FakeCompressor, jobSupervisor *fakejobsuper.FakeJobSupervisor, applier JobApplier, ) { jobsBc = fakebc.NewFakeBundleCollection() blobstore = fakeblob.NewFakeBlobstore() compressor = fakecmd.NewFakeCompressor() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() applier = NewRenderedJobApplier(jobsBc, blobstore, compressor, jobSupervisor) return }
func buildGetStateAction(settings boshsettings.Service) ( specService *fakeas.FakeV1Service, jobSupervisor *fakejobsuper.FakeJobSupervisor, vitalsService *fakevitals.FakeService, action GetStateAction, ) { jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() vitalsService = fakevitals.NewFakeService() fakeNTPService := &fakentp.FakeService{ GetOffsetNTPOffset: boshntp.NTPInfo{ Offset: "0.34958", Timestamp: "12 Oct 17:37:58", }, } action = NewGetState(settings, specService, jobSupervisor, vitalsService, fakeNTPService) return }
func init() { Describe("renderedJobApplier", func() { var ( jobsBc *fakebc.FakeBundleCollection jobSupervisor *fakejobsuper.FakeJobSupervisor packageApplierProvider *fakepa.FakePackageApplierProvider blobstore *fakeblob.FakeBlobstore compressor *fakecmd.FakeCompressor fs *fakesys.FakeFileSystem applier JobApplier ) BeforeEach(func() { jobsBc = fakebc.NewFakeBundleCollection() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() packageApplierProvider = fakepa.NewFakePackageApplierProvider() blobstore = fakeblob.NewFakeBlobstore() fs = fakesys.NewFakeFileSystem() compressor = fakecmd.NewFakeCompressor() logger := boshlog.NewLogger(boshlog.LevelNone) applier = NewRenderedJobApplier( jobsBc, jobSupervisor, packageApplierProvider, blobstore, compressor, fs, logger, ) }) Describe("Prepare & Apply", func() { var ( job models.Job bundle *fakebc.FakeBundle ) BeforeEach(func() { job, bundle = buildJob(jobsBc) }) ItInstallsJob := func(act func() error) { It("returns error when installing job fails", func() { bundle.InstallError = errors.New("fake-install-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-install-error")) }) It("downloads and later cleans up downloaded job template blob", func() { blobstore.GetFileName = "/fake-blobstore-file-name" err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs[0]).To(Equal("fake-blobstore-id")) Expect(blobstore.GetFingerprints[0]).To(Equal("fake-blob-sha1")) // downloaded file is cleaned up Expect(blobstore.CleanUpFileName).To(Equal("/fake-blobstore-file-name")) }) It("returns error when downloading job template blob fails", func() { blobstore.GetError = errors.New("fake-get-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-error")) }) It("decompresses job template blob to tmp path and later cleans it up", func() { fs.TempDirDir = "/fake-tmp-dir" blobstore.GetFileName = "/fake-blobstore-file-name" var tmpDirExistsBeforeInstall bool bundle.InstallCallBack = func() { tmpDirExistsBeforeInstall = true } err := act() Expect(err).ToNot(HaveOccurred()) Expect(compressor.DecompressFileToDirTarballPaths[0]).To(Equal("/fake-blobstore-file-name")) Expect(compressor.DecompressFileToDirDirs[0]).To(Equal("/fake-tmp-dir")) // tmp dir exists before bundle install Expect(tmpDirExistsBeforeInstall).To(BeTrue()) // tmp dir is cleaned up after install Expect(fs.FileExists(fs.TempDirDir)).To(BeFalse()) }) It("returns error when temporary directory creation fails", func() { fs.TempDirError = errors.New("fake-filesystem-tempdir-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-filesystem-tempdir-error")) }) It("returns error when decompressing job template fails", func() { compressor.DecompressFileToDirErr = errors.New("fake-decompress-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-decompress-error")) }) It("returns error when getting the list of bin files fails", func() { fs.GlobErr = errors.New("fake-glob-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-glob-error")) }) It("returns error when changing permissions on bin files fails", func() { fs.TempDirDir = "/fake-tmp-dir" fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{ "/fake-tmp-dir/fake-path-in-archive/bin/test", }) fs.ChmodErr = errors.New("fake-chmod-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-chmod-error")) }) It("installs bundle from decompressed tmp path of a job template", func() { fs.TempDirDir = "/fake-tmp-dir" var installedBeforeDecompression bool compressor.DecompressFileToDirCallBack = func() { installedBeforeDecompression = bundle.Installed } err := act() Expect(err).ToNot(HaveOccurred()) // bundle installation did not happen before decompression Expect(installedBeforeDecompression).To(BeFalse()) // make sure that bundle install happened after decompression Expect(bundle.InstallSourcePath).To(Equal("/fake-tmp-dir/fake-path-in-archive")) }) It("sets executable bit for files in bin", func() { fs.TempDirDir = "/fake-tmp-dir" compressor.DecompressFileToDirCallBack = func() { fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test1", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/bin/test2", []byte{}) fs.WriteFile("/fake-tmp-dir/fake-path-in-archive/config/test", []byte{}) } fs.SetGlob("/fake-tmp-dir/fake-path-in-archive/bin/*", []string{ "/fake-tmp-dir/fake-path-in-archive/bin/test1", "/fake-tmp-dir/fake-path-in-archive/bin/test2", }) var binTest1Stats, binTest2Stats, configTestStats *fakesys.FakeFileStats bundle.InstallCallBack = func() { binTest1Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test1") binTest2Stats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/bin/test2") configTestStats = fs.GetFileTestStat("/fake-tmp-dir/fake-path-in-archive/config/test") } err := act() Expect(err).ToNot(HaveOccurred()) // bin files are executable Expect(int(binTest1Stats.FileMode)).To(Equal(0755)) Expect(int(binTest2Stats.FileMode)).To(Equal(0755)) // non-bin files are not made executable Expect(int(configTestStats.FileMode)).ToNot(Equal(0755)) }) } ItUpdatesPackages := func(act func() error) { var packageApplier *fakepa.FakePackageApplier BeforeEach(func() { packageApplier = fakepa.NewFakePackageApplier() packageApplierProvider.JobSpecificPackageAppliers[job.Name] = packageApplier }) It("applies each package that job depends on and then cleans up packages", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(packageApplier.ActionsCalled).To(Equal([]string{"Apply", "Apply", "KeepOnly"})) Expect(len(packageApplier.AppliedPackages)).To(Equal(2)) // present Expect(packageApplier.AppliedPackages).To(Equal(job.Packages)) }) It("returns error when applying package that job depends on fails", func() { packageApplier.ApplyError = errors.New("fake-apply-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-err")) }) It("keeps only currently required packages but does not completely uninstall them", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(len(packageApplier.KeptOnlyPackages)).To(Equal(2)) // present Expect(packageApplier.KeptOnlyPackages).To(Equal(job.Packages)) }) It("returns error when keeping only currently required packages fails", func() { packageApplier.KeepOnlyErr = errors.New("fake-keep-only-err") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-keep-only-err")) }) } Describe("Prepare", func() { act := func() error { return applier.Prepare(job) } It("return an error if getting file bundle fails", func() { jobsBc.GetErr = errors.New("fake-get-bundle-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error")) }) It("returns an error if checking for installed path fails", func() { bundle.IsInstalledErr = errors.New("fake-is-installed-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-installed-error")) }) Context("when job is already installed", func() { BeforeEach(func() { bundle.Installed = true }) It("does not install", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{})) // no Install }) It("does not download the job template", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs).To(BeNil()) }) }) Context("when job is not installed", func() { BeforeEach(func() { bundle.Installed = false }) It("installs job (but does not enable)", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Install"})) }) ItInstallsJob(act) }) }) Describe("Apply", func() { act := func() error { return applier.Apply(job) } It("return an error if getting file bundle fails", func() { jobsBc.GetErr = errors.New("fake-get-bundle-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-get-bundle-error")) }) It("returns an error if checking for installed path fails", func() { bundle.IsInstalledErr = errors.New("fake-is-installed-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-is-installed-error")) }) Context("when job is already installed", func() { BeforeEach(func() { bundle.Installed = true }) It("does not install but only enables job", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Enable"})) // no Install }) It("returns error when job enable fails", func() { bundle.EnableError = errors.New("fake-enable-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-enable-error")) }) It("does not download the job template", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(blobstore.GetBlobIDs).To(BeNil()) }) ItUpdatesPackages(act) }) Context("when job is not installed", func() { BeforeEach(func() { bundle.Installed = false }) It("installs and enables job", func() { err := act() Expect(err).ToNot(HaveOccurred()) Expect(bundle.ActionsCalled).To(Equal([]string{"Install", "Enable"})) }) It("returns error when job enable fails", func() { bundle.EnableError = errors.New("fake-enable-error") err := act() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-enable-error")) }) ItInstallsJob(act) ItUpdatesPackages(act) }) }) }) Describe("Configure", func() { It("adds job to the job supervisor", func() { job, bundle := buildJob(jobsBc) fs := fakesys.NewFakeFileSystem() fs.WriteFileString("/path/to/job/monit", "some conf") fs.SetGlob("/path/to/job/*.monit", []string{"/path/to/job/subjob.monit"}) bundle.GetDirPath = "/path/to/job" bundle.GetDirFs = fs err := applier.Configure(job, 0) Expect(err).ToNot(HaveOccurred()) Expect(2).To(Equal(len(jobSupervisor.AddJobArgs))) firstArgs := fakejobsuper.AddJobArgs{ Name: job.Name, Index: 0, ConfigPath: "/path/to/job/monit", } secondArgs := fakejobsuper.AddJobArgs{ Name: job.Name + "_subjob", Index: 0, ConfigPath: "/path/to/job/subjob.monit", } Expect(firstArgs).To(Equal(jobSupervisor.AddJobArgs[0])) Expect(secondArgs).To(Equal(jobSupervisor.AddJobArgs[1])) }) }) Describe("KeepOnly", func() { It("first disables and then uninstalls jobs that are not in keeponly list", func() { _, bundle1 := buildJob(jobsBc) job2, bundle2 := buildJob(jobsBc) _, bundle3 := buildJob(jobsBc) job4, bundle4 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1, bundle2, bundle3, bundle4} err := applier.KeepOnly([]models.Job{job4, job2}) Expect(err).ToNot(HaveOccurred()) Expect(bundle1.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"})) Expect(bundle2.ActionsCalled).To(Equal([]string{})) Expect(bundle3.ActionsCalled).To(Equal([]string{"Disable", "Uninstall"})) Expect(bundle4.ActionsCalled).To(Equal([]string{})) }) It("returns error when bundle collection fails to return list of installed bundles", func() { jobsBc.ListErr = errors.New("fake-bc-list-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-list-error")) }) It("returns error when bundle collection cannot retrieve bundle for keep-only job", func() { job1, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} jobsBc.GetErr = errors.New("fake-bc-get-error") err := applier.KeepOnly([]models.Job{job1}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-get-error")) }) It("returns error when at least one bundle cannot be disabled", func() { _, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} bundle1.DisableErr = errors.New("fake-bc-disable-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-disable-error")) }) It("returns error when at least one bundle cannot be uninstalled", func() { _, bundle1 := buildJob(jobsBc) jobsBc.ListBundles = []boshbc.Bundle{bundle1} bundle1.UninstallErr = errors.New("fake-bc-uninstall-error") err := applier.KeepOnly([]models.Job{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-bc-uninstall-error")) }) }) }) }
func init() { Describe("concreteApplier", func() { var ( jobApplier *fakeja.FakeJobApplier packageApplier *fakepa.FakePackageApplier logRotateDelegate *FakeLogRotateDelegate jobSupervisor *fakejobsuper.FakeJobSupervisor applier Applier ) BeforeEach(func() { jobApplier = fakeja.NewFakeJobApplier() packageApplier = fakepa.NewFakePackageApplier() logRotateDelegate = &FakeLogRotateDelegate{} jobSupervisor = fakejobsuper.NewFakeJobSupervisor() applier = NewConcreteApplier( jobApplier, packageApplier, logRotateDelegate, jobSupervisor, boshdirs.NewDirectoriesProvider("/fake-base-dir"), ) }) It("removes all jobs", func() { err := applier.Apply(&fakeas.FakeApplySpec{}) Expect(err).ToNot(HaveOccurred()) Expect(jobSupervisor.RemovedAllJobs).To(BeTrue()) }) It("removes all previous jobs 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{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 fails", func() { jobSupervisor.RemovedAllJobsErr = errors.New("fake-remove-all-jobs-error") err := applier.Apply(&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{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{JobResults: []models.Job{job}}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-job-error")) }) It("apply applies packages", func() { pkg1 := buildPackage() pkg2 := buildPackage() err := applier.Apply(&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{PackageResults: []models.Package{pkg}}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-apply-package-error")) }) It("apply 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.Apply(&fakeas.FakeApplySpec{JobResults: jobs}) Expect(err).ToNot(HaveOccurred()) Expect(jobApplier.ConfiguredJobs).To(Equal([]models.Job{job2, job1})) Expect(jobApplier.ConfiguredJobIndices).To(Equal([]int{0, 1})) 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{JobResults: jobs}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("error reloading monit")) }) It("apply errs if a job fails configuring", func() { jobApplier.ConfigureError = errors.New("error configuring job") job := models.Job{Name: "fake-job-name-1", Version: "fake-version-name-1"} err := applier.Apply(&fakeas.FakeApplySpec{JobResults: []models.Job{job}}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("error configuring job")) }) It("apply sets up logrotation", func() { err := applier.Apply(&fakeas.FakeApplySpec{MaxLogFileSizeResult: "fake-size"}) Expect(err).ToNot(HaveOccurred()) assert.Equal(GinkgoT(), logRotateDelegate.SetupLogrotateArgs, SetupLogrotateArgs{ GroupName: boshsettings.VCAP_USERNAME, BasePath: "/fake-base-dir", Size: "fake-size", }) }) It("apply errs if setup logrotate fails", func() { logRotateDelegate.SetupLogrotateErr = errors.New("fake-msg") err := applier.Apply(&fakeas.FakeApplySpec{}) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("Logrotate setup failed: fake-msg")) }) }) }
func init() { Describe("Agent", func() { var ( agent Agent logger boshlog.Logger handler *fakembus.FakeHandler platform *fakeplatform.FakePlatform actionDispatcher *FakeActionDispatcher alertBuilder *fakealert.FakeAlertBuilder alertSender AlertSender jobSupervisor *fakejobsuper.FakeJobSupervisor specService *fakeas.FakeV1Service ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LevelDebug) handler = &fakembus.FakeHandler{} platform = fakeplatform.NewFakePlatform() actionDispatcher = &FakeActionDispatcher{} alertBuilder = fakealert.NewFakeAlertBuilder() alertSender = NewAlertSender(handler, alertBuilder) jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() agent = New(logger, handler, platform, actionDispatcher, alertSender, jobSupervisor, specService, 5*time.Millisecond) }) 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" jobIndex := 1 specService.Spec = boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{Name: &jobName}, Index: &jobIndex, } jobSupervisor.StatusStatus = "fake-state" platform.FakeVitalsService.GetVitals = boshvitals.Vitals{ Load: []string{"a", "b", "c"}, } }) expectedJobName := "fake-job" expectedJobIndex := 1 expectedHb := boshmbus.Heartbeat{ Job: &expectedJobName, Index: &expectedJobIndex, JobState: "fake-state", 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, alertSender, jobSupervisor, specService, 5*time.Hour) // Immediately exit after sending initial heartbeat handler.SendToHealthManagerErr = errors.New("stop") err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(handler.HMRequests()).To(Equal([]fakembus.HMRequest{ fakembus.HMRequest{Topic: "heartbeat", Payload: expectedHb}, })) }) It("sends periodic heartbeats", func() { sentRequests := 0 handler.SendToHealthManagerCallBack = func(_ fakembus.HMRequest) { sentRequests++ if sentRequests == 3 { handler.SendToHealthManagerErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(handler.HMRequests()).To(Equal([]fakembus.HMRequest{ fakembus.HMRequest{Topic: "heartbeat", Payload: expectedHb}, fakembus.HMRequest{Topic: "heartbeat", Payload: expectedHb}, fakembus.HMRequest{Topic: "heartbeat", Payload: 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 failure alerts to health manager", func() { handler.KeepOnRunning() failureAlert := boshalert.MonitAlert{ID: "fake-monit-alert"} jobSupervisor.JobFailureAlert = &failureAlert builtAlert := boshalert.Alert{ID: "fake-built-alert"} alertBuilder.BuildAlert = builtAlert // Immediately exit from Run() after alert is sent handler.SendToHealthManagerCallBack = func(hmRequest fakembus.HMRequest) { if hmRequest.Topic == "alert" { handler.SendToHealthManagerErr = errors.New("stop") } } err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("stop")) Expect(alertBuilder.BuildInput).To(Equal(failureAlert)) // Check for inclusion because heartbeats might have been received Expect(handler.HMRequests()).To(ContainElement( fakembus.HMRequest{Topic: "alert", Payload: builtAlert}, )) }) }) }) }
func buildStopAction() (jobSupervisor *fakejobsuper.FakeJobSupervisor, action stopAction) { jobSupervisor = fakejobsuper.NewFakeJobSupervisor() action = newStop(jobSupervisor) return }
func init() { Describe("concreteFactory", func() { var ( settings *fakesettings.FakeSettingsService platform *fakeplatform.FakePlatform infrastructure *fakeinfrastructure.FakeInfrastructure blobstore *fakeblobstore.FakeBlobstore taskService *faketask.FakeService notifier *fakenotif.FakeNotifier applier *fakeappl.FakeApplier compiler *fakecomp.FakeCompiler jobSupervisor *fakejobsuper.FakeJobSupervisor specService *fakeas.FakeV1Service drainScriptProvider boshdrain.DrainScriptProvider factory Factory logger boshlog.Logger ) BeforeEach(func() { settings = &fakesettings.FakeSettingsService{} platform = fakeplatform.NewFakePlatform() infrastructure = fakeinfrastructure.NewFakeInfrastructure() blobstore = &fakeblobstore.FakeBlobstore{} taskService = &faketask.FakeService{} notifier = fakenotif.NewFakeNotifier() applier = fakeappl.NewFakeApplier() compiler = fakecomp.NewFakeCompiler() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() drainScriptProvider = boshdrain.NewConcreteDrainScriptProvider(nil, nil, platform.GetDirProvider()) logger = boshlog.NewLogger(boshlog.LEVEL_NONE) }) JustBeforeEach(func() { factory = NewFactory( settings, platform, infrastructure, blobstore, taskService, notifier, applier, compiler, jobSupervisor, specService, drainScriptProvider, logger, ) }) It("new factory", func() { actions := []string{ "apply", "drain", "fetch_logs", "get_task", "get_state", "list_disk", "migrate_disk", "mount_disk", "ping", "prepare_network_change", "ssh", "start", "stop", "unmount_disk", "compile_package", "release_apply_spec", } for _, actionName := range actions { action, err := factory.Create(actionName) Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) } action, err := factory.Create("gobberish") Expect(err).To(HaveOccurred()) Expect(action).To(BeNil()) }) It("apply", func() { action, err := factory.Create("apply") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewApply(applier, specService)).To(Equal(action)) }) It("drain", func() { action, err := factory.Create("drain") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewDrain(notifier, specService, drainScriptProvider, jobSupervisor)).To(Equal(action)) }) It("fetch_logs", func() { action, err := factory.Create("fetch_logs") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewLogs(platform.GetCompressor(), platform.GetCopier(), blobstore, platform.GetDirProvider())).To(Equal(action)) }) It("get_task", func() { action, err := factory.Create("get_task") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewGetTask(taskService)).To(Equal(action)) }) It("get_state", func() { ntpService := boshntp.NewConcreteService(platform.GetFs(), platform.GetDirProvider()) action, err := factory.Create("get_state") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewGetState(settings, specService, jobSupervisor, platform.GetVitalsService(), ntpService)).To(Equal(action)) }) It("list_disk", func() { action, err := factory.Create("list_disk") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewListDisk(settings, platform, logger)).To(Equal(action)) }) It("migrate_disk", func() { action, err := factory.Create("migrate_disk") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewMigrateDisk(platform, platform.GetDirProvider())).To(Equal(action)) }) It("mount_disk", func() { action, err := factory.Create("mount_disk") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewMountDisk(settings, infrastructure, platform, platform.GetDirProvider())).To(Equal(action)) }) It("prepare_network_change", func() { action, err := factory.Create("prepare_network_change") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewPrepareNetworkChange(platform.GetFs(), settings)).To(Equal(action)) }) It("prepare_configure_networks", func() { action, err := factory.Create("prepare_configure_networks") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewPrepareConfigureNetworks(platform.GetFs(), settings)).To(Equal(action)) }) It("configure_networks", func() { action, err := factory.Create("configure_networks") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewConfigureNetworks()).To(Equal(action)) }) It("ssh", func() { action, err := factory.Create("ssh") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewSsh(settings, platform, platform.GetDirProvider())).To(Equal(action)) }) It("start", func() { action, err := factory.Create("start") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewStart(jobSupervisor)).To(Equal(action)) }) It("unmount_disk", func() { action, err := factory.Create("unmount_disk") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewUnmountDisk(settings, platform)).To(Equal(action)) }) It("compile_package", func() { action, err := factory.Create("compile_package") Expect(err).NotTo(HaveOccurred()) Expect(action).ToNot(BeNil()) Expect(NewCompilePackage(compiler)).To(Equal(action)) }) }) }
func init() { Describe("Agent", func() { var ( agent Agent logger boshlog.Logger handler *fakembus.FakeHandler platform *fakeplatform.FakePlatform actionDispatcher *FakeActionDispatcher alertBuilder *fakealert.FakeAlertBuilder jobSupervisor *fakejobsuper.FakeJobSupervisor specService *fakeas.FakeV1Service ) BeforeEach(func() { logger = boshlog.NewLogger(boshlog.LEVEL_NONE) handler = &fakembus.FakeHandler{} platform = fakeplatform.NewFakePlatform() actionDispatcher = &FakeActionDispatcher{} alertBuilder = fakealert.NewFakeAlertBuilder() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() agent = New(logger, handler, platform, actionDispatcher, alertBuilder, jobSupervisor, specService, 5*time.Millisecond) }) Describe("Run", func() { It("sets the dispatcher as message handler", func() { actionDispatcher.DispatchResp = boshhandler.NewValueResponse("pong") err := agent.Run() Expect(err).ToNot(HaveOccurred()) Expect(handler.ReceivedRun).To(BeTrue()) req := boshhandler.NewRequest("fake-reply", "fake-action", []byte("fake-payload")) resp := handler.Func(req) Expect(req).To(Equal(actionDispatcher.DispatchReq)) Expect(actionDispatcher.DispatchResp).To(Equal(resp)) }) It("resumes persistent actions *before* dispatching new requests", func() { resumedBefore := false handler.RunFunc = func() { resumedBefore = actionDispatcher.ResumedPreviouslyDispatchedTasks } err := agent.Run() Expect(err).ToNot(HaveOccurred()) Expect(resumedBefore).To(BeTrue()) }) Context("when heartbeats can be sent", func() { BeforeEach(func() { jobName := "fake-job" jobIndex := 1 specService.Spec = boshas.V1ApplySpec{ JobSpec: boshas.JobSpec{Name: &jobName}, Index: &jobIndex, } jobSupervisor.StatusStatus = "fake-state" platform.FakeVitalsService.GetVitals = boshvitals.Vitals{ Load: []string{"a", "b", "c"}, } }) expectedJobName := "fake-job" expectedJobIndex := 1 expectedHb := boshmbus.Heartbeat{ Job: &expectedJobName, Index: &expectedJobIndex, JobState: "fake-state", Vitals: boshvitals.Vitals{Load: []string{"a", "b", "c"}}, } It("sends initial heartbeat", func() { err := agent.Run() Expect(err).ToNot(HaveOccurred()) Expect(handler.InitialHeartbeatSent).To(BeTrue()) Expect(handler.TickHeartbeatsSent).To(BeFalse()) Expect(handler.SendToHealthManagerTopic).To(Equal("heartbeat")) Expect(handler.SendToHealthManagerPayload.(boshmbus.Heartbeat)).To(Equal(expectedHb)) }) It("sends periodic heartbeats", func() { err := agent.Run() Expect(err).ToNot(HaveOccurred()) Expect(handler.TickHeartbeatsSent).To(BeFalse()) time.Sleep(5 * time.Millisecond) Expect(handler.TickHeartbeatsSent).To(BeTrue()) Expect(handler.SendToHealthManagerTopic).To(Equal("heartbeat")) Expect(handler.SendToHealthManagerPayload.(boshmbus.Heartbeat)).To(Equal(expectedHb)) }) }) Context("when the agent fails to get job spec for a heartbeat", func() { BeforeEach(func() { block := make(chan error) handler.RunFunc = func() { <-block } specService.GetErr = errors.New("fake-spec-service-error") }) 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() { block := make(chan error) handler.RunFunc = func() { <-block } platform.FakeVitalsService.GetErr = errors.New("fake-vitals-service-error") }) It("returns the error", func() { err := agent.Run() Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("fake-vitals-service-error")) }) }) It("sets the callback for job failures monitoring", func() { builtAlert := boshalert.Alert{Id: "some built alert id"} alertBuilder.BuildAlert = builtAlert err := agent.Run() Expect(err).ToNot(HaveOccurred()) Expect(handler.SendToHealthManagerTopic).ToNot(Equal("alert")) failureAlert := boshalert.MonitAlert{Id: "some random id"} jobSupervisor.OnJobFailure(failureAlert) Expect(failureAlert).To(Equal(alertBuilder.BuildInput)) Expect(handler.SendToHealthManagerTopic).To(Equal("alert")) Expect(builtAlert).To(Equal(handler.SendToHealthManagerPayload)) }) }) }) }
func buildStartAction() (jobSupervisor *fakejobsuper.FakeJobSupervisor, action StartAction) { jobSupervisor = fakejobsuper.NewFakeJobSupervisor() action = NewStart(jobSupervisor) return }
jobSupervisor *fakejobsuper.FakeJobSupervisor specService *fakeas.FakeV1Service drainScriptProvider boshdrain.DrainScriptProvider factory Factory logger boshlog.Logger ) BeforeEach(func() { settingsService = &fakesettings.FakeSettingsService{} platform = fakeplatform.NewFakePlatform() blobstore = &fakeblobstore.FakeBlobstore{} taskService = &faketask.FakeService{} notifier = fakenotif.NewFakeNotifier() applier = fakeappl.NewFakeApplier() compiler = fakecomp.NewFakeCompiler() jobSupervisor = fakejobsuper.NewFakeJobSupervisor() specService = fakeas.NewFakeV1Service() drainScriptProvider = boshdrain.NewConcreteDrainScriptProvider(nil, nil, platform.GetDirProvider()) logger = boshlog.NewLogger(boshlog.LevelNone) factory = NewFactory( settingsService, platform, blobstore, taskService, notifier, applier, compiler, jobSupervisor, specService, drainScriptProvider,
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)) }) }) }) }) }