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  })