Key: "syslog_drain_binder/leader", Value: []byte("some-other-instance"), }) Expect(err).NotTo(HaveOccurred()) go candidate.RunForElection() Eventually(func() int { return len(testingSink.Records()) }, 3).Should(BeNumerically(">=", 2)) for _, record := range testingSink.Records() { Expect(record.Message).To(Equal("Elector: 'name' lost election for cluster leader.")) } }) It("returns an error if any other error occurs while setting key", func() { testError := errors.New("test error") fakeStore.CreateErrInjector = fakestoreadapter.NewFakeStoreAdapterErrorInjector("syslog_drain_binder", testError) err := candidate.RunForElection() Expect(err).To(Equal(testError)) Expect(candidate.IsLeader()).To(BeFalse()) }) It("returns nil when it eventually wins", func() { preExistingNode := storeadapter.StoreNode{ Key: "syslog_drain_binder/leader", Value: []byte("some-other-instance"), } err := fakeStore.Create(preExistingNode) Expect(err).NotTo(HaveOccurred()) errChan := make(chan error)
"StartMissing": 0, "StartEvacuating": 0, "StopExtra": 0, "StopDuplicate": 0, "StopEvacuationComplete": 0, "DesiredStateSyncTimeInMilliseconds": 0, "ActualStateListenerStoreUsagePercentage": 0, "ReceivedHeartbeats": 0, "SavedHeartbeats": 0, })) }) }) Context("when the store errors for some other reason", func() { BeforeEach(func() { fakeStoreAdapter.GetErrInjector = fakestoreadapter.NewFakeStoreAdapterErrorInjector("metrics", errors.New("oops")) }) It("should return an error and an empty map", func() { metrics, err := accountant.GetMetrics() Ω(err).Should(Equal(errors.New("oops"))) Ω(metrics).Should(BeEmpty()) }) }) }) Describe("TrackReceivedHeartbeats", func() { It("should record the number of received heartbeats appropriately", func() { err := accountant.TrackReceivedHeartbeats(127) Ω(err).ShouldNot(HaveOccurred()) metrics, err := accountant.GetMetrics()
node, _ = fakeStoreAdapter.Get(drainKey("app-id", "url2")) Expect(node.Value).To(BeEquivalentTo("url2")) }) It("sets TTL on the app node if there are drain changes", func() { appDrainUrlMap := map[shared_types.AppId][]shared_types.DrainURL{ "app-id": {"url1"}, } syslogDrainStore.UpdateDrains(appDrainUrlMap) node, _ := fakeStoreAdapter.Get(drainKey("app-id", "url1")) Expect(node.TTL).To(BeEquivalentTo(10)) }) It("returns an error if adapter.SetMulti fails", func() { fakeError := errors.New("fake error") fakeStoreAdapter.SetErrInjector = fakestoreadapter.NewFakeStoreAdapterErrorInjector(".*", fakeError) appDrainUrlMap := map[shared_types.AppId][]shared_types.DrainURL{ "app-id": {"url1"}, } err := syslogDrainStore.UpdateDrains(appDrainUrlMap) Expect(err).To(Equal(fakeError)) }) It("does not store drain nodes if they have an empty URL", func() { appDrainUrlMap := map[shared_types.AppId][]shared_types.DrainURL{ "app-id": {" ", "", "\t"}, } syslogDrainStore.UpdateDrains(appDrainUrlMap) Expect(fakeStoreAdapter.SetKeyCounters).NotTo(HaveKey(drainKey("app-id", ""))) Expect(fakeStoreAdapter.SetKeyCounters).NotTo(HaveKey(drainKey("app-id", " "))) Expect(fakeStoreAdapter.SetKeyCounters).NotTo(HaveKey(drainKey("app-id", "\t")))
Context("when the actual state is not fresh", func() { BeforeEach(func() { store.BumpDesiredFreshness(time.Unix(10, 0)) }) It("should not send any start or stop messages", func() { err := analyzer.Analyze() Ω(err).Should(Equal(storepackage.ActualIsNotFreshError)) Ω(startMessages()).Should(BeEmpty()) Ω(stopMessages()).Should(BeEmpty()) }) }) Context("when the apps fail to fetch", func() { BeforeEach(func() { store.BumpActualFreshness(time.Unix(10, 0)) store.BumpDesiredFreshness(time.Unix(10, 0)) storeAdapter.ListErrInjector = fakestoreadapter.NewFakeStoreAdapterErrorInjector("apps", errors.New("oops!")) }) It("should return the store's error and not send any start/stop messages", func() { err := analyzer.Analyze() Ω(err).Should(Equal(errors.New("oops!"))) Ω(startMessages()).Should(BeEmpty()) Ω(stopMessages()).Should(BeEmpty()) }) }) }) })
It("should respond with an empty hash", func() { response := makeRequest(`{"droplet":"elephant","version":"pink-flamingo"}`) Ω(response).Should(Equal("{}")) }) }) Context("when the app query parameters correspond to an existing app", func() { It("should return the actual instances and crashes of the app", func() { response := makeRequest(validRequestPayload) Ω(response).Should(Equal(string(expectedApp.ToJSON()))) }) }) Context("when something else goes wrong with the store", func() { BeforeEach(func() { storeAdapter.GetErrInjector = fakestoreadapter.NewFakeStoreAdapterErrorInjector("desired", fmt.Errorf("No desired state for you!")) }) It("should return an empty hash", func() { response := makeRequest(validRequestPayload) Ω(response).Should(Equal("{}")) }) }) }) Context("when the store is not fresh", func() { It("should return an empty hash", func() { response := makeRequest(validRequestPayload) Ω(response).Should(Equal("{}")) }) })
conf.ListenerHeartbeatSyncIntervalInMilliseconds = 0 forceHeartbeatSync() }) It("should not bump the freshness", func() { isFresh, _ := store.IsActualStateFresh(freshByTime) Ω(isFresh).Should(BeFalse()) }) }) Context("when the save fails", func() { BeforeEach(func() { store.BumpActualFreshness(timeProvider.Time()) storeAdapter.SetErrInjector = fakestoreadapter.NewFakeStoreAdapterErrorInjector(app.InstanceAtIndex(0).InstanceGuid, errors.New("oops")) messageBus.Subscriptions["dea.heartbeat"][0].Callback(&yagnats.Message{ Payload: heartbeat.ToJSON(), }) forceHeartbeatSync() }) It("logs about the failed save", func() { Ω(logger.LoggedSubjects).Should(ContainElement(ContainSubstring("Could not put instance heartbeats in store"))) }) It("does not bump the SavedHeartbeats metric", func() { Ω(metricsAccountant.SavedHeartbeats).Should(Equal(0)) })
metricsAccountant = fakemetricsaccountant.New() timeProvider = &faketimeprovider.FakeTimeProvider{ TimeToProvide: time.Unix(int64(10+conf.ActualFreshnessTTL()), 0), } storeAdapter = fakestoreadapter.New() store = storepackage.NewStore(conf, storeAdapter, fakelogger.NewFakeLogger()) sender = New(store, metricsAccountant, conf, messageBus, timeProvider, fakelogger.NewFakeLogger()) store.BumpActualFreshness(time.Unix(10, 0)) store.BumpDesiredFreshness(time.Unix(10, 0)) }) Context("when the sender fails to pull messages out of the start queue", func() { BeforeEach(func() { storeAdapter.ListErrInjector = fakestoreadapter.NewFakeStoreAdapterErrorInjector("start", errors.New("oops")) }) It("should return an error and not send any messages", func() { err := sender.Send() Ω(err).Should(Equal(errors.New("oops"))) Ω(messageBus.PublishedMessages).Should(BeEmpty()) }) }) Context("when the sender fails to pull messages out of the stop queue", func() { BeforeEach(func() { storeAdapter.ListErrInjector = fakestoreadapter.NewFakeStoreAdapterErrorInjector("stop", errors.New("oops")) }) It("should return an error and not send any messages", func() {