1package worker_test 2 3import ( 4 "context" 5 "errors" 6 "time" 7 8 "github.com/concourse/concourse/atc/db/dbfakes" 9 "github.com/concourse/concourse/atc/resource" 10 "github.com/concourse/concourse/atc/runtime" 11 "github.com/concourse/concourse/atc/worker" 12 13 "code.cloudfoundry.org/clock/fakeclock" 14 "code.cloudfoundry.org/lager" 15 "code.cloudfoundry.org/lager/lagertest" 16 "github.com/concourse/concourse/atc" 17 "github.com/concourse/concourse/atc/db" 18 "github.com/concourse/concourse/atc/db/lock" 19 "github.com/concourse/concourse/atc/db/lock/lockfakes" 20 "github.com/concourse/concourse/atc/resource/resourcefakes" 21 "github.com/concourse/concourse/atc/worker/workerfakes" 22 . "github.com/onsi/ginkgo" 23 . "github.com/onsi/gomega" 24) 25 26var _ = Describe("Fetcher", func() { 27 var ( 28 fakeClock *fakeclock.FakeClock 29 fakeLockFactory *lockfakes.FakeLockFactory 30 fetcher worker.Fetcher 31 ctx context.Context 32 cancel func() 33 fakeBuildStepDelegate *workerfakes.FakeImageFetchingDelegate 34 35 fakeWorker *workerfakes.FakeWorker 36 fakeVolume *workerfakes.FakeVolume 37 fakeFetchSourceFactory *workerfakes.FakeFetchSourceFactory 38 fakeResource *resourcefakes.FakeResource 39 fakeUsedResourceCache *dbfakes.FakeUsedResourceCache 40 41 getResult worker.GetResult 42 fetchErr error 43 teamID = 123 44 45 volume worker.Volume 46 ) 47 48 BeforeEach(func() { 49 fakeClock = fakeclock.NewFakeClock(time.Unix(0, 123)) 50 fakeLockFactory = new(lockfakes.FakeLockFactory) 51 fakeFetchSourceFactory = new(workerfakes.FakeFetchSourceFactory) 52 53 fakeWorker = new(workerfakes.FakeWorker) 54 fakeWorker.NameReturns("some-worker") 55 56 fakeVolume = new(workerfakes.FakeVolume) 57 fakeVolume.HandleReturns("some-handle") 58 fakeResource = new(resourcefakes.FakeResource) 59 fakeUsedResourceCache = new(dbfakes.FakeUsedResourceCache) 60 61 fetcher = worker.NewFetcher( 62 fakeClock, 63 fakeLockFactory, 64 fakeFetchSourceFactory, 65 ) 66 67 ctx, cancel = context.WithCancel(context.Background()) 68 69 fakeBuildStepDelegate = new(workerfakes.FakeImageFetchingDelegate) 70 }) 71 72 JustBeforeEach(func() { 73 getResult, volume, fetchErr = fetcher.Fetch( 74 ctx, 75 lagertest.NewTestLogger("test"), 76 db.ContainerMetadata{}, 77 fakeWorker, 78 worker.ContainerSpec{ 79 TeamID: teamID, 80 }, 81 runtime.ProcessSpec{ 82 Args: []string{resource.ResourcesDir("get")}, 83 }, 84 fakeResource, 85 db.NewBuildStepContainerOwner(0, "some-plan-id", 0), 86 worker.ImageFetcherSpec{ 87 atc.VersionedResourceTypes{}, 88 fakeBuildStepDelegate, 89 }, 90 fakeUsedResourceCache, 91 "fake-lock-name", 92 ) 93 }) 94 95 Context("when getting source", func() { 96 var fakeFetchSource *workerfakes.FakeFetchSource 97 98 BeforeEach(func() { 99 fakeFetchSource = new(workerfakes.FakeFetchSource) 100 fakeFetchSourceFactory.NewFetchSourceReturns(fakeFetchSource) 101 102 fakeFetchSource.FindReturns(worker.GetResult{}, fakeVolume, false, nil) 103 }) 104 105 Describe("failing to get a lock", func() { 106 Context("when did not get a lock", func() { 107 BeforeEach(func() { 108 fakeLock := new(lockfakes.FakeLock) 109 callCount := 0 110 fakeLockFactory.AcquireStub = func(lager.Logger, lock.LockID) (lock.Lock, bool, error) { 111 callCount++ 112 fakeClock.Increment(worker.GetResourceLockInterval) 113 if callCount == 1 { 114 return nil, false, nil 115 } 116 return fakeLock, true, nil 117 } 118 }) 119 120 It("retries until it gets the lock", func() { 121 Expect(fakeLockFactory.AcquireCallCount()).To(Equal(2)) 122 }) 123 124 It("creates fetch source after lock is acquired", func() { 125 Expect(fakeFetchSource.CreateCallCount()).To(Equal(1)) 126 }) 127 }) 128 129 Context("when acquiring lock returns error", func() { 130 BeforeEach(func() { 131 fakeLock := new(lockfakes.FakeLock) 132 callCount := 0 133 fakeLockFactory.AcquireStub = func(lager.Logger, lock.LockID) (lock.Lock, bool, error) { 134 callCount++ 135 fakeClock.Increment(worker.GetResourceLockInterval) 136 if callCount == 1 { 137 return nil, false, errors.New("disaster") 138 } 139 return fakeLock, true, nil 140 } 141 }) 142 143 It("retries until it gets the lock", func() { 144 Expect(fakeLockFactory.AcquireCallCount()).To(Equal(2)) 145 }) 146 147 It("creates fetch source after lock is acquired", func() { 148 Expect(fakeFetchSource.CreateCallCount()).To(Equal(1)) 149 }) 150 }) 151 }) 152 153 Context("when getting lock succeeds", func() { 154 var fakeLock *lockfakes.FakeLock 155 156 BeforeEach(func() { 157 fakeLock = new(lockfakes.FakeLock) 158 fakeLockFactory.AcquireReturns(fakeLock, true, nil) 159 fakeFetchSource.CreateReturns(worker.GetResult{}, fakeVolume, nil) 160 }) 161 162 It("acquires a lock with source lock name", func() { 163 Expect(fakeLockFactory.AcquireCallCount()).To(Equal(1)) 164 _, lockID := fakeLockFactory.AcquireArgsForCall(0) 165 Expect(lockID).To(Equal(lock.NewTaskLockID("fake-lock-name"))) 166 }) 167 168 It("releases the lock", func() { 169 Expect(fakeLock.ReleaseCallCount()).To(Equal(1)) 170 }) 171 172 It("creates source", func() { 173 Expect(fakeFetchSource.CreateCallCount()).To(Equal(1)) 174 }) 175 176 It("returns the result and volume", func() { 177 Expect(getResult).To(Equal(worker.GetResult{})) 178 Expect(volume).ToNot(BeNil()) 179 }) 180 }) 181 182 Context("when finding fails", func() { 183 var disaster error 184 185 BeforeEach(func() { 186 disaster = errors.New("fail") 187 fakeFetchSource.FindReturns(worker.GetResult{}, nil, false, disaster) 188 }) 189 190 It("returns an error", func() { 191 Expect(fetchErr).To(HaveOccurred()) 192 Expect(fetchErr).To(Equal(disaster)) 193 }) 194 }) 195 196 Context("when cancelled", func() { 197 BeforeEach(func() { 198 cancel() 199 }) 200 201 It("returns the context err", func() { 202 Expect(fetchErr).To(Equal(context.Canceled)) 203 }) 204 }) 205 }) 206}) 207