var _ = Describe("MultipleClientsSingleBroker", func() {
	var (
		URL     string
		session *gexec.Session
	)

	BeforeEach(func() {
		var err error
		tmpDir, err = ioutil.TempDir("/tmp", "systemtalaria")
		Expect(err).ToNot(HaveOccurred())
		URL, session = startTalaria(tmpDir)
	})

	AfterEach(func() {
		session.Kill()
		session.Wait("10s", "100ms")

		Expect(os.RemoveAll(tmpDir)).To(Succeed())
	})

	It("Writes and reads from separate files", func(done Done) {
		defer close(done)
		var wg sync.WaitGroup
		defer wg.Wait()

		runTest := func(name string) {
			defer wg.Done()
			client := startClient(URL)
			fileId, err := client.FetchFile(name)
			Expect(err).ToNot(HaveOccurred())
			for i := byte(0); i < 100; i++ {
Example #2
0
func itWorksWithBranch(branchName string) {
	Context("when the branch name is "+branchName, func() {

		var gitRepo string
		var bareGitRepo string
		var sourceDir string

		var outResponse out.OutResponse
		var outRequest out.OutRequest

		BeforeEach(func() {
			var err error
			gitRepo, err = ioutil.TempDir("", "git-repo")
			Ω(err).ShouldNot(HaveOccurred())

			bareGitRepo, err = ioutil.TempDir("", "bare-git-repo")
			Ω(err).ShouldNot(HaveOccurred())

			sourceDir, err = ioutil.TempDir("", "source-dir")
			Ω(err).ShouldNot(HaveOccurred())

			setupGitRepo(gitRepo)

			bareGitSetup := exec.Command("bash", "-e", "-c", fmt.Sprintf(`
			git clone %s --bare .
		`, gitRepo))
			bareGitSetup.Dir = bareGitRepo

			err = bareGitSetup.Run()
			Ω(err).ShouldNot(HaveOccurred())
		})

		AfterEach(func() {
			err := os.RemoveAll(bareGitRepo)
			Ω(err).ShouldNot(HaveOccurred())

			err = os.RemoveAll(gitRepo)
			Ω(err).ShouldNot(HaveOccurred())

			err = os.RemoveAll(sourceDir)
			Ω(err).ShouldNot(HaveOccurred())
		})

		Context("when the config is incomplete", func() {
			var session *gexec.Session

			BeforeEach(func() {
				outRequest = out.OutRequest{
					Source: out.Source{
						URI:        bareGitRepo,
						Branch:     branchName,
						Pool:       "lock-pool",
						RetryDelay: 100 * time.Millisecond,
					},
					Params: out.OutParams{
						Acquire: true,
					},
				}
			})

			JustBeforeEach(func() {
				session = runOut(outRequest, sourceDir)
				Eventually(session).Should(gexec.Exit(1))
			})

			Context("when the uri isn't set", func() {
				BeforeEach(func() {
					outRequest.Source.URI = ""
				})

				It("complains about it", func() {
					errorMessages := string(session.Err.Contents())

					Ω(errorMessages).Should(ContainSubstring("invalid payload (missing uri)"))
				})
			})

			Context("when the pool isn't set", func() {
				BeforeEach(func() {
					outRequest.Source.Pool = ""
				})

				It("complains about it", func() {
					errorMessages := string(session.Err.Contents())

					Ω(errorMessages).Should(ContainSubstring("invalid payload (missing pool)"))
				})
			})

			Context("when the branch isn't set", func() {
				BeforeEach(func() {
					outRequest.Source.Branch = ""
				})

				It("complains about it", func() {
					errorMessages := string(session.Err.Contents())

					Ω(errorMessages).Should(ContainSubstring("invalid payload (missing branch)"))
				})
			})

			Context("when the branch isn't set", func() {
				BeforeEach(func() {
					outRequest.Params = out.OutParams{}
				})

				It("complains about it", func() {
					errorMessages := string(session.Err.Contents())

					Ω(errorMessages).Should(ContainSubstring("invalid payload (missing acquire, release, remove, or add)"))
				})
			})
		})

		Context("When acquiring a lock", func() {
			BeforeEach(func() {
				outRequest = out.OutRequest{
					Source: out.Source{
						URI:        bareGitRepo,
						Branch:     branchName,
						Pool:       "lock-pool",
						RetryDelay: 100 * time.Millisecond,
					},
					Params: out.OutParams{
						Acquire: true,
					},
				}

				session := runOut(outRequest, sourceDir)
				Eventually(session).Should(gexec.Exit(0))

				err := json.Unmarshal(session.Out.Contents(), &outResponse)
				Ω(err).ShouldNot(HaveOccurred())
			})

			It("moves a lock to claimed", func() {
				version := getVersion(bareGitRepo, "origin/"+branchName)

				reCloneRepo, err := ioutil.TempDir("", "git-version-repo")
				Ω(err).ShouldNot(HaveOccurred())

				defer os.RemoveAll(reCloneRepo)

				reClone := exec.Command("git", "clone", "--branch", branchName, bareGitRepo, ".")
				reClone.Dir = reCloneRepo
				err = reClone.Run()
				Ω(err).ShouldNot(HaveOccurred())

				claimedFiles, err := ioutil.ReadDir(filepath.Join(reCloneRepo, "lock-pool", "claimed"))
				Ω(err).ShouldNot(HaveOccurred())

				Ω(len(claimedFiles)).Should(Equal(2))

				var lockFile string
				for _, file := range claimedFiles {
					filename := filepath.Base(file.Name())
					if filename != ".gitkeep" {
						lockFile = filename
					}
				}

				Ω(outResponse).Should(Equal(out.OutResponse{
					Version: version,
					Metadata: []out.MetadataPair{
						{Name: "lock_name", Value: lockFile},
						{Name: "pool_name", Value: "lock-pool"},
					},
				}))
			})
		})

		Context("when there are no locks to be claimed", func() {
			var session *gexec.Session
			var claimAllLocksDir string

			BeforeEach(func() {
				var err error

				outRequest = out.OutRequest{
					Source: out.Source{
						URI:        bareGitRepo,
						Branch:     branchName,
						Pool:       "lock-pool",
						RetryDelay: 1 * time.Second,
					},
					Params: out.OutParams{
						Acquire: true,
					},
				}

				claimAllLocksDir, err = ioutil.TempDir("", "claiming-locks")
				Ω(err).ShouldNot(HaveOccurred())

				claimAllLocks := exec.Command("bash", "-e", "-c", fmt.Sprintf(`
				git clone --branch %s %s .

				git config user.email "ginkgo@localhost"
				git config user.name "Ginkgo Local"

				git mv lock-pool/unclaimed/* lock-pool/claimed/
				git commit -am "claiming all locks"
				git push
			`, branchName, bareGitRepo))

				claimAllLocks.Stdout = GinkgoWriter
				claimAllLocks.Stderr = GinkgoWriter
				claimAllLocks.Dir = claimAllLocksDir

				err = claimAllLocks.Run()
				Ω(err).ShouldNot(HaveOccurred())

				session = runOut(outRequest, sourceDir)
			})

			AfterEach(func() {
				err := os.RemoveAll(claimAllLocksDir)
				Ω(err).ShouldNot(HaveOccurred())
			})

			It("retries until a lock can be claimed", func() {
				Consistently(session, 2*time.Second).ShouldNot(gexec.Exit(0))

				releaseLock := exec.Command("bash", "-e", "-c", fmt.Sprint(`
				git mv lock-pool/claimed/some-lock lock-pool/unclaimed/some-lock
				git commit -am "unclaiming some-lock"
				git push
			`))

				releaseLock.Dir = claimAllLocksDir

				err := releaseLock.Run()
				Ω(err).ShouldNot(HaveOccurred())

				Eventually(session, 2*time.Second).Should(gexec.Exit(0))

				err = json.Unmarshal(session.Out.Contents(), &outResponse)
				Ω(err).ShouldNot(HaveOccurred())

				Ω(outResponse).Should(Equal(out.OutResponse{
					Version: out.Version{
						Ref: outResponse.Version.Ref,
					},
					Metadata: []out.MetadataPair{
						{Name: "lock_name", Value: "some-lock"},
						{Name: "pool_name", Value: "lock-pool"},
					},
				}))
			})
		})

		Context("When removing a lock", func() {
			var myLocksGetDir string
			var outReleaseRequest out.OutRequest
			var outReleaseResponse out.OutResponse

			BeforeEach(func() {
				outRequest = out.OutRequest{
					Source: out.Source{
						URI:    bareGitRepo,
						Branch: branchName,
						Pool:   "lock-pool",
					},
					Params: out.OutParams{
						Acquire: true,
					},
				}

				session := runOut(outRequest, sourceDir)
				Eventually(session).Should(gexec.Exit(0))

				err := json.Unmarshal(session.Out.Contents(), &outResponse)
				Ω(err).ShouldNot(HaveOccurred())
			})

			JustBeforeEach(func() {
				var err error

				myLocksGetDir, err = ioutil.TempDir("", "my-locks")
				Ω(err).ShouldNot(HaveOccurred())

				jsonIn := fmt.Sprintf(`
				{
					"source": {
						"uri": "%s",
						"branch": "%s",
						"pool": "lock-pool"
					},
					"version": {
						"ref": "%s"
					}
				}`, bareGitRepo, branchName, string(outResponse.Version.Ref))

				runIn(jsonIn, filepath.Join(myLocksGetDir, "lock-step-name"), 0)

				outReleaseRequest = out.OutRequest{
					Source: out.Source{
						URI:    bareGitRepo,
						Branch: branchName,
						Pool:   "lock-pool",
					},
					Params: out.OutParams{
						Remove: "lock-step-name",
					},
				}

				session := runOut(outReleaseRequest, myLocksGetDir)
				Eventually(session).Should(gexec.Exit(0))

				err = json.Unmarshal(session.Out.Contents(), &outReleaseResponse)
				Ω(err).ShouldNot(HaveOccurred())
			})

			AfterEach(func() {
				err := os.RemoveAll(myLocksGetDir)
				Ω(err).ShouldNot(HaveOccurred())
			})

			It("removes the lock from the pool", func() {
				version := getVersion(bareGitRepo, "origin/"+branchName)

				reCloneRepo, err := ioutil.TempDir("", "git-version-repo")
				Ω(err).ShouldNot(HaveOccurred())

				defer os.RemoveAll(reCloneRepo)

				reClone := exec.Command("git", "clone", "--branch", branchName, bareGitRepo, ".")
				reClone.Dir = reCloneRepo
				err = reClone.Run()
				Ω(err).ShouldNot(HaveOccurred())

				claimedFiles, err := ioutil.ReadDir(filepath.Join(reCloneRepo, "lock-pool", "claimed"))
				Ω(err).ShouldNot(HaveOccurred())

				Ω(len(claimedFiles)).Should(Equal(1))

				unclaimedFiles, err := ioutil.ReadDir(filepath.Join(reCloneRepo, "lock-pool", "unclaimed"))
				Ω(err).ShouldNot(HaveOccurred())

				Ω(len(unclaimedFiles)).Should(Equal(2))

				var removedLockName string
				for _, metaDataPair := range outResponse.Metadata {
					if metaDataPair.Name == "lock_name" {
						removedLockName = metaDataPair.Value
					}
				}

				Ω(outReleaseResponse).Should(Equal(out.OutResponse{
					Version: version,
					Metadata: []out.MetadataPair{
						{Name: "lock_name", Value: removedLockName},
						{Name: "pool_name", Value: "lock-pool"},
					},
				}))
			})
		})

		Context("When releasing a lock", func() {
			var myLocksGetDir string
			var outReleaseRequest out.OutRequest
			var outReleaseResponse out.OutResponse

			BeforeEach(func() {
				outRequest = out.OutRequest{
					Source: out.Source{
						URI:    bareGitRepo,
						Branch: branchName,
						Pool:   "lock-pool",
					},
					Params: out.OutParams{
						Acquire: true,
					},
				}

				session := runOut(outRequest, sourceDir)
				Eventually(session).Should(gexec.Exit(0))

				err := json.Unmarshal(session.Out.Contents(), &outResponse)
				Ω(err).ShouldNot(HaveOccurred())
			})

			JustBeforeEach(func() {
				var err error

				myLocksGetDir, err = ioutil.TempDir("", "my-locks")
				Ω(err).ShouldNot(HaveOccurred())

				jsonIn := fmt.Sprintf(`
				{
					"source": {
						"uri": "%s",
						"branch": "%s",
						"pool": "lock-pool"
					},
					"version": {
						"ref": "%s"
					}
				}`, bareGitRepo, branchName, string(outResponse.Version.Ref))

				runIn(jsonIn, filepath.Join(myLocksGetDir, "lock-step-name"), 0)

				outReleaseRequest = out.OutRequest{
					Source: out.Source{
						URI:    bareGitRepo,
						Branch: branchName,
						Pool:   "lock-pool",
					},
					Params: out.OutParams{
						Release: "lock-step-name",
					},
				}

				session := runOut(outReleaseRequest, myLocksGetDir)
				Eventually(session).Should(gexec.Exit(0))

				err = json.Unmarshal(session.Out.Contents(), &outReleaseResponse)
				Ω(err).ShouldNot(HaveOccurred())
			})

			AfterEach(func() {
				err := os.RemoveAll(myLocksGetDir)
				Ω(err).ShouldNot(HaveOccurred())
			})

			It("moves the lock to unclaimed", func() {
				version := getVersion(bareGitRepo, "origin/"+branchName)

				reCloneRepo, err := ioutil.TempDir("", "git-version-repo")
				Ω(err).ShouldNot(HaveOccurred())

				defer os.RemoveAll(reCloneRepo)

				reClone := exec.Command("git", "clone", "--branch", branchName, bareGitRepo, ".")
				reClone.Dir = reCloneRepo
				err = reClone.Run()
				Ω(err).ShouldNot(HaveOccurred())

				claimedFiles, err := ioutil.ReadDir(filepath.Join(reCloneRepo, "lock-pool", "claimed"))
				Ω(err).ShouldNot(HaveOccurred())

				Ω(len(claimedFiles)).Should(Equal(1))

				unclaimedFiles, err := ioutil.ReadDir(filepath.Join(reCloneRepo, "lock-pool", "unclaimed"))
				Ω(err).ShouldNot(HaveOccurred())

				Ω(len(unclaimedFiles)).Should(Equal(3))

				var releasedLockName string
				for _, metaDataPair := range outResponse.Metadata {
					if metaDataPair.Name == "lock_name" {
						releasedLockName = metaDataPair.Value
					}
				}

				Ω(outReleaseResponse).Should(Equal(out.OutResponse{
					Version: version,
					Metadata: []out.MetadataPair{
						{Name: "lock_name", Value: releasedLockName},
						{Name: "pool_name", Value: "lock-pool"},
					},
				}))
			})
		})

		Context("when adding a lock to the pool", func() {
			var lockToAddDir string
			var cloneDir string

			BeforeEach(func() {
				lockToAddDir, err := ioutil.TempDir("", "lock-to-add")
				Ω(err).ShouldNot(HaveOccurred())

				cloneDir, err = ioutil.TempDir("", "clone")
				Ω(err).ShouldNot(HaveOccurred())

				taskDir := filepath.Join(lockToAddDir, "task-name")
				err = os.Mkdir(taskDir, 0755)

				err = ioutil.WriteFile(filepath.Join(taskDir, "metadata"), []byte("hello"), 0555)
				Ω(err).ShouldNot(HaveOccurred())

				err = ioutil.WriteFile(filepath.Join(taskDir, "name"), []byte("added-lock-name"), 0555)
				Ω(err).ShouldNot(HaveOccurred())

				outRequest = out.OutRequest{
					Source: out.Source{
						URI:        bareGitRepo,
						Branch:     branchName,
						Pool:       "lock-pool",
						RetryDelay: 100 * time.Millisecond,
					},
					Params: out.OutParams{
						Add: "task-name",
					},
				}

				session := runOut(outRequest, lockToAddDir)
				Eventually(session).Should(gexec.Exit(0))

				err = json.Unmarshal(session.Out.Contents(), &outResponse)
				Ω(err).ShouldNot(HaveOccurred())
			})

			AfterEach(func() {
				err := os.RemoveAll(lockToAddDir)
				Ω(err).ShouldNot(HaveOccurred())

				err = os.RemoveAll(cloneDir)
				Ω(err).ShouldNot(HaveOccurred())
			})

			It("adds the new lock", func() {
				clone := exec.Command("git", "clone", "--branch", branchName, bareGitRepo, ".")
				clone.Dir = cloneDir
				err := clone.Run()
				Ω(err).ShouldNot(HaveOccurred())

				lockPath := filepath.Join(cloneDir, "lock-pool", "unclaimed", "added-lock-name")

				Ω(lockPath).Should(BeARegularFile())
				contents, err := ioutil.ReadFile(lockPath)
				Ω(err).ShouldNot(HaveOccurred())

				Ω(string(contents)).Should(Equal("hello"))
			})
		})

		Context("when 2 processes are acquiring a lock at the same time", func() {
			var sessionOne *gexec.Session
			var sessionTwo *gexec.Session
			var gitServerSession *gexec.Session

			var sessionOneDir string
			var sessionTwoDir string
			var claimLockDir string

			var exitedCounter uint64

			BeforeEach(func() {
				var err error
				sessionOneDir, err = ioutil.TempDir("", "session-one")
				Ω(err).ShouldNot(HaveOccurred())

				sessionTwoDir, err = ioutil.TempDir("", "session-two")
				Ω(err).ShouldNot(HaveOccurred())

				claimLockDir, err = ioutil.TempDir("", "claiming-locks")
				Ω(err).ShouldNot(HaveOccurred())

				gitPort := GinkgoParallelNode() + 9418
				gitURI := fmt.Sprintf("git://*****:*****@localhost"
				git config user.name "Ginkgo Local"

				git mv lock-pool/unclaimed/some-lock lock-pool/claimed/
				git commit -am "claiming a lock"
				git push
			`, branchName, bareGitRepo))

					claimOneLock.Stdout = GinkgoWriter
					claimOneLock.Stderr = GinkgoWriter
					claimOneLock.Dir = claimLockDir

					err = claimOneLock.Run()
					Ω(err).ShouldNot(HaveOccurred())

				})

				It("does not acquire the same lock", func() {
					Eventually(func() uint64 {
						return exitedCounter
					}, 5*time.Second).Should(Equal(uint64(1)))
					Consistently(func() uint64 {
						return exitedCounter
					}, 2*time.Second).Should(Equal(uint64(1)))

					sessionOne.Terminate().Wait()
					sessionTwo.Terminate().Wait()

					Ω(sessionOne.Err).ShouldNot(gbytes.Say("err"))
					Ω(sessionTwo.Err).ShouldNot(gbytes.Say("err"))
				})
			})
		})
	})
}
Example #3
0
var _ = BeforeSuite(func() {
	logging.SetLevel(logging.CRITICAL)
	consulPath, err := gexec.Build("github.com/hashicorp/consul")
	Expect(err).ToNot(HaveOccurred())

	tmpDir, err = ioutil.TempDir("", "consul")
	Expect(err).ToNot(HaveOccurred())

	consulCmd := exec.Command(consulPath, "agent", "-server", "-bootstrap-expect", "1", "-data-dir", tmpDir, "-bind", "127.0.0.1")
	consulSession, err = gexec.Start(consulCmd, nil, nil)
	Expect(err).ToNot(HaveOccurred())
	Consistently(consulSession).ShouldNot(gexec.Exit())

	consulClient, err = api.NewClient(api.DefaultConfig())
	Expect(err).ToNot(HaveOccurred())

	f := func() error {
		_, _, err := consulClient.Catalog().Nodes(nil)
		return err
	}
	Eventually(f, 10).Should(BeNil())
})

var _ = AfterSuite(func() {
	consulSession.Kill()
	consulSession.Wait("60s", "200ms")
	Expect(os.RemoveAll(tmpDir)).To(Succeed())
	gexec.CleanupBuildArtifacts()
})