Ω(a2.Desired).Should(BeZero()) Ω(a2.InstanceHeartbeats).Should(HaveLen(1)) Ω(a2.InstanceHeartbeats).Should(ContainElement(app2.InstanceAtIndex(0).Heartbeat())) Ω(a2.CrashCounts[0]).Should(Equal(crashCount[2])) a3 := apps[app3.AppGuid+","+app3.AppVersion] Ω(a3.Desired).Should(EqualDesiredState(app3.DesiredState(1))) Ω(a3.InstanceHeartbeats).Should(HaveLen(0)) Ω(a3.CrashCounts).Should(BeEmpty()) }) }) Context("when there is an empty app directory", func() { It("should ignore that app directory", func() { storeAdapter.SetMulti([]storeadapter.StoreNode{{ Key: "/hm/v1/apps/actual/foo-bar", Value: []byte("foo"), }}) apps, err := store.GetApps() Ω(err).ShouldNot(HaveOccurred()) Ω(apps).Should(HaveLen(3)) }) }) }) Describe("GetApp", func() { Context("when there are no store errors", func() { Context("when the app has desired and actual state", func() { It("should return the app", func() { app, err := store.GetApp(app1.AppGuid, app1.AppVersion) Ω(err).ShouldNot(HaveOccurred())
BeforeEach(func() { store.BumpDesiredFreshness(time.Unix(100, 0)) }) It("returns that the state is fresh", func() { fresh, err := store.IsDesiredStateFresh() Ω(err).ShouldNot(HaveOccurred()) Ω(fresh).Should(BeTrue()) }) }) Context("when the store returns an error", func() { BeforeEach(func() { err := storeAdapter.SetMulti([]storeadapter.StoreNode{ { Key: "/hm/v1/desired-fresh/mwahaha", Value: []byte("i'm a directory...."), }, }) Ω(err).ShouldNot(HaveOccurred()) }) It("should return the store's error", func() { fresh, err := store.IsDesiredStateFresh() Ω(err).Should(Equal(storeadapter.ErrorNodeIsDirectory)) Ω(fresh).Should(BeFalse()) }) }) }) Describe("Checking actual state freshness", func() { Context("if the freshness key is not present", func() {
storeAdapter = etcdstoreadapter.NewETCDStoreAdapter(etcdRunner.NodeURLS(), workpool.NewWorkPool(conf.StoreMaxConcurrentRequests)) err = storeAdapter.Connect() Ω(err).ShouldNot(HaveOccurred()) store = NewStore(conf, storeAdapter, fakelogger.NewFakeLogger()) }) Describe("Deleting old schema version", func() { BeforeEach(func() { storeAdapter.SetMulti([]storeadapter.StoreNode{ {Key: "/hm/v3/delete/me", Value: []byte("abc")}, {Key: "/hm/v16/delete/me", Value: []byte("abc")}, {Key: "/hm/v17/leave/me/alone", Value: []byte("abc")}, {Key: "/hm/v17/leave/me/v1/alone", Value: []byte("abc")}, {Key: "/hm/v18/leave/me/alone", Value: []byte("abc")}, {Key: "/hm/delete/me", Value: []byte("abc")}, {Key: "/hm/v1ola/delete/me", Value: []byte("abc")}, {Key: "/hm/delete/me/too", Value: []byte("abc")}, {Key: "/hm/locks/keep", Value: []byte("abc")}, {Key: "/other/keep", Value: []byte("abc")}, {Key: "/foo", Value: []byte("abc")}, {Key: "/v3/keep", Value: []byte("abc")}, }) err := store.Compact() Ω(err).ShouldNot(HaveOccurred()) }) It("should delete everything under older versions", func() { _, err := storeAdapter.Get("/hm/v3/delete/me") Ω(err).Should(Equal(storeadapter.ErrorKeyNotFound))
Context("when an existing app has a new service (create)", func() { It("adds that service to the outgoing add channel", func(done Done) { app2Service2 := domain.AppService{AppId: app2Service1.AppId, Url: "syslog://new.example.com:12345"} adapter.Create(buildNode(app2Service2)) Expect(<-outAddChan).To(Equal(app2Service2)) assertNoDataOnChannel(outRemoveChan) close(done) }) }) Context("When an existing app gets a new service (update)", func() { It("adds that service to the outgoing add channel", func(done Done) { app2Service2 := domain.AppService{AppId: app2Service1.AppId, Url: "syslog://new.example.com:12345"} adapter.SetMulti([]storeadapter.StoreNode{buildNode(app2Service2)}) Expect(<-outAddChan).To(Equal(app2Service2)) assertNoDataOnChannel(outRemoveChan) close(done) }) }) Context("when a new app appears", func() { It("adds that app and its services to the outgoing add channel", func(done Done) { app3Service1 := domain.AppService{AppId: "app-3", Url: "syslog://app3.example.com:12345"} app3Service2 := domain.AppService{AppId: "app-3", Url: "syslog://app3.example.com:12346"} adapter.Create(buildNode(app3Service1)) adapter.Create(buildNode(app3Service2))