<commit_before>package runner

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"syscall"
	"time"

	"github.com/cloudfoundry-incubator/garden/client"
	"github.com/cloudfoundry-incubator/garden/client/connection"
	"github.com/cloudfoundry-incubator/garden/warden"
	"github.com/onsi/ginkgo"
	"github.com/onsi/gomega/gexec"
)

type Runner struct {
	addr string

	bin  string
	argv []string

	binPath    string
	rootFSPath string

	tmpdir string
}

func New(addr string, bin, binPath, rootFSPath string, argv ...string) *Runner {
	return &Runner{
		addr: addr,

		bin:  bin,
		argv: argv,

		binPath:    binPath,
		rootFSPath: rootFSPath,

		tmpdir: filepath.Join(
			os.TempDir(),
			fmt.Sprintf("test-warden-%d", ginkgo.GinkgoParallelNode()),
		),
	}
}

func (r *Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	err := os.MkdirAll(r.tmpdir, 0755)
	if err != nil {
		return err
	}

	depotPath := filepath.Join(r.tmpdir, "containers")
	overlaysPath := filepath.Join(r.tmpdir, "overlays")
	snapshotsPath := filepath.Join(r.tmpdir, "snapshots")
	graphPath := filepath.Join(r.tmpdir, "graph")

	if err := os.MkdirAll(depotPath, 0755); err != nil {
		return err
	}

	if err := os.MkdirAll(snapshotsPath, 0755); err != nil {
		return err
	}

	wardenArgs := append(
		r.argv,
		"--listenNetwork", "tcp",
		"--listenAddr", r.addr,
		"--bin", r.binPath,
		"--rootfs", r.rootFSPath,
		"--depot", depotPath,
		"--overlays", overlaysPath,
		"--snapshots", snapshotsPath,
		"--graph", graphPath,
		"--debug",
		"--disableQuotas",
		"--networkPool", fmt.Sprintf("10.250.%d.0/24", ginkgo.GinkgoParallelNode()),
		"--portPoolStart", strconv.Itoa(51000+(1000*ginkgo.GinkgoParallelNode())),
		"--portPoolSize", "1000",
		"--uidPoolStart", strconv.Itoa(10000*ginkgo.GinkgoParallelNode()),
		"--tag", strconv.Itoa(ginkgo.GinkgoParallelNode()),
	)

	session, err := gexec.Start(
		exec.Command(r.bin, wardenArgs...),
		gexec.NewPrefixedWriter("\x1b[32m[o]\x1b[31m[warden-linux]\x1b[0m ", ginkgo.GinkgoWriter),
		gexec.NewPrefixedWriter("\x1b[91m[e]\x1b[31m[warden-linux]\x1b[0m ", ginkgo.GinkgoWriter),
	)
	if err != nil {
		return err
	}

	var dialErr error
	for i := 0; i < 10; i++ {
		dialErr = r.TryDial()
		if dialErr == nil {
			break
		}

		time.Sleep(time.Second)
	}

	if dialErr != nil {
		return err
	}

	close(ready)

	var signal os.Signal

dance:
	for {
		select {
		case signal = <-signals:
			if signal == syscall.SIGKILL {
				if err := r.destroyContainers(); err != nil {
					return err
				}
			}

			session.Signal(syscall.SIGTERM)
		case <-session.Exited:
			break dance
		}
	}

	if signal == syscall.SIGKILL {
		if err := os.RemoveAll(r.tmpdir); err != nil {
			return err
		}
	}

	if session.ExitCode() == 0 {
		return nil
	}

	return fmt.Errorf("exit status %d", session.ExitCode())
}

func (r *Runner) TryDial() error {
	conn, dialErr := net.Dial("tcp", r.addr)

	if dialErr == nil {
		conn.Close()
		return nil
	}

	return dialErr
}

func (r *Runner) NewClient() warden.Client {
	return client.New(connection.New("tcp", r.addr))
}

func (r *Runner) destroyContainers() error {
	client := r.NewClient()

	containers, err := client.Containers(nil)<commit_msg>Add logging to test runner<commit_after>package runner

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"syscall"
	"time"

	"github.com/cloudfoundry-incubator/garden/client"
	"github.com/cloudfoundry-incubator/garden/client/connection"
	"github.com/cloudfoundry-incubator/garden/warden"
	"github.com/onsi/ginkgo"
	"github.com/onsi/gomega/gexec"
	"github.com/pivotal-golang/lager"
)

type Runner struct {
	addr string

	bin  string
	argv []string

	binPath    string
	rootFSPath string

	tmpdir string
}

func New(addr string, bin, binPath, rootFSPath string, argv ...string) *Runner {
	return &Runner{
		addr: addr,

		bin:  bin,
		argv: argv,

		binPath:    binPath,
		rootFSPath: rootFSPath,

		tmpdir: filepath.Join(
			os.TempDir(),
			fmt.Sprintf("test-warden-%d", ginkgo.GinkgoParallelNode()),
		),
	}
}

func (r *Runner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := lager.NewLogger("warden-runner")
	logger.RegisterSink(lager.NewWriterSink(ginkgo.GinkgoWriter, lager.DEBUG))

	err := os.MkdirAll(r.tmpdir, 0755)
	if err != nil {
		return err
	}

	depotPath := filepath.Join(r.tmpdir, "containers")
	overlaysPath := filepath.Join(r.tmpdir, "overlays")
	snapshotsPath := filepath.Join(r.tmpdir, "snapshots")
	graphPath := filepath.Join(r.tmpdir, "graph")

	if err := os.MkdirAll(depotPath, 0755); err != nil {
		return err
	}

	if err := os.MkdirAll(snapshotsPath, 0755); err != nil {
		return err
	}

	wardenArgs := append(
		r.argv,
		"--listenNetwork", "tcp",
		"--listenAddr", r.addr,
		"--bin", r.binPath,
		"--rootfs", r.rootFSPath,
		"--depot", depotPath,
		"--overlays", overlaysPath,
		"--snapshots", snapshotsPath,
		"--graph", graphPath,
		"--debug",
		"--disableQuotas",
		"--networkPool", fmt.Sprintf("10.250.%d.0/24", ginkgo.GinkgoParallelNode()),
		"--portPoolStart", strconv.Itoa(51000+(1000*ginkgo.GinkgoParallelNode())),
		"--portPoolSize", "1000",
		"--uidPoolStart", strconv.Itoa(10000*ginkgo.GinkgoParallelNode()),
		"--tag", strconv.Itoa(ginkgo.GinkgoParallelNode()),
	)

	session, err := gexec.Start(
		exec.Command(r.bin, wardenArgs...),
		gexec.NewPrefixedWriter("\x1b[32m[o]\x1b[31m[warden-linux]\x1b[0m ", ginkgo.GinkgoWriter),
		gexec.NewPrefixedWriter("\x1b[91m[e]\x1b[31m[warden-linux]\x1b[0m ", ginkgo.GinkgoWriter),
	)
	if err != nil {
		return err
	}

	var dialErr error
	for i := 0; i < 10; i++ {
		dialErr = r.TryDial()
		if dialErr == nil {
			break
		}

		time.Sleep(time.Second)
	}

	if dialErr != nil {
		return err
	}

	close(ready)

	var signal os.Signal

dance:
	for {
		select {
		case signal = <-signals:
			if signal == syscall.SIGKILL {
				logger.Info("received-sigkill")
				if err := r.destroyContainers(); err != nil {
					logger.Error("destroy-containers-failed", err)
					return err
				}
				logger.Info("destroyed-containers")
			}

			session.Signal(syscall.SIGTERM)
		case <-session.Exited:
			break dance
		}
	}

	logger.Info("process-exited")

	if signal == syscall.SIGKILL {
		if err := os.RemoveAll(r.tmpdir); err != nil {
			logger.Error("cleanup-tempdirs-failed", err, lager.Data{"tmpdir": r.tmpdir})
			return err
		}
	}

	if session.ExitCode() == 0 {
		logger.Info("runner-exited-success")
		return nil
	}

	err = fmt.Errorf("exit status %d", session.ExitCode())
	logger.Error("runner-exited-failure", err, lager.Data{"exit_code": session.ExitCode()})
	return err
}

func (r *Runner) TryDial() error {
	conn, dialErr := net.Dial("tcp", r.addr)

	if dialErr == nil {
		conn.Close()
		return nil
	}

	return dialErr
}

func (r *Runner) NewClient() warden.Client {
	return client.New(connection.New("tcp", r.addr))
}

func (r *Runner) destroyContainers() error {
	client := r.NewClient()

	containers, err := client.Containers(nil)
{'fraction_non_alphanumeric': 0.1680103656780881, 'fraction_numerical': 0.016700259141952202, 'mean_word_length': 3.7258503401360543, 'pattern_counts': {'":': 2, '<': 13, '<?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': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3281525', 'n_tokens_mistral': 3044, 'n_tokens_neox': 2728, 'n_words': 526}