github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/exec/run_state_test.go (about) 1 package exec_test 2 3 import ( 4 "context" 5 "errors" 6 7 "github.com/pf-qiu/concourse/v6/atc" 8 "github.com/pf-qiu/concourse/v6/atc/exec" 9 "github.com/pf-qiu/concourse/v6/atc/exec/execfakes" 10 "github.com/pf-qiu/concourse/v6/vars" 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/gomega" 13 ) 14 15 var _ = Describe("RunState", func() { 16 var ( 17 stepper exec.Stepper 18 steppedPlan atc.Plan 19 fakeStep *execfakes.FakeStep 20 21 credVars vars.Variables 22 23 state exec.RunState 24 ) 25 26 BeforeEach(func() { 27 fakeStep = new(execfakes.FakeStep) 28 stepper = func(plan atc.Plan) exec.Step { 29 steppedPlan = plan 30 return fakeStep 31 } 32 33 credVars = vars.StaticVariables{"k1": "v1", "k2": "v2", "k3": "v3"} 34 35 state = exec.NewRunState(stepper, credVars, false) 36 }) 37 38 Describe("Run", func() { 39 var ctx context.Context 40 var plan atc.Plan 41 42 var runOk bool 43 var runErr error 44 45 BeforeEach(func() { 46 ctx = context.Background() 47 plan = atc.Plan{ 48 ID: "some-plan", 49 LoadVar: &atc.LoadVarPlan{ 50 Name: "foo", 51 File: "bar", 52 }, 53 } 54 55 fakeStep.RunReturns(true, nil) 56 }) 57 58 JustBeforeEach(func() { 59 runOk, runErr = state.Run(ctx, plan) 60 }) 61 62 It("constructs and runs a step for the plan", func() { 63 Expect(steppedPlan).To(Equal(plan)) 64 Expect(fakeStep.RunCallCount()).To(Equal(1)) 65 runCtx, runState := fakeStep.RunArgsForCall(0) 66 Expect(runCtx).To(Equal(ctx)) 67 Expect(runState).To(Equal(state)) 68 }) 69 70 Context("when the step succeeds", func() { 71 BeforeEach(func() { 72 fakeStep.RunReturns(true, nil) 73 }) 74 75 It("succeeds", func() { 76 Expect(runOk).To(BeTrue()) 77 }) 78 }) 79 80 Context("when the step fails", func() { 81 BeforeEach(func() { 82 fakeStep.RunReturns(false, nil) 83 }) 84 85 It("fails", func() { 86 Expect(runOk).To(BeFalse()) 87 }) 88 }) 89 90 Context("when the step errors", func() { 91 disaster := errors.New("nope") 92 93 BeforeEach(func() { 94 fakeStep.RunReturns(false, disaster) 95 }) 96 97 It("returns the error", func() { 98 Expect(runErr).To(Equal(disaster)) 99 }) 100 }) 101 }) 102 103 Describe("Result", func() { 104 var to int 105 106 BeforeEach(func() { 107 to = 42 108 }) 109 110 Context("when no result is present", func() { 111 It("returns false", func() { 112 Expect(state.Result("some-id", &to)).To(BeFalse()) 113 }) 114 115 It("does not mutate the var", func() { 116 state.Result("some-id", &to) 117 Expect(to).To(Equal(42)) 118 }) 119 }) 120 121 Context("when a result under a different id is present", func() { 122 BeforeEach(func() { 123 state.StoreResult("other", 43) 124 }) 125 126 It("returns false", func() { 127 Expect(state.Result("some-id", &to)).To(BeFalse()) 128 }) 129 130 It("does not mutate the var", func() { 131 state.Result("some-id", &to) 132 Expect(to).To(Equal(42)) 133 }) 134 }) 135 136 Context("when a result under the given id is present", func() { 137 BeforeEach(func() { 138 state.StoreResult("some-id", 123) 139 }) 140 141 It("returns true", func() { 142 Expect(state.Result("some-id", &to)).To(BeTrue()) 143 }) 144 145 It("mutates the var", func() { 146 state.Result("some-id", &to) 147 Expect(to).To(Equal(123)) 148 }) 149 150 Context("but with a different type", func() { 151 BeforeEach(func() { 152 state.StoreResult("some-id", "one hundred and twenty-three") 153 }) 154 155 It("returns false", func() { 156 Expect(state.Result("some-id", &to)).To(BeFalse()) 157 }) 158 159 It("does not mutate the var", func() { 160 state.Result("some-id", &to) 161 Expect(to).To(Equal(42)) 162 }) 163 }) 164 }) 165 }) 166 167 Describe("Get", func() { 168 BeforeEach(func() { 169 state = exec.NewRunState(stepper, credVars, false) 170 }) 171 172 It("fetches from cred vars", func() { 173 val, found, err := state.Get(vars.Reference{Path: "k1"}) 174 Expect(err).ToNot(HaveOccurred()) 175 Expect(found).To(BeTrue()) 176 Expect(val).To(Equal("v1")) 177 }) 178 179 Context("when local var subfield does not exist", func() { 180 It("errors", func() { 181 state.AddLocalVar("foo", map[string]interface{}{"bar": "baz"}, false) 182 _, _, err := state.Get(vars.Reference{Source: ".", Path: "foo", Fields: []string{"missing"}}) 183 Expect(err).To(HaveOccurred()) 184 }) 185 }) 186 187 Context("when redaction is enabled", func() { 188 BeforeEach(func() { 189 state = exec.NewRunState(stepper, credVars, true) 190 }) 191 192 It("fetched variables are tracked", func() { 193 state.Get(vars.Reference{Path: "k1"}) 194 state.Get(vars.Reference{Path: "k2"}) 195 mapit := vars.TrackedVarsMap{} 196 state.IterateInterpolatedCreds(mapit) 197 Expect(mapit["k1"]).To(Equal("v1")) 198 Expect(mapit["k2"]).To(Equal("v2")) 199 // "k3" has not been Get, thus should not be tracked. 200 Expect(mapit).ToNot(HaveKey("k3")) 201 }) 202 }) 203 204 Context("when redaction is not enabled", func() { 205 BeforeEach(func() { 206 state = exec.NewRunState(stepper, credVars, false) 207 }) 208 209 It("fetched variables are not tracked", func() { 210 state.Get(vars.Reference{Path: "k1"}) 211 state.Get(vars.Reference{Path: "k2"}) 212 mapit := vars.TrackedVarsMap{} 213 state.IterateInterpolatedCreds(mapit) 214 Expect(mapit).ToNot(HaveKey("k1")) 215 Expect(mapit).ToNot(HaveKey("k2")) 216 Expect(mapit).ToNot(HaveKey("k3")) 217 }) 218 }) 219 }) 220 221 Describe("List", func() { 222 It("returns list of names from multiple vars with duplicates", func() { 223 defs, err := state.List() 224 Expect(defs).To(ConsistOf([]vars.Reference{ 225 {Path: "k1"}, 226 {Path: "k2"}, 227 {Path: "k3"}, 228 })) 229 Expect(err).ToNot(HaveOccurred()) 230 }) 231 232 It("includes all local vars", func() { 233 state.AddLocalVar("l1", 1, false) 234 state.AddLocalVar("l2", 2, false) 235 236 defs, err := state.List() 237 Expect(defs).To(ConsistOf([]vars.Reference{ 238 {Source: ".", Path: "l1"}, 239 {Source: ".", Path: "l2"}, 240 241 {Path: "k1"}, 242 {Path: "k2"}, 243 {Path: "k3"}, 244 })) 245 Expect(err).ToNot(HaveOccurred()) 246 }) 247 }) 248 249 Describe("AddLocalVar", func() { 250 Describe("redact", func() { 251 BeforeEach(func() { 252 state = exec.NewRunState(stepper, credVars, true) 253 state.AddLocalVar("foo", "bar", true) 254 }) 255 256 It("should get local value", func() { 257 val, found, err := state.Get(vars.Reference{Source: ".", Path: "foo"}) 258 Expect(err).To(BeNil()) 259 Expect(found).To(BeTrue()) 260 Expect(val).To(Equal("bar")) 261 }) 262 263 It("fetched variables are tracked when added", func() { 264 mapit := vars.TrackedVarsMap{} 265 state.IterateInterpolatedCreds(mapit) 266 Expect(mapit["foo"]).To(Equal("bar")) 267 }) 268 }) 269 270 Describe("not redact", func() { 271 BeforeEach(func() { 272 state.AddLocalVar("foo", "bar", false) 273 }) 274 275 It("should get local value", func() { 276 val, found, err := state.Get(vars.Reference{Source: ".", Path: "foo"}) 277 Expect(err).To(BeNil()) 278 Expect(found).To(BeTrue()) 279 Expect(val).To(Equal("bar")) 280 }) 281 282 It("fetched variables are not tracked", func() { 283 state.Get(vars.Reference{Source: ".", Path: "foo"}) 284 mapit := vars.TrackedVarsMap{} 285 state.IterateInterpolatedCreds(mapit) 286 Expect(mapit).ToNot(ContainElement("foo")) 287 }) 288 }) 289 }) 290 291 Describe("NewLocalScope", func() { 292 It("maintains a reference to the parent", func() { 293 Expect(state.NewLocalScope().Parent()).To(Equal(state)) 294 }) 295 296 It("can access local vars from parent scope", func() { 297 state.AddLocalVar("hello", "world", false) 298 scope := state.NewLocalScope() 299 val, _, _ := scope.Get(vars.Reference{Source: ".", Path: "hello"}) 300 Expect(val).To(Equal("world")) 301 }) 302 303 It("adding local vars does not affect the original tracker", func() { 304 scope := state.NewLocalScope() 305 scope.AddLocalVar("hello", "world", false) 306 _, found, _ := state.Get(vars.Reference{Source: ".", Path: "hello"}) 307 Expect(found).To(BeFalse()) 308 }) 309 310 It("shares the underlying non-local variables", func() { 311 scope := state.NewLocalScope() 312 val, _, _ := scope.Get(vars.Reference{Path: "k1"}) 313 Expect(val).To(Equal("v1")) 314 }) 315 316 It("local vars added after creating the subscope are accessible", func() { 317 scope := state.NewLocalScope() 318 state.AddLocalVar("hello", "world", false) 319 val, _, _ := scope.Get(vars.Reference{Source: ".", Path: "hello"}) 320 Expect(val).To(Equal("world")) 321 }) 322 323 It("current scope is preferred over parent scope", func() { 324 state.AddLocalVar("a", 1, false) 325 scope := state.NewLocalScope() 326 scope.AddLocalVar("a", 2, false) 327 328 val, _, _ := scope.Get(vars.Reference{Source: ".", Path: "a"}) 329 Expect(val).To(Equal(2)) 330 }) 331 332 It("results set in parent scope are accessible in child", func() { 333 parent := state 334 child := parent.NewLocalScope() 335 336 parent.StoreResult("id", "hello") 337 338 var dst string 339 child.Result("id", &dst) 340 Expect(dst).To(Equal("hello")) 341 }) 342 343 It("results set in child scope are accessible in parent", func() { 344 parent := state 345 child := parent.NewLocalScope() 346 347 child.StoreResult("id", "hello") 348 349 var dst string 350 state.Result("id", &dst) 351 Expect(dst).To(Equal("hello")) 352 }) 353 354 It("has a local artifact scope inheriting from the outer scope", func() { 355 Expect(state.NewLocalScope().ArtifactRepository().Parent()).To(Equal(state.ArtifactRepository())) 356 }) 357 358 Describe("TrackedVarsMap", func() { 359 BeforeEach(func() { 360 state = exec.NewRunState(stepper, credVars, true) 361 }) 362 363 It("prefers the value set in the current scope over the parent scope", func() { 364 state.AddLocalVar("a", "from parent", true) 365 scope := state.NewLocalScope() 366 scope.AddLocalVar("a", "from child", true) 367 368 mapit := vars.TrackedVarsMap{} 369 scope.IterateInterpolatedCreds(mapit) 370 371 Expect(mapit["a"]).To(Equal("from child")) 372 }) 373 }) 374 }) 375 })