<commit_before>package cell_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"time"

	"code.cloudfoundry.org/archiver/extractor/test_helper"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/inigo/helpers"
	"code.cloudfoundry.org/inigo/inigo_announcement_server"
	repconfig "code.cloudfoundry.org/rep/cmd/rep/config"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/ghttp"
)

var _ = Describe("Tasks", func() {
	var (
		cellProcess ifrit.Process
	)

	var fileServerStaticDir string

	BeforeEach(func() {
		var fileServerRunner ifrit.Runner

		fileServerRunner, fileServerStaticDir = componentMaker.FileServer()

		cellGroup := grouper.Members{
			{"file-server", fileServerRunner},
			{"rep", componentMaker.Rep(func(config *repconfig.RepConfig) { config.MemoryMB = "1024" })},
			{"auctioneer", componentMaker.Auctioneer()},
		}
		cellProcess = ginkgomon.Invoke(grouper.NewParallel(os.Interrupt, cellGroup))

		Eventually(func() (models.CellSet, error) { return bbsServiceClient.Cells(logger) }).Should(HaveLen(1))
	})

	AfterEach(func() {
		helpers.StopProcesses(cellProcess)
	})

	Describe("Running a task", func() {
		var guid string

		BeforeEach(func() {
			guid = helpers.GenerateGuid()
		})

		It("runs the command with the provided environment", func() {
			expectedTask := helpers.TaskCreateRequest(
				guid,
				&models.RunAction{
					User: "vcap",
					Path: "sh",
					Args: []string{"-c", `[ "$FOO" = NEW-BAR -a "$BAZ" = WIBBLE ]`},
					Env: []*models.EnvironmentVariable{
						{"FOO", "OLD-BAR"},
						{"BAZ", "WIBBLE"},
						{"FOO", "NEW-BAR"},
					},
				},
			)
			expectedTask.Privileged = true

			err := bbsClient.DesireTask(logger, expectedTask.TaskGuid, expectedTask.Domain, expectedTask.TaskDefinition)
			Expect(err).NotTo(HaveOccurred())

			var task *models.Task

			Eventually(func() interface{} {
				var err error

				task, err = bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())

				return task.State
			}).Should(Equal(models.Task_Completed))

			Expect(task.Failed).To(BeFalse())
		})

		It("runs the command with the provided working directory", func() {
			expectedTask := helpers.TaskCreateRequest(
				guid,
				&models.RunAction{
					User: "vcap",
					Path: "sh",
					Args: []string{"-c", `[ $PWD = /tmp ]`},
					Dir:  "/tmp",
				},
			)
			expectedTask.Privileged = true

			err := bbsClient.DesireTask(logger, expectedTask.TaskGuid, expectedTask.Domain, expectedTask.TaskDefinition)

			Expect(err).NotTo(HaveOccurred())

			var task *models.Task

			Eventually(func() interface{} {
				var err error

				task, err = bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())

				return task.State
			}).Should(Equal(models.Task_Completed))

			Expect(task.Failed).To(BeFalse())
		})

		Context("when using a private image", func() {
			var (
				privateRef              string
				privateDockerRootFSPath string
				privateUser             string
				privatePassword         string
			)
			BeforeEach(func() {
				privateRef = os.Getenv("INIGO_PRIVATE_DOCKER_IMAGE_REF")
				privateDockerRootFSPath = os.Getenv("INIGO_PRIVATE_DOCKER_IMAGE_ROOTFS_PATH")
				privateUser = os.Getenv("INIGO_PRIVATE_DOCKER_IMAGE_USERNAME")
				privatePassword = os.Getenv("INIGO_PRIVATE_DOCKER_IMAGE_PASSWORD")
				if privateRef == "" {
					Skip("no private docker image specified")
				}
			})

			It("fetches the metadata", func() {
				expectedTask := helpers.TaskCreateRequest(
					guid,
					&models.RunAction{
						User: "vcap",
						Path: "/tmp/diego/dockerapplifecycle/builder",
						Args: []string{"--dockerRef", privateRef, "--dockerUser", privateUser, "--dockerPassword", <PASSWORD>Password, "--outputMetadataJSONFilename", "/tmp/result.json"},
					},
				)
				expectedTask.CachedDependencies = []*models.CachedDependency{{
					From:      fmt.Sprintf("http://%s/v1/static/docker_app_lifecycle/docker_app_lifecycle.tgz", componentMaker.Addresses().FileServer),
					To:        "/tmp/diego/dockerapplifecycle",
					Name:      "docker app lifecycle",
					CacheKey:  "docker-app-lifecycle",
					LogSource: "docker-app-lifecycle",
				}}
				expectedTask.Privileged = true
				expectedTask.ResultFile = "/tmp/result.json"
				expectedTask.EgressRules = []*models.SecurityGroupRule{
					{
						Protocol:     models.TCPProtocol,
						Destinations: []string{"9.0.0.0-89.255.255.255", "172.16.58.3-94.0.0.0"},
						Ports:        []uint32{80, 443},
					},
					{
						Protocol:     models.UDPProtocol,
						Destinations: []string{"0.0.0.0/0"},
						PortRange: &models.PortRange{
							Start: 53,
							End:   53,
						},
					},
				}

				err := bbsClient.DesireTask(logger, expectedTask.TaskGuid, expectedTask.Domain, expectedTask.TaskDefinition)
				Expect(err).NotTo(HaveOccurred())

				var task *models.Task

				Eventually(func() interface{} {
					var err error

					task, err = bbsClient.TaskByGuid(logger, guid)
					Expect(err).NotTo(HaveOccurred())

					return task.State
				}).Should(Equal(models.Task_Completed))

				Expect(task.FailureReason).To(BeZero())
				Expect(task.Failed).To(BeFalse())
				Expect(task.Result).To(ContainSubstring(privateRef))
			})

			It("eventually runs", func() {
				expectedTask := helpers.TaskCreateRequest(
					guid,
					&models.RunAction{
						User: "vcap",
						Path: "sh",
						Args: []string{"-c", `[ "$FOO" = NEW-BAR -a "$BAZ" = WIBBLE ]`},
						Env: []*models.EnvironmentVariable{
							{"FOO", "OLD-BAR"},<commit_msg>allow all traffic from the task<commit_after>package cell_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"time"

	"code.cloudfoundry.org/archiver/extractor/test_helper"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/inigo/helpers"
	"code.cloudfoundry.org/inigo/inigo_announcement_server"
	repconfig "code.cloudfoundry.org/rep/cmd/rep/config"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/ghttp"
)

var _ = Describe("Tasks", func() {
	var (
		cellProcess ifrit.Process
	)

	var fileServerStaticDir string

	BeforeEach(func() {
		var fileServerRunner ifrit.Runner

		fileServerRunner, fileServerStaticDir = componentMaker.FileServer()

		cellGroup := grouper.Members{
			{"file-server", fileServerRunner},
			{"rep", componentMaker.Rep(func(config *repconfig.RepConfig) { config.MemoryMB = "1024" })},
			{"auctioneer", componentMaker.Auctioneer()},
		}
		cellProcess = ginkgomon.Invoke(grouper.NewParallel(os.Interrupt, cellGroup))

		Eventually(func() (models.CellSet, error) { return bbsServiceClient.Cells(logger) }).Should(HaveLen(1))
	})

	AfterEach(func() {
		helpers.StopProcesses(cellProcess)
	})

	Describe("Running a task", func() {
		var guid string

		BeforeEach(func() {
			guid = helpers.GenerateGuid()
		})

		It("runs the command with the provided environment", func() {
			expectedTask := helpers.TaskCreateRequest(
				guid,
				&models.RunAction{
					User: "vcap",
					Path: "sh",
					Args: []string{"-c", `[ "$FOO" = NEW-BAR -a "$BAZ" = WIBBLE ]`},
					Env: []*models.EnvironmentVariable{
						{"FOO", "OLD-BAR"},
						{"BAZ", "WIBBLE"},
						{"FOO", "NEW-BAR"},
					},
				},
			)
			expectedTask.Privileged = true

			err := bbsClient.DesireTask(logger, expectedTask.TaskGuid, expectedTask.Domain, expectedTask.TaskDefinition)
			Expect(err).NotTo(HaveOccurred())

			var task *models.Task

			Eventually(func() interface{} {
				var err error

				task, err = bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())

				return task.State
			}).Should(Equal(models.Task_Completed))

			Expect(task.Failed).To(BeFalse())
		})

		It("runs the command with the provided working directory", func() {
			expectedTask := helpers.TaskCreateRequest(
				guid,
				&models.RunAction{
					User: "vcap",
					Path: "sh",
					Args: []string{"-c", `[ $PWD = /tmp ]`},
					Dir:  "/tmp",
				},
			)
			expectedTask.Privileged = true

			err := bbsClient.DesireTask(logger, expectedTask.TaskGuid, expectedTask.Domain, expectedTask.TaskDefinition)

			Expect(err).NotTo(HaveOccurred())

			var task *models.Task

			Eventually(func() interface{} {
				var err error

				task, err = bbsClient.TaskByGuid(logger, guid)
				Expect(err).NotTo(HaveOccurred())

				return task.State
			}).Should(Equal(models.Task_Completed))

			Expect(task.Failed).To(BeFalse())
		})

		Context("when using a private image", func() {
			var (
				privateRef              string
				privateDockerRootFSPath string
				privateUser             string
				privatePassword         string
			)
			BeforeEach(func() {
				privateRef = os.Getenv("INIGO_PRIVATE_DOCKER_IMAGE_REF")
				privateDockerRootFSPath = os.Getenv("INIGO_PRIVATE_DOCKER_IMAGE_ROOTFS_PATH")
				privateUser = os.Getenv("INIGO_PRIVATE_DOCKER_IMAGE_USERNAME")
				privatePassword = os.Getenv("INIGO_PRIVATE_DOCKER_IMAGE_PASSWORD")
				if privateRef == "" {
					Skip("no private docker image specified")
				}
			})

			It("fetches the metadata", func() {
				expectedTask := helpers.TaskCreateRequest(
					guid,
					&models.RunAction{
						User: "vcap",
						Path: "/tmp/diego/dockerapplifecycle/builder",
						Args: []string{"--dockerRef", privateRef, "--dockerUser", privateUser, "--dockerPassword", privatePassword, "--outputMetadataJSONFilename", "/tmp/result.json"},
					},
				)
				expectedTask.CachedDependencies = []*models.CachedDependency{{
					From:      fmt.Sprintf("http://%s/v1/static/docker_app_lifecycle/docker_app_lifecycle.tgz", componentMaker.Addresses().FileServer),
					To:        "/tmp/diego/dockerapplifecycle",
					Name:      "docker app lifecycle",
					CacheKey:  "docker-app-lifecycle",
					LogSource: "docker-app-lifecycle",
				}}
				expectedTask.Privileged = true
				expectedTask.ResultFile = "/tmp/result.json"
				expectedTask.EgressRules = []*models.SecurityGroupRule{
					{
						// allow traffic to the docker registry
						Protocol:     models.AllProtocol,
						Destinations: []string{"0.0.0.0/0"},
					},
				}

				err := bbsClient.DesireTask(logger, expectedTask.TaskGuid, expectedTask.Domain, expectedTask.TaskDefinition)
				Expect(err).NotTo(HaveOccurred())

				var task *models.Task

				Eventually(func() interface{} {
					var err error

					task, err = bbsClient.TaskByGuid(logger, guid)
					Expect(err).NotTo(HaveOccurred())

					return task.State
				}).Should(Equal(models.Task_Completed))

				Expect(task.FailureReason).To(BeZero())
				Expect(task.Failed).To(BeFalse())
				Expect(task.Result).To(ContainSubstring(privateRef))
			})

			It("eventually runs", func() {
				expectedTask := helpers.TaskCreateRequest(
					guid,
					&models.RunAction{
						User: "vcap",
						Path: "sh",
						Args: []string{"-c", `[ "$FOO" = NEW-BAR -a "$BAZ" = WIBBLE ]`},
						Env: []*models.EnvironmentVariable{
							{"FOO", "OLD-BAR"},
{'fraction_non_alphanumeric': 0.1480621539560636, 'fraction_numerical': 0.005447401321664583, 'mean_word_length': 3.5030156815440288, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2593355', 'n_tokens_mistral': 4710, 'n_tokens_neox': 3770, 'n_words': 622}