<commit_before>package define

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"github.com/containers/image/v5/manifest"
	"github.com/containers/storage/pkg/archive"
	"github.com/containers/storage/pkg/chrootarchive"
	"github.com/containers/storage/pkg/ioutils"
	v1 "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	// Package is the name of this package, used in help output and to
	// identify working containers.
	Package = "buildah"
	// Version for the Package.  Bump version in contrib/rpm/buildah.spec
	// too.
	Version = "1.21.1-dev"

	// DefaultRuntime if containers.conf fails.
	DefaultRuntime = "runc"

	DefaultCNIPluginPath = "/usr/libexec/cni:/opt/cni/bin"
	// DefaultCNIConfigDir is the default location of CNI configuration files.
	DefaultCNIConfigDir = "/etc/cni/net.d"

	// OCIv1ImageManifest is the MIME type of an OCIv1 image manifest,
	// suitable for specifying as a value of the PreferredManifestType
	// member of a CommitOptions structure.  It is also the default.
	OCIv1ImageManifest = v1.MediaTypeImageManifest
	// Dockerv2ImageManifest is the MIME type of a Docker v2s2 image
	// manifest, suitable for specifying as a value of the
	// PreferredManifestType member of a CommitOptions structure.
	Dockerv2ImageManifest = manifest.DockerV2Schema2MediaType

	// OCI used to define the "oci" image format
	OCI = "oci"
	// DOCKER used to define the "docker" image format
	DOCKER = "docker"
)

var (
	// DefaultCapabilities is the list of capabilities which we grant by
	// default to containers which are running under UID 0.
	DefaultCapabilities = []string{
		"CAP_AUDIT_WRITE",
		"CAP_CHOWN",
		"CAP_DAC_OVERRIDE",
		"CAP_FOWNER",
		"CAP_FSETID",
		"CAP_KILL",
		"CAP_MKNOD",
		"CAP_NET_BIND_SERVICE",
		"CAP_SETFCAP",
		"CAP_SETGID",
		"CAP_SETPCAP",
		"CAP_SETUID",
		"CAP_SYS_CHROOT",
	}
	// DefaultNetworkSysctl is the list of Kernel parameters which we
	// grant by default to containers which are running under UID 0.
	DefaultNetworkSysctl = map[string]string{
		"net.ipv4.ping_group_range": "0 0",
	}

	Gzip         = archive.Gzip
	Bzip2        = archive.Bzip2
	Xz           = archive.Xz
	Zstd         = archive.Zstd
	Uncompressed = archive.Uncompressed
)

// IDMappingOptions controls how we set up UID/GID mapping when we set up a
// user namespace.
type IDMappingOptions struct {
	HostUIDMapping bool
	HostGIDMapping bool
	UIDMap         []specs.LinuxIDMapping
	GIDMap         []specs.LinuxIDMapping
}

// TempDirForURL checks if the passed-in string looks like a URL or -.  If it is,
// TempDirForURL creates a temporary directory, arranges for its contents to be
// the contents of that URL, and returns the temporary directory's path, along
// with the name of a subdirectory which should be used as the build context
// (which may be empty or ".").  Removal of the temporary directory is the
// responsibility of the caller.  If the string doesn't look like a URL,
// TempDirForURL returns empty strings and a nil error code.
func TempDirForURL(dir, prefix, url string) (name string, subdir string, err error) {
	if !strings.HasPrefix(url, "http://") &&
		!strings.HasPrefix(url, "https://") &&
		!strings.HasPrefix(url, "git://") &&
		!strings.HasPrefix(url, "github.com/") &&
		url != "-" {
		return "", "", nil
	}
	name, err = ioutil.TempDir(dir, prefix)
	if err != nil {
		return "", "", errors.Wrapf(err, "error creating temporary directory for %q", url)
	}
	if strings.HasPrefix(url, "git://") || strings.HasSuffix(url, ".git") {
		err = cloneToDirectory(url, name)
		if err != nil {
			if err2 := os.RemoveAll(name); err2 != nil {
				logrus.Debugf("error removing temporary directory %q: %v", name, err2)
			}
			return "", "", err
		}
		return name, "", nil
	}
	if strings.HasPrefix(url, "github.com/") {
		ghurl := url
		url = fmt.Sprintf("https://%s/archive/master.tar.gz", ghurl)
		logrus.Debugf("resolving url %q to %q", ghurl, url)
		subdir = path.Base(ghurl) + "-master"
	}
	if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
		err = downloadToDirectory(url, name)
		if err != nil {
			if err2 := os.RemoveAll(name); err2 != nil {
				logrus.Debugf("error removing temporary directory %q: %v", name, err2)
			}
			return "", subdir, err
		}
		return name, subdir, nil
	}
	if url == "-" {
		err = stdinToDirectory(name)
		if err != nil {
			if err2 := os.RemoveAll(name); err2 != nil {
				logrus.Debugf("error removing temporary directory %q: %v", name, err2)
			}
			return "", subdir, err
		}
		logrus.Debugf("Build context is at %q", name)
		return name, subdir, nil
	}
	logrus.Debugf("don't know how to retrieve %q", url)
	if err2 := os.Remove(name); err2 != nil {
		logrus.Debugf("error removing temporary directory %q: %v", name, err2)
	}
	return "", "", errors.Errorf("unreachable code reached")
}

func cloneToDirectory(url, dir string) error {
	if !strings.HasPrefix(url, "git://") && !strings.HasSuffix(url, ".git") {
		url = "git://" + url
	}
	gitBranch := strings.Split(url, "#")
	var cmd *exec.Cmd
	if len(gitBranch) < 2 {
		logrus.Debugf("cloning %q to %q", url, dir)
		cmd = exec.Command("git", "clone", url, dir)
	} else {
		logrus.Debugf("cloning repo %q and branch %q to %q", gitBranch[0], gitBranch[1], dir)
		cmd = exec.Command("git", "clone", "--recurse-submodules", "-b", gitBranch[1], gitBranch[0], dir)
	}
	return cmd.Run()
}

func downloadToDirectory(url, dir string) error {
	logrus.Debugf("extracting %q to %q", url, dir)
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.ContentLength == 0 {
		return errors.Errorf("no contents in %q", url)
	}
	if err := chrootarchive.Untar(resp.Body, dir, nil); err != nil {
		resp1, err := http.Get(url)
		if err != nil {
			return err
		}
		defer resp1.Body.Close()
		body, err := ioutil.ReadAll(resp1.Body)
		if err != nil {
			return err
		}
		dockerfile := filepath.Join(dir, "Dockerfile")
		// Assume this is a Dockerfile
		if err := ioutils.AtomicWriteFile(dockerfile, body, 0600); err != nil {
			return errors.Wrapf(err, "Failed to write %q to %q", url, dockerfile)
		}
	}
	return nil
}

func stdinToDirectory(dir string) error {
	logrus.Debugf("extracting stdin to %q", dir)
	r := bufio.NewReader(os.Stdin)
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return errors.Wrapf(err, "Failed to read from stdin")
	}
	reader := bytes.NewReader(b)
	if err := chrootarchive.Untar(reader, dir, nil); err != nil {
		dockerfile := filepath.Join(dir, "Dockerfile")
		// Assume this is a Dockerfile
		if err := ioutils.AtomicWriteFile(dockerfile, b, 0600); err != nil {
			return errors.Wrapf(err, "Failed to write bytes to %q", dockerfile)
		}
	}
	return nil
}
<commit_msg>Move to v1.22.0-dev<commit_after>package define

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"

	"github.com/containers/image/v5/manifest"
	"github.com/containers/storage/pkg/archive"
	"github.com/containers/storage/pkg/chrootarchive"
	"github.com/containers/storage/pkg/ioutils"
	v1 "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	// Package is the name of this package, used in help output and to
	// identify working containers.
	Package = "buildah"
	// Version for the Package.  Bump version in contrib/rpm/buildah.spec
	// too.
	Version = "1.22.0-dev"

	// DefaultRuntime if containers.conf fails.
	DefaultRuntime = "runc"

	DefaultCNIPluginPath = "/usr/libexec/cni:/opt/cni/bin"
	// DefaultCNIConfigDir is the default location of CNI configuration files.
	DefaultCNIConfigDir = "/etc/cni/net.d"

	// OCIv1ImageManifest is the MIME type of an OCIv1 image manifest,
	// suitable for specifying as a value of the PreferredManifestType
	// member of a CommitOptions structure.  It is also the default.
	OCIv1ImageManifest = v1.MediaTypeImageManifest
	// Dockerv2ImageManifest is the MIME type of a Docker v2s2 image
	// manifest, suitable for specifying as a value of the
	// PreferredManifestType member of a CommitOptions structure.
	Dockerv2ImageManifest = manifest.DockerV2Schema2MediaType

	// OCI used to define the "oci" image format
	OCI = "oci"
	// DOCKER used to define the "docker" image format
	DOCKER = "docker"
)

var (
	// DefaultCapabilities is the list of capabilities which we grant by
	// default to containers which are running under UID 0.
	DefaultCapabilities = []string{
		"CAP_AUDIT_WRITE",
		"CAP_CHOWN",
		"CAP_DAC_OVERRIDE",
		"CAP_FOWNER",
		"CAP_FSETID",
		"CAP_KILL",
		"CAP_MKNOD",
		"CAP_NET_BIND_SERVICE",
		"CAP_SETFCAP",
		"CAP_SETGID",
		"CAP_SETPCAP",
		"CAP_SETUID",
		"CAP_SYS_CHROOT",
	}
	// DefaultNetworkSysctl is the list of Kernel parameters which we
	// grant by default to containers which are running under UID 0.
	DefaultNetworkSysctl = map[string]string{
		"net.ipv4.ping_group_range": "0 0",
	}

	Gzip         = archive.Gzip
	Bzip2        = archive.Bzip2
	Xz           = archive.Xz
	Zstd         = archive.Zstd
	Uncompressed = archive.Uncompressed
)

// IDMappingOptions controls how we set up UID/GID mapping when we set up a
// user namespace.
type IDMappingOptions struct {
	HostUIDMapping bool
	HostGIDMapping bool
	UIDMap         []specs.LinuxIDMapping
	GIDMap         []specs.LinuxIDMapping
}

// TempDirForURL checks if the passed-in string looks like a URL or -.  If it is,
// TempDirForURL creates a temporary directory, arranges for its contents to be
// the contents of that URL, and returns the temporary directory's path, along
// with the name of a subdirectory which should be used as the build context
// (which may be empty or ".").  Removal of the temporary directory is the
// responsibility of the caller.  If the string doesn't look like a URL,
// TempDirForURL returns empty strings and a nil error code.
func TempDirForURL(dir, prefix, url string) (name string, subdir string, err error) {
	if !strings.HasPrefix(url, "http://") &&
		!strings.HasPrefix(url, "https://") &&
		!strings.HasPrefix(url, "git://") &&
		!strings.HasPrefix(url, "github.com/") &&
		url != "-" {
		return "", "", nil
	}
	name, err = ioutil.TempDir(dir, prefix)
	if err != nil {
		return "", "", errors.Wrapf(err, "error creating temporary directory for %q", url)
	}
	if strings.HasPrefix(url, "git://") || strings.HasSuffix(url, ".git") {
		err = cloneToDirectory(url, name)
		if err != nil {
			if err2 := os.RemoveAll(name); err2 != nil {
				logrus.Debugf("error removing temporary directory %q: %v", name, err2)
			}
			return "", "", err
		}
		return name, "", nil
	}
	if strings.HasPrefix(url, "github.com/") {
		ghurl := url
		url = fmt.Sprintf("https://%s/archive/master.tar.gz", ghurl)
		logrus.Debugf("resolving url %q to %q", ghurl, url)
		subdir = path.Base(ghurl) + "-master"
	}
	if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
		err = downloadToDirectory(url, name)
		if err != nil {
			if err2 := os.RemoveAll(name); err2 != nil {
				logrus.Debugf("error removing temporary directory %q: %v", name, err2)
			}
			return "", subdir, err
		}
		return name, subdir, nil
	}
	if url == "-" {
		err = stdinToDirectory(name)
		if err != nil {
			if err2 := os.RemoveAll(name); err2 != nil {
				logrus.Debugf("error removing temporary directory %q: %v", name, err2)
			}
			return "", subdir, err
		}
		logrus.Debugf("Build context is at %q", name)
		return name, subdir, nil
	}
	logrus.Debugf("don't know how to retrieve %q", url)
	if err2 := os.Remove(name); err2 != nil {
		logrus.Debugf("error removing temporary directory %q: %v", name, err2)
	}
	return "", "", errors.Errorf("unreachable code reached")
}

func cloneToDirectory(url, dir string) error {
	if !strings.HasPrefix(url, "git://") && !strings.HasSuffix(url, ".git") {
		url = "git://" + url
	}
	gitBranch := strings.Split(url, "#")
	var cmd *exec.Cmd
	if len(gitBranch) < 2 {
		logrus.Debugf("cloning %q to %q", url, dir)
		cmd = exec.Command("git", "clone", url, dir)
	} else {
		logrus.Debugf("cloning repo %q and branch %q to %q", gitBranch[0], gitBranch[1], dir)
		cmd = exec.Command("git", "clone", "--recurse-submodules", "-b", gitBranch[1], gitBranch[0], dir)
	}
	return cmd.Run()
}

func downloadToDirectory(url, dir string) error {
	logrus.Debugf("extracting %q to %q", url, dir)
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.ContentLength == 0 {
		return errors.Errorf("no contents in %q", url)
	}
	if err := chrootarchive.Untar(resp.Body, dir, nil); err != nil {
		resp1, err := http.Get(url)
		if err != nil {
			return err
		}
		defer resp1.Body.Close()
		body, err := ioutil.ReadAll(resp1.Body)
		if err != nil {
			return err
		}
		dockerfile := filepath.Join(dir, "Dockerfile")
		// Assume this is a Dockerfile
		if err := ioutils.AtomicWriteFile(dockerfile, body, 0600); err != nil {
			return errors.Wrapf(err, "Failed to write %q to %q", url, dockerfile)
		}
	}
	return nil
}

func stdinToDirectory(dir string) error {
	logrus.Debugf("extracting stdin to %q", dir)
	r := bufio.NewReader(os.Stdin)
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return errors.Wrapf(err, "Failed to read from stdin")
	}
	reader := bytes.NewReader(b)
	if err := chrootarchive.Untar(reader, dir, nil); err != nil {
		dockerfile := filepath.Join(dir, "Dockerfile")
		// Assume this is a Dockerfile
		if err := ioutils.AtomicWriteFile(dockerfile, b, 0600); err != nil {
			return errors.Wrapf(err, "Failed to write bytes to %q", dockerfile)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package workflow

import (
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/pkg/errors"
)

// taskCmdRunner defines all the info of a runner responsible for executing as
// sequence of taskCmd, handling failure, cancellation, timeouts and for generating
// and/or collecting all the workflow artifacts (junit_runner.xml, task logs, etc)
type taskCmdRunner struct {
	start    time.Time
	suite    junitTestSuite
	failed   bool
	canceled bool
	timedOut bool
}

// junitTestSuite implements junit TestSuite standard object
type junitTestSuite struct {
	XMLName  xml.Name `xml:"testsuite"`
	Failures int      `xml:"failures,attr"`
	Tests    int      `xml:"tests,attr"`
	Time     float64  `xml:"time,attr"`
	Cases    []junitTestCase
}

// junitTestCase implements junit TestCase standard object
type junitTestCase struct {
	XMLName   xml.Name `xml:"testcase"`
	ClassName string   `xml:"classname,attr"`
	Name      string   `xml:"name,attr"`
	Time      float64  `xml:"time,attr"`
	Failure   string   `xml:"failure,omitempty"`
	Skipped   string   `xml:"skipped,omitempty"`
}

// newTaskCmdRunner returns a new taskCmdRunner
func newTaskCmdRunner() *taskCmdRunner {
	return &taskCmdRunner{
		start: time.Now(),
		suite: junitTestSuite{},
	}
}

// Run a taskCmd
func (c *taskCmdRunner) Run(t *taskCmd, artifacts string, verbose bool) error {
	start := time.Now()

	// unless the cmd execution is forced, check if the taskCmd should be skipped because one of
	// the previous taskCmd failed, timedOut or was canceled.
	// if this is the case record test case as skipped and exits with error
	if !t.Force {
		if c.failed {
			return c.registerTestCase(t.Name, withSkipped("skipping because a predecessor task failed"))
		}
		if c.timedOut {
			return c.registerTestCase(t.Name, withSkipped("skipping because a predecessor task timed-out"))
		}
		if c.canceled {
			return c.registerTestCase(t.Name, withSkipped("skipping because task workflow was canceled by the user"))
		}
	}

	// creates a channel for handling command cancellation
	cancel := make(chan os.Signal, 1)
	signal.Notify(cancel, syscall.SIGINT, syscall.SIGTERM)

	// sets Stdout and Stderr for the command.
	// please note that the command output will go on files by default,
	// and it will be echoed on video only if specifically requested
	taskLog := filepath.Join(artifacts, fmt.Sprintf("%s-log.txt", t.Name))
	writer, err := os.Create(taskLog)
	if err != nil {
		return errors.Wrapf(err, "error creating %q log file", taskLog)
	}

	t.Cmd.Stdout = writer
	t.Cmd.Stderr = writer

	if verbose {
		t.Cmd.Stdout = io.MultiWriter(writer, os.Stdout)
		t.Cmd.Stderr = io.MultiWriter(writer, os.Stderr)
	}

	// outputs a command overview before executing it
	writer.WriteString(fmt.Sprintf("%s\n", strings.Repeat("-", 80)))
	writer.WriteString(fmt.Sprintf("%s\n", t.Name))
	if t.Description != "" {
		writer.WriteString(fmt.Sprintf("%s\n", t.Description))
	}
	writer.WriteString(fmt.Sprintf("command : %s\n", t.CmdText))
	writer.WriteString(fmt.Sprintf("timeout : %s\n", t.Timeout.Duration))
	writer.WriteString(fmt.Sprintf("force   : %v\n", t.Force))
	writer.WriteString(fmt.Sprintf("%s\n\n", strings.Repeat("-", 80)))

	// starts the command
	if err := t.Cmd.Start(); err != nil {
		// keeps track of this failure type to block execution of following TestCmd
		c.failed = true

		// record test case timeout and exits with error
		return c.registerTestCase(t.Name, withFailure(err.Error()), withDuration(time.Since(start)))
	}

	// starts a go ruting responsible for waiting the command completes
	result := make(chan error, 1)
	go func() {
		result <- t.Cmd.Wait()
	}()

	// Wait for one of:
	// - the command completes
	// - the command is canceled
	// - the timeout is reached
	select {
	case err := <-result:
		// if the command completed without an error or if we are ignoring errors, record the test case success and exit
		if err == nil || t.IgnoreError {
			// record test case timeout as success
			return c.registerTestCase(t.Name,
				withDuration(time.Since(start)),
			)
		}
		// keeps track of this failure type to block execution of following TestCmd
		c.failed = true

		// cleanup command process and its child, if any
		cleanup(t.Cmd)

		// otherwise record test case failure and exits with error
		return c.registerTestCase(t.Name,
			withFailure(err.Error()),
			withDuration(time.Since(start)),
		)

	case <-cancel:
		// keeps track of this failure type to block execution of following TestCmd
		c.canceled = true

		// cleanup command process and its child, if any
		cleanup(t.Cmd)

		// record test case cancellation and exits with error
		return c.registerTestCase(t.Name,
			withFailure("task was canceled by the user"),
			withDuration(time.Since(start)),
		)

	case <-time.After(t.Timeout.Duration):
		// keeps track of this failure type to block execution of following TestCmd
		c.timedOut = true

		// cleanup command process and its child, if any
		cleanup(t.Cmd)

		// record test case timeout and exits with error
		return c.registerTestCase(t.Name,
			withFailure(fmt.Sprintf("timeout. task did not completed in less than %s as expected", t.Timeout.Duration)),
			withDuration(time.Since(start)),
		)
	}
}

// ReportSummary prints a summary of executed task
func (c *taskCmdRunner) ReportSummary() {
	total := c.suite.Tests
	skipped := 0
	for _, t := range c.suite.Cases {
		if t.Skipped != "" {
			skipped++
		}
	}
	run := total - skipped
	failures := c.suite.Failures
	passed := run - failures

	fmt.Printf("Ran %d of %d tasks in %.3f seconds\n", run, total, c.suite.Time)
	if failures > 0 {
		fmt.Printf("FAIL! -- %d tasks Passed | %d Failed | %d Skipped\n\n", passed, failures, skipped)
		return
	}
	fmt.Printf("SUCCESS! -- %d tasks Passed | %d Failed | %d Skipped\n\n", passed, failures, skipped)
}

// DumpJUnitRunner writes a report of executed tasks as a junit file
func (c *taskCmdRunner) DumpJUnitRunner(artifacts string) error {
	// sets test suite duration
	c.suite.Time = time.Since(c.start).Seconds()

	// marshal test suite into the junit_runner.xml file
	out, err := xml.MarshalIndent(&c.suite, "", "    ")
	if err != nil {
		return errors.Wrapf(err, "error marshaling test suite results")
	}
	file := filepath.Join(artifacts, "junit_runner.xml")
	f, err := os.Create(file)
	if err != nil {
		return errors.Wrapf(err, "error creating %s", file)
	}
	defer f.Close()
	if _, err := f.WriteString(xml.Header); err != nil {
		return errors.Wrapf(err, "error writing XML header to %s", file)
	}
	if _, err := f.Write(out); err != nil {
		return errors.Wrapf(err, "error writing XML data to %s", file)
	}

	return nil
}

type testCaseOption func(*junitTestCase)

func withDuration(duration time.Duration) testCaseOption {
	return func(t *junitTestCase) {
		t.Time = duration.Seconds()
	}
}
func withFailure(message string) testCaseOption {
	return func(t *junitTestCase) {
		t.Failure = message
	}
}

func withSkipped(message string) testCaseOption {
	return func(t *junitTestCase) {
		t.Skipped = message
	}
}

// registerTestCase register task output as a test case result
func (c *taskCmdRunner) registerTestCase(name string, options ...testCaseOption) error {
	tc := &junitTestCase{
		ClassName: "kinder.test.workflow",
		Name:      name,
	}

	for _, option := range options {
		option(tc)
	}

	c.suite.Cases = append(c.suite.Cases, *tc)
	c.suite.Tests++
	if tc.Failure != "" {
		c.suite.Failures++
		return errors.New(tc.Failure)
	}

	if tc.Skipped != "" {
		return errors.New(tc.Skipped)
	}

	return nil
}

// cleanup tries to ensure a cmdtask is properly closed
func cleanup(cmd *exec.Cmd) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered in f", r)
		}
	}()

	/* temporary disabled to better investigate test-grid failures
	pgid, err := syscall.Getpgid(cmd.Process.Pid)
	if err != nil {
		cmd.Process.Kill()
	}

	if err := syscall.Kill(-pgid, syscall.SIGABRT); err == nil {
		return
	}

	syscall.Kill(-pgid, syscall.SIGTERM)
	*/

	cmd.Process.Kill()
}
<commit_msg>kinder: fix typo in timeouts<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package workflow

import (
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/pkg/errors"
)

// taskCmdRunner defines all the info of a runner responsible for executing as
// sequence of taskCmd, handling failure, cancellation, timeouts and for generating
// and/or collecting all the workflow artifacts (junit_runner.xml, task logs, etc)
type taskCmdRunner struct {
	start    time.Time
	suite    junitTestSuite
	failed   bool
	canceled bool
	timedOut bool
}

// junitTestSuite implements junit TestSuite standard object
type junitTestSuite struct {
	XMLName  xml.Name `xml:"testsuite"`
	Failures int      `xml:"failures,attr"`
	Tests    int      `xml:"tests,attr"`
	Time     float64  `xml:"time,attr"`
	Cases    []junitTestCase
}

// junitTestCase implements junit TestCase standard object
type junitTestCase struct {
	XMLName   xml.Name `xml:"testcase"`
	ClassName string   `xml:"classname,attr"`
	Name      string   `xml:"name,attr"`
	Time      float64  `xml:"time,attr"`
	Failure   string   `xml:"failure,omitempty"`
	Skipped   string   `xml:"skipped,omitempty"`
}

// newTaskCmdRunner returns a new taskCmdRunner
func newTaskCmdRunner() *taskCmdRunner {
	return &taskCmdRunner{
		start: time.Now(),
		suite: junitTestSuite{},
	}
}

// Run a taskCmd
func (c *taskCmdRunner) Run(t *taskCmd, artifacts string, verbose bool) error {
	start := time.Now()

	// unless the cmd execution is forced, check if the taskCmd should be skipped because one of
	// the previous taskCmd failed, timedOut or was canceled.
	// if this is the case record test case as skipped and exits with error
	if !t.Force {
		if c.failed {
			return c.registerTestCase(t.Name, withSkipped("skipping because a predecessor task failed"))
		}
		if c.timedOut {
			return c.registerTestCase(t.Name, withSkipped("skipping because a predecessor task timed-out"))
		}
		if c.canceled {
			return c.registerTestCase(t.Name, withSkipped("skipping because task workflow was canceled by the user"))
		}
	}

	// creates a channel for handling command cancellation
	cancel := make(chan os.Signal, 1)
	signal.Notify(cancel, syscall.SIGINT, syscall.SIGTERM)

	// sets Stdout and Stderr for the command.
	// please note that the command output will go on files by default,
	// and it will be echoed on video only if specifically requested
	taskLog := filepath.Join(artifacts, fmt.Sprintf("%s-log.txt", t.Name))
	writer, err := os.Create(taskLog)
	if err != nil {
		return errors.Wrapf(err, "error creating %q log file", taskLog)
	}

	t.Cmd.Stdout = writer
	t.Cmd.Stderr = writer

	if verbose {
		t.Cmd.Stdout = io.MultiWriter(writer, os.Stdout)
		t.Cmd.Stderr = io.MultiWriter(writer, os.Stderr)
	}

	// outputs a command overview before executing it
	writer.WriteString(fmt.Sprintf("%s\n", strings.Repeat("-", 80)))
	writer.WriteString(fmt.Sprintf("%s\n", t.Name))
	if t.Description != "" {
		writer.WriteString(fmt.Sprintf("%s\n", t.Description))
	}
	writer.WriteString(fmt.Sprintf("command : %s\n", t.CmdText))
	writer.WriteString(fmt.Sprintf("timeout : %s\n", t.Timeout.Duration))
	writer.WriteString(fmt.Sprintf("force   : %v\n", t.Force))
	writer.WriteString(fmt.Sprintf("%s\n\n", strings.Repeat("-", 80)))

	// starts the command
	if err := t.Cmd.Start(); err != nil {
		// keeps track of this failure type to block execution of following TestCmd
		c.failed = true

		// record test case timeout and exits with error
		return c.registerTestCase(t.Name, withFailure(err.Error()), withDuration(time.Since(start)))
	}

	// starts a go ruting responsible for waiting the command completes
	result := make(chan error, 1)
	go func() {
		result <- t.Cmd.Wait()
	}()

	// Wait for one of:
	// - the command completes
	// - the command is canceled
	// - the timeout is reached
	select {
	case err := <-result:
		// if the command completed without an error or if we are ignoring errors, record the test case success and exit
		if err == nil || t.IgnoreError {
			// record test case timeout as success
			return c.registerTestCase(t.Name,
				withDuration(time.Since(start)),
			)
		}
		// keeps track of this failure type to block execution of following TestCmd
		c.failed = true

		// cleanup command process and its child, if any
		cleanup(t.Cmd)

		// otherwise record test case failure and exits with error
		return c.registerTestCase(t.Name,
			withFailure(err.Error()),
			withDuration(time.Since(start)),
		)

	case <-cancel:
		// keeps track of this failure type to block execution of following TestCmd
		c.canceled = true

		// cleanup command process and its child, if any
		cleanup(t.Cmd)

		// record test case cancellation and exits with error
		return c.registerTestCase(t.Name,
			withFailure("task was canceled by the user"),
			withDuration(time.Since(start)),
		)

	case <-time.After(t.Timeout.Duration):
		// keeps track of this failure type to block execution of following TestCmd
		c.timedOut = true

		// cleanup command process and its child, if any
		cleanup(t.Cmd)

		// record test case timeout and exits with error
		return c.registerTestCase(t.Name,
			withFailure(fmt.Sprintf("timeout. The task did not complete in less than %s as expected", t.Timeout.Duration)),
			withDuration(time.Since(start)),
		)
	}
}

// ReportSummary prints a summary of executed task
func (c *taskCmdRunner) ReportSummary() {
	total := c.suite.Tests
	skipped := 0
	for _, t := range c.suite.Cases {
		if t.Skipped != "" {
			skipped++
		}
	}
	run := total - skipped
	failures := c.suite.Failures
	passed := run - failures

	fmt.Printf("Ran %d of %d tasks in %.3f seconds\n", run, total, c.suite.Time)
	if failures > 0 {
		fmt.Printf("FAIL! -- %d tasks Passed | %d Failed | %d Skipped\n\n", passed, failures, skipped)
		return
	}
	fmt.Printf("SUCCESS! -- %d tasks Passed | %d Failed | %d Skipped\n\n", passed, failures, skipped)
}

// DumpJUnitRunner writes a report of executed tasks as a junit file
func (c *taskCmdRunner) DumpJUnitRunner(artifacts string) error {
	// sets test suite duration
	c.suite.Time = time.Since(c.start).Seconds()

	// marshal test suite into the junit_runner.xml file
	out, err := xml.MarshalIndent(&c.suite, "", "    ")
	if err != nil {
		return errors.Wrapf(err, "error marshaling test suite results")
	}
	file := filepath.Join(artifacts, "junit_runner.xml")
	f, err := os.Create(file)
	if err != nil {
		return errors.Wrapf(err, "error creating %s", file)
	}
	defer f.Close()
	if _, err := f.WriteString(xml.Header); err != nil {
		return errors.Wrapf(err, "error writing XML header to %s", file)
	}
	if _, err := f.Write(out); err != nil {
		return errors.Wrapf(err, "error writing XML data to %s", file)
	}

	return nil
}

type testCaseOption func(*junitTestCase)

func withDuration(duration time.Duration) testCaseOption {
	return func(t *junitTestCase) {
		t.Time = duration.Seconds()
	}
}
func withFailure(message string) testCaseOption {
	return func(t *junitTestCase) {
		t.Failure = message
	}
}

func withSkipped(message string) testCaseOption {
	return func(t *junitTestCase) {
		t.Skipped = message
	}
}

// registerTestCase register task output as a test case result
func (c *taskCmdRunner) registerTestCase(name string, options ...testCaseOption) error {
	tc := &junitTestCase{
		ClassName: "kinder.test.workflow",
		Name:      name,
	}

	for _, option := range options {
		option(tc)
	}

	c.suite.Cases = append(c.suite.Cases, *tc)
	c.suite.Tests++
	if tc.Failure != "" {
		c.suite.Failures++
		return errors.New(tc.Failure)
	}

	if tc.Skipped != "" {
		return errors.New(tc.Skipped)
	}

	return nil
}

// cleanup tries to ensure a cmdtask is properly closed
func cleanup(cmd *exec.Cmd) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered in f", r)
		}
	}()

	/* temporary disabled to better investigate test-grid failures
	pgid, err := syscall.Getpgid(cmd.Process.Pid)
	if err != nil {
		cmd.Process.Kill()
	}

	if err := syscall.Kill(-pgid, syscall.SIGABRT); err == nil {
		return
	}

	syscall.Kill(-pgid, syscall.SIGTERM)
	*/

	cmd.Process.Kill()
}
<|endoftext|>


<commit_before>package daemon

import (
	"github.com/BluePecker/JwtAuth/dialog/server/parameter/token/request"
	coderQ "github.com/BluePecker/JwtAuth/dialog/server/parameter/coder/request"
	"github.com/BluePecker/JwtAuth/dialog/server/parameter/token/response"
	"github.com/BluePecker/JwtAuth/daemon/coder"
	"github.com/Sirupsen/logrus"
)

func (d *Daemon) List(req request.List) ([]response.Token, error) {
	if sings, err := (*d.Cache).LRange(req.Unique, 0, coder.LoginNum); err != nil {
		logrus.Error("token error: ", err)
		return nil, err
	} else {
		ttl := (*d.Cache).TTL(req.Unique)
		tokens := []response.Token{}
		for _, singed := range sings {
			if token, err := coder.Decode(coderQ.Decode{
				JsonWebToken: singed,
			}, (*d.Options).Secret); err == nil {
				if claims, ok := token.Claims.(*coder.CustomClaim); ok {
					tokens = append(tokens, response.Token{
						Singed: singed,
						TTL:    ttl,
						Addr:   claims.Addr,
						Device: claims.Device,
					})
				}
			}
		}
		return tokens, nil
	}
}
<commit_msg>fix bug<commit_after>package daemon

import (
	"github.com/BluePecker/JwtAuth/dialog/server/parameter/token/request"
	coderQ "github.com/BluePecker/JwtAuth/dialog/server/parameter/coder/request"
	"github.com/BluePecker/JwtAuth/dialog/server/parameter/token/response"
	"github.com/BluePecker/JwtAuth/daemon/coder"
	"github.com/Sirupsen/logrus"
)

func (d *Daemon) List(req request.List) ([]response.Token, error) {
	if sings, err := (*d.Cache).LRange(req.Unique, 0, coder.LoginNum); err != nil {
		return nil, err
	} else {
		ttl := (*d.Cache).TTL(req.Unique)
		tokens := []response.Token{}
		for _, singed := range sings {
			if token, err := coder.Decode(coderQ.Decode{
				JsonWebToken: singed,
			}, (*d.Options).Secret); err == nil {
				logrus.Error("token error: ", token, err)
				if claims, ok := token.Claims.(*coder.CustomClaim); ok {
					tokens = append(tokens, response.Token{
						Singed: singed,
						TTL:    ttl,
						Addr:   claims.Addr,
						Device: claims.Device,
					})
				}
			}
		}
		return tokens, nil
	}
}
<|endoftext|>


<commit_before>package herd

import (
	"fmt"
	"github.com/Symantec/Dominator/lib/constants"
	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/hash"
	subproto "github.com/Symantec/Dominator/proto/sub"
	"net/rpc"
	"strings"
	"time"
)

func (sub *Sub) tryMakeBusy() bool {
	sub.busyMutex.Lock()
	defer sub.busyMutex.Unlock()
	if sub.busy {
		return false
	}
	sub.busy = true
	return true
}

func (sub *Sub) makeUnbusy() {
	sub.busyMutex.Lock()
	defer sub.busyMutex.Unlock()
	sub.busy = false
}

func (sub *Sub) connectAndPoll() {
	sub.status = statusConnecting
	hostname := strings.SplitN(sub.hostname, "*", 2)[0]
	var err error
	connection, err := rpc.DialHTTP("tcp",
		fmt.Sprintf("%s:%d", hostname, constants.SubPortNumber))
	if err != nil {
		sub.status = statusFailedToConnect
		return
	}
	defer connection.Close()
	sub.status = statusWaitingToPoll
	sub.herd.pollSemaphore <- true
	sub.status = statusPolling
	sub.poll(connection)
	<-sub.herd.pollSemaphore
}

func (sub *Sub) poll(connection *rpc.Client) {
	var request subproto.PollRequest
	request.HaveGeneration = sub.generationCount
	var reply subproto.PollResponse
	sub.lastPollStartTime = time.Now()
	logger := sub.herd.logger
	if err := connection.Call("Subd.Poll", request, &reply); err != nil {
		sub.status = statusFailedToPoll
		logger.Printf("Error calling %s.Poll()\t%s\n", sub.hostname, err)
		return
	}
	sub.lastPollSucceededTime = time.Now()
	if reply.GenerationCount == 0 {
		sub.fileSystem = nil
		sub.generationCount = 0
	}
	if fs := reply.FileSystem; fs == nil {
		sub.lastShortPollDuration =
			sub.lastPollSucceededTime.Sub(sub.lastPollStartTime)
	} else {
		fs.RebuildInodePointers()
		fs.BuildInodeToFilenamesTable()
		fs.BuildEntryMap()
		sub.fileSystem = fs
		sub.generationCount = reply.GenerationCount
		sub.lastFullPollDuration =
			sub.lastPollSucceededTime.Sub(sub.lastPollStartTime)
		logger.Printf("Polled: %s, GenerationCount=%d\n",
			sub.hostname, reply.GenerationCount)
	}
	if sub.fileSystem == nil {
		sub.status = statusSubNotReady
		return
	}
	if reply.FetchInProgress {
		sub.status = statusFetching
		return
	}
	if reply.UpdateInProgress {
		sub.status = statusUpdating
		return
	}
	if sub.generationCountAtChangeStart == sub.generationCount {
		sub.status = statusWaitingForNextPoll
		return
	}
	if idle, status := sub.fetchMissingObjects(connection,
		sub.requiredImage); !idle {
		sub.status = status
		return
	}
	sub.status = statusComputingUpdate
	if idle, status := sub.sendUpdate(connection); !idle {
		sub.status = status
		return
	}
	if idle, status := sub.fetchMissingObjects(connection,
		sub.plannedImage); !idle {
		sub.status = status
		return
	}
	sub.status = statusSynced
	sub.cleanup(connection, sub.plannedImage)
}

// Returns true if all required objects are available.
func (sub *Sub) fetchMissingObjects(connection *rpc.Client, imageName string) (
	bool, uint) {
	image := sub.herd.getImage(imageName)
	if image == nil {
		return false, statusImageNotReady
	}
	missingObjects := make(map[hash.Hash]bool)
	for _, inode := range image.FileSystem.InodeTable {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			if inode.Size > 0 {
				missingObjects[inode.Hash] = true
			}
		}
	}
	for _, hash := range sub.fileSystem.ObjectCache {
		delete(missingObjects, hash)
	}
	for _, inode := range sub.fileSystem.InodeTable {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			if inode.Size > 0 {
				delete(missingObjects, inode.Hash)
			}
		}
	}
	if len(missingObjects) < 1 {
		return true, statusSynced
	}
	logger := sub.herd.logger
	logger.Printf("Calling %s.Fetch() for: %d objects\n",
		sub.hostname, len(missingObjects))
	var request subproto.FetchRequest
	var reply subproto.FetchResponse
	request.ServerAddress = sub.herd.imageServerAddress
	for hash := range missingObjects {
		request.Hashes = append(request.Hashes, hash)
	}
	if err := connection.Call("Subd.Fetch", request, &reply); err != nil {
		logger.Printf("Error calling %s.Fetch()\t%s\n", sub.hostname, err)
		return false, statusFailedToFetch
	}
	sub.generationCountAtChangeStart = sub.generationCount
	return false, statusFetching
}

// Returns true if no update needs to be performed.
func (sub *Sub) sendUpdate(connection *rpc.Client) (bool, uint) {
	logger := sub.herd.logger
	var request subproto.UpdateRequest
	var reply subproto.UpdateResponse
	if sub.buildUpdateRequest(&request) {
		return true, statusSynced
	}
	if err := connection.Call("Subd.Update", request, &reply); err != nil {
		logger.Printf("Error calling %s:Subd.Update()\t%s\n", sub.hostname, err)
		return false, statusFailedToUpdate
	}
	sub.generationCountAtChangeStart = sub.generationCount
	return false, statusUpdating
}

func (sub *Sub) cleanup(connection *rpc.Client, plannedImageName string) {
	logger := sub.herd.logger
	unusedObjects := make(map[hash.Hash]bool)
	for _, hash := range sub.fileSystem.ObjectCache {
		unusedObjects[hash] = false // Potential cleanup candidate.
	}
	for _, inode := range sub.fileSystem.InodeTable {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			if inode.Size > 0 {
				if _, ok := unusedObjects[inode.Hash]; ok {
					unusedObjects[inode.Hash] = true // Must clean this one up.
				}
			}
		}
	}
	image := sub.herd.getImage(plannedImageName)
	if image != nil {
		for _, inode := range image.FileSystem.InodeTable {
			if inode, ok := inode.(*filesystem.RegularInode); ok {
				if inode.Size > 0 {
					if clean, ok := unusedObjects[inode.Hash]; !clean && ok {
						delete(unusedObjects, inode.Hash)
					}
				}
			}
		}
	}
	if len(unusedObjects) < 1 {
		return
	}
	var request subproto.CleanupRequest
	var reply subproto.CleanupResponse
	request.Hashes = make([]hash.Hash, 0, len(unusedObjects))
	for hash := range unusedObjects {
		request.Hashes = append(request.Hashes, hash)
	}
	if err := connection.Call("Subd.Cleanup", request, &reply); err != nil {
		logger.Printf("Error calling %s:Subd.Update()\t%s\n", sub.hostname, err)
	} else {
		sub.generationCountAtChangeStart = sub.generationCount
	}
}
<commit_msg>Do not set sub status to ImageNotReady if the planned image is missing.<commit_after>package herd

import (
	"fmt"
	"github.com/Symantec/Dominator/lib/constants"
	"github.com/Symantec/Dominator/lib/filesystem"
	"github.com/Symantec/Dominator/lib/hash"
	subproto "github.com/Symantec/Dominator/proto/sub"
	"net/rpc"
	"strings"
	"time"
)

func (sub *Sub) tryMakeBusy() bool {
	sub.busyMutex.Lock()
	defer sub.busyMutex.Unlock()
	if sub.busy {
		return false
	}
	sub.busy = true
	return true
}

func (sub *Sub) makeUnbusy() {
	sub.busyMutex.Lock()
	defer sub.busyMutex.Unlock()
	sub.busy = false
}

func (sub *Sub) connectAndPoll() {
	sub.status = statusConnecting
	hostname := strings.SplitN(sub.hostname, "*", 2)[0]
	var err error
	connection, err := rpc.DialHTTP("tcp",
		fmt.Sprintf("%s:%d", hostname, constants.SubPortNumber))
	if err != nil {
		sub.status = statusFailedToConnect
		return
	}
	defer connection.Close()
	sub.status = statusWaitingToPoll
	sub.herd.pollSemaphore <- true
	sub.status = statusPolling
	sub.poll(connection)
	<-sub.herd.pollSemaphore
}

func (sub *Sub) poll(connection *rpc.Client) {
	var request subproto.PollRequest
	request.HaveGeneration = sub.generationCount
	var reply subproto.PollResponse
	sub.lastPollStartTime = time.Now()
	logger := sub.herd.logger
	if err := connection.Call("Subd.Poll", request, &reply); err != nil {
		sub.status = statusFailedToPoll
		logger.Printf("Error calling %s.Poll()\t%s\n", sub.hostname, err)
		return
	}
	sub.lastPollSucceededTime = time.Now()
	if reply.GenerationCount == 0 {
		sub.fileSystem = nil
		sub.generationCount = 0
	}
	if fs := reply.FileSystem; fs == nil {
		sub.lastShortPollDuration =
			sub.lastPollSucceededTime.Sub(sub.lastPollStartTime)
	} else {
		fs.RebuildInodePointers()
		fs.BuildInodeToFilenamesTable()
		fs.BuildEntryMap()
		sub.fileSystem = fs
		sub.generationCount = reply.GenerationCount
		sub.lastFullPollDuration =
			sub.lastPollSucceededTime.Sub(sub.lastPollStartTime)
		logger.Printf("Polled: %s, GenerationCount=%d\n",
			sub.hostname, reply.GenerationCount)
	}
	if sub.fileSystem == nil {
		sub.status = statusSubNotReady
		return
	}
	if reply.FetchInProgress {
		sub.status = statusFetching
		return
	}
	if reply.UpdateInProgress {
		sub.status = statusUpdating
		return
	}
	if sub.generationCountAtChangeStart == sub.generationCount {
		sub.status = statusWaitingForNextPoll
		return
	}
	if idle, status := sub.fetchMissingObjects(connection,
		sub.requiredImage); !idle {
		sub.status = status
		return
	}
	sub.status = statusComputingUpdate
	if idle, status := sub.sendUpdate(connection); !idle {
		sub.status = status
		return
	}
	if idle, status := sub.fetchMissingObjects(connection,
		sub.plannedImage); !idle {
		if status != statusImageNotReady {
			sub.status = status
			return
		}
	}
	sub.status = statusSynced
	sub.cleanup(connection, sub.plannedImage)
}

// Returns true if all required objects are available.
func (sub *Sub) fetchMissingObjects(connection *rpc.Client, imageName string) (
	bool, uint) {
	image := sub.herd.getImage(imageName)
	if image == nil {
		return false, statusImageNotReady
	}
	missingObjects := make(map[hash.Hash]bool)
	for _, inode := range image.FileSystem.InodeTable {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			if inode.Size > 0 {
				missingObjects[inode.Hash] = true
			}
		}
	}
	for _, hash := range sub.fileSystem.ObjectCache {
		delete(missingObjects, hash)
	}
	for _, inode := range sub.fileSystem.InodeTable {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			if inode.Size > 0 {
				delete(missingObjects, inode.Hash)
			}
		}
	}
	if len(missingObjects) < 1 {
		return true, statusSynced
	}
	logger := sub.herd.logger
	logger.Printf("Calling %s.Fetch() for: %d objects\n",
		sub.hostname, len(missingObjects))
	var request subproto.FetchRequest
	var reply subproto.FetchResponse
	request.ServerAddress = sub.herd.imageServerAddress
	for hash := range missingObjects {
		request.Hashes = append(request.Hashes, hash)
	}
	if err := connection.Call("Subd.Fetch", request, &reply); err != nil {
		logger.Printf("Error calling %s.Fetch()\t%s\n", sub.hostname, err)
		return false, statusFailedToFetch
	}
	sub.generationCountAtChangeStart = sub.generationCount
	return false, statusFetching
}

// Returns true if no update needs to be performed.
func (sub *Sub) sendUpdate(connection *rpc.Client) (bool, uint) {
	logger := sub.herd.logger
	var request subproto.UpdateRequest
	var reply subproto.UpdateResponse
	if sub.buildUpdateRequest(&request) {
		return true, statusSynced
	}
	if err := connection.Call("Subd.Update", request, &reply); err != nil {
		logger.Printf("Error calling %s:Subd.Update()\t%s\n", sub.hostname, err)
		return false, statusFailedToUpdate
	}
	sub.generationCountAtChangeStart = sub.generationCount
	return false, statusUpdating
}

func (sub *Sub) cleanup(connection *rpc.Client, plannedImageName string) {
	logger := sub.herd.logger
	unusedObjects := make(map[hash.Hash]bool)
	for _, hash := range sub.fileSystem.ObjectCache {
		unusedObjects[hash] = false // Potential cleanup candidate.
	}
	for _, inode := range sub.fileSystem.InodeTable {
		if inode, ok := inode.(*filesystem.RegularInode); ok {
			if inode.Size > 0 {
				if _, ok := unusedObjects[inode.Hash]; ok {
					unusedObjects[inode.Hash] = true // Must clean this one up.
				}
			}
		}
	}
	image := sub.herd.getImage(plannedImageName)
	if image != nil {
		for _, inode := range image.FileSystem.InodeTable {
			if inode, ok := inode.(*filesystem.RegularInode); ok {
				if inode.Size > 0 {
					if clean, ok := unusedObjects[inode.Hash]; !clean && ok {
						delete(unusedObjects, inode.Hash)
					}
				}
			}
		}
	}
	if len(unusedObjects) < 1 {
		return
	}
	var request subproto.CleanupRequest
	var reply subproto.CleanupResponse
	request.Hashes = make([]hash.Hash, 0, len(unusedObjects))
	for hash := range unusedObjects {
		request.Hashes = append(request.Hashes, hash)
	}
	if err := connection.Call("Subd.Cleanup", request, &reply); err != nil {
		logger.Printf("Error calling %s:Subd.Update()\t%s\n", sub.hostname, err)
	} else {
		sub.generationCountAtChangeStart = sub.generationCount
	}
}
<|endoftext|>


<commit_before>package alistorage

import (
	"strconv"
	"github.com/cloudlibz/gocloud/aliauth"
)

// Createdisk create ECS-Disk accept map[string]interface{}
func (aliStorage *Alistorage) Createdisk(request interface{}) (resp interface{}, err error) {
	var options CreateDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "RegionId":
			regionID, _ := value.(string)
			options.RegionID = regionID
		case "ZoneId":
			zoneID, _ := value.(string)
			options.ZoneID = zoneID
		case "DiskName":
			diskName, _ := value.(string)
			options.DiskName = diskName
		case "Description":
			description, _ := value.(string)
			options.Description = description
		case "Encrypted":
			switch value.(type) {
			case bool:
				options.Encrypted = value.(bool)
			case string:
				options.Encrypted = value.(string) == "true" || value.(string) == "True"
			}
		case "DiskCategory":
			diskCategory, _ := value.(string)
			options.DiskCategory = diskCategory
		case "Size":
			switch value.(type) {
			case int:
				options.Size = value.(int)
			case string:
				options.Size, _ = strconv.Atoi(value.(string))
			}
		case "SnapshotId":
			snapshotID, _ := value.(string)
			options.SnapshotID = snapshotID
		case "ClientToken":
			clientToken, _ := value.(string)
			options.ClientToken = clientToken
		}
	}

	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("CreateDisk", params, response)
	resp = response
	return resp, err
}

// Deletedisk delete ECS-Disk accept map[string]interface{}
func (aliStorage *Alistorage) Deletedisk(request interface{}) (resp interface{}, err error) {
	var options DeleteDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("DeleteDisk", params, response)
	resp = response
	return resp, err
}

// Createsnapshot
func (aliStorage *Alistorage) Createsnapshot(request interface{}) (resp interface{}, err error) {
	return resp, err
}

//TODO
func (aliStorage *Alistorage) Deletesnapshot(request interface{}) (resp interface{}, err error) {
	return resp, err
}

// Attachdisk attach ECS-Disk to ECS, accept map[string]interface{}
func (aliStorage *Alistorage) Attachdisk(request interface{}) (resp interface{}, err error) {
	var options AttachDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "InstanceId":
			instanceID, _ := value.(string)
			options.InstanceID = instanceID
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		case "DeleteWithInstance":
			switch value.(type) {
			case bool:
				options.DeleteWithInstance = value.(bool)
			case string:
				options.DeleteWithInstance = value.(string) == "true" || value.(string) == "True"
			}
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("AttachDisk", params, response)
	resp = response
	return resp, err
}

// Detachdisk detach ECS-Disk from ECS, accept map[string]interface{}
func (aliStorage *Alistorage) Detachdisk(request interface{}) (resp interface{}, err error) {
	var options AttachDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "InstanceId":
			instanceID, _ := value.(string)
			options.InstanceID = instanceID
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("DetachDisk", params, response)
	resp = response
	return resp, err
}
<commit_msg>Ali storage: improve code suggested by codacy<commit_after>package alistorage

import (
	"strconv"
	"github.com/cloudlibz/gocloud/aliauth"
)

// Createdisk create ECS-Disk accept map[string]interface{}
func (aliStorage *Alistorage) Createdisk(request interface{}) (resp interface{}, err error) {
	var options CreateDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "RegionId":
			regionID, _ := value.(string)
			options.RegionID = regionID
		case "ZoneId":
			zoneID, _ := value.(string)
			options.ZoneID = zoneID
		case "DiskName":
			diskName, _ := value.(string)
			options.DiskName = diskName
		case "Description":
			description, _ := value.(string)
			options.Description = description
		case "Encrypted":
			switch value.(type) {
			case bool:
				options.Encrypted = value.(bool)
			case string:
				options.Encrypted = value.(string) == "true" || value.(string) == "True"
			}
		case "DiskCategory":
			diskCategory, _ := value.(string)
			options.DiskCategory = diskCategory
		case "Size":
			switch value.(type) {
			case int:
				options.Size = value.(int)
			case string:
				options.Size, _ = strconv.Atoi(value.(string))
			}
		case "SnapshotId":
			snapshotID, _ := value.(string)
			options.SnapshotID = snapshotID
		case "ClientToken":
			clientToken, _ := value.(string)
			options.ClientToken = clientToken
		}
	}

	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("CreateDisk", params, response)
	resp = response
	return resp, err
}

// Deletedisk delete ECS-Disk accept map[string]interface{}
func (aliStorage *Alistorage) Deletedisk(request interface{}) (resp interface{}, err error) {
	var options DeleteDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("DeleteDisk", params, response)
	resp = response
	return resp, err
}

// Createsnapshot create snapshot accept map[string]interface{}
func (aliStorage *Alistorage) Createsnapshot(request interface{}) (resp interface{}, err error) {
	return resp, err
}

// Deletesnapshot delete snapshot accept map[string]interface{}
func (aliStorage *Alistorage) Deletesnapshot(request interface{}) (resp interface{}, err error) {
	return resp, err
}

// Attachdisk attach ECS-Disk to ECS, accept map[string]interface{}
func (aliStorage *Alistorage) Attachdisk(request interface{}) (resp interface{}, err error) {
	var options AttachDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "InstanceId":
			instanceID, _ := value.(string)
			options.InstanceID = instanceID
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		case "DeleteWithInstance":
			switch value.(type) {
			case bool:
				options.DeleteWithInstance = value.(bool)
			case string:
				options.DeleteWithInstance = value.(string) == "true" || value.(string) == "True"
			}
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("AttachDisk", params, response)
	resp = response
	return resp, err
}

// Detachdisk detach ECS-Disk from ECS, accept map[string]interface{}
func (aliStorage *Alistorage) Detachdisk(request interface{}) (resp interface{}, err error) {
	var options AttachDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "InstanceId":
			instanceID, _ := value.(string)
			options.InstanceID = instanceID
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("DetachDisk", params, response)
	resp = response
	return resp, err
}
<|endoftext|>


<commit_before>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
	"context"
	"encoding/base64"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"testing"

	"github.com/matt-tyler/elasticsearch-operator/e2e/suite"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"

	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"

	"github.com/matt-tyler/elasticsearch-operator/e2e/gke"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

var Kubeconfig string
var Image string
var Up bool
var Down bool
var Test bool

func init() {
	flag.StringVar(&Kubeconfig, "kubeconfig", "", "Location of kubeconfig")
	flag.StringVar(&Image, "image", "gcr.io/schnauzer-163208/elasticsearch-operator:latest", "image under test")
	flag.BoolVar(&Up, "up", false, "")
	flag.BoolVar(&Down, "down", false, "")
	flag.BoolVar(&Test, "test", false, "")
}

func TestE2E(t *testing.T) {
	RunE2ETests(t)
}

func RunE2ETests(t *testing.T) {
	flag.Parse()

	clusterID := "e2e-test-cluster"
	ctx := context.Background()
	client := gke.GkeClient{}

	var config *rest.Config

	if Up || Down {
		if err := gke.NewGkeClient(&client, ctx, os.Getenv("PROJECT"), os.Getenv("ZONE")); err != nil {
			panic(err)
		}
	}

	if Up {
		createCluster(client, clusterID)
		cluster, err := client.GetCluster(clusterID)
		if err != nil {
			panic(err)
		}

		config, err = cluster.Config()
		if err != nil {
			panic(err)
		}

		configAccess := clientcmd.NewDefaultClientConfigLoadingRules()
		if err := clientcmd.ModifyConfig(configAccess, *(clientConfig(cluster)), false); err != nil {
			panic(err)
		}
	}

	if Down {
		defer deleteCluster(client, clusterID)
	}

	if !Test {
		return
	}

	if config == nil {
		var err error
		config, err = buildConfig(Kubeconfig)
		if err != nil {
			panic(err)
		}
	}

	err := suite.Setup(config, Image)
	if err != nil {
		panic(err)
	}

	RegisterFailHandler(Fail)

	r := make([]Reporter, 0)

	RunSpecsWithDefaultAndCustomReporters(t, "Elasticsearch Operator E2E Suite", r)
}

func buildConfig(kubeconfig string) (*rest.Config, error) {
	// If kubeconfig flag was passed in, we try this first
	if kubeconfig != "" {
		return clientcmd.BuildConfigFromFlags("", kubeconfig)
	}

	// Otherwise, see if we are running inside a kubernetes cluster
	if config, err := rest.InClusterConfig(); err == nil {
		return config, nil
	}

	// else try running with the from the default kubeconfig location
	c := clientcmd.NewDefaultClientConfigLoadingRules().DefaultClientConfig
	return c.ClientConfig()
}

func deleteCluster(client gke.GkeClient, clusterID string) {
	fmt.Printf("Deleting Cluster: %v\n", clusterID)
	op, err := client.DeleteCluster(clusterID)
	if err != nil {
		panic(err)
	}
	client.Done(op)
	fmt.Printf("Cluster %v deleted\n", clusterID)
}

func createCluster(client gke.GkeClient, clusterID string) {
	fmt.Printf("Creating cluster: %v\n", clusterID)
	op, err := client.CreateCluster(clusterID)
	if err != nil {
		panic(err)
	}
	client.Done(op)
	fmt.Printf("Cluster %v created\n", clusterID)
}

func clientConfig(gc *gke.Cluster) *clientcmdapi.Config {
	gcloudPath, err := exec.LookPath("gcloud")
	if err != nil {
		panic(err)
	}

	config := clientcmdapi.NewConfig()

	cluster := clientcmdapi.NewCluster()

	caCert, err := base64.StdEncoding.DecodeString(gc.Auth.ClusterCaCertificate)
	if err != nil {
		panic(err)
	}

	cluster.CertificateAuthorityData = []byte(caCert)
	cluster.Server = fmt.Sprintf("https://%v", gc.Endpoint)

	context := clientcmdapi.NewContext()
	context.Cluster = "e2e-test-cluster"
	context.AuthInfo = "e2e-test-cluster-user"

	authInfo := clientcmdapi.NewAuthInfo()
	authInfo.AuthProvider = &clientcmdapi.AuthProviderConfig{
		Name: "gcp",
		Config: map[string]string{
			"cmd-args":   "config config-helper --format=json",
			"cmd-path":   gcloudPath,
			"expiry-key": "{.credential.token_expiry}",
			"token-key":  "{.credential.access_token}",
		},
	}

	config.Clusters["e2e-test-cluster"] = cluster
	config.Contexts["e2e-test-cluster-user"] = context
	config.AuthInfos["e2e-test-cluster-user"] = authInfo

	config.CurrentContext = "e2e-test-cluster-user"

	return config
}
<commit_msg>e2e: correctly falls back to default cluster configuration<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
	"context"
	"encoding/base64"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"testing"

	"github.com/matt-tyler/elasticsearch-operator/e2e/suite"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"

	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"

	"github.com/matt-tyler/elasticsearch-operator/e2e/gke"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

var Kubeconfig string
var Image string
var Up bool
var Down bool
var Test bool

func init() {
	flag.StringVar(&Kubeconfig, "kubeconfig", "", "Location of kubeconfig")
	flag.StringVar(&Image, "image", "gcr.io/schnauzer-163208/elasticsearch-operator:latest", "image under test")
	flag.BoolVar(&Up, "up", false, "")
	flag.BoolVar(&Down, "down", false, "")
	flag.BoolVar(&Test, "test", false, "")
}

func TestE2E(t *testing.T) {
	RunE2ETests(t)
}

func RunE2ETests(t *testing.T) {
	flag.Parse()

	clusterID := "e2e-test-cluster"
	ctx := context.Background()
	client := gke.GkeClient{}

	var config *rest.Config

	if Up || Down {
		if err := gke.NewGkeClient(&client, ctx, os.Getenv("PROJECT"), os.Getenv("ZONE")); err != nil {
			panic(err)
		}
	}

	if Up {
		createCluster(client, clusterID)
		cluster, err := client.GetCluster(clusterID)
		if err != nil {
			panic(err)
		}

		config, err = cluster.Config()
		if err != nil {
			panic(err)
		}

		configAccess := clientcmd.NewDefaultClientConfigLoadingRules()
		if err := clientcmd.ModifyConfig(configAccess, *(clientConfig(cluster)), false); err != nil {
			panic(err)
		}
	}

	if Down {
		defer deleteCluster(client, clusterID)
	}

	if !Test {
		return
	}

	if config == nil {
		var err error
		config, err = buildConfig(Kubeconfig)
		if err != nil {
			panic(err)
		}
	}

	err := suite.Setup(config, Image)
	if err != nil {
		panic(err)
	}

	RegisterFailHandler(Fail)

	r := make([]Reporter, 0)

	RunSpecsWithDefaultAndCustomReporters(t, "Elasticsearch Operator E2E Suite", r)
}

func buildConfig(kubeconfig string) (*rest.Config, error) {
	if config, err := clientcmd.BuildConfigFromFlags("", kubeconfig); err == nil {
		return config, err
	}

	// else try running with the from the default kubeconfig location
	return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		clientcmd.NewDefaultClientConfigLoadingRules(),
		&clientcmd.ConfigOverrides{},
	).ClientConfig()
}

func deleteCluster(client gke.GkeClient, clusterID string) {
	fmt.Printf("Deleting Cluster: %v\n", clusterID)
	op, err := client.DeleteCluster(clusterID)
	if err != nil {
		panic(err)
	}
	client.Done(op)
	fmt.Printf("Cluster %v deleted\n", clusterID)
}

func createCluster(client gke.GkeClient, clusterID string) {
	fmt.Printf("Creating cluster: %v\n", clusterID)
	op, err := client.CreateCluster(clusterID)
	if err != nil {
		panic(err)
	}
	client.Done(op)
	fmt.Printf("Cluster %v created\n", clusterID)
}

func clientConfig(gc *gke.Cluster) *clientcmdapi.Config {
	gcloudPath, err := exec.LookPath("gcloud")
	if err != nil {
		panic(err)
	}

	config := clientcmdapi.NewConfig()

	cluster := clientcmdapi.NewCluster()

	caCert, err := base64.StdEncoding.DecodeString(gc.Auth.ClusterCaCertificate)
	if err != nil {
		panic(err)
	}

	cluster.CertificateAuthorityData = []byte(caCert)
	cluster.Server = fmt.Sprintf("https://%v", gc.Endpoint)

	context := clientcmdapi.NewContext()
	context.Cluster = "e2e-test-cluster"
	context.AuthInfo = "e2e-test-cluster-user"

	authInfo := clientcmdapi.NewAuthInfo()
	authInfo.AuthProvider = &clientcmdapi.AuthProviderConfig{
		Name: "gcp",
		Config: map[string]string{
			"cmd-args":   "config config-helper --format=json",
			"cmd-path":   gcloudPath,
			"expiry-key": "{.credential.token_expiry}",
			"token-key":  "{.credential.access_token}",
		},
	}

	config.Clusters["e2e-test-cluster"] = cluster
	config.Contexts["e2e-test-cluster-user"] = context
	config.AuthInfos["e2e-test-cluster-user"] = authInfo

	config.CurrentContext = "e2e-test-cluster-user"

	return config
}
<|endoftext|>


<commit_before><commit_msg>Fix pachctl delete-file<commit_after><|endoftext|>


<commit_before>package main_test

import (
	"bytes"
	"io"
	"io/ioutil"
	"time"

	"github.com/elasticlic/els-api-sdk-go/els"
	em "github.com/elasticlic/els-api-sdk-go/els/mock"
	cli "github.com/elasticlic/els-cli"
	"github.com/elasticlic/go-utils/datetime"
	jcli "github.com/jawher/mow.cli"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/spf13/afero"
)

// MockPipe is used to simulate piped input to the command via the commandline.
type MockPipe struct {
	Data string
	Err  error
}

// Reader implements interface main.Pipe and presents our test data in the
// MockPipe.
func (p *MockPipe) Reader() (io.ReadCloser, error) {
	return ioutil.NopCloser(bytes.NewReader([]byte(p.Data))), p.Err
}

var _ = Describe("els_cliTest Suite", func() {

	var (
		fatalErr        error
		config          cli.Config
		cFile           = "aConfigFile"
		jFile           = "t.json"
		pw              = "password"
		expiryDays      = 30
		pwr             = cli.NewStringPassworder(pw, nil)
		ID              = els.AccessKeyID("anID")
		SAC             = els.SecretAccessKey("aSAC")
		email           = "email@example.com"
		expiry          = time.Now().Add(time.Hour)
		reqJ            = `{"send":"aValue"}`
		repJ            = `{"rec":"aValue"}`
		prof            *cli.Profile
		vendorID            = "aVendor"
		cloudProviderID     = "aCloudProvider"
		rulesetID           = "aRuleset"
		URL                 = "/a/path/and?querystring"
		maxAPITries     int = 1
		accessKey           = els.AccessKey{
			ID:              ID,
			SecretAccessKey: SAC,
			Email:           email,
			ExpiryDate:      expiry,
		}
	)

	Describe("ELSCLI", func() {

		var (
			sut  *cli.ELSCLI
			fr   *jcli.Cli
			args []string
			ac   *em.APICaller
			outS bytes.Buffer
			errS bytes.Buffer
			pipe *MockPipe
			fs   afero.Fs
			tp   *datetime.NowTimeProvider

			// checkSentContent checks if the els-cli passed on the expected content
			// in the body of the request to the ELS.
			checkSentContent = func(json string) {
				sentJ, err := ioutil.ReadAll(ac.GetCall(0).ACArgs.Req.Body)
				Expect(err).To(BeNil())
				Expect(sentJ).To(MatchJSON(json))
			}

			// checkOutputContent checks if the els-cli emitted the JSON response
			// body received from the ELS.
			checkOutputContent = func(json string) {
				Expect(errS.String()).To(BeZero())
				if json != "" {
					Expect(outS.String()).To(MatchJSON(json))
				}
			}

			checkRequest = func(httpMethod string, URL string) {
				r := ac.GetCall(0).ACArgs.Req
				Expect(httpMethod).To(Equal(r.Method))

				u := r.URL
				if u.RawQuery != "" {
					Expect(URL).To(Equal(u.Path + "?" + u.RawQuery))
				} else {
					Expect(URL).To(Equal(u.Path))
				}
			}

			// initAPIResponse sets a simple expectation on an APICaller method
			// being invoked and a response returned.
			initResponse = func(callMethod string, statusCode int, repJson string) {
				ac.AddExpectedCall(callMethod, em.APICall{
					ACRep: em.ACRep{Rep: em.HTTPResponse(statusCode, repJson)},
				})
			}
		)

		BeforeEach(func() {
			args = []string{"els-cli"}
			ac = em.NewAPICaller()
			pipe = &MockPipe{}
			fs = afero.NewMemMapFs()
			tp = datetime.NewNowTimeProvider()
			fr = jcli.App("els-cli", "")

			outS = bytes.Buffer{}
			errS = bytes.Buffer{}
			config.Profiles = make(map[string]*cli.Profile)
			config.Profiles["default"] = &cli.Profile{
				AccessKey:   accessKey,
				MaxAPITries: maxAPITries,
				Output:      cli.OutputBodyOnly,
			}
			prof = config.Profiles["default"]

			sut = cli.NewELSCLI(fr, &config, cFile, tp, fs, ac, pipe, pwr, &outS, &errS)
		})

		JustBeforeEach(func() {

			fatalErr = sut.Run(args)
		})

		Describe("General Response Processing", func() {
			// These tests are the only place we'll test the pipe input and
			// the different output types
			BeforeEach(func() {
				args = append(args, "vendors", vendorID, "put")
			})
			Context("JSON is piped to the command-line", func() {
				BeforeEach(func() {
					pipe.Data = reqJ

					initResponse("Do", 200, repJ)
				})
				It("Receives a result from the API", func() {
					checkSentContent(reqJ)
					checkOutputContent(repJ)
				})
			})
			Context("A file containing JSON is specified on the commandline", func() {
				BeforeEach(func() {
					args = append(args, jFile)

					// Add a file to our FS simulation which the els-cli will
					// access:
					afero.WriteFile(fs, jFile, []byte(reqJ), 0644)

				})
				Context("200 is returned", func() {
					BeforeEach(func() {
						initResponse("Do", 200, repJ)
					})
					It("Sends the correct content and outputs the  API response body", func() {
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})

				Context("401 is retured", func() {
					BeforeEach(func() {
						config.Profiles["default"].Output = cli.OutputWhole
						initResponse("Do", 401, "")
					})
					It("Reports the error", func() {
						checkSentContent(reqJ)
						Expect(outS.String()).Should(HavePrefix("401"))
					})
				})
			})
		})

		Describe("user", func() {
			BeforeEach(func() {
				args = append(args, "users", email)
			})

			Describe("accessKey", func() {
				BeforeEach(func() {
					args = append(args, "accessKeys")
				})
				Describe("create", func() {
					BeforeEach(func() {
						args = append(args, "create")
					})

					Context("The correct password is entered", func() {
						BeforeEach(func() {
							ac.AddExpectedCall("CreateAccessKey", em.APICall{
								ACRep: em.ACRep{
									StatusCode: 201,
									AccessKey:  &accessKey,
								},
							})
						})
						It("Returns the expected access key", func() {
							args := ac.GetCall(0).ACArgs
							Expect(args.EmailAddress).To(Equal(email))
							Expect(args.Password).To(Equal(pw))
							Expect(args.ExpiryDays).To(BeEquivalentTo(expiryDays))

							Expect(outS.String()).Should(HavePrefix("Access Key Created"))
							Expect(outS.String()).Should(ContainSubstring(accessKey.Email))
							Expect(outS.String()).Should(ContainSubstring(string(accessKey.SecretAccessKey)))
							Expect(outS.String()).Should(ContainSubstring(string(accessKey.ID)))
						})
					})
					Context("An invalid password is entered", func() {
						BeforeEach(func() {
							ac.AddExpectedCall("CreateAccessKey", em.APICall{
								ACRep: em.ACRep{
									StatusCode: 401,
								},
							})
						})
						It("Returns the failure statuscode", func() {
							args := ac.GetCall(0).ACArgs
							Expect(args.EmailAddress).To(Equal(email))
							Expect(args.Password).To(Equal(pw))
							Expect(args.ExpiryDays).To(BeEquivalentTo(expiryDays))
							Expect(outS.String()).Should(HavePrefix("The email address or password are incorrect"))
						})
					})
				})
				Describe("delete", func() {
					BeforeEach(func() {
						args = append(args, "delete", string(ID))
					})
					Context("The request succeeds", func() {
						BeforeEach(func() {
							config.Profiles["default"].Output = cli.OutputWhole
							initResponse("Do", 204, "")
						})
						It("returns the success code", func() {
							checkRequest("DELETE", "/users/"+email+"/accessKeys/"+string(ID))
							Expect(outS.String()).Should(HavePrefix("204"))
						})
					})
					Context("The user isn't permitted to make the call", func() {
						BeforeEach(func() {
							config.Profiles["default"].Output = cli.OutputWhole
							initResponse("Do", 401, "")
						})
						It("returns the failure code", func() {
							checkRequest("DELETE", "/users/"+email+"/accessKeys/"+string(ID))
							Expect(outS.String()).Should(HavePrefix("401"))
						})
					})
				})
				Describe("list", func() {
					BeforeEach(func() {
						args = append(args, "list")
					})
					Context("The request succeeds", func() {
						BeforeEach(func() {
							initResponse("Do", 200, repJ)
						})
						It("returns the success code", func() {
							checkRequest("GET", "/users/"+email+"/accessKeys")
							Expect(outS.String()).Should(MatchJSON(repJ))
						})
					})
					Context("The user isn't permitted to make the call", func() {
						BeforeEach(func() {
							config.Profiles["default"].Output = cli.OutputWhole
							initResponse("Do", 401, "")
						})
						It("returns the failure code", func() {
							checkRequest("GET", "/users/"+email+"/accessKeys")
							Expect(outS.String()).Should(HavePrefix("401"))
						})
					})
				})
			})
		})

		Describe("vendor", func() {
			BeforeEach(func() {
				args = append(args, "vendors", vendorID)
			})

			Describe("put", func() {
				BeforeEach(func() {
					args = append(args, "put")
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PUT", "/vendors/"+vendorID)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
			Describe("get", func() {
				BeforeEach(func() {
					args = append(args, "get")
					initResponse("Do", 200, repJ)
				})

				It("Receives a result from the API", func() {
					checkRequest("GET", "/vendors/"+vendorID)
					checkOutputContent(repJ)
				})
			})
			Describe("rulesets", func() {
				BeforeEach(func() {
					args = append(args, "rulesets")
				})

				Describe("put", func() {
					BeforeEach(func() {
						args = append(args, rulesetID, "put")
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PUT", "/vendors/"+vendorID+"/paygRuleSets/"+rulesetID)
						checkOutputContent(repJ)
					})
				})
				Describe("activate", func() {
					BeforeEach(func() {
						args = append(args, rulesetID, "activate")
						initResponse("Do", 204, "")
					})
					It("Receives a result from the API", func() {
						checkRequest("PATCH", "/vendors/"+vendorID+"/paygRuleSets/"+rulesetID+"/activate")
						checkOutputContent("")
					})
				})
			})
		})

		Describe("cloud-provider", func() {
			BeforeEach(func() {
				args = append(args, "cloud-providers", cloudProviderID)
			})

			Describe("put", func() {
				BeforeEach(func() {
					args = append(args, "put")
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PUT", "/partners/"+cloudProviderID)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
			Describe("get", func() {
				BeforeEach(func() {
					args = append(args, "get")
					initResponse("Do", 200, repJ)
				})

				It("Receives a result from the API", func() {
					checkRequest("GET", "/partners/"+cloudProviderID)
					checkOutputContent(repJ)
				})
			})
		})
		Describe("do", func() {
			BeforeEach(func() {
				args = append(args, "do")
			})

			Describe("GET", func() {
				BeforeEach(func() {
					args = append(args, "GET", URL)
					initResponse("Do", 200, repJ)
				})

				It("Receives a result from the API", func() {
					checkRequest("GET", URL)
					checkOutputContent(repJ)
				})
			})
			Describe("POST", func() {
				BeforeEach(func() {
					args = append(args, "POST", URL)
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("POST", URL)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
			Describe("PUT", func() {
				BeforeEach(func() {
					args = append(args, "PUT", URL)
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PUT", URL)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
			Describe("PATCH", func() {
				BeforeEach(func() {
					args = append(args, "PATCH", URL)
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PATCH", URL)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
		})
	})
})
<commit_msg>Removed body response check for ruleset activate<commit_after>package main_test

import (
	"bytes"
	"io"
	"io/ioutil"
	"time"

	"github.com/elasticlic/els-api-sdk-go/els"
	em "github.com/elasticlic/els-api-sdk-go/els/mock"
	cli "github.com/elasticlic/els-cli"
	"github.com/elasticlic/go-utils/datetime"
	jcli "github.com/jawher/mow.cli"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/spf13/afero"
)

// MockPipe is used to simulate piped input to the command via the commandline.
type MockPipe struct {
	Data string
	Err  error
}

// Reader implements interface main.Pipe and presents our test data in the
// MockPipe.
func (p *MockPipe) Reader() (io.ReadCloser, error) {
	return ioutil.NopCloser(bytes.NewReader([]byte(p.Data))), p.Err
}

var _ = Describe("els_cliTest Suite", func() {

	var (
		fatalErr        error
		config          cli.Config
		cFile           = "aConfigFile"
		jFile           = "t.json"
		pw              = "password"
		expiryDays      = 30
		pwr             = cli.NewStringPassworder(pw, nil)
		ID              = els.AccessKeyID("anID")
		SAC             = els.SecretAccessKey("aSAC")
		email           = "email@example.com"
		expiry          = time.Now().Add(time.Hour)
		reqJ            = `{"send":"aValue"}`
		repJ            = `{"rec":"aValue"}`
		prof            *cli.Profile
		vendorID            = "aVendor"
		cloudProviderID     = "aCloudProvider"
		rulesetID           = "aRuleset"
		URL                 = "/a/path/and?querystring"
		maxAPITries     int = 1
		accessKey           = els.AccessKey{
			ID:              ID,
			SecretAccessKey: SAC,
			Email:           email,
			ExpiryDate:      expiry,
		}
	)

	Describe("ELSCLI", func() {

		var (
			sut  *cli.ELSCLI
			fr   *jcli.Cli
			args []string
			ac   *em.APICaller
			outS bytes.Buffer
			errS bytes.Buffer
			pipe *MockPipe
			fs   afero.Fs
			tp   *datetime.NowTimeProvider

			// checkSentContent checks if the els-cli passed on the expected content
			// in the body of the request to the ELS.
			checkSentContent = func(json string) {
				sentJ, err := ioutil.ReadAll(ac.GetCall(0).ACArgs.Req.Body)
				Expect(err).To(BeNil())
				Expect(sentJ).To(MatchJSON(json))
			}

			// checkOutputContent checks if the els-cli emitted the JSON response
			// body received from the ELS.
			checkOutputContent = func(json string) {
				Expect(errS.String()).To(BeZero())
				if json != "" {
					Expect(outS.String()).To(MatchJSON(json))
				}
			}

			checkRequest = func(httpMethod string, URL string) {
				r := ac.GetCall(0).ACArgs.Req
				Expect(httpMethod).To(Equal(r.Method))

				u := r.URL
				if u.RawQuery != "" {
					Expect(URL).To(Equal(u.Path + "?" + u.RawQuery))
				} else {
					Expect(URL).To(Equal(u.Path))
				}
			}

			// initAPIResponse sets a simple expectation on an APICaller method
			// being invoked and a response returned.
			initResponse = func(callMethod string, statusCode int, repJson string) {
				ac.AddExpectedCall(callMethod, em.APICall{
					ACRep: em.ACRep{Rep: em.HTTPResponse(statusCode, repJson)},
				})
			}
		)

		BeforeEach(func() {
			args = []string{"els-cli"}
			ac = em.NewAPICaller()
			pipe = &MockPipe{}
			fs = afero.NewMemMapFs()
			tp = datetime.NewNowTimeProvider()
			fr = jcli.App("els-cli", "")

			outS = bytes.Buffer{}
			errS = bytes.Buffer{}
			config.Profiles = make(map[string]*cli.Profile)
			config.Profiles["default"] = &cli.Profile{
				AccessKey:   accessKey,
				MaxAPITries: maxAPITries,
				Output:      cli.OutputBodyOnly,
			}
			prof = config.Profiles["default"]

			sut = cli.NewELSCLI(fr, &config, cFile, tp, fs, ac, pipe, pwr, &outS, &errS)
		})

		JustBeforeEach(func() {

			fatalErr = sut.Run(args)
		})

		Describe("General Response Processing", func() {
			// These tests are the only place we'll test the pipe input and
			// the different output types
			BeforeEach(func() {
				args = append(args, "vendors", vendorID, "put")
			})
			Context("JSON is piped to the command-line", func() {
				BeforeEach(func() {
					pipe.Data = reqJ

					initResponse("Do", 200, repJ)
				})
				It("Receives a result from the API", func() {
					checkSentContent(reqJ)
					checkOutputContent(repJ)
				})
			})
			Context("A file containing JSON is specified on the commandline", func() {
				BeforeEach(func() {
					args = append(args, jFile)

					// Add a file to our FS simulation which the els-cli will
					// access:
					afero.WriteFile(fs, jFile, []byte(reqJ), 0644)

				})
				Context("200 is returned", func() {
					BeforeEach(func() {
						initResponse("Do", 200, repJ)
					})
					It("Sends the correct content and outputs the  API response body", func() {
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})

				Context("401 is retured", func() {
					BeforeEach(func() {
						config.Profiles["default"].Output = cli.OutputWhole
						initResponse("Do", 401, "")
					})
					It("Reports the error", func() {
						checkSentContent(reqJ)
						Expect(outS.String()).Should(HavePrefix("401"))
					})
				})
			})
		})

		Describe("user", func() {
			BeforeEach(func() {
				args = append(args, "users", email)
			})

			Describe("accessKey", func() {
				BeforeEach(func() {
					args = append(args, "accessKeys")
				})
				Describe("create", func() {
					BeforeEach(func() {
						args = append(args, "create")
					})

					Context("The correct password is entered", func() {
						BeforeEach(func() {
							ac.AddExpectedCall("CreateAccessKey", em.APICall{
								ACRep: em.ACRep{
									StatusCode: 201,
									AccessKey:  &accessKey,
								},
							})
						})
						It("Returns the expected access key", func() {
							args := ac.GetCall(0).ACArgs
							Expect(args.EmailAddress).To(Equal(email))
							Expect(args.Password).To(Equal(pw))
							Expect(args.ExpiryDays).To(BeEquivalentTo(expiryDays))

							Expect(outS.String()).Should(HavePrefix("Access Key Created"))
							Expect(outS.String()).Should(ContainSubstring(accessKey.Email))
							Expect(outS.String()).Should(ContainSubstring(string(accessKey.SecretAccessKey)))
							Expect(outS.String()).Should(ContainSubstring(string(accessKey.ID)))
						})
					})
					Context("An invalid password is entered", func() {
						BeforeEach(func() {
							ac.AddExpectedCall("CreateAccessKey", em.APICall{
								ACRep: em.ACRep{
									StatusCode: 401,
								},
							})
						})
						It("Returns the failure statuscode", func() {
							args := ac.GetCall(0).ACArgs
							Expect(args.EmailAddress).To(Equal(email))
							Expect(args.Password).To(Equal(pw))
							Expect(args.ExpiryDays).To(BeEquivalentTo(expiryDays))
							Expect(outS.String()).Should(HavePrefix("The email address or password are incorrect"))
						})
					})
				})
				Describe("delete", func() {
					BeforeEach(func() {
						args = append(args, "delete", string(ID))
					})
					Context("The request succeeds", func() {
						BeforeEach(func() {
							config.Profiles["default"].Output = cli.OutputWhole
							initResponse("Do", 204, "")
						})
						It("returns the success code", func() {
							checkRequest("DELETE", "/users/"+email+"/accessKeys/"+string(ID))
							Expect(outS.String()).Should(HavePrefix("204"))
						})
					})
					Context("The user isn't permitted to make the call", func() {
						BeforeEach(func() {
							config.Profiles["default"].Output = cli.OutputWhole
							initResponse("Do", 401, "")
						})
						It("returns the failure code", func() {
							checkRequest("DELETE", "/users/"+email+"/accessKeys/"+string(ID))
							Expect(outS.String()).Should(HavePrefix("401"))
						})
					})
				})
				Describe("list", func() {
					BeforeEach(func() {
						args = append(args, "list")
					})
					Context("The request succeeds", func() {
						BeforeEach(func() {
							initResponse("Do", 200, repJ)
						})
						It("returns the success code", func() {
							checkRequest("GET", "/users/"+email+"/accessKeys")
							Expect(outS.String()).Should(MatchJSON(repJ))
						})
					})
					Context("The user isn't permitted to make the call", func() {
						BeforeEach(func() {
							config.Profiles["default"].Output = cli.OutputWhole
							initResponse("Do", 401, "")
						})
						It("returns the failure code", func() {
							checkRequest("GET", "/users/"+email+"/accessKeys")
							Expect(outS.String()).Should(HavePrefix("401"))
						})
					})
				})
			})
		})

		Describe("vendor", func() {
			BeforeEach(func() {
				args = append(args, "vendors", vendorID)
			})

			Describe("put", func() {
				BeforeEach(func() {
					args = append(args, "put")
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PUT", "/vendors/"+vendorID)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
			Describe("get", func() {
				BeforeEach(func() {
					args = append(args, "get")
					initResponse("Do", 200, repJ)
				})

				It("Receives a result from the API", func() {
					checkRequest("GET", "/vendors/"+vendorID)
					checkOutputContent(repJ)
				})
			})
			Describe("rulesets", func() {
				BeforeEach(func() {
					args = append(args, "rulesets")
				})

				Describe("put", func() {
					BeforeEach(func() {
						args = append(args, rulesetID, "put")
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PUT", "/vendors/"+vendorID+"/paygRuleSets/"+rulesetID)
						checkOutputContent(repJ)
					})
				})
				Describe("activate", func() {
					BeforeEach(func() {
						args = append(args, rulesetID, "activate")
						initResponse("Do", 204, "")
					})
					It("Receives a result from the API", func() {
						checkRequest("PATCH", "/vendors/"+vendorID+"/paygRuleSets/"+rulesetID+"/activate")
						checkOutputContent("")
					})
				})
			})
		})

		Describe("cloud-provider", func() {
			BeforeEach(func() {
				args = append(args, "cloud-providers", cloudProviderID)
			})

			Describe("put", func() {
				BeforeEach(func() {
					args = append(args, "put")
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PUT", "/partners/"+cloudProviderID)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
			Describe("get", func() {
				BeforeEach(func() {
					args = append(args, "get")
					initResponse("Do", 200, repJ)
				})

				It("Receives a result from the API", func() {
					checkRequest("GET", "/partners/"+cloudProviderID)
					checkOutputContent(repJ)
				})
			})
		})
		Describe("do", func() {
			BeforeEach(func() {
				args = append(args, "do")
			})

			Describe("GET", func() {
				BeforeEach(func() {
					args = append(args, "GET", URL)
					initResponse("Do", 200, repJ)
				})

				It("Receives a result from the API", func() {
					checkRequest("GET", URL)
					checkOutputContent(repJ)
				})
			})
			Describe("POST", func() {
				BeforeEach(func() {
					args = append(args, "POST", URL)
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("POST", URL)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
			Describe("PUT", func() {
				BeforeEach(func() {
					args = append(args, "PUT", URL)
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 200, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PUT", URL)
						checkSentContent(reqJ)
						checkOutputContent(repJ)
					})
				})
			})
			Describe("PATCH", func() {
				BeforeEach(func() {
					args = append(args, "PATCH", URL)
				})
				Context("JSON is piped to the command-line", func() {
					BeforeEach(func() {
						pipe.Data = reqJ
						initResponse("Do", 204, repJ)
					})
					It("Receives a result from the API", func() {
						checkRequest("PATCH", URL)
						checkSentContent(reqJ)
					})
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package mongo

import (
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"testing"

	jc "github.com/juju/testing/checkers"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/testing/testbase"
	"launchpad.net/juju-core/upstart"
)

func Test(t *testing.T) { gc.TestingT(t) }

type MongoSuite struct {
	testbase.LoggingSuite
}

var _ = gc.Suite(&MongoSuite{})

func (s *MongoSuite) SetUpSuite(c *gc.C) {
	testpath := c.MkDir()
	s.PatchEnvPathPrepend(testpath)
	// mock out the upstart commands so we can fake install services without sudo
	fakeCmd(filepath.Join(testpath, "start"))
	fakeCmd(filepath.Join(testpath, "stop"))

	s.PatchValue(&upstart.InitDir, c.MkDir())
}

func fakeCmd(path string) {
	err := ioutil.WriteFile(path, []byte("#!/bin/bash --norc\nexit 0"), 0755)
	if err != nil {
		panic(err)
	}
}
func (s *MongoSuite) TestJujuMongodPath(c *gc.C) {
	d := c.MkDir()
	defer os.RemoveAll(d)
	mongoPath := filepath.Join(d, "mongod")
	s.PatchValue(&JujuMongodPath, mongoPath)

	err := ioutil.WriteFile(mongoPath, nil, 0777)
	c.Assert(err, gc.IsNil)

	obtained, err := MongodPath()
	c.Check(err, gc.IsNil)
	c.Check(obtained, gc.Equals, mongoPath)
}

func (s *MongoSuite) TestDefaultMongodPath(c *gc.C) {
	s.PatchValue(&JujuMongodPath, "/not/going/to/exist/mongod")

	dir := c.MkDir()
	s.PatchEnvPathPrepend(dir)
	filename := filepath.Join(dir, "mongod")
	err := ioutil.WriteFile(filename, nil, 0777)
	c.Assert(err, gc.IsNil)

	obtained, err := MongodPath()
	c.Check(err, gc.IsNil)
	c.Check(obtained, gc.Equals, filename)
}

func (s *MongoSuite) TestRemoveOldMongoServices(c *gc.C) {
	s.PatchValue(&oldMongoServiceName, "someNameThatShouldntExist")

	// Make fake old services.
	// We defer the removes manually just in case the test fails, we don't leave
	// junk behind.
	conf := makeService(oldMongoServiceName, c)
	defer conf.Remove()
	conf2 := makeService(makeServiceName(2), c)
	defer conf2.Remove()
	conf3 := makeService(makeServiceName(3), c)
	defer conf3.Remove()

	// Remove with current version = 4, which should remove all previous
	// versions plus the old service name.
	err := removeOldMongoServices(4)
	c.Assert(err, gc.IsNil)

	c.Assert(conf.Installed(), jc.IsFalse)
	c.Assert(conf2.Installed(), jc.IsFalse)
	c.Assert(conf3.Installed(), jc.IsFalse)
}

func (s *MongoSuite) TestMakeJournalDirs(c *gc.C) {
	dir := c.MkDir()
	err := makeJournalDirs(dir)
	c.Assert(err, gc.IsNil)

	testJournalDirs(dir, c)
}

func testJournalDirs(dir string, c *gc.C) {
	journalDir := path.Join(dir, "journal")

	c.Check(journalDir, jc.IsDirectory)
	info, err := os.Stat(filepath.Join(journalDir, "prealloc.0"))
	c.Check(err, gc.IsNil)

	size := int64(1024 * 1024)

	c.Check(info.Size(), gc.Equals, size)
	info, err = os.Stat(filepath.Join(journalDir, "prealloc.1"))
	c.Check(err, gc.IsNil)
	c.Check(info.Size(), gc.Equals, size)
	info, err = os.Stat(filepath.Join(journalDir, "prealloc.2"))
	c.Check(err, gc.IsNil)
	c.Check(info.Size(), gc.Equals, size)

}

func (s *MongoSuite) TestEnsureMongoServer(c *gc.C) {
	dir := c.MkDir()
	port := 25252

	oldsvc := makeService(oldMongoServiceName, c)
	defer oldsvc.Remove()

	err := EnsureMongoServer(dir, port)
	c.Assert(err, gc.IsNil)
	mongodPath := MongodPathForSeries("some-series")
	svc, err := MongoUpstartService(makeServiceName(mongoScriptVersion), mongodPath, dir, port)
	c.Assert(err, gc.IsNil)
	defer svc.Remove()

	testJournalDirs(dir, c)
	c.Check(oldsvc.Installed(), jc.IsFalse)
	c.Check(svc.Installed(), jc.IsTrue)

	// now check we can call it multiple times without error
	err = EnsureMongoServer(dir, port)
	c.Assert(err, gc.IsNil)

}

func makeService(name string, c *gc.C) *upstart.Conf {
	conf := &upstart.Conf{
		Desc:    "foo",
		Service: *upstart.NewService(name),
		Cmd:     "echo hi",
	}
	err := conf.Install()
	c.Assert(err, gc.IsNil)
	return conf
}
<commit_msg>white space<commit_after>package mongo

import (
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"testing"

	jc "github.com/juju/testing/checkers"
	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/testing/testbase"
	"launchpad.net/juju-core/upstart"
)

func Test(t *testing.T) { gc.TestingT(t) }

type MongoSuite struct {
	testbase.LoggingSuite
}

var _ = gc.Suite(&MongoSuite{})

func (s *MongoSuite) SetUpSuite(c *gc.C) {
	testpath := c.MkDir()
	s.PatchEnvPathPrepend(testpath)
	// mock out the upstart commands so we can fake install services without sudo
	fakeCmd(filepath.Join(testpath, "start"))
	fakeCmd(filepath.Join(testpath, "stop"))

	s.PatchValue(&upstart.InitDir, c.MkDir())
}

func fakeCmd(path string) {
	err := ioutil.WriteFile(path, []byte("#!/bin/bash --norc\nexit 0"), 0755)
	if err != nil {
		panic(err)
	}
}

func (s *MongoSuite) TestJujuMongodPath(c *gc.C) {
	d := c.MkDir()
	defer os.RemoveAll(d)
	mongoPath := filepath.Join(d, "mongod")
	s.PatchValue(&JujuMongodPath, mongoPath)

	err := ioutil.WriteFile(mongoPath, nil, 0777)
	c.Assert(err, gc.IsNil)

	obtained, err := MongodPath()
	c.Check(err, gc.IsNil)
	c.Check(obtained, gc.Equals, mongoPath)
}

func (s *MongoSuite) TestDefaultMongodPath(c *gc.C) {
	s.PatchValue(&JujuMongodPath, "/not/going/to/exist/mongod")

	dir := c.MkDir()
	s.PatchEnvPathPrepend(dir)
	filename := filepath.Join(dir, "mongod")
	err := ioutil.WriteFile(filename, nil, 0777)
	c.Assert(err, gc.IsNil)

	obtained, err := MongodPath()
	c.Check(err, gc.IsNil)
	c.Check(obtained, gc.Equals, filename)
}

func (s *MongoSuite) TestRemoveOldMongoServices(c *gc.C) {
	s.PatchValue(&oldMongoServiceName, "someNameThatShouldntExist")

	// Make fake old services.
	// We defer the removes manually just in case the test fails, we don't leave
	// junk behind.
	conf := makeService(oldMongoServiceName, c)
	defer conf.Remove()
	conf2 := makeService(makeServiceName(2), c)
	defer conf2.Remove()
	conf3 := makeService(makeServiceName(3), c)
	defer conf3.Remove()

	// Remove with current version = 4, which should remove all previous
	// versions plus the old service name.
	err := removeOldMongoServices(4)
	c.Assert(err, gc.IsNil)

	c.Assert(conf.Installed(), jc.IsFalse)
	c.Assert(conf2.Installed(), jc.IsFalse)
	c.Assert(conf3.Installed(), jc.IsFalse)
}

func (s *MongoSuite) TestMakeJournalDirs(c *gc.C) {
	dir := c.MkDir()
	err := makeJournalDirs(dir)
	c.Assert(err, gc.IsNil)

	testJournalDirs(dir, c)
}

func testJournalDirs(dir string, c *gc.C) {
	journalDir := path.Join(dir, "journal")

	c.Check(journalDir, jc.IsDirectory)
	info, err := os.Stat(filepath.Join(journalDir, "prealloc.0"))
	c.Check(err, gc.IsNil)

	size := int64(1024 * 1024)

	c.Check(info.Size(), gc.Equals, size)
	info, err = os.Stat(filepath.Join(journalDir, "prealloc.1"))
	c.Check(err, gc.IsNil)
	c.Check(info.Size(), gc.Equals, size)
	info, err = os.Stat(filepath.Join(journalDir, "prealloc.2"))
	c.Check(err, gc.IsNil)
	c.Check(info.Size(), gc.Equals, size)

}

func (s *MongoSuite) TestEnsureMongoServer(c *gc.C) {
	dir := c.MkDir()
	port := 25252

	oldsvc := makeService(oldMongoServiceName, c)
	defer oldsvc.Remove()

	err := EnsureMongoServer(dir, port)
	c.Assert(err, gc.IsNil)
	mongodPath := MongodPathForSeries("some-series")
	svc, err := MongoUpstartService(makeServiceName(mongoScriptVersion), mongodPath, dir, port)
	c.Assert(err, gc.IsNil)
	defer svc.Remove()

	testJournalDirs(dir, c)
	c.Check(oldsvc.Installed(), jc.IsFalse)
	c.Check(svc.Installed(), jc.IsTrue)

	// now check we can call it multiple times without error
	err = EnsureMongoServer(dir, port)
	c.Assert(err, gc.IsNil)

}

func makeService(name string, c *gc.C) *upstart.Conf {
	conf := &upstart.Conf{
		Desc:    "foo",
		Service: *upstart.NewService(name),
		Cmd:     "echo hi",
	}
	err := conf.Install()
	c.Assert(err, gc.IsNil)
	return conf
}
<|endoftext|>