Describe("The steady state", func() { Context("When there are no desired or running apps", func() { It("should not send any start or stop messages", func() { err := analyzer.Analyze() Ω(err).ShouldNot(HaveOccurred()) Ω(startMessages()).Should(BeEmpty()) Ω(stopMessages()).Should(BeEmpty()) }) }) Context("When the desired number of instances and the running number of instances match", func() { BeforeEach(func() { desired := app.DesiredState(3) desired.State = models.AppStateStarted store.SyncDesiredState( desired, ) store.SyncHeartbeats(app.Heartbeat(3)) }) It("should not send any start or stop messages", func() { err := analyzer.Analyze() Ω(err).ShouldNot(HaveOccurred()) Ω(startMessages()).Should(BeEmpty()) Ω(stopMessages()).Should(BeEmpty()) }) }) }) Describe("Starting missing instances", func() { Context("where an app has desired instances", func() {
} crashCount := models.CrashCount{ AppGuid: app.AppGuid, AppVersion: app.AppVersion, InstanceIndex: 1, CrashCount: 2, } expectedApp = models.NewApp( app.AppGuid, app.AppVersion, app.DesiredState(3), instanceHeartbeats, map[int]models.CrashCount{1: crashCount}, ) store.SyncDesiredState(app.DesiredState(3)) store.SyncHeartbeats(app.Heartbeat(3)) store.SaveCrashCounts(crashCount) validRequestPayload = fmt.Sprintf(`{"droplet":"%s","version":"%s"}`, app.AppGuid, app.AppVersion) }) Context("when the store is fresh", func() { BeforeEach(func() { store.BumpDesiredFreshness(time.Unix(0, 0)) store.BumpActualFreshness(time.Unix(0, 0)) }) Context("when the app query parameters do not correspond to an existing app", func() { It("should respond with an empty hash", func() { response := makeRequest(`{"droplet":"elephant","version":"pink-flamingo"}`) Ω(response).Should(Equal("{}"))
Context("when a response with desired state is received", func() { var ( a1 appfixture.AppFixture a2 appfixture.AppFixture stoppedApp appfixture.AppFixture pendingStagingApp appfixture.AppFixture failedToStageApp appfixture.AppFixture deletedApp appfixture.AppFixture pendingStagingDesiredState models.DesiredAppState ) BeforeEach(func() { deletedApp = appfixture.NewAppFixture() store.SyncDesiredState(deletedApp.DesiredState(1)) a1 = appfixture.NewAppFixture() a2 = appfixture.NewAppFixture() stoppedApp = appfixture.NewAppFixture() stoppedDesiredState := stoppedApp.DesiredState(1) stoppedDesiredState.State = models.AppStateStopped pendingStagingApp = appfixture.NewAppFixture() pendingStagingDesiredState = pendingStagingApp.DesiredState(1) pendingStagingDesiredState.PackageState = models.AppPackageStatePending failedToStageApp = appfixture.NewAppFixture() failedStagingDesiredState := failedToStageApp.DesiredState(1) failedStagingDesiredState.PackageState = models.AppPackageStateFailed
Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfUndesiredRunningApps", Value: -1})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfRunningInstances", Value: -1})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfMissingIndices", Value: -1})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfCrashedInstances", Value: -1})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfCrashedIndices", Value: -1})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfDesiredApps", Value: -1})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfDesiredInstances", Value: -1})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfDesiredAppsPendingStaging", Value: -1})) }) }) Context("When a desired app is pending staging", func() { BeforeEach(func() { desired := a.DesiredState(3) desired.PackageState = models.AppPackageStatePending store.SyncDesiredState(desired) store.SyncHeartbeats(a.Heartbeat(1)) }) It("should have the correct stats", func() { context := metricsServer.Emit() Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfAppsWithAllInstancesReporting", Value: 0})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfAppsWithMissingInstances", Value: 0})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfUndesiredRunningApps", Value: 0})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfRunningInstances", Value: 1})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfMissingIndices", Value: 0})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfCrashedInstances", Value: 0})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfCrashedIndices", Value: 0})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfDesiredApps", Value: 0})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfDesiredInstances", Value: 0})) Ω(context.Metrics).Should(ContainElement(instrumentation.Metric{Name: "NumberOfDesiredAppsPendingStaging", Value: 1}))
It("should not send any messages", func() { err := sender.Send() Ω(err).ShouldNot(HaveOccurred()) Ω(messageBus.PublishedMessages).Should(BeEmpty()) }) }) Context("when there are start messages", func() { var keepAliveTime int var sentOn int64 var err error var pendingMessage models.PendingStartMessage var storeSetErrInjector *fakestoreadapter.FakeStoreAdapterErrorInjector JustBeforeEach(func() { store.SyncDesiredState(app.DesiredState(1)) pendingMessage = models.NewPendingStartMessage(time.Unix(100, 0), 30, keepAliveTime, app.AppGuid, app.AppVersion, 0, 1.0, models.PendingStartMessageReasonInvalid) pendingMessage.SentOn = sentOn store.SavePendingStartMessages( pendingMessage, ) storeAdapter.SetErrInjector = storeSetErrInjector err = sender.Send() }) BeforeEach(func() { keepAliveTime = 0 sentOn = 0 err = nil storeSetErrInjector = nil })