From c24ee9980df3cce258df9aba5aa525006d182bd8 Mon Sep 17 00:00:00 2001 From: nkuacac Date: Tue, 10 Nov 2015 09:09:49 +0000 Subject: [PATCH] cf workload can support multiple user - currently there is a limitation "cf workloads assume single already-logged-in-and-targetted user" in [Known Limitations / TODOs etc.] (https://github.com/cloudfoundry-incubator/pat/blob/master/README.md#known-limitations--todos-etc) - cf cli support different user by CF_HOME - set cfhomes can achive multi already logged user - also add the test case for the feature Signed-off-by: zyw69542 --- cmdline/cmdline.go | 3 ++ cmdline/cmdline_test.go | 20 ++++++++ workloads/cf.go | 78 ++++++++++++++++++++++++------- workloads/cf_test.go | 92 +++++++++++++++++++++++++++++++++++++ workloads/workloads.go | 4 ++ workloads/workloads_test.go | 11 +++++ 6 files changed, 192 insertions(+), 16 deletions(-) diff --git a/cmdline/cmdline.go b/cmdline/cmdline.go index ede1ded..b54d22b 100644 --- a/cmdline/cmdline.go +++ b/cmdline/cmdline.go @@ -27,6 +27,7 @@ var params = struct { workload string interval int stop int + cfHomes string restUser string restPass string restTarget string @@ -45,6 +46,7 @@ func InitCommandLineFlags(config config.Config) { config.IntVar(¶ms.stop, "stop", 0, "repeat a repeating interval until n seconds, to be used with -interval") config.BoolVar(¶ms.listWorkloads, "list-workloads", false, "Lists the available workloads") config.StringVar(¶ms.restTarget, "rest:target", "", "the target for the REST api") + config.StringVar(¶ms.cfHomes, "cfhomes", "", "cfhome for cli") config.StringVar(¶ms.restUser, "rest:username", "", "username for REST api") config.StringVar(¶ms.restPass, "rest:password", "", "password for REST api") config.StringVar(¶ms.restSpace, "rest:space", "dev", "space to target for REST api") @@ -58,6 +60,7 @@ func RunCommandLine() error { workloadContext := NewContext() workloads.PopulateRestContext(params.restTarget, params.restUser, params.restPass, params.restSpace, workloadContext) workloads.PopulateAppContext(params.app, params.manifest, workloadContext) + workloads.PopulateCliContext(params.cfHomes, workloadContext) return WithConfiguredWorkerAndSlaves(func(worker benchmarker.Worker) error { return validateParameters(worker, func() error { diff --git a/cmdline/cmdline_test.go b/cmdline/cmdline_test.go index 1a1ab11..3731244 100644 --- a/cmdline/cmdline_test.go +++ b/cmdline/cmdline_test.go @@ -84,6 +84,26 @@ var _ = Describe("Cmdline", func() { }) }) + Describe("When -cfhomes is supplied", func() { + var ( + ctx context.Context + ) + + BeforeEach(func() { + ctx = context.New() + args = []string{"-cfhomes", "somehomes"} + NewContext = func() context.Context { + return ctx + } + }) + + It("configures the experiment with the parameter", func() { + path, ok := ctx.GetString("cfhomes") + Ω(ok).To(BeTrue()) + Ω(path).To(Equal("somehomes")) + }) + }) + Describe("When -app is supplied", func() { var ( ctx context.Context diff --git a/workloads/cf.go b/workloads/cf.go index 6096044..8b4b468 100644 --- a/workloads/cf.go +++ b/workloads/cf.go @@ -14,9 +14,11 @@ import ( "strings" "time" + "github.com/cloudfoundry-incubator/cf-test-helpers/runner" "github.com/cloudfoundry-incubator/pat/context" "github.com/nu7hatch/gouuid" "github.com/onsi/ginkgo" + . "github.com/onsi/gomega/gexec" . "github.com/pivotal-cf-experimental/cf-test-helpers/cf" ) @@ -70,10 +72,11 @@ func Push(ctx context.Context) error { } ctx.PutString("appNames", appNames) + cfhome := cfhomeForWorker(ctx) if pathToManifest == "" { - return expectCfToSay("App started", "push", appName, "-m", "64M", "-p", pathToApp) + return expectCfToSay("App started", cfhome, "push", appName, "-m", "64M", "-p", pathToApp) } else { - return expectCfToSay("App started", "push", appName, "-p", pathToApp, "-f", pathToManifest) + return expectCfToSay("App started", cfhome, "push", appName, "-p", pathToApp, "-f", pathToManifest) } } @@ -88,8 +91,10 @@ func Delete(ctx context.Context) error { appNames = strings.Replace(appNames, ","+appNameToDelete, "", -1) appNames = strings.Replace(appNames, appNameToDelete, "", -1) ctx.PutString("appNames", appNames) - return expectCfToSay("Deleting app", "delete", appNameToDelete, "-f") + cfhome := cfhomeForWorker(ctx) + return expectCfToSay("Deleting app", cfhome, "delete", appNameToDelete, "-f") } + func CopyAndReplaceText(srcDir string, dstDir string, searchText string, replaceText string) error { return filepath.Walk(srcDir, func(file string, info os.FileInfo, err error) error { if err != nil { @@ -135,23 +140,64 @@ func GenerateAndPush(ctx context.Context) error { return err } + cfhome := cfhomeForWorker(ctx) if pathToManifest == "" { - return expectCfToSay("App started", "push", "pats-"+guid.String(), "-m", "64M", "-p", pathToApp) + return expectCfToSay("App started", cfhome, "push", "pats-"+guid.String(), "-m", "64M", "-p", pathToApp) } else { - return expectCfToSay("App started", "push", "pats-"+guid.String(), "-p", pathToApp, "-f", pathToManifest) + return expectCfToSay("App started", cfhome, "push", "pats-"+guid.String(), "-p", pathToApp, "-f", pathToManifest) } } -func expectCfToSay(expect string, args ...string) error { - var outBuffer bytes.Buffer - oldWriter := ginkgo.GinkgoWriter - ginkgo.GinkgoWriter = bufio.NewWriter(&outBuffer) - cfOutBuffer := Cf(args...).Wait(10 * time.Minute).Out - cfContents := cfOutBuffer.Contents() - ginkgo.GinkgoWriter = oldWriter - if strings.Contains(string(cfContents), expect) { - return nil - } else { - return errors.New(string(cfContents)) +type ExpectToSay func(expect string, home string, args ...string) error + +var expectCfToSay ExpectToSay + +func NewExpectCFToSay(expectfunc ExpectToSay) { + expectCfToSay = expectfunc +} + +func init() { + NewExpectCFToSay(func(expect string, cfhome string, args ...string) error { + var outBuffer bytes.Buffer + oldWriter := ginkgo.GinkgoWriter + ginkgo.GinkgoWriter = bufio.NewWriter(&outBuffer) + if cfhome == "" { + cfOutBuffer := Cf(args...).Wait(10 * time.Minute).Out + cfContents := cfOutBuffer.Contents() + ginkgo.GinkgoWriter = oldWriter + if strings.Contains(string(cfContents), expect) { + return nil + } else { + return errors.New(string(cfContents)) + } + } else { + cfOutBuffer := envCf(cfhome, args...).Wait(10 * time.Minute).Out + cfContents := cfOutBuffer.Contents() + ginkgo.GinkgoWriter = oldWriter + if strings.Contains(string(cfContents), expect) { + return nil + } else { + return errors.New(string(cfContents)) + } + } + }) +} + +func envCf(cfhome string, args ...string) *Session { + env := fmt.Sprintf("CF_HOME=%s", cfhome) + args = append([]string{env, "cf"}, args...) + return runner.Run("env", args...) +} + +func cfhomeForWorker(ctx context.Context) string { + iterationIndex, exist := ctx.GetInt("iterationIndex") + if !exist { + return "" + } + cfhomes, exist := ctx.GetString("cfhomes") + if !exist || len(cfhomes) == 0 { + return "" } + var cfhomeList = strings.Split(cfhomes, ",") + return cfhomeList[iterationIndex%len(cfhomeList)] } diff --git a/workloads/cf_test.go b/workloads/cf_test.go index 82adbac..8850aca 100644 --- a/workloads/cf_test.go +++ b/workloads/cf_test.go @@ -2,11 +2,15 @@ package workloads_test import ( //"crypto/md5" + "errors" + "fmt" "io/ioutil" "os" "path" "strings" + "github.com/cloudfoundry-incubator/pat/context" + . "github.com/cloudfoundry-incubator/pat/workloads" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -82,4 +86,92 @@ var _ = Describe("cf Workloads", func() { }) }) }) + + Describe("Mulit user", func() { + var ( + replies map[string]string + cli *dummyCfCli + cliContext context.Context + ) + + BeforeEach(func() { + cliContext = context.New() + cliContext.PutInt("iterationIndex", 0) + replies = make(map[string]string) + cli = &dummyCfCli{"", make([]string, 0), replies} + NewExpectCFToSay(cli.expectCFToSay) + }) + Context("when cfhomes is not set", func() { + BeforeEach(func() { + replies["push"] = "App started" + cliContext.PutString("app", "someapp") + }) + + It("cfhome should be empty string", func() { + err := Push(cliContext) + Ω(err).ShouldNot(HaveOccurred()) + cli.ShouldHaveBeenCalledWith("", "push") + + }) + }) + + Context("when cfhomes is set", func() { + BeforeEach(func() { + replies["home1push"] = "App started" + replies["home2push"] = "App started" + replies["home3push"] = "App started" + cliContext.PutString("app", "someapp") + cliContext.PutString("cfhomes", "home1,home2,home3") + }) + + It("cfhome should be different from iterationIndex", func() { + cliContext.PutInt("iterationIndex", 0) + err := Push(cliContext) + Ω(err).ShouldNot(HaveOccurred()) + cli.ShouldHaveBeenCalledWith("home1", "push") + cliContext.PutInt("iterationIndex", 1) + err = Push(cliContext) + Ω(err).ShouldNot(HaveOccurred()) + cli.ShouldHaveBeenCalledWith("home2", "push") + cliContext.PutInt("iterationIndex", 2) + err = Push(cliContext) + Ω(err).ShouldNot(HaveOccurred()) + cli.ShouldHaveBeenCalledWith("home3", "push") + cliContext.PutInt("iterationIndex", 3) + err = Push(cliContext) + Ω(err).ShouldNot(HaveOccurred()) + cli.ShouldHaveBeenCalledWith("home1", "push") + + }) + }) + + }) + }) + +type dummyCfCli struct { + cfhome string + args []string + replies map[string]string +} + +func (cli *dummyCfCli) ShouldHaveBeenCalledWith(cfhome, method string, args ...string) { + Ω(cli.cfhome).Should(Equal(cfhome)) + Ω(cli.args[0]).Should(Equal(method)) +} + +func (cli *dummyCfCli) expectCFToSay(expect, cfhome string, args ...string) error { + cli.cfhome = cfhome + for _, arg := range args { + cli.args = append(cli.args, arg) + } + + if len(cli.args) == 0 { + return errors.New("no method") + } + + if cli.replies[cli.cfhome+cli.args[0]] != expect { + return errors.New(fmt.Sprintf("expect :%s, but :%s", expect, cli.replies[cli.cfhome+cli.args[0]])) + } + return nil +} diff --git a/workloads/workloads.go b/workloads/workloads.go index adfecae..ba0d954 100644 --- a/workloads/workloads.go +++ b/workloads/workloads.go @@ -68,6 +68,10 @@ func PopulateAppContext(appPath string, manifestPath string, ctx context.Context return nil } +func PopulateCliContext(cfhomes string, ctx context.Context) { + ctx.PutString("cfhomes", cfhomes) +} + func normalizePath(aPath string) (string, error) { if aPath == "" { return "", nil diff --git a/workloads/workloads_test.go b/workloads/workloads_test.go index 65d9aad..b04e025 100644 --- a/workloads/workloads_test.go +++ b/workloads/workloads_test.go @@ -78,4 +78,15 @@ var _ = Describe("Workloads", func() { }) }) + + Describe("#PopulateCliContext", func() { + It("inserts the cfhomes into the context", func() { + ctx := context.New() + PopulateCliContext("somehomes", ctx) + homePath, ok := ctx.GetString("cfhomes") + Ω(Expect(ok).To(BeTrue())) + Ω(Expect(homePath).To(Equal("somehomes"))) + + }) + }) })