From 19231792198213c470ef5c67cee3f162e5a97f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20H=C3=B6rl?= Date: Mon, 4 Dec 2017 12:20:36 +0000 Subject: [PATCH] Use a fake datadir manager in etcd tests --- pkg/framework/test/etcd.go | 10 +- pkg/framework/test/etcd_test.go | 32 +++- .../test/testfakes/fake_data_dir_manager.go | 140 ++++++++++++++++++ 3 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 pkg/framework/test/testfakes/fake_data_dir_manager.go diff --git a/pkg/framework/test/etcd.go b/pkg/framework/test/etcd.go index f9118f5b6..1b703d98c 100644 --- a/pkg/framework/test/etcd.go +++ b/pkg/framework/test/etcd.go @@ -16,10 +16,10 @@ type Etcd struct { Path string EtcdURL string ProcessStarter simpleSessionStarter + DataDirManager dataDirManager session SimpleSession stdOut *gbytes.Buffer stdErr *gbytes.Buffer - dataDirManager dataDirManager } type dataDirManager interface { @@ -27,6 +27,8 @@ type dataDirManager interface { Destroy() error } +//go:generate counterfeiter . dataDirManager + // SimpleSession describes a CLI session. You can get output, and you can kill it. It is implemented by *gexec.Session. type SimpleSession interface { Buffer() *gbytes.Buffer @@ -49,6 +51,7 @@ func NewEtcd(pathToEtcd string, etcdURL string) *Etcd { Path: pathToEtcd, EtcdURL: etcdURL, ProcessStarter: starter, + DataDirManager: NewTempDirManager(), } return etcd @@ -56,11 +59,10 @@ func NewEtcd(pathToEtcd string, etcdURL string) *Etcd { // Start starts the etcd, waits for it to come up, and returns an error, if occoured. func (e *Etcd) Start() error { - e.dataDirManager = NewTempDirManager() e.stdOut = gbytes.NewBuffer() e.stdErr = gbytes.NewBuffer() - dataDir, err := e.dataDirManager.Create() + dataDir, err := e.DataDirManager.Create() if err != nil { return err } @@ -97,7 +99,7 @@ func (e *Etcd) Stop() { if e.session != nil { e.session.Terminate() e.session.Wait(20 * time.Second) - err := e.dataDirManager.Destroy() + err := e.DataDirManager.Destroy() gomega.Expect(err).NotTo(gomega.HaveOccurred()) } } diff --git a/pkg/framework/test/etcd_test.go b/pkg/framework/test/etcd_test.go index 2fb7f875a..5ddaf5673 100644 --- a/pkg/framework/test/etcd_test.go +++ b/pkg/framework/test/etcd_test.go @@ -17,15 +17,19 @@ import ( var _ = Describe("Etcd", func() { var ( - fakeSession *testfakes.FakeSimpleSession - etcd *Etcd + fakeSession *testfakes.FakeSimpleSession + fakeDataDirManager *testfakes.FakeDataDirManager + etcd *Etcd ) BeforeEach(func() { fakeSession = &testfakes.FakeSimpleSession{} + fakeDataDirManager = &testfakes.FakeDataDirManager{} + etcd = &Etcd{ - Path: "", - EtcdURL: "our etcd url", + Path: "", + EtcdURL: "our etcd url", + DataDirManager: fakeDataDirManager, } }) @@ -51,6 +55,7 @@ var _ = Describe("Etcd", func() { Expect(fakeSession.ExitCodeCallCount()).To(Equal(0)) Expect(etcd).NotTo(gexec.Exit()) Expect(fakeSession.ExitCodeCallCount()).To(Equal(1)) + Expect(fakeDataDirManager.CreateCallCount()).To(Equal(1)) By("Stopping the Etcd Server") etcd.Stop() @@ -58,11 +63,28 @@ var _ = Describe("Etcd", func() { Expect(fakeSession.TerminateCallCount()).To(Equal(1)) Expect(fakeSession.WaitCallCount()).To(Equal(1)) Expect(fakeSession.ExitCodeCallCount()).To(Equal(2)) + Expect(fakeDataDirManager.DestroyCallCount()).To(Equal(1)) + }) + }) + + Context("when the data directory cannot be created", func() { + It("propagates the error, and does not start the process", func() { + fakeDataDirManager.CreateReturnsOnCall(0, "", fmt.Errorf("Error on directory creation.")) + + processStarterCounter := 0 + etcd.ProcessStarter = func(Command *exec.Cmd, out, err io.Writer) (SimpleSession, error) { + processStarterCounter += 1 + return fakeSession, nil + } + + err := etcd.Start() + Expect(err).To(MatchError(ContainSubstring("Error on directory creation."))) + Expect(processStarterCounter).To(Equal(0)) }) }) Context("when the starter returns an error", func() { - It("passes the error to the caller", func() { + It("propagates the error", func() { etcd.ProcessStarter = func(command *exec.Cmd, out, err io.Writer) (SimpleSession, error) { return nil, fmt.Errorf("Some error in the starter.") } diff --git a/pkg/framework/test/testfakes/fake_data_dir_manager.go b/pkg/framework/test/testfakes/fake_data_dir_manager.go new file mode 100644 index 000000000..ea458ba5a --- /dev/null +++ b/pkg/framework/test/testfakes/fake_data_dir_manager.go @@ -0,0 +1,140 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package testfakes + +import ( + "sync" +) + +type FakeDataDirManager struct { + CreateStub func() (string, error) + createMutex sync.RWMutex + createArgsForCall []struct{} + createReturns struct { + result1 string + result2 error + } + createReturnsOnCall map[int]struct { + result1 string + result2 error + } + DestroyStub func() error + destroyMutex sync.RWMutex + destroyArgsForCall []struct{} + destroyReturns struct { + result1 error + } + destroyReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeDataDirManager) Create() (string, error) { + fake.createMutex.Lock() + ret, specificReturn := fake.createReturnsOnCall[len(fake.createArgsForCall)] + fake.createArgsForCall = append(fake.createArgsForCall, struct{}{}) + fake.recordInvocation("Create", []interface{}{}) + fake.createMutex.Unlock() + if fake.CreateStub != nil { + return fake.CreateStub() + } + if specificReturn { + return ret.result1, ret.result2 + } + return fake.createReturns.result1, fake.createReturns.result2 +} + +func (fake *FakeDataDirManager) CreateCallCount() int { + fake.createMutex.RLock() + defer fake.createMutex.RUnlock() + return len(fake.createArgsForCall) +} + +func (fake *FakeDataDirManager) CreateReturns(result1 string, result2 error) { + fake.CreateStub = nil + fake.createReturns = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeDataDirManager) CreateReturnsOnCall(i int, result1 string, result2 error) { + fake.CreateStub = nil + if fake.createReturnsOnCall == nil { + fake.createReturnsOnCall = make(map[int]struct { + result1 string + result2 error + }) + } + fake.createReturnsOnCall[i] = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeDataDirManager) Destroy() error { + fake.destroyMutex.Lock() + ret, specificReturn := fake.destroyReturnsOnCall[len(fake.destroyArgsForCall)] + fake.destroyArgsForCall = append(fake.destroyArgsForCall, struct{}{}) + fake.recordInvocation("Destroy", []interface{}{}) + fake.destroyMutex.Unlock() + if fake.DestroyStub != nil { + return fake.DestroyStub() + } + if specificReturn { + return ret.result1 + } + return fake.destroyReturns.result1 +} + +func (fake *FakeDataDirManager) DestroyCallCount() int { + fake.destroyMutex.RLock() + defer fake.destroyMutex.RUnlock() + return len(fake.destroyArgsForCall) +} + +func (fake *FakeDataDirManager) DestroyReturns(result1 error) { + fake.DestroyStub = nil + fake.destroyReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeDataDirManager) DestroyReturnsOnCall(i int, result1 error) { + fake.DestroyStub = nil + if fake.destroyReturnsOnCall == nil { + fake.destroyReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.destroyReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeDataDirManager) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.createMutex.RLock() + defer fake.createMutex.RUnlock() + fake.destroyMutex.RLock() + defer fake.destroyMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeDataDirManager) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +}