Example #1
0
				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")))
Example #4
0
		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() {