github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/check_factory_test.go (about) 1 package db_test 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/pf-qiu/concourse/v6/atc" 8 "github.com/pf-qiu/concourse/v6/atc/db" 9 "github.com/pf-qiu/concourse/v6/atc/db/dbfakes" 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("CheckFactory", func() { 15 var ( 16 err error 17 ) 18 19 Describe("TryCreateCheck", func() { 20 var ( 21 created bool 22 build db.Build 23 24 fakeResource *dbfakes.FakeResource 25 fakeResourceType *dbfakes.FakeResourceType 26 fakeResourceTypes db.ResourceTypes 27 fromVersion atc.Version 28 manuallyTriggered bool 29 30 checkPlan atc.CheckPlan 31 fakeBuild *dbfakes.FakeBuild 32 ) 33 34 BeforeEach(func() { 35 fromVersion = atc.Version{"from": "version"} 36 37 checkPlan = atc.CheckPlan{ 38 Type: "doesnt-matter", 39 Source: atc.Source{"doesnt": "matter"}, 40 } 41 42 fakeResource = new(dbfakes.FakeResource) 43 fakeResource.NameReturns("some-name") 44 fakeResource.TagsReturns([]string{"tag-a", "tag-b"}) 45 fakeResource.SourceReturns(atc.Source{"some": "source"}) 46 fakeResource.PipelineIDReturns(defaultPipeline.ID()) 47 fakeResource.PipelineNameReturns(defaultPipeline.Name()) 48 fakeResource.PipelineInstanceVarsReturns(defaultPipeline.InstanceVars()) 49 fakeResource.PipelineReturns(defaultPipeline, true, nil) 50 fakeResource.CheckPlanReturns(checkPlan) 51 52 fakeBuild = new(dbfakes.FakeBuild) 53 fakeResource.CreateBuildReturns(fakeBuild, true, nil) 54 55 fakeResourceType = new(dbfakes.FakeResourceType) 56 fakeResourceType.NameReturns("some-type") 57 fakeResourceType.TypeReturns("some-base-type") 58 fakeResourceType.TagsReturns([]string{"some-tag"}) 59 fakeResourceType.SourceReturns(atc.Source{"some": "type-source"}) 60 fakeResourceType.DefaultsReturns(atc.Source{"some-default": "some-default-value"}) 61 fakeResourceType.PipelineIDReturns(defaultPipeline.ID()) 62 fakeResourceType.PipelineNameReturns(defaultPipeline.Name()) 63 fakeResourceType.PipelineInstanceVarsReturns(defaultPipeline.InstanceVars()) 64 fakeResourceType.PipelineReturns(defaultPipeline, true, nil) 65 66 fakeResourceTypes = db.ResourceTypes{fakeResourceType} 67 manuallyTriggered = false 68 }) 69 70 JustBeforeEach(func() { 71 build, created, err = checkFactory.TryCreateCheck(context.TODO(), fakeResource, fakeResourceTypes, fromVersion, manuallyTriggered) 72 }) 73 74 Context("when the resource parent type is not a custom type", func() { 75 BeforeEach(func() { 76 fakeResource.TypeReturns("base-type") 77 }) 78 79 It("returns the build", func() { 80 Expect(err).NotTo(HaveOccurred()) 81 Expect(created).To(BeTrue()) 82 Expect(build).To(Equal(fakeBuild)) 83 }) 84 85 It("starts the build with the check plan", func() { 86 Expect(fakeResource.CreateBuildCallCount()).To(Equal(1)) 87 _, manuallyTriggered, plan := fakeResource.CreateBuildArgsForCall(0) 88 Expect(manuallyTriggered).To(BeFalse()) 89 Expect(plan.ID).ToNot(BeEmpty()) 90 Expect(plan.Check).To(Equal(&checkPlan)) 91 }) 92 93 Context("when the interval has not elapsed", func() { 94 BeforeEach(func() { 95 fakeResource.LastCheckEndTimeReturns(time.Now().Add(defaultCheckInterval)) 96 }) 97 98 It("does not create a build for the resource", func() { 99 Expect(fakeResource.CheckPlanCallCount()).To(Equal(0)) 100 Expect(fakeResource.CreateBuildCallCount()).To(Equal(0)) 101 }) 102 103 Context("but the check is manually triggered", func() { 104 BeforeEach(func() { 105 manuallyTriggered = true 106 }) 107 108 It("creates the build anyway", func() { 109 Expect(fakeResource.CheckPlanCallCount()).To(Equal(1)) 110 Expect(fakeResource.CreateBuildCallCount()).To(Equal(1)) 111 }) 112 }) 113 }) 114 115 Context("when a build is not created", func() { 116 BeforeEach(func() { 117 fakeResource.CreateBuildReturns(nil, false, nil) 118 }) 119 120 It("returns false", func() { 121 Expect(err).NotTo(HaveOccurred()) 122 Expect(created).To(BeFalse()) 123 Expect(build).To(BeNil()) 124 }) 125 }) 126 }) 127 128 Context("when the resource has a webhook configured", func() { 129 BeforeEach(func() { 130 fakeResource.HasWebhookReturns(true) 131 }) 132 133 It("creates a check plan with the default webhook interval", func() { 134 Expect(fakeResource.CheckPlanCallCount()).To(Equal(1)) 135 version, interval, types, defaults := fakeResource.CheckPlanArgsForCall(0) 136 Expect(version).To(Equal(atc.Version{"from": "version"})) 137 Expect(interval).To(Equal(defaultWebhookCheckInterval)) 138 Expect(types).To(BeNil()) 139 Expect(defaults).To(BeEmpty()) 140 }) 141 142 Context("when the default webhook interval has not elapsed", func() { 143 BeforeEach(func() { 144 fakeResource.LastCheckEndTimeReturns(time.Now().Add(-(defaultWebhookCheckInterval / 2))) 145 }) 146 147 It("does not create a build for the resource", func() { 148 Expect(fakeResource.CheckPlanCallCount()).To(Equal(0)) 149 Expect(fakeResource.CreateBuildCallCount()).To(Equal(0)) 150 }) 151 }) 152 }) 153 154 Context("when an interval is specified", func() { 155 BeforeEach(func() { 156 fakeResource.CheckEveryReturns("42s") 157 }) 158 159 It("sets it in the check plan", func() { 160 Expect(fakeResource.CheckPlanCallCount()).To(Equal(1)) 161 version, interval, types, defaults := fakeResource.CheckPlanArgsForCall(0) 162 Expect(version).To(Equal(atc.Version{"from": "version"})) 163 Expect(interval).To(Equal(42 * time.Second)) 164 Expect(types).To(BeNil()) 165 Expect(defaults).To(BeEmpty()) 166 }) 167 }) 168 169 Context("when the interval is not parseable", func() { 170 BeforeEach(func() { 171 fakeResource.CheckEveryReturns("not-a-duration") 172 }) 173 174 It("errors", func() { 175 Expect(err).To(HaveOccurred()) 176 }) 177 }) 178 179 Context("when the resource has a parent type", func() { 180 BeforeEach(func() { 181 fakeResource.TypeReturns("custom-type") 182 fakeResource.PipelineIDReturns(1) 183 fakeResourceType.NameReturns("custom-type") 184 fakeResourceType.PipelineIDReturns(1) 185 fakeResourceType.DefaultsReturns(atc.Source{"sdk": "sdk"}) 186 }) 187 188 Context("when the parent type has no version", func() { 189 BeforeEach(func() { 190 fakeResourceType.VersionReturns(nil) 191 }) 192 193 It("errors", func() { 194 Expect(err).To(HaveOccurred()) 195 }) 196 }) 197 198 Context("when the parent type has a version", func() { 199 BeforeEach(func() { 200 fakeResourceType.VersionReturns(atc.Version{"some": "version"}) 201 }) 202 203 Context("when the parent type's interval has not elapsed", func() { 204 BeforeEach(func() { 205 fakeResourceType.LastCheckEndTimeReturns(time.Now().Add(defaultCheckInterval)) 206 }) 207 208 It("does not create a build for the parent type", func() { 209 Expect(fakeResourceType.CheckPlanCallCount()).To(Equal(0)) 210 Expect(fakeResourceType.CreateBuildCallCount()).To(Equal(0)) 211 }) 212 }) 213 214 Context("when the parent type's interval has elapsed", func() { 215 BeforeEach(func() { 216 fakeResourceType.LastCheckEndTimeReturns(time.Now().Add(-defaultCheckInterval)) 217 fakeResource.LastCheckEndTimeReturns(time.Now().Add(-defaultCheckInterval)) 218 }) 219 220 It("creates a check plan", func() { 221 Expect(fakeResource.CheckPlanCallCount()).To(Equal(1)) 222 version, interval, types, defaults := fakeResource.CheckPlanArgsForCall(0) 223 Expect(version).To(Equal(atc.Version{"from": "version"})) 224 Expect(interval).To(Equal(defaultCheckInterval)) 225 Expect(types).To(Equal(fakeResourceTypes)) 226 Expect(defaults).To(Equal(atc.Source{"sdk": "sdk"})) 227 }) 228 229 It("returns the build", func() { 230 Expect(err).NotTo(HaveOccurred()) 231 Expect(created).To(BeTrue()) 232 Expect(build).To(Equal(fakeBuild)) 233 }) 234 235 It("starts the build with the check plan", func() { 236 Expect(fakeResource.CreateBuildCallCount()).To(Equal(1)) 237 _, manuallyTriggered, plan := fakeResource.CreateBuildArgsForCall(0) 238 Expect(manuallyTriggered).To(BeFalse()) 239 Expect(plan.ID).ToNot(BeEmpty()) 240 Expect(plan.Check).To(Equal(&checkPlan)) 241 }) 242 }) 243 }) 244 }) 245 }) 246 247 Describe("Resources", func() { 248 var ( 249 resources []db.Resource 250 ) 251 252 BeforeEach(func() { 253 defaultPipelineConfig = atc.Config{ 254 Jobs: atc.JobConfigs{ 255 { 256 Name: "some-job", 257 PlanSequence: []atc.Step{ 258 { 259 Config: &atc.GetStep{ 260 Name: "some-resource", 261 }, 262 }, 263 { 264 Config: &atc.PutStep{ 265 Name: "some-put-only-resource", 266 }, 267 }, 268 }, 269 }, 270 }, 271 Resources: atc.ResourceConfigs{ 272 { 273 Name: "some-resource", 274 Type: "some-base-resource-type", 275 Source: atc.Source{ 276 "some": "source", 277 }, 278 }, 279 { 280 Name: "some-put-only-resource", 281 Type: "some-base-resource-type", 282 Source: atc.Source{ 283 "some": "source", 284 }, 285 }, 286 }, 287 ResourceTypes: atc.ResourceTypes{ 288 { 289 Name: "some-type", 290 Type: "some-base-resource-type", 291 Source: atc.Source{ 292 "some-type": "source", 293 }, 294 }, 295 }, 296 } 297 298 defaultPipelineRef = atc.PipelineRef{Name: "default-pipeline", InstanceVars: atc.InstanceVars{"branch": "master"}} 299 defaultPipeline, _, err = defaultTeam.SavePipeline(defaultPipelineRef, defaultPipelineConfig, db.ConfigVersion(1), false) 300 Expect(err).NotTo(HaveOccurred()) 301 302 _, found, err := defaultPipeline.Resource("some-put-only-resource") 303 Expect(err).ToNot(HaveOccurred()) 304 Expect(found).To(BeTrue()) 305 }) 306 307 JustBeforeEach(func() { 308 resources, err = checkFactory.Resources() 309 Expect(err).NotTo(HaveOccurred()) 310 }) 311 312 It("include only resources-in-use in return", func() { 313 Expect(resources).To(HaveLen(1)) 314 Expect(resources[0].Name()).To(Equal("some-resource")) 315 }) 316 317 Context("when the resource is not active", func() { 318 BeforeEach(func() { 319 _, err = dbConn.Exec(`UPDATE resources SET active = false`) 320 Expect(err).NotTo(HaveOccurred()) 321 }) 322 323 It("does not return the resource", func() { 324 Expect(resources).To(HaveLen(0)) 325 }) 326 }) 327 328 Context("when the resource pipeline is paused", func() { 329 BeforeEach(func() { 330 _, err = dbConn.Exec(`UPDATE pipelines SET paused = true`) 331 Expect(err).NotTo(HaveOccurred()) 332 }) 333 334 It("does not return the resource", func() { 335 Expect(resources).To(HaveLen(0)) 336 }) 337 }) 338 }) 339 340 Describe("ResourceTypes", func() { 341 var ( 342 resourceTypes db.ResourceTypes 343 ) 344 345 JustBeforeEach(func() { 346 resourceTypes, err = checkFactory.ResourceTypes() 347 Expect(err).NotTo(HaveOccurred()) 348 }) 349 350 It("include resource types in return", func() { 351 Expect(resourceTypes).To(HaveLen(1)) 352 Expect(resourceTypes[0].Name()).To(Equal("some-type")) 353 }) 354 355 Context("when the resource type is not active", func() { 356 BeforeEach(func() { 357 _, err = dbConn.Exec(`UPDATE resource_types SET active = false`) 358 Expect(err).NotTo(HaveOccurred()) 359 }) 360 361 It("does not return the resource type", func() { 362 Expect(resourceTypes).To(HaveLen(0)) 363 }) 364 }) 365 }) 366 })