<commit_before>package vizzini_test

import (
	"io/ioutil"
	"net/http"
	"strings"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/routing-info/cfroutes"
	. "code.cloudfoundry.org/vizzini/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("LRPs", func() {
	var lrp *models.DesiredLRP
	var url string

	BeforeEach(func() {
		url = "http://" + RouteForGuid(guid) + "/env"
		lrp = DesiredLRPWithGuid(guid)
	})

	Describe("Desiring LRPs", func() {
		Context("when the LRP is well-formed", func() {
			BeforeEach(func() {
				Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())
			})

			It("desires the LRP", func() {
				Eventually(LRPGetter(logger, guid)).ShouldNot(BeZero())
				Eventually(EndpointCurler(url)).Should(Equal(http.StatusOK))
				Eventually(ActualByDomainGetter(logger, domain)).Should(ContainElement(BeActualLRP(guid, 0)))

				fetchedLRP, err := bbsClient.DesiredLRPByProcessGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(fetchedLRP.Annotation).To(Equal("arbitrary-data"))
			})
		})

		Context("when the LRP's process guid contains invalid characters", func() {
			It("should fail to create", func() {
				lrp.ProcessGuid = "abc def"
				err := bbsClient.DesireLRP(logger, lrp)
				Expect(models.ConvertError(err).Type).To(Equal(models.Error_InvalidRequest))

				lrp.ProcessGuid = "abc/def"
				Expect(bbsClient.DesireLRP(logger, lrp)).NotTo(Succeed())

				lrp.ProcessGuid = "abc,def"
				Expect(bbsClient.DesireLRP(logger, lrp)).NotTo(Succeed())

				lrp.ProcessGuid = "abc.def"
				Expect(bbsClient.DesireLRP(logger, lrp)).NotTo(Succeed())

				lrp.ProcessGuid = "abc∆def"
				Expect(bbsClient.DesireLRP(logger, lrp)).NotTo(Succeed())
			})
		})

		Context("when the LRP's # of instances is == 0", func() {
			It("should create the LRP and allow the user to subsequently scale up", func() {
				lrp.Instances = 0
				Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())

				two := int32(2)
				Expect(bbsClient.UpdateDesiredLRP(logger, lrp.ProcessGuid, &models.DesiredLRPUpdate{
					Instances: &two,
				})).To(Succeed())

				Eventually(IndexCounter(guid)).Should(Equal(2))
			})
		})

		Context("when required fields are missing", func() {
			It("should fail to create", func() {
				lrpCopy := new(models.DesiredLRP)

				By("not having ProcessGuid")
				*lrpCopy = *lrp
				lrpCopy.ProcessGuid = ""
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())

				By("not having a domain")
				*lrpCopy = *lrp
				lrpCopy.Domain = ""
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())

				By("not having an action")
				*lrpCopy = *lrp
				lrpCopy.Action = nil
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())

				By("not having a rootfs")
				*lrpCopy = *lrp
				lrpCopy.RootFs = ""
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())

				By("having a malformed rootfs")
				*lrpCopy = *lrp
				lrpCopy.RootFs = "ploop"
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())
			})
		})

		Context("when the CPUWeight is out of bounds", func() {
			It("should fail", func() {
				lrp.CpuWeight = 101
				err := bbsClient.DesireLRP(logger, lrp)
				Expect(models.ConvertError(err).Type).To(Equal(models.Error_InvalidRequest))
			})
		})

		Context("when the annotation is too large", func() {
			It("should fail", func() {
				lrp.Annotation = strings.Repeat("7", 1024*10+1)
				err := bbsClient.DesireLRP(logger, lrp)
				Expect(models.ConvertError(err).Type).To(Equal(models.Error_InvalidRequest))
			})
		})

		Context("when the DesiredLRP already exists", func() {
			BeforeEach(func() {
				Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())
				Eventually(EndpointCurler(url)).Should(Equal(http.StatusOK))
			})

			It("should fail", func() {
				err := bbsClient.DesireLRP(logger, lrp)
				Expect(models.ConvertError(err).Type).To(Equal(models.Error_ResourceExists))
			})
		})
	})

	Describe("Specifying environment variables", func() {
		BeforeEach(func() {
			lrp.EnvironmentVariables = []*models.EnvironmentVariable{
				{"CONTAINER_LEVEL", "AARDVARK"},
				{"OVERRIDE", "BANANA"},
			}

			Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())
			Eventually(EndpointCurler(url)).Should(Equal(http.StatusOK))
		})

		It("should be possible to specify environment variables on both the DesiredLRP and the RunAction", func() {
			resp, err := http.Get(url)
			Expect(err).NotTo(HaveOccurred())
			body, err := ioutil.ReadAll(resp.Body)
			Expect(err).NotTo(HaveOccurred())
			resp.Body.Close()

			Expect(body).To(ContainSubstring("AARDVARK"))
			Expect(body).To(ContainSubstring("COYOTE"))
			Expect(body).To(ContainSubstring("DAQUIRI"))
			Expect(body).NotTo(ContainSubstring("BANANA"))
		})
	})

	Describe("Specifying HTTP-based health check (move to inigo or DATs once CC can specify an HTTP-based health-check)", func() {
		BeforeEach(func() {
			lrp.Setup = models.WrapAction(models.Serial(
				&models.DownloadAction{
					From:     GraceTarballURL,
					To:       ".",
					CacheKey: "grace",
					User:     "vcap",
				},
				&models.DownloadAction{<commit_msg>Improve env var assertions<commit_after>package vizzini_test

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strings"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/routing-info/cfroutes"
	. "code.cloudfoundry.org/vizzini/matchers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("LRPs", func() {
	var lrp *models.DesiredLRP
	var url string

	BeforeEach(func() {
		url = "http://" + RouteForGuid(guid) + "/env?json=true"
		lrp = DesiredLRPWithGuid(guid)
	})

	Describe("Desiring LRPs", func() {
		Context("when the LRP is well-formed", func() {
			BeforeEach(func() {
				Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())
			})

			It("desires the LRP", func() {
				Eventually(LRPGetter(logger, guid)).ShouldNot(BeZero())
				Eventually(EndpointCurler(url)).Should(Equal(http.StatusOK))
				Eventually(ActualByDomainGetter(logger, domain)).Should(ContainElement(BeActualLRP(guid, 0)))

				fetchedLRP, err := bbsClient.DesiredLRPByProcessGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())
				Expect(fetchedLRP.Annotation).To(Equal("arbitrary-data"))
			})
		})

		Context("when the LRP's process guid contains invalid characters", func() {
			It("should fail to create", func() {
				lrp.ProcessGuid = "abc def"
				err := bbsClient.DesireLRP(logger, lrp)
				Expect(models.ConvertError(err).Type).To(Equal(models.Error_InvalidRequest))

				lrp.ProcessGuid = "abc/def"
				Expect(bbsClient.DesireLRP(logger, lrp)).NotTo(Succeed())

				lrp.ProcessGuid = "abc,def"
				Expect(bbsClient.DesireLRP(logger, lrp)).NotTo(Succeed())

				lrp.ProcessGuid = "abc.def"
				Expect(bbsClient.DesireLRP(logger, lrp)).NotTo(Succeed())

				lrp.ProcessGuid = "abc∆def"
				Expect(bbsClient.DesireLRP(logger, lrp)).NotTo(Succeed())
			})
		})

		Context("when the LRP's # of instances is == 0", func() {
			It("should create the LRP and allow the user to subsequently scale up", func() {
				lrp.Instances = 0
				Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())

				two := int32(2)
				Expect(bbsClient.UpdateDesiredLRP(logger, lrp.ProcessGuid, &models.DesiredLRPUpdate{
					Instances: &two,
				})).To(Succeed())

				Eventually(IndexCounter(guid)).Should(Equal(2))
			})
		})

		Context("when required fields are missing", func() {
			It("should fail to create", func() {
				lrpCopy := new(models.DesiredLRP)

				By("not having ProcessGuid")
				*lrpCopy = *lrp
				lrpCopy.ProcessGuid = ""
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())

				By("not having a domain")
				*lrpCopy = *lrp
				lrpCopy.Domain = ""
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())

				By("not having an action")
				*lrpCopy = *lrp
				lrpCopy.Action = nil
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())

				By("not having a rootfs")
				*lrpCopy = *lrp
				lrpCopy.RootFs = ""
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())

				By("having a malformed rootfs")
				*lrpCopy = *lrp
				lrpCopy.RootFs = "ploop"
				Expect(bbsClient.DesireLRP(logger, lrpCopy)).NotTo(Succeed())
			})
		})

		Context("when the CPUWeight is out of bounds", func() {
			It("should fail", func() {
				lrp.CpuWeight = 101
				err := bbsClient.DesireLRP(logger, lrp)
				Expect(models.ConvertError(err).Type).To(Equal(models.Error_InvalidRequest))
			})
		})

		Context("when the annotation is too large", func() {
			It("should fail", func() {
				lrp.Annotation = strings.Repeat("7", 1024*10+1)
				err := bbsClient.DesireLRP(logger, lrp)
				Expect(models.ConvertError(err).Type).To(Equal(models.Error_InvalidRequest))
			})
		})

		Context("when the DesiredLRP already exists", func() {
			BeforeEach(func() {
				Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())
				Eventually(EndpointCurler(url)).Should(Equal(http.StatusOK))
			})

			It("should fail", func() {
				err := bbsClient.DesireLRP(logger, lrp)
				Expect(models.ConvertError(err).Type).To(Equal(models.Error_ResourceExists))
			})
		})
	})

	Describe("Specifying environment variables", func() {
		BeforeEach(func() {
			lrp.EnvironmentVariables = []*models.EnvironmentVariable{
				{"CONTAINER_LEVEL", "AARDVARK"},
				{"OVERRIDE", "BANANA"},
			}

			Expect(bbsClient.DesireLRP(logger, lrp)).To(Succeed())
			Eventually(EndpointCurler(url)).Should(Equal(http.StatusOK))
		})

		It("should be possible to specify environment variables on both the DesiredLRP and the RunAction", func() {
			resp, err := http.Get(url)
			Expect(err).NotTo(HaveOccurred())
			defer resp.Body.Close()

			bodyBytes, err := ioutil.ReadAll(resp.Body)
			Expect(err).NotTo(HaveOccurred())

			env := [][]string{}
			err = json.Unmarshal(bodyBytes, &env)
			Expect(err).NotTo(HaveOccurred())

			Expect(env).To(ContainElement([]string{"CONTAINER_LEVEL", "AARDVARK"}))
			Expect(env).To(ContainElement([]string{"ACTION_LEVEL", "COYOTE"}))
			Expect(env).To(ContainElement([]string{"OVERRIDE", "DAQUIRI"}))
			Expect(env).NotTo(ContainElement([]string{"OVERRIDE", "BANANA"}))
		})
	})

	Describe("Specifying HTTP-based health check (move to inigo or DATs once CC can specify an HTTP-based health-check)", func() {
		BeforeEach(func() {
			lrp.Setup = models.WrapAction(models.Serial(
				&models.DownloadAction{
					From:     GraceTarballURL,
					To:       ".",
					CacheKey: "grace",
					User:     "vcap",
				},
				&models.DownloadAction{
{'fraction_non_alphanumeric': 0.15924836291164468, 'fraction_numerical': 0.0034165322197969063, 'mean_word_length': 4.209095402867029, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7407838', 'n_tokens_mistral': 4442, 'n_tokens_neox': 3744, 'n_words': 628}