<commit_before>package tmp_manager

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/flant/werf/pkg/dappdeps"
	"github.com/flant/werf/pkg/docker"
	"github.com/flant/werf/pkg/lock"
	"github.com/flant/werf/pkg/logger"
	"github.com/flant/werf/pkg/werf"
	"github.com/otiai10/copy"
)

const (
	projectsDir      = "projects"
	dockerConfigsDir = "docker_configs"
)

func GetCreatedTmpDirs() string {
	return filepath.Join(werf.GetServiceDir(), "tmp", "created")
}

func GetReleasedTmpDirs() string {
	return filepath.Join(werf.GetServiceDir(), "tmp", "released")
}

func registerCreatedDir(newDir, createdDirs string) error {
	if err := os.MkdirAll(createdDirs, os.ModePerm); err != nil {
		return fmt.Errorf("unable to create dir %s: %s", createdDirs, err)
	}

	createdDir := filepath.Join(createdDirs, filepath.Base(newDir))
	if err := os.Symlink(newDir, createdDir); err != nil {
		return err
	}

	return nil
}

func releaseDir(dir, createdDirs, releasedDirs string) error {
	if err := os.MkdirAll(releasedDirs, os.ModePerm); err != nil {
		return fmt.Errorf("unable to create dir %s: %s", releaseDir, err)
	}

	releasedDir := filepath.Join(releasedDirs, filepath.Base(dir))
	if err := os.Symlink(dir, releasedDir); err != nil {
		return err
	}

	createdDir := filepath.Join(createdDirs, filepath.Base(dir))
	if err := os.Remove(createdDir); err != nil {
		return err
	}

	return nil
}

func checkShouldRunGC() (bool, error) {
	var releasedProjectsDirs []os.FileInfo
	var releasedDockerConfigsDirs []os.FileInfo

	releasedProjectsDir := filepath.Join(GetReleasedTmpDirs(), projectsDir)
	if _, err := os.Stat(releasedProjectsDir); !os.IsNotExist(err) {
		var err error
		releasedProjectsDirs, err = ioutil.ReadDir(releasedProjectsDir)
		if err != nil {
			return false, fmt.Errorf("unable to list released projects tmp dirs in %s: %s", releasedProjectsDir, err)
		}
	}

	releasedDockerConfigsDir := filepath.Join(GetReleasedTmpDirs(), projectsDir)
	if _, err := os.Stat(releasedProjectsDir); !os.IsNotExist(err) {
		var err error
		releasedDockerConfigsDirs, err = ioutil.ReadDir(releasedDockerConfigsDir)
		if err != nil {
			return false, fmt.Errorf("unable to list released docker configs tmp dirs in %s: %s", releasedDockerConfigsDir, err)
		}
	}

	if len(releasedProjectsDirs) > 50 || len(releasedDockerConfigsDirs) > 50 {
		return true, nil
	}

	return false, nil
}

func newTmpDir(prefix string) (string, error) {
	newDir, err := ioutil.TempDir(werf.GetTmpDir(), prefix)
	if err != nil {
		return "", err
	}

	if runtime.GOOS == "darwin" {
		dir, err := filepath.EvalSymlinks(newDir)
		if err != nil {
			return "", fmt.Errorf("eval symlink %s failed: %s", newDir, err)
		}
		newDir = dir
	}

	return newDir, nil
}

func CreateProjectDir() (string, error) {
	newDir, err := newTmpDir("werf-project-data-")
	if err != nil {
		return "", err
	}

	if err := registerCreatedDir(newDir, filepath.Join(GetCreatedTmpDirs(), projectsDir)); err != nil {
		os.RemoveAll(newDir)
		return "", err
	}

	shouldRunGC, err := checkShouldRunGC()
	if err != nil {
		return "", err
	}

	if shouldRunGC {
		err := lock.WithLock("gc", lock.LockOptions{}, GC)
		if err != nil {
			return "", fmt.Errorf("GC failed: %s", err)
		}
	}

	return newDir, nil
}

func ReleaseProjectDir(dir string) error {
	return releaseDir(dir, filepath.Join(GetCreatedTmpDirs(), projectsDir), filepath.Join(GetReleasedTmpDirs(), projectsDir))
}

func CreateDockerConfigDir(fromDockerConfig string) (string, error) {
	newDir, err := newTmpDir("werf-docker-config-")
	if err != nil {
		return "", err
	}

	if _, err := os.Stat(fromDockerConfig); !os.IsNotExist(err) {
		err := copy.Copy(fromDockerConfig, newDir)
		if err != nil {
			return "", fmt.Errorf("unable to copy %s to %s: %s", fromDockerConfig, newDir, err)
		}
	}

	if err := registerCreatedDir(newDir, filepath.Join(GetCreatedTmpDirs(), dockerConfigsDir)); err != nil {
		os.RemoveAll(newDir)
		return "", err
	}

	shouldRunGC, err := checkShouldRunGC()
	if err != nil {
		return "", err
	}

	if shouldRunGC {
		err := lock.WithLock("gc", lock.LockOptions{}, GC)
		if err != nil {
			return "", fmt.Errorf("GC failed: %s", err)
		}
	}

	return newDir, nil
}

func ReleaseDockerConfigDir(dir string) error {
	return releaseDir(dir, filepath.Join(GetCreatedTmpDirs(), dockerConfigsDir), filepath.Join(GetReleasedTmpDirs(), dockerConfigsDir))
}

type DirDesc struct {
	FileInfo os.FileInfo
	LinkPath string
}

func getDirsDescs(dir string) ([]*DirDesc, error) {
	var res []*DirDesc

	if _, err := os.Stat(dir); !os.IsNotExist(err) {
		infos, err := ioutil.ReadDir(dir)
		if err != nil {
			return nil, fmt.Errorf("unable to list dirs in %s: %s", dir, err)
		}

		for _, info := range infos {
			res = append(res, &DirDesc{FileInfo: info, LinkPath: filepath.Join(dir, info.Name())})
		}
	}

	return res, nil
}

func getReleasedDirsToRemove(releasedDirs []*DirDesc) ([]string, error) {
	var res []string

	for _, desc := range releasedDirs {
		origDir, err := os.Readlink(desc.LinkPath)
		if err != nil {
			return nil, fmt.Errorf("unable to read link %s: %s", desc.LinkPath, err)
		}
		res = append(res, origDir)
	}

	return res, nil
}

func getCreatedDirsToRemove(createdDirs []*DirDesc) ([]string, error) {
	var res []string

	now := time.Now()
	for _, desc := range createdDirs {
		if now.Sub(desc.FileInfo.ModTime()) < 2*time.Hour {
			continue
		}

		origDir, err := os.Readlink(desc.LinkPath)
		if err != nil {
			return nil, fmt.Errorf("unable to read link %s: %s", desc.LinkPath, err)
		}

		res = append(res, origDir)
	}

	return res, nil
}

func GC() error {
	logger.LogInfoF("Running GC\n")

	releasedProjectsDescs, err := getDirsDescs(filepath.Join(GetReleasedTmpDirs(), projectsDir))
	if err != nil {
		return fmt.Errorf("unable to get released tmp projects dirs: %s", err)
	}

	createdProjectsDescs, err := getDirsDescs(filepath.Join(GetCreatedTmpDirs(), projectsDir))
	if err != nil {
		return fmt.Errorf("unable to get created tmp projects dirs: %s", err)
	}

	releasedDockerConfigsDescs, err := getDirsDescs(filepath.Join(GetReleasedTmpDirs(), dockerConfigsDir))
	if err != nil {
		return fmt.Errorf("unable to get released tmp docker configs dirs: %s", err)
	}

	createdDockerConfigsDescs, err := getDirsDescs(filepath.Join(GetCreatedTmpDirs(), dockerConfigsDir))
	if err != nil {
		return fmt.Errorf("unable to get created tmp docker configs dirs: %s", err)
	}

	var dirs []string

	projectsToRemove := []string{}
	dockerConfigsToRemove := []string{}

	dirs, err = getReleasedDirsToRemove(releasedProjectsDescs)
	if err != nil {
		return fmt.Errorf("unable to get released tmp projects dirs to remove: %s", err)
	}
	projectsToRemove = append(projectsToRemove, dirs...)

	dirs, err = getCreatedDirsToRemove(createdProjectsDescs)
	if err != nil {
		return fmt.Errorf("unable to get created tmp projects dirs to remove: %s", err)
	}
	projectsToRemove = append(projectsToRemove, dirs...)

	dirs, err = getReleasedDirsToRemove(releasedDockerConfigsDescs)
	if err != nil {
		return fmt.Errorf("unable to get released tmp docker configs dirs to remove: %s", err)
	}
	dockerConfigsToRemove = append(dockerConfigsToRemove, dirs...)

	dirs, err = getCreatedDirsToRemove(createdDockerConfigsDescs)
	if err != nil {
		return fmt.Errorf("unable to get created tmp docker configs dirs to remove: %s", err)
	}
	dockerConfigsToRemove = append(dockerConfigsToRemove, dirs...)

	var removeErrors []error

	if len(projectsToRemove) > 0 {
		if err := removeProjectDirs(projectsToRemove); err != nil {
			removeErrors = append(removeErrors, fmt.Errorf("unable to remove tmp projects dirs %s: %s", strings.Join(projectsToRemove, ", "), err))
		}
	}

	for _, dir := range dockerConfigsToRemove {
		err := os.RemoveAll(dir)
		if err != nil {
			removeErrors = append(removeErrors, fmt.Errorf("unable to remove %s: %s", dir, err))
		}
	}

	for _, descs := range [][]*DirDesc{
		releasedProjectsDescs, releasedDockerConfigsDescs,
		createdProjectsDescs, createdDockerConfigsDescs,
	} {
		for _, desc := range descs {
			if err := os.Remove(desc.LinkPath); err != nil {
				removeErrors = append(removeErrors, fmt.Errorf("unable to remove %s: %s", desc.LinkPath, err))
			}
		}
	}

	return nil
}

func Purge() error {
	tmpFiles, err := ioutil.ReadDir(werf.GetTmpDir())
	if err != nil {
		return fmt.Errorf("unable to list tmp files in %s: %s", werf.GetTmpDir(), err)
	}

	filesToRemove := []string{}
	for _, finfo := range tmpFiles {
		if strings.HasPrefix(finfo.Name(), "werf") {
			filesToRemove = append(filesToRemove, filepath.Join(werf.GetTmpDir(), finfo.Name()))
		}
	}

	for _, file := range filesToRemove {
		err := os.RemoveAll(file)
		if err != nil {
			logger.LogErrorF("WARNING: unable to remove %s: %s\n", file, err)
		}
	}

	return nil
}

func removeProjectDirs(dirs []string) error {
	toolchainContainerName, err := dappdeps.ToolchainContainer()
	if err != nil {
		return err
	}

	args := []string{
		"--rm",
		"--volumes-from", toolchainContainerName,
		"--volume", fmt.Sprintf("%s:%s", werf.GetTmpDir(), werf.GetTmpDir()),
		dappdeps.BaseImageName(),
		dappdeps.RmBinPath(), "-rf",
	}

	args = append(args, dirs...)

	return docker.CliRun(args...)
}
<commit_msg>[way2alpha13] Docker configs gc and permissions fixed<commit_after>package tmp_manager

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/flant/werf/pkg/dappdeps"
	"github.com/flant/werf/pkg/docker"
	"github.com/flant/werf/pkg/lock"
	"github.com/flant/werf/pkg/logger"
	"github.com/flant/werf/pkg/werf"
	"github.com/otiai10/copy"
)

const (
	projectsDir      = "projects"
	dockerConfigsDir = "docker_configs"
)

func GetCreatedTmpDirs() string {
	return filepath.Join(werf.GetServiceDir(), "tmp", "created")
}

func GetReleasedTmpDirs() string {
	return filepath.Join(werf.GetServiceDir(), "tmp", "released")
}

func registerCreatedDir(newDir, createdDirs string) error {
	if err := os.MkdirAll(createdDirs, os.ModePerm); err != nil {
		return fmt.Errorf("unable to create dir %s: %s", createdDirs, err)
	}

	createdDir := filepath.Join(createdDirs, filepath.Base(newDir))
	if err := os.Symlink(newDir, createdDir); err != nil {
		return err
	}

	return nil
}

func releaseDir(dir, createdDirs, releasedDirs string) error {
	if err := os.MkdirAll(releasedDirs, os.ModePerm); err != nil {
		return fmt.Errorf("unable to create dir %s: %s", releaseDir, err)
	}

	releasedDir := filepath.Join(releasedDirs, filepath.Base(dir))
	if err := os.Symlink(dir, releasedDir); err != nil {
		return err
	}

	createdDir := filepath.Join(createdDirs, filepath.Base(dir))
	if err := os.Remove(createdDir); err != nil {
		return err
	}

	return nil
}

func checkShouldRunGC() (bool, error) {
	releasedProjectsDir := filepath.Join(GetReleasedTmpDirs(), projectsDir)
	if _, err := os.Stat(releasedProjectsDir); !os.IsNotExist(err) {
		var err error
		releasedProjectsDirs, err := ioutil.ReadDir(releasedProjectsDir)
		if err != nil {
			return false, fmt.Errorf("unable to list released projects tmp dirs in %s: %s", releasedProjectsDir, err)
		}

		if len(releasedProjectsDirs) > 50 {
			return true, nil
		}
	}

	createdDockerConfigsDir := filepath.Join(GetCreatedTmpDirs(), dockerConfigsDir)
	if _, err := os.Stat(createdDockerConfigsDir); !os.IsNotExist(err) {
		var err error
		createdDockerConfigsDirs, err := ioutil.ReadDir(createdDockerConfigsDir)
		if err != nil {
			return false, fmt.Errorf("unable to list released docker configs tmp dirs in %s: %s", createdDockerConfigsDir, err)
		}

		now := time.Now()
		for _, info := range createdDockerConfigsDirs {
			if now.Sub(info.ModTime()) > 24*time.Hour {
				return true, nil
			}
		}
	}

	return false, nil
}

func newTmpDir(prefix string) (string, error) {
	newDir, err := ioutil.TempDir(werf.GetTmpDir(), prefix)
	if err != nil {
		return "", err
	}

	if runtime.GOOS == "darwin" {
		dir, err := filepath.EvalSymlinks(newDir)
		if err != nil {
			return "", fmt.Errorf("eval symlink %s failed: %s", newDir, err)
		}
		newDir = dir
	}

	return newDir, nil
}

func CreateProjectDir() (string, error) {
	newDir, err := newTmpDir("werf-project-data-")
	if err != nil {
		return "", err
	}

	if err := registerCreatedDir(newDir, filepath.Join(GetCreatedTmpDirs(), projectsDir)); err != nil {
		os.RemoveAll(newDir)
		return "", err
	}

	shouldRunGC, err := checkShouldRunGC()
	if err != nil {
		return "", err
	}

	if shouldRunGC {
		err := lock.WithLock("gc", lock.LockOptions{}, GC)
		if err != nil {
			return "", fmt.Errorf("GC failed: %s", err)
		}
	}

	return newDir, nil
}

func ReleaseProjectDir(dir string) error {
	return releaseDir(dir, filepath.Join(GetCreatedTmpDirs(), projectsDir), filepath.Join(GetReleasedTmpDirs(), projectsDir))
}

func CreateDockerConfigDir(fromDockerConfig string) (string, error) {
	newDir, err := newTmpDir("werf-docker-config-")
	if err != nil {
		return "", err
	}

	if err := os.Chmod(newDir, 0700); err != nil {
		return "", err
	}

	if _, err := os.Stat(fromDockerConfig); !os.IsNotExist(err) {
		err := copy.Copy(fromDockerConfig, newDir)
		if err != nil {
			return "", fmt.Errorf("unable to copy %s to %s: %s", fromDockerConfig, newDir, err)
		}
	}

	if err := registerCreatedDir(newDir, filepath.Join(GetCreatedTmpDirs(), dockerConfigsDir)); err != nil {
		os.RemoveAll(newDir)
		return "", err
	}

	shouldRunGC, err := checkShouldRunGC()
	if err != nil {
		return "", err
	}

	if shouldRunGC {
		err := lock.WithLock("gc", lock.LockOptions{}, GC)
		if err != nil {
			return "", fmt.Errorf("GC failed: %s", err)
		}
	}

	return newDir, nil
}

type DirDesc struct {
	FileInfo os.FileInfo
	LinkPath string
}

func getDirsDescs(dir string) ([]*DirDesc, error) {
	var res []*DirDesc

	if _, err := os.Stat(dir); !os.IsNotExist(err) {
		infos, err := ioutil.ReadDir(dir)
		if err != nil {
			return nil, fmt.Errorf("unable to list dirs in %s: %s", dir, err)
		}

		for _, info := range infos {
			res = append(res, &DirDesc{FileInfo: info, LinkPath: filepath.Join(dir, info.Name())})
		}
	}

	return res, nil
}

func getReleasedDirsToRemove(releasedDirs []*DirDesc) ([]string, error) {
	var res []string

	for _, desc := range releasedDirs {
		origDir, err := os.Readlink(desc.LinkPath)
		if err != nil {
			return nil, fmt.Errorf("unable to read link %s: %s", desc.LinkPath, err)
		}
		res = append(res, origDir, desc.LinkPath)
	}

	return res, nil
}

func getCreatedDirsToRemove(createdDirs []*DirDesc) ([]string, error) {
	var res []string

	now := time.Now()
	for _, desc := range createdDirs {
		if now.Sub(desc.FileInfo.ModTime()) < 2*time.Hour {
			continue
		}

		origDir, err := os.Readlink(desc.LinkPath)
		if err != nil {
			return nil, fmt.Errorf("unable to read link %s: %s", desc.LinkPath, err)
		}

		res = append(res, origDir, desc.LinkPath)
	}

	return res, nil
}

func GC() error {
	logger.LogInfoF("Running GC\n")

	releasedProjectsDescs, err := getDirsDescs(filepath.Join(GetReleasedTmpDirs(), projectsDir))
	if err != nil {
		return fmt.Errorf("unable to get released tmp projects dirs: %s", err)
	}

	createdProjectsDescs, err := getDirsDescs(filepath.Join(GetCreatedTmpDirs(), projectsDir))
	if err != nil {
		return fmt.Errorf("unable to get created tmp projects dirs: %s", err)
	}

	createdDockerConfigsDescs, err := getDirsDescs(filepath.Join(GetCreatedTmpDirs(), dockerConfigsDir))
	if err != nil {
		return fmt.Errorf("unable to get created tmp docker configs dirs: %s", err)
	}

	var dirs []string

	projectsToRemove := []string{}
	dockerConfigsToRemove := []string{}

	dirs, err = getReleasedDirsToRemove(releasedProjectsDescs)
	if err != nil {
		return fmt.Errorf("unable to get released tmp projects dirs to remove: %s", err)
	}
	projectsToRemove = append(projectsToRemove, dirs...)

	dirs, err = getCreatedDirsToRemove(createdProjectsDescs)
	if err != nil {
		return fmt.Errorf("unable to get created tmp projects dirs to remove: %s", err)
	}
	projectsToRemove = append(projectsToRemove, dirs...)

	dirs, err = getCreatedDirsToRemove(createdDockerConfigsDescs)
	if err != nil {
		return fmt.Errorf("unable to get created tmp docker configs dirs to remove: %s", err)
	}
	dockerConfigsToRemove = append(dockerConfigsToRemove, dirs...)

	var removeErrors []error

	if len(projectsToRemove) > 0 {
		if err := removeProjectDirs(projectsToRemove); err != nil {
			removeErrors = append(removeErrors, fmt.Errorf("unable to remove tmp projects dirs %s: %s", strings.Join(projectsToRemove, ", "), err))
		}
	}

	for _, dir := range dockerConfigsToRemove {
		err := os.RemoveAll(dir)
		if err != nil {
			removeErrors = append(removeErrors, fmt.Errorf("unable to remove %s: %s", dir, err))
		}
	}

	if len(removeErrors) > 0 {
		msg := ""
		for _, err := range removeErrors {
			msg += fmt.Sprintf("%s\n", err)
		}
		return fmt.Errorf("%s", msg)
	}

	return nil
}

func Purge() error {
	tmpFiles, err := ioutil.ReadDir(werf.GetTmpDir())
	if err != nil {
		return fmt.Errorf("unable to list tmp files in %s: %s", werf.GetTmpDir(), err)
	}

	filesToRemove := []string{}
	for _, finfo := range tmpFiles {
		if strings.HasPrefix(finfo.Name(), "werf") {
			filesToRemove = append(filesToRemove, filepath.Join(werf.GetTmpDir(), finfo.Name()))
		}
	}

	for _, file := range filesToRemove {
		err := os.RemoveAll(file)
		if err != nil {
			logger.LogErrorF("WARNING: unable to remove %s: %s\n", file, err)
		}
	}

	return nil
}

func removeProjectDirs(dirs []string) error {
	toolchainContainerName, err := dappdeps.ToolchainContainer()
	if err != nil {
		return err
	}

	args := []string{
		"--rm",
		"--volumes-from", toolchainContainerName,
		"--volume", fmt.Sprintf("%s:%s", werf.GetTmpDir(), werf.GetTmpDir()),
		dappdeps.BaseImageName(),
		dappdeps.RmBinPath(), "-rf",
	}

	args = append(args, dirs...)

	return docker.CliRun(args...)
}
<|endoftext|>


<commit_before>package input

import (
	"bytes"
	"errors"
	"strconv"
	"sync"
)

const (
	LenBuffEnd = ":"
	ValBuffEnd = ";"
	NoResult   = false
)

var (
	err        error
	mutex      *sync.Mutex = &sync.Mutex{}
	brokenErr              = errors.New("broken")
	lenIncErr              = errors.New("length-buffer-incomplete")
	lenInvErr              = errors.New("length-buffer-invalid-byte")
	lenConvErr             = errors.New("length-buffer-conversion-error")
	valIncErr              = errors.New("value-buffer-incomplete")
)

// A NetstrDelimiter detects when message lines start.
type NetstrDelimiter struct {
	Result      string
	lenBuff     bytes.Buffer
	valBuff     bytes.Buffer
	valBuffLen  int
	valBuffMode bool
	ignoreMode  bool
	brokenMode  bool
}

// NewNetstrDelimiter returns an initialized NetstrDelimiter.
func NewNetstrDelimiter() *NetstrDelimiter {
	return &NetstrDelimiter{
		lenBuff: *bytes.NewBuffer([]byte{}),
		valBuff: *bytes.NewBuffer([]byte{}),
	}
}

// Push the given byte into a buffer, return when a new result is available,
// as well as the first occurring error (if any occurred).
func (d *NetstrDelimiter) Push(b byte) (bool, error) {
	if d.brokenMode {
		return NoResult, errors.New("broken")
	}
	return d.processByte(b)
}

// Reset the NetstrDelimiter instance to its initial state.
func (d *NetstrDelimiter) Reset() {
	mutex.Lock()
	d.useLenBuff()
	mutex.Unlock()
}

// processByte checks if a byte must be processed as "length byte" or as "value byte".
func (d *NetstrDelimiter) processByte(b byte) (bool, error) {
	if d.valBuffMode {
		return d.processValByte(b)
	}
	return d.processLenByte(b)
}

// processLenBytes writes the passed byte to the "length buffer",
// unless the passed byte is the end of the "length buffer".
func (d *NetstrDelimiter) processLenByte(b byte) (bool, error) {
	if b == LenBuffEnd[0] {
		return NoResult, d.useValBuff()
	}
	if d.checkLenByte(b) {
		if err = d.lenBuff.WriteByte(b); err != nil {
			d.brokenMode = true
			return NoResult, lenIncErr
		}
		return NoResult, nil
	}
	d.brokenMode = true
	return NoResult, lenInvErr
}

// checkLenByte checks that the current byte is a digit.
func (d *NetstrDelimiter) checkLenByte(b byte) bool {
	for i := 0; i < 10; i++ {
		if strconv.Itoa(i)[0] == b {
			return true
		}
	}
	return false
}

// processValByte writess the passed byte to the "value buffer",
// unless the "value buffer length" is equal to 0.
func (d *NetstrDelimiter) processValByte(b byte) (bool, error) {
	if d.valBuffLen == 0 {
		d.useLenBuff()
		return true, nil
	}
	d.valBuffLen--
	if d.ignoreMode {
		return NoResult, nil
	}
	// If an error occurs, while writing to the buffer,
	// the current "value buffer" gets ignored.
	if err = d.valBuff.WriteByte(b); err != nil {
		d.ignoreMode = true
		return NoResult, valIncErr
	}
	return NoResult, nil
}

// useLenBuff overwrites the old result and resets values.
func (d *NetstrDelimiter) useLenBuff() {
	if d.ignoreMode {
		d.Result = ""
		d.ignoreMode = false
	} else {
		d.Result = d.valBuff.String()
	}
	d.valBuff.Reset()
	d.valBuffMode = false
}

// useValBuff converts the "length buffer" value to an integer,
// representing the "value buffer length" and resets values.
func (d *NetstrDelimiter) useValBuff() error {
	if d.valBuffLen, err = strconv.Atoi(d.lenBuff.String()); err != nil {
		d.brokenMode = true
		return lenConvErr
	}
	d.lenBuff.Reset()
	d.valBuffMode = true
	return nil
}
<commit_msg>Better error naming<commit_after>package input

import (
	"bytes"
	"errors"
	"strconv"
	"sync"
)

const (
	LenBuffEnd = ":"
	ValBuffEnd = ";"
	NoResult   = false
)

var (
	err        error
	mutex      *sync.Mutex = &sync.Mutex{}
	errBroken              = errors.New("broken")
	errLenInc              = errors.New("length-buffer-incomplete")
	errLenInv              = errors.New("length-buffer-invalid-byte")
	errLenConv             = errors.New("length-buffer-conversion-error")
	errValInc              = errors.New("value-buffer-incomplete")
)

// A NetstrDelimiter detects when message lines start.
type NetstrDelimiter struct {
	Result      string
	lenBuff     bytes.Buffer
	valBuff     bytes.Buffer
	valBuffLen  int
	valBuffMode bool
	ignoreMode  bool
	brokenMode  bool
}

// NewNetstrDelimiter returns an initialized NetstrDelimiter.
func NewNetstrDelimiter() *NetstrDelimiter {
	return &NetstrDelimiter{
		lenBuff: *bytes.NewBuffer([]byte{}),
		valBuff: *bytes.NewBuffer([]byte{}),
	}
}

// Push the given byte into a buffer, return when a new result is available,
// as well as the first occurring error (if any occurred).
func (d *NetstrDelimiter) Push(b byte) (bool, error) {
	if d.brokenMode {
		return NoResult, errors.New("broken")
	}
	return d.processByte(b)
}

// Reset the NetstrDelimiter instance to its initial state.
func (d *NetstrDelimiter) Reset() {
	mutex.Lock()
	d.useLenBuff()
	mutex.Unlock()
}

// processByte checks if a byte must be processed as "length byte" or as "value byte".
func (d *NetstrDelimiter) processByte(b byte) (bool, error) {
	if d.valBuffMode {
		return d.processValByte(b)
	}
	return d.processLenByte(b)
}

// processLenBytes writes the passed byte to the "length buffer",
// unless the passed byte is the end of the "length buffer".
func (d *NetstrDelimiter) processLenByte(b byte) (bool, error) {
	if b == LenBuffEnd[0] {
		return NoResult, d.useValBuff()
	}
	if d.checkLenByte(b) {
		if err = d.lenBuff.WriteByte(b); err != nil {
			d.brokenMode = true
			return NoResult, errLenInc
		}
		return NoResult, nil
	}
	d.brokenMode = true
	return NoResult, errLenInv
}

// checkLenByte checks that the current byte is a digit.
func (d *NetstrDelimiter) checkLenByte(b byte) bool {
	for i := 0; i < 10; i++ {
		if strconv.Itoa(i)[0] == b {
			return true
		}
	}
	return false
}

// processValByte writess the passed byte to the "value buffer",
// unless the "value buffer length" is equal to 0.
func (d *NetstrDelimiter) processValByte(b byte) (bool, error) {
	if d.valBuffLen == 0 {
		d.useLenBuff()
		return true, nil
	}
	d.valBuffLen--
	if d.ignoreMode {
		return NoResult, nil
	}
	// If an error occurs, while writing to the buffer,
	// the current "value buffer" gets ignored.
	if err = d.valBuff.WriteByte(b); err != nil {
		d.ignoreMode = true
		return NoResult, errValInc
	}
	return NoResult, nil
}

// useLenBuff overwrites the old result and resets values.
func (d *NetstrDelimiter) useLenBuff() {
	if d.ignoreMode {
		d.Result = ""
		d.ignoreMode = false
	} else {
		d.Result = d.valBuff.String()
	}
	d.valBuff.Reset()
	d.valBuffMode = false
}

// useValBuff converts the "length buffer" value to an integer,
// representing the "value buffer length" and resets values.
func (d *NetstrDelimiter) useValBuff() error {
	if d.valBuffLen, err = strconv.Atoi(d.lenBuff.String()); err != nil {
		d.brokenMode = true
		return errLenConv
	}
	d.lenBuff.Reset()
	d.valBuffMode = true
	return nil
}
<|endoftext|>


<commit_before>package vitali

import (
    "testing"
    "net/http"
    "net/url"
    "net/http/httptest"
)

func TestNotFound(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{})
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusNotFound {
        t.Errorf("response code is %d", rr.Code)
    }
}

type Root struct {
    Ctx
}

func (c Root) Get() interface{} {
    return "root"
}

func TestOK(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/", Root{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "root" {
        t.Errorf("entity is `%s`", entity)
    }
}

func TestMethodNotAllowed(t *testing.T) {
    r := &http.Request{
        Method: "POST",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/", Root{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusMethodNotAllowed {
        t.Errorf("response code is %d", rr.Code)
    }
    allowed := rr.HeaderMap.Get("Allow")
    if allowed != "GET, HEAD" {
        t.Errorf("allow header is %s", allowed)
    }
}

func TestNotImplemented(t *testing.T) {
    r := &http.Request{
        Method: "WTF",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/", Root{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusNotImplemented {
        t.Errorf("response code is %d", rr.Code)
    }
}

type Something struct {
    Ctx
}

func (c Something) Get() interface{} {
    return c.PathParam("id1") + c.PathParam("id2")
}

func TestPathParam(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/foo/123/bar/456/something",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/foo/{id1}/bar/{id2}/something", Something{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "123456" {
        t.Errorf("entity is `%s`", entity)
    }
}

type NeedAuth struct {
    Ctx
    Perm
}

func (c NeedAuth) Get() interface{} {
    return c.Username
}

func (c NeedAuth) Post() interface{} {
    return "public post"
}

func (c NeedAuth) Delete() interface{} {
    return c.Username
}

func TestNeedAuth(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/needauth",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/needauth", NeedAuth{
            Perm: Perm{"GET": AUTHENTICATED, "POST": PUBLIC, "*": AUTHENTICATED},
        }},
    })
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusUnauthorized {
        t.Errorf("response code is %d", rr.Code)
    }

    r.Method = "POST"
    rr = httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "public post" {
        t.Errorf("entity is `%s`", entity)
    }

    r.Method = "DELETE"
    rr = httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusUnauthorized {
        t.Errorf("response code is %d", rr.Code)
    }
}

type Auther struct {
}

func (c Auther) User(r *http.Request) string {
    return "bob"
}

func (c Auther) AuthHeader(r *http.Request) string {
    return `Basic realm="test"`
}

func TestAuthed(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/needauth",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/needauth", NeedAuth{
            Perm: Perm{"GET": AUTHENTICATED, "POST": PUBLIC, "*": AUTHENTICATED},
        }},
    })
    webapp.UserProvider = Auther{}
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "bob" {
        t.Errorf("user is `%s`", entity)
    }
}

type Panikr struct {
    Ctx
}

func (c Panikr) Get() interface{} {
    panic("panic!!")
    return ""
}

func TestRecoverPanic(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/panic",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/panic", Panikr{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusInternalServerError {
        t.Errorf("response code is %d", rr.Code)
    }
}
<commit_msg>add more tests<commit_after>package vitali

import (
    "testing"
    "net/http"
    "net/url"
    "net/http/httptest"
)

func TestNotFound(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{})
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusNotFound {
        t.Errorf("response code is %d", rr.Code)
    }
}

type Root struct {
    Ctx
}

func (c Root) Get() interface{} {
    return "root"
}

func TestOK(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/", Root{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "root" {
        t.Errorf("entity is `%s`", entity)
    }
}

type Info struct {
    Ctx
    Provided string
    Provided2 string
}

func (c Info) Get() interface{} {
    return c.Provided + c.Provided2
}

func TestProvided(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/info",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/info", Info{
            Provided: "foo",
            Provided2: "bar",
            }},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "foobar" {
        t.Errorf("entity is `%s`", entity)
    }
}

func TestMethodNotAllowed(t *testing.T) {
    r := &http.Request{
        Method: "POST",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/", Root{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusMethodNotAllowed {
        t.Errorf("response code is %d", rr.Code)
    }
    allowed := rr.HeaderMap.Get("Allow")
    if allowed != "GET, HEAD" {
        t.Errorf("allow header is %s", allowed)
    }
}

func TestNotImplemented(t *testing.T) {
    r := &http.Request{
        Method: "WTF",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/", Root{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusNotImplemented {
        t.Errorf("response code is %d", rr.Code)
    }
}

type Something struct {
    Ctx
}

func (c Something) Get() interface{} {
    return c.PathParam("id1") + c.PathParam("id2")
}

func TestPathParam(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/foo/123/bar/456/something",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/foo/{id1}/bar/{id2}/something", Something{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "123456" {
        t.Errorf("entity is `%s`", entity)
    }
}

type Something2 struct {
    Ctx
}

func (c Something2) Get() interface{} {
    return c.Param("id")
}

func TestForm(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/something2",
        },
        Form: make(url.Values),
    }
    r.Form.Add("id", "5566")
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/something2", Something2{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "5566" {
        t.Errorf("id is `%s`", entity)
    }
}

type NeedAuth struct {
    Ctx
    Perm
}

func (c NeedAuth) Get() interface{} {
    return c.Username
}

func (c NeedAuth) Post() interface{} {
    return "public post"
}

func (c NeedAuth) Delete() interface{} {
    return c.Username
}

func TestNeedAuth(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/needauth",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/needauth", NeedAuth{
            Perm: Perm{"GET": AUTHENTICATED, "POST": PUBLIC, "*": AUTHENTICATED},
        }},
    })
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusUnauthorized {
        t.Errorf("response code is %d", rr.Code)
    }

    r.Method = "POST"
    rr = httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "public post" {
        t.Errorf("entity is `%s`", entity)
    }

    r.Method = "DELETE"
    rr = httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusUnauthorized {
        t.Errorf("response code is %d", rr.Code)
    }
}

type Auther struct {
}

func (c Auther) User(r *http.Request) string {
    return "bob"
}

func (c Auther) AuthHeader(r *http.Request) string {
    return `Basic realm="test"`
}

func TestAuthed(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/needauth",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/needauth", NeedAuth{
            Perm: Perm{"GET": AUTHENTICATED, "POST": PUBLIC, "*": AUTHENTICATED},
        }},
    })
    webapp.UserProvider = Auther{}
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "bob" {
        t.Errorf("user is `%s`", entity)
    }
}

type Bad struct {
    Ctx
}

func (c Bad) Get() interface{} {
    return c.BadRequest("reason")
}

func TestBadRequest(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/bad",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/bad", Bad{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusBadRequest {
        t.Errorf("response code is %d", rr.Code)
    }
    entity := rr.Body.String()
    if entity != "reason\n" {
        t.Errorf("entity is `%s`", entity)
    }
}

type AcceptSomething struct {
    Ctx
    Accept
}

func (c AcceptSomething) Post() interface{} {
    return "success"
}

func TestAccept(t *testing.T) {
    r := &http.Request{
        Method: "POST",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/accept",
        },
        Header: make(http.Header),
    }
    webapp := CreateWebApp([]RouteRule{
        {"/accept", AcceptSomething{
            Accept: Accept{"POST": MediaTypes{"application/json", "application/xml"}},
        }},
    })

    rr := httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusUnsupportedMediaType {
        t.Errorf("response code is %d", rr.Code)
    }

    r.Header.Set("Content-Type", "application/json")
    rr = httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }

    r.Header.Set("Content-Type", "application/xml")
    rr = httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusOK {
        t.Errorf("response code is %d", rr.Code)
    }

    r.Header.Set("Content-Type", "text/plain")
    rr = httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusUnsupportedMediaType {
        t.Errorf("response code is %d", rr.Code)
    }
}

type Redirects struct {
    Ctx
}

func (c Redirects) Get() interface{} {
    switch c.Param("type") {
    case "found":
        return c.Found("/found")
    case "seeother":
        return c.SeeOther("/seeother")
    }
    return ""
}

func TestRedirects(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/redirects",
        },
        Form: make(url.Values),
    }
    webapp := CreateWebApp([]RouteRule{
        {"/redirects", Redirects{}},
    })

    r.Form.Set("type", "found")
    rr := httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusFound {
        t.Errorf("response code is %d", rr.Code)
    }
    location := rr.Header().Get("Location")
    if location != "/found" {
        t.Errorf("location is `%s`", location)
    }

    r.Form.Set("type", "seeother")
    rr = httptest.NewRecorder()
    webapp.ServeHTTP(rr, r)
    if rr.Code != http.StatusSeeOther {
        t.Errorf("response code is %d", rr.Code)
    }
    location = rr.Header().Get("Location")
    if location != "/seeother" {
        t.Errorf("location is `%s`", location)
    }
}

type Panikr struct {
    Ctx
}

func (c Panikr) Get() interface{} {
    panic("panic!!")
    return ""
}

func TestRecoverPanic(t *testing.T) {
    r := &http.Request{
        Method: "GET",
        Host:   "lunastorm.tw",
        URL: &url.URL{
            Path: "/panic",
        },
    }
    rr := httptest.NewRecorder()
    webapp := CreateWebApp([]RouteRule{
        {"/panic", Panikr{}},
    })
    webapp.ServeHTTP(rr, r)

    if rr.Code != http.StatusInternalServerError {
        t.Errorf("response code is %d", rr.Code)
    }
}
<|endoftext|>


<commit_before>package helpers

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"

	"code.cloudfoundry.org/ykk"

	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

type Package struct {
	Checksum string
}

func (p *Package) UnmarshalJSON(data []byte) error {
	var ccPackage struct {
		Data struct {
			Checksum struct {
				Value string `json:"value"`
			} `json:"checksum"`
		} `json:"data"`
	}

	if err := json.Unmarshal(data, &ccPackage); err != nil {
		return err
	}

	p.Checksum = ccPackage.Data.Checksum.Value

	return nil
}

func VerifyAppPackageContentsV3(appName string, files ...string) {
	tmpZipFilepath, err := ioutil.TempFile("", "")
	defer os.Remove(tmpZipFilepath.Name())
	Expect(err).ToNot(HaveOccurred())

	downloadFirstAppPackage(appName, tmpZipFilepath.Name())
	Expect(err).ToNot(HaveOccurred())

	info, err := tmpZipFilepath.Stat()
	Expect(err).ToNot(HaveOccurred())
	reader, err := ykk.NewReader(tmpZipFilepath, info.Size())
	Expect(err).ToNot(HaveOccurred())

	seenFiles := []string{}
	for _, file := range reader.File {
		seenFiles = append(seenFiles, file.Name)
	}

	Expect(seenFiles).To(ConsistOf(files))
}

func getFirstAppPackageGuid(appName string) string {
	session := CF("v3-packages", appName)
	Eventually(session).Should(Exit(0))

	myRegexp, err := regexp.Compile(GUIDRegex)
	Expect(err).NotTo(HaveOccurred())
	matches := myRegexp.FindAll(session.Out.Contents(), -1)
	packageGUID := matches[3]

	return string(packageGUID)
}

func downloadFirstAppPackage(appName string, tmpZipFilepath string) {
	appGUID := getFirstAppPackageGuid(appName)
	session := CF("curl", fmt.Sprintf("/v3/packages/%s/download", appGUID), "--output", tmpZipFilepath)
	Eventually(session).Should(Exit(0))
}

func VerifyAppPackageContentsV2(appName string, files ...string) {
	tmpZipFilepath, err := ioutil.TempFile("", "")
	defer os.Remove(tmpZipFilepath.Name())
	Expect(err).ToNot(HaveOccurred())

	downloadFirstAppBits(appName, tmpZipFilepath.Name())
	Expect(err).ToNot(HaveOccurred())

	info, err := tmpZipFilepath.Stat()
	Expect(err).ToNot(HaveOccurred())
	reader, err := ykk.NewReader(tmpZipFilepath, info.Size())
	Expect(err).ToNot(HaveOccurred())

	seenFiles := []string{}
	for _, file := range reader.File {
		seenFiles = append(seenFiles, file.Name)
	}

	Expect(seenFiles).To(ConsistOf(files))
}

func downloadFirstAppBits(appName string, tmpZipFilepath string) {
	appGUID := AppGUID(appName)
	session := CF("curl", fmt.Sprintf("/v2/apps/%s/download", appGUID), "--output", tmpZipFilepath)
	Eventually(session).Should(Exit(0))
}
<commit_msg>Remove unsused helper package struct<commit_after>package helpers

import (
	"fmt"
	"io/ioutil"
	"os"
	"regexp"

	"code.cloudfoundry.org/ykk"

	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"
)

func VerifyAppPackageContentsV3(appName string, files ...string) {
	tmpZipFilepath, err := ioutil.TempFile("", "")
	defer os.Remove(tmpZipFilepath.Name())
	Expect(err).ToNot(HaveOccurred())

	downloadFirstAppPackage(appName, tmpZipFilepath.Name())
	Expect(err).ToNot(HaveOccurred())

	info, err := tmpZipFilepath.Stat()
	Expect(err).ToNot(HaveOccurred())
	reader, err := ykk.NewReader(tmpZipFilepath, info.Size())
	Expect(err).ToNot(HaveOccurred())

	seenFiles := []string{}
	for _, file := range reader.File {
		seenFiles = append(seenFiles, file.Name)
	}

	Expect(seenFiles).To(ConsistOf(files))
}

func getFirstAppPackageGuid(appName string) string {
	session := CF("v3-packages", appName)
	Eventually(session).Should(Exit(0))

	myRegexp, err := regexp.Compile(GUIDRegex)
	Expect(err).NotTo(HaveOccurred())
	matches := myRegexp.FindAll(session.Out.Contents(), -1)
	packageGUID := matches[3]

	return string(packageGUID)
}

func downloadFirstAppPackage(appName string, tmpZipFilepath string) {
	appGUID := getFirstAppPackageGuid(appName)
	session := CF("curl", fmt.Sprintf("/v3/packages/%s/download", appGUID), "--output", tmpZipFilepath)
	Eventually(session).Should(Exit(0))
}

func VerifyAppPackageContentsV2(appName string, files ...string) {
	tmpZipFilepath, err := ioutil.TempFile("", "")
	defer os.Remove(tmpZipFilepath.Name())
	Expect(err).ToNot(HaveOccurred())

	downloadFirstAppBits(appName, tmpZipFilepath.Name())
	Expect(err).ToNot(HaveOccurred())

	info, err := tmpZipFilepath.Stat()
	Expect(err).ToNot(HaveOccurred())
	reader, err := ykk.NewReader(tmpZipFilepath, info.Size())
	Expect(err).ToNot(HaveOccurred())

	seenFiles := []string{}
	for _, file := range reader.File {
		seenFiles = append(seenFiles, file.Name)
	}

	Expect(seenFiles).To(ConsistOf(files))
}

func downloadFirstAppBits(appName string, tmpZipFilepath string) {
	appGUID := AppGUID(appName)
	session := CF("curl", fmt.Sprintf("/v2/apps/%s/download", appGUID), "--output", tmpZipFilepath)
	Eventually(session).Should(Exit(0))
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 net

import (
	"crypto/tls"
	"net"
	"net/http"
	"net/url"
	"os"
	"reflect"
	"testing"

	"k8s.io/kubernetes/pkg/util/sets"
)

func TestCloneTLSConfig(t *testing.T) {
	expected := sets.NewString(
		// These fields are copied in CloneTLSConfig
		"Rand",
		"Time",
		"Certificates",
		"RootCAs",
		"NextProtos",
		"ServerName",
		"InsecureSkipVerify",
		"CipherSuites",
		"PreferServerCipherSuites",
		"MinVersion",
		"MaxVersion",
		"CurvePreferences",
		"NameToCertificate",
		"GetCertificate",
		"ClientAuth",
		"ClientCAs",
		"ClientSessionCache",

		// These fields are not copied
		"SessionTicketsDisabled",
		"SessionTicketKey",
		"DynamicRecordSizingDisabled",
		"Renegotiation",

		// These fields are unexported
		"serverInitOnce",
		"mutex",
		"sessionTicketKeys",
	)

	fields := sets.NewString()
	structType := reflect.TypeOf(tls.Config{})
	for i := 0; i < structType.NumField(); i++ {
		fields.Insert(structType.Field(i).Name)
	}

	if missing := expected.Difference(fields); len(missing) > 0 {
		t.Errorf("Expected fields that were not seen in http.Transport: %v", missing.List())
	}
	if extra := fields.Difference(expected); len(extra) > 0 {
		t.Errorf("New fields seen in http.Transport: %v\nAdd to CopyClientTLSConfig if client-relevant, then add to expected list in TestCopyClientTLSConfig", extra.List())
	}
}

func TestGetClientIP(t *testing.T) {
	ipString := "10.0.0.1"
	ip := net.ParseIP(ipString)
	invalidIPString := "invalidIPString"
	testCases := []struct {
		Request    http.Request
		ExpectedIP net.IP
	}{
		{
			Request: http.Request{},
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Real-Ip": {ipString},
				},
			},
			ExpectedIP: ip,
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Real-Ip": {invalidIPString},
				},
			},
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Forwarded-For": {ipString},
				},
			},
			ExpectedIP: ip,
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Forwarded-For": {invalidIPString},
				},
			},
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Forwarded-For": {invalidIPString + "," + ipString},
				},
			},
			ExpectedIP: ip,
		},
		{
			Request: http.Request{
				// RemoteAddr is in the form host:port
				RemoteAddr: ipString + ":1234",
			},
			ExpectedIP: ip,
		},
		{
			Request: http.Request{
				RemoteAddr: invalidIPString,
			},
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Forwarded-For": {invalidIPString},
				},
				// RemoteAddr is in the form host:port
				RemoteAddr: ipString,
			},
			ExpectedIP: ip,
		},
	}

	for i, test := range testCases {
		if a, e := GetClientIP(&test.Request), test.ExpectedIP; reflect.DeepEqual(e, a) != true {
			t.Fatalf("test case %d failed. expected: %v, actual: %v", i, e, a)
		}
	}
}

func TestProxierWithNoProxyCIDR(t *testing.T) {
	testCases := []struct {
		name    string
		noProxy string
		url     string

		expectedDelegated bool
	}{
		{
			name:              "no env",
			url:               "https://192.168.143.1/api",
			expectedDelegated: true,
		},
		{
			name:              "no cidr",
			noProxy:           "192.168.63.1",
			url:               "https://192.168.143.1/api",
			expectedDelegated: true,
		},
		{
			name:              "hostname",
			noProxy:           "192.168.63.0/24,192.168.143.0/24",
			url:               "https://my-hostname/api",
			expectedDelegated: true,
		},
		{
			name:              "match second cidr",
			noProxy:           "192.168.63.0/24,192.168.143.0/24",
			url:               "https://192.168.143.1/api",
			expectedDelegated: false,
		},
		{
			name:              "match second cidr with host:port",
			noProxy:           "192.168.63.0/24,192.168.143.0/24",
			url:               "https://192.168.143.1:8443/api",
			expectedDelegated: false,
		},
	}

	for _, test := range testCases {
		os.Setenv("NO_PROXY", test.noProxy)
		actualDelegated := false
		proxyFunc := NewProxierWithNoProxyCIDR(func(req *http.Request) (*url.URL, error) {
			actualDelegated = true
			return nil, nil
		})

		req, err := http.NewRequest("GET", test.url, nil)
		if err != nil {
			t.Errorf("%s: unexpected err: %v", test.name, err)
			continue
		}
		if _, err := proxyFunc(req); err != nil {
			t.Errorf("%s: unexpected err: %v", test.name, err)
			continue
		}

		if test.expectedDelegated != actualDelegated {
			t.Errorf("%s: expected %v, got %v", test.name, test.expectedDelegated, actualDelegated)
			continue
		}
	}
}

type fakeTLSClientConfigHolder struct {
	called bool
}

func (f *fakeTLSClientConfigHolder) TLSClientConfig() *tls.Config {
	f.called = true
	return nil
}
func (f *fakeTLSClientConfigHolder) RoundTrip(*http.Request) (*http.Response, error) {
	return nil, nil
}

func TestTLSClientConfigHolder(t *testing.T) {
	rt := &fakeTLSClientConfigHolder{}
	TLSClientConfig(rt)

	if !rt.called {
		t.Errorf("didn't find tls config")
	}
}
<commit_msg>Add TLS conf for Go1.7<commit_after>/*
Copyright 2016 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 net

import (
	"crypto/tls"
	"net"
	"net/http"
	"net/url"
	"os"
	"reflect"
	"runtime"
	"strings"
	"testing"

	"k8s.io/kubernetes/pkg/util/sets"
)

func TestCloneTLSConfig(t *testing.T) {
	expected := sets.NewString(
		// These fields are copied in CloneTLSConfig
		"Rand",
		"Time",
		"Certificates",
		"RootCAs",
		"NextProtos",
		"ServerName",
		"InsecureSkipVerify",
		"CipherSuites",
		"PreferServerCipherSuites",
		"MinVersion",
		"MaxVersion",
		"CurvePreferences",
		"NameToCertificate",
		"GetCertificate",
		"ClientAuth",
		"ClientCAs",
		"ClientSessionCache",

		// These fields are not copied
		"SessionTicketsDisabled",
		"SessionTicketKey",

		// These fields are unexported
		"serverInitOnce",
		"mutex",
		"sessionTicketKeys",
	)

	// See #33936.
	if strings.HasPrefix(runtime.Version(), "go1.7") {
		expected.Insert("DynamicRecordSizingDisabled", "Renegotiation")
	}

	fields := sets.NewString()
	structType := reflect.TypeOf(tls.Config{})
	for i := 0; i < structType.NumField(); i++ {
		fields.Insert(structType.Field(i).Name)
	}

	if missing := expected.Difference(fields); len(missing) > 0 {
		t.Errorf("Expected fields that were not seen in http.Transport: %v", missing.List())
	}
	if extra := fields.Difference(expected); len(extra) > 0 {
		t.Errorf("New fields seen in http.Transport: %v\nAdd to CopyClientTLSConfig if client-relevant, then add to expected list in TestCopyClientTLSConfig", extra.List())
	}
}

func TestGetClientIP(t *testing.T) {
	ipString := "10.0.0.1"
	ip := net.ParseIP(ipString)
	invalidIPString := "invalidIPString"
	testCases := []struct {
		Request    http.Request
		ExpectedIP net.IP
	}{
		{
			Request: http.Request{},
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Real-Ip": {ipString},
				},
			},
			ExpectedIP: ip,
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Real-Ip": {invalidIPString},
				},
			},
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Forwarded-For": {ipString},
				},
			},
			ExpectedIP: ip,
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Forwarded-For": {invalidIPString},
				},
			},
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Forwarded-For": {invalidIPString + "," + ipString},
				},
			},
			ExpectedIP: ip,
		},
		{
			Request: http.Request{
				// RemoteAddr is in the form host:port
				RemoteAddr: ipString + ":1234",
			},
			ExpectedIP: ip,
		},
		{
			Request: http.Request{
				RemoteAddr: invalidIPString,
			},
		},
		{
			Request: http.Request{
				Header: map[string][]string{
					"X-Forwarded-For": {invalidIPString},
				},
				// RemoteAddr is in the form host:port
				RemoteAddr: ipString,
			},
			ExpectedIP: ip,
		},
	}

	for i, test := range testCases {
		if a, e := GetClientIP(&test.Request), test.ExpectedIP; reflect.DeepEqual(e, a) != true {
			t.Fatalf("test case %d failed. expected: %v, actual: %v", i, e, a)
		}
	}
}

func TestProxierWithNoProxyCIDR(t *testing.T) {
	testCases := []struct {
		name    string
		noProxy string
		url     string

		expectedDelegated bool
	}{
		{
			name:              "no env",
			url:               "https://192.168.143.1/api",
			expectedDelegated: true,
		},
		{
			name:              "no cidr",
			noProxy:           "192.168.63.1",
			url:               "https://192.168.143.1/api",
			expectedDelegated: true,
		},
		{
			name:              "hostname",
			noProxy:           "192.168.63.0/24,192.168.143.0/24",
			url:               "https://my-hostname/api",
			expectedDelegated: true,
		},
		{
			name:              "match second cidr",
			noProxy:           "192.168.63.0/24,192.168.143.0/24",
			url:               "https://192.168.143.1/api",
			expectedDelegated: false,
		},
		{
			name:              "match second cidr with host:port",
			noProxy:           "192.168.63.0/24,192.168.143.0/24",
			url:               "https://192.168.143.1:8443/api",
			expectedDelegated: false,
		},
	}

	for _, test := range testCases {
		os.Setenv("NO_PROXY", test.noProxy)
		actualDelegated := false
		proxyFunc := NewProxierWithNoProxyCIDR(func(req *http.Request) (*url.URL, error) {
			actualDelegated = true
			return nil, nil
		})

		req, err := http.NewRequest("GET", test.url, nil)
		if err != nil {
			t.Errorf("%s: unexpected err: %v", test.name, err)
			continue
		}
		if _, err := proxyFunc(req); err != nil {
			t.Errorf("%s: unexpected err: %v", test.name, err)
			continue
		}

		if test.expectedDelegated != actualDelegated {
			t.Errorf("%s: expected %v, got %v", test.name, test.expectedDelegated, actualDelegated)
			continue
		}
	}
}

type fakeTLSClientConfigHolder struct {
	called bool
}

func (f *fakeTLSClientConfigHolder) TLSClientConfig() *tls.Config {
	f.called = true
	return nil
}
func (f *fakeTLSClientConfigHolder) RoundTrip(*http.Request) (*http.Response, error) {
	return nil, nil
}

func TestTLSClientConfigHolder(t *testing.T) {
	rt := &fakeTLSClientConfigHolder{}
	TLSClientConfig(rt)

	if !rt.called {
		t.Errorf("didn't find tls config")
	}
}
<|endoftext|>


<commit_before>package testutil

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"v.io/x/devtools/internal/tool"
	"v.io/x/devtools/internal/util"
)

type testCoverage struct {
	BranchRate int               `xml:"branch-rate,attr"`
	LineRate   int               `xml:"line-rate,attr"`
	TimeStamp  int64             `xml:"timestamp,attr"`
	Version    string            `xml:"version,attr"`
	Packages   []testCoveragePkg `xml:"packages>package"`
	Sources    []string          `xml:"sources>source"`
	XMLName    xml.Name          `xml:"coverage"`
}

type testCoveragePkg struct {
	Name       string              `xml:"name,attr"`
	BranchRate int                 `xml:"branch-rate,attr"`
	LineRate   int                 `xml:"line-rate,attr"`
	Complexity int                 `xml:"complexity,attr"`
	Classes    []testCoverageClass `xml:"classes>class"`
}

type testCoverageClass struct {
	Name       string               `xml:"name,attr"`
	Filename   string               `xml:"filename,attr"`
	BranchRate int                  `xml:"branch-rate,attr"`
	LineRate   int                  `xml:"line-rate,attr"`
	Complexity int                  `xml:"complexity,attr"`
	Methods    []testCoverageMethod `xml:"methods>method"`
}

type testCoverageMethod struct {
	Name       string             `xml:"name,attr"`
	Signature  string             `xml:"signature,attr"`
	BranchRate int                `xml:"branch-rate,attr"`
	LineRate   int                `xml:"line-rate,attr"`
	Lines      []testCoverageLine `xml:"lines>line"`
}

type testCoverageLine struct {
	Number int `xml:"number,attr"`
	Hits   int `xml:"hits,attr"`
}

// coberturaReportPath returns the path to the cobertura report.
func coberturaReportPath(testName string) string {
	workspace, fileName := os.Getenv("WORKSPACE"), "cobertura_report.xml"
	if workspace == "" {
		return filepath.Join(os.Getenv("HOME"), "tmp", testName, fileName)
	} else {
		return filepath.Join(workspace, fileName)
	}
}

// coverageFromGoTestOutput reads data from the given input, assuming
// it contains the coverage information generated by "go test -cover",
// and returns it as an in-memory data structure.
func coverageFromGoTestOutput(ctx *tool.Context, testOutput io.Reader) (*testCoverage, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	bin := filepath.Join(root, "third_party", "go", "bin", "gocover-cobertura")
	env, err := util.VanadiumEnvironment(ctx, util.HostPlatform())
	if err != nil {
		return nil, err
	}
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdin = testOutput
	opts.Stdout = &out
	opts.Env = env.Map()
	if err := ctx.Run().CommandWithOpts(opts, bin); err != nil {
		return nil, err
	}
	var coverage testCoverage
	if err := xml.Unmarshal(out.Bytes(), &coverage); err != nil {
		return nil, fmt.Errorf("Unmarshal() failed: %v\n%v", err, out.String())
	}
	return &coverage, nil
}

// createCoberturaReport generates a cobertura report using the given
// coverage information.
func createCoberturaReport(ctx *tool.Context, testName string, data *testCoverage) error {
	bytes, err := xml.MarshalIndent(*data, "", "  ")
	if err != nil {
		return fmt.Errorf("MarshalIndent(%v) failed: %v", *data, err)
	}
	if err := ctx.Run().WriteFile(coberturaReportPath(testName), bytes, os.FileMode(0644)); err != nil {
		return fmt.Errorf("WriteFile(%v) failed: %v", coberturaReportPath(testName), err)
	}
	return nil
}
<commit_msg>TBR: devtools/internal/testutil: fix path in cobertura.go<commit_after>package testutil

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"v.io/x/devtools/internal/tool"
	"v.io/x/devtools/internal/util"
)

type testCoverage struct {
	BranchRate int               `xml:"branch-rate,attr"`
	LineRate   int               `xml:"line-rate,attr"`
	TimeStamp  int64             `xml:"timestamp,attr"`
	Version    string            `xml:"version,attr"`
	Packages   []testCoveragePkg `xml:"packages>package"`
	Sources    []string          `xml:"sources>source"`
	XMLName    xml.Name          `xml:"coverage"`
}

type testCoveragePkg struct {
	Name       string              `xml:"name,attr"`
	BranchRate int                 `xml:"branch-rate,attr"`
	LineRate   int                 `xml:"line-rate,attr"`
	Complexity int                 `xml:"complexity,attr"`
	Classes    []testCoverageClass `xml:"classes>class"`
}

type testCoverageClass struct {
	Name       string               `xml:"name,attr"`
	Filename   string               `xml:"filename,attr"`
	BranchRate int                  `xml:"branch-rate,attr"`
	LineRate   int                  `xml:"line-rate,attr"`
	Complexity int                  `xml:"complexity,attr"`
	Methods    []testCoverageMethod `xml:"methods>method"`
}

type testCoverageMethod struct {
	Name       string             `xml:"name,attr"`
	Signature  string             `xml:"signature,attr"`
	BranchRate int                `xml:"branch-rate,attr"`
	LineRate   int                `xml:"line-rate,attr"`
	Lines      []testCoverageLine `xml:"lines>line"`
}

type testCoverageLine struct {
	Number int `xml:"number,attr"`
	Hits   int `xml:"hits,attr"`
}

// coberturaReportPath returns the path to the cobertura report.
func coberturaReportPath(testName string) string {
	workspace, fileName := os.Getenv("WORKSPACE"), "cobertura_report.xml"
	if workspace == "" {
		return filepath.Join(os.Getenv("HOME"), "tmp", testName, fileName)
	} else {
		return filepath.Join(workspace, fileName)
	}
}

// coverageFromGoTestOutput reads data from the given input, assuming
// it contains the coverage information generated by "go test -cover",
// and returns it as an in-memory data structure.
func coverageFromGoTestOutput(ctx *tool.Context, testOutput io.Reader) (*testCoverage, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	bin := util.ThirdPartyBinPath(root, "gocover-cobertura")
	env, err := util.VanadiumEnvironment(ctx, util.HostPlatform())
	if err != nil {
		return nil, err
	}
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdin = testOutput
	opts.Stdout = &out
	opts.Env = env.Map()
	if err := ctx.Run().CommandWithOpts(opts, bin); err != nil {
		return nil, err
	}
	var coverage testCoverage
	if err := xml.Unmarshal(out.Bytes(), &coverage); err != nil {
		return nil, fmt.Errorf("Unmarshal() failed: %v\n%v", err, out.String())
	}
	return &coverage, nil
}

// createCoberturaReport generates a cobertura report using the given
// coverage information.
func createCoberturaReport(ctx *tool.Context, testName string, data *testCoverage) error {
	bytes, err := xml.MarshalIndent(*data, "", "  ")
	if err != nil {
		return fmt.Errorf("MarshalIndent(%v) failed: %v", *data, err)
	}
	if err := ctx.Run().WriteFile(coberturaReportPath(testName), bytes, os.FileMode(0644)); err != nil {
		return fmt.Errorf("WriteFile(%v) failed: %v", coberturaReportPath(testName), err)
	}
	return nil
}
<|endoftext|>


<commit_before>package integration_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("GCSclient", func() {
	var (
		err             error
		tempDir         string
		tempFile        *os.File
		tempVerDir      string
		tempVerFile     *os.File
		runtime         string
		directoryPrefix string
	)

	BeforeEach(func() {
		directoryPrefix = "gcsclient-tests"
		runtime = fmt.Sprintf("%d", time.Now().Unix())
	})

	Describe("with a non versioned bucket", func() {
		BeforeEach(func() {
			tempDir, err = ioutil.TempDir("", "gcs_client_integration_test")
			Expect(err).ToNot(HaveOccurred())

			tempFile, err = ioutil.TempFile(tempDir, "file-to-upload")
			Expect(err).ToNot(HaveOccurred())

			tempFile.Write([]byte("hello-" + runtime))
		})

		AfterEach(func() {
			err := os.RemoveAll(tempDir)
			Expect(err).ToNot(HaveOccurred())

			err = gcsClient.DeleteObject(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0)
			Expect(err).ToNot(HaveOccurred())

			err = gcsClient.DeleteObject(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), 0)
			Expect(err).ToNot(HaveOccurred())

			err = gcsClient.DeleteObject(bucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"), 0)
			Expect(err).ToNot(HaveOccurred())
		})

		It("can interact with buckets", func() {
			_, err := gcsClient.UploadFile(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), "", tempFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			_, err = gcsClient.UploadFile(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), "", tempFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			_, err = gcsClient.UploadFile(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), "", tempFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			_, err = gcsClient.UploadFile(bucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"), "application/zip", tempFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fakeZipFileObject, err := gcsClient.GetBucketObjectInfo(bucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fakeZipFileObject.ContentType).To(Equal("application/zip"))

			files, err := gcsClient.BucketObjects(bucketName, directoryPrefix)
			Expect(err).ToNot(HaveOccurred())
			Expect(files).To(ConsistOf([]string{filepath.Join(directoryPrefix, "file-to-upload-1"), filepath.Join(directoryPrefix, "file-to-upload-2"), filepath.Join(directoryPrefix, "zip-to-upload.zip")}))

			_, err = gcsClient.ObjectGenerations(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("bucket is not versioned"))

			fileOneURL, err := gcsClient.URL(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneURL).To(Equal(fmt.Sprintf("gs://%s/%s", bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))))

			_, err = gcsClient.ObjectGenerations(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("bucket is not versioned"))

			fileTwoURL, err := gcsClient.URL(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), 0)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoURL).To(Equal(fmt.Sprintf("gs://%s/%s", bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))))

			err = gcsClient.DownloadFile(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0, filepath.Join(tempDir, "downloaded-file"))
			Expect(err).ToNot(HaveOccurred())

			read, err := ioutil.ReadFile(filepath.Join(tempDir, "downloaded-file"))
			Expect(err).ToNot(HaveOccurred())
			Expect(read).To(Equal([]byte("hello-" + runtime)))
		})
	})

	Describe("with a versioned bucket", func() {
		BeforeEach(func() {
			tempVerDir, err = ioutil.TempDir("", "gcs-versioned-upload-dir")
			Expect(err).ToNot(HaveOccurred())

			tempVerFile, err = ioutil.TempFile(tempVerDir, "file-to-upload")
			Expect(err).ToNot(HaveOccurred())

			tempVerFile.Write([]byte("hello-" + runtime))
		})

		AfterEach(func() {
			err := os.RemoveAll(tempVerDir)
			Expect(err).ToNot(HaveOccurred())

			fileOneGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))
			Expect(err).ToNot(HaveOccurred())

			for _, fileOneGeneration := range fileOneGenerations {
				err := gcsClient.DeleteObject(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), fileOneGeneration)
				Expect(err).ToNot(HaveOccurred())
			}

			fileTwoGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))
			Expect(err).ToNot(HaveOccurred())

			for _, fileTwoGeneration := range fileTwoGenerations {
				err := gcsClient.DeleteObject(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration)
				Expect(err).ToNot(HaveOccurred())
			}

			fakeZipFileGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"))
			Expect(err).ToNot(HaveOccurred())

			for _, fakeZipFileGeneration := range fakeZipFileGenerations {
				err := gcsClient.DeleteObject(versionedBucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"), fakeZipFileGeneration)
				Expect(err).ToNot(HaveOccurred())
			}
		})

		It("can interact with buckets", func() {
			fileOneGeneration, err := gcsClient.UploadFile(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), "", tempVerFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fileTwoGeneration1, err := gcsClient.UploadFile(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), "", tempVerFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fileTwoGeneration2, err := gcsClient.UploadFile(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), "", tempVerFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fakeZipFileGeneration, err := gcsClient.UploadFile(versionedBucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"), "application/zip", tempVerFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fakeZipFileObject, err := gcsClient.GetBucketObjectInfo(versionedBucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fakeZipFileObject.ContentType).To(Equal("application/zip"))
			Expect(fakeZipFileGeneration).To(Equal(fakeZipFileObject.Generation))

			files, err := gcsClient.BucketObjects(versionedBucketName, directoryPrefix)
			Expect(err).ToNot(HaveOccurred())
			Expect(files).To(ConsistOf([]string{filepath.Join(directoryPrefix, "file-to-upload-1"), filepath.Join(directoryPrefix, "file-to-upload-2"), filepath.Join(directoryPrefix, "zip-to-upload.zip")}))

			fileOneGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneGenerations).To(ConsistOf([]int64{fileOneGeneration}))

			fileOneGenerationsObject, err := gcsClient.GetBucketObjectInfo(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneGenerations).To(ConsistOf([]int64{fileOneGenerationsObject.Generation}))

			fileOneURL, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneURL).To(Equal(fmt.Sprintf("gs://%s/%s", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))))

			fileOneURLGeneration, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), fileOneGeneration)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneURLGeneration).To(Equal(fmt.Sprintf("gs://%s/%s#%d", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), fileOneGeneration)))

			fileTwoGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoGenerations).To(ConsistOf([]int64{fileTwoGeneration1, fileTwoGeneration2}))

			fileTwoURL, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), 0)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoURL).To(Equal(fmt.Sprintf("gs://%s/%s", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))))

			fileTwoURLGeneration1, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration1)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoURLGeneration1).To(Equal(fmt.Sprintf("gs://%s/%s#%d", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration1)))

			fileTwoURLGeneration2, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration2)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoURLGeneration2).To(Equal(fmt.Sprintf("gs://%s/%s#%d", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration2)))

			err = gcsClient.DownloadFile(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0, filepath.Join(tempVerDir, "downloaded-file"))
			Expect(err).ToNot(HaveOccurred())

			read, err := ioutil.ReadFile(filepath.Join(tempVerDir, "downloaded-file"))
			Expect(err).ToNot(HaveOccurred())
			Expect(read).To(Equal([]byte("hello-" + runtime)))
		})
	})
})
<commit_msg>Update gcsClient.DownloadFile signature in integration/gcsclient_test.go<commit_after>package integration_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("GCSclient", func() {
	var (
		err             error
		tempDir         string
		tempFile        *os.File
		tempVerDir      string
		tempVerFile     *os.File
		runtime         string
		directoryPrefix string
	)

	BeforeEach(func() {
		directoryPrefix = "gcsclient-tests"
		runtime = fmt.Sprintf("%d", time.Now().Unix())
	})

	Describe("with a non versioned bucket", func() {
		BeforeEach(func() {
			tempDir, err = ioutil.TempDir("", "gcs_client_integration_test")
			Expect(err).ToNot(HaveOccurred())

			tempFile, err = ioutil.TempFile(tempDir, "file-to-upload")
			Expect(err).ToNot(HaveOccurred())

			tempFile.Write([]byte("hello-" + runtime))
		})

		AfterEach(func() {
			err := os.RemoveAll(tempDir)
			Expect(err).ToNot(HaveOccurred())

			err = gcsClient.DeleteObject(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0)
			Expect(err).ToNot(HaveOccurred())

			err = gcsClient.DeleteObject(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), 0)
			Expect(err).ToNot(HaveOccurred())

			err = gcsClient.DeleteObject(bucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"), 0)
			Expect(err).ToNot(HaveOccurred())
		})

		It("can interact with buckets", func() {
			_, err := gcsClient.UploadFile(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), "", tempFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			_, err = gcsClient.UploadFile(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), "", tempFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			_, err = gcsClient.UploadFile(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), "", tempFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			_, err = gcsClient.UploadFile(bucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"), "application/zip", tempFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fakeZipFileObject, err := gcsClient.GetBucketObjectInfo(bucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fakeZipFileObject.ContentType).To(Equal("application/zip"))

			files, err := gcsClient.BucketObjects(bucketName, directoryPrefix)
			Expect(err).ToNot(HaveOccurred())
			Expect(files).To(ConsistOf([]string{filepath.Join(directoryPrefix, "file-to-upload-1"), filepath.Join(directoryPrefix, "file-to-upload-2"), filepath.Join(directoryPrefix, "zip-to-upload.zip")}))

			_, err = gcsClient.ObjectGenerations(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("bucket is not versioned"))

			fileOneURL, err := gcsClient.URL(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneURL).To(Equal(fmt.Sprintf("gs://%s/%s", bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))))

			_, err = gcsClient.ObjectGenerations(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))
			Expect(err).To(HaveOccurred())
			Expect(err.Error()).To(ContainSubstring("bucket is not versioned"))

			fileTwoURL, err := gcsClient.URL(bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), 0)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoURL).To(Equal(fmt.Sprintf("gs://%s/%s", bucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))))

			tempFile, err := gcsClient.DownloadFile(bucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0)
			Expect(err).ToNot(HaveOccurred())

			read, err := ioutil.ReadFile(tempFile)
			Expect(err).ToNot(HaveOccurred())
			Expect(read).To(Equal([]byte("hello-" + runtime)))
		})
	})

	Describe("with a versioned bucket", func() {
		BeforeEach(func() {
			tempVerDir, err = ioutil.TempDir("", "gcs-versioned-upload-dir")
			Expect(err).ToNot(HaveOccurred())

			tempVerFile, err = ioutil.TempFile(tempVerDir, "file-to-upload")
			Expect(err).ToNot(HaveOccurred())

			tempVerFile.Write([]byte("hello-" + runtime))
		})

		AfterEach(func() {
			err := os.RemoveAll(tempVerDir)
			Expect(err).ToNot(HaveOccurred())

			fileOneGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))
			Expect(err).ToNot(HaveOccurred())

			for _, fileOneGeneration := range fileOneGenerations {
				err := gcsClient.DeleteObject(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), fileOneGeneration)
				Expect(err).ToNot(HaveOccurred())
			}

			fileTwoGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))
			Expect(err).ToNot(HaveOccurred())

			for _, fileTwoGeneration := range fileTwoGenerations {
				err := gcsClient.DeleteObject(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration)
				Expect(err).ToNot(HaveOccurred())
			}

			fakeZipFileGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"))
			Expect(err).ToNot(HaveOccurred())

			for _, fakeZipFileGeneration := range fakeZipFileGenerations {
				err := gcsClient.DeleteObject(versionedBucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"), fakeZipFileGeneration)
				Expect(err).ToNot(HaveOccurred())
			}
		})

		It("can interact with buckets", func() {
			fileOneGeneration, err := gcsClient.UploadFile(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), "", tempVerFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fileTwoGeneration1, err := gcsClient.UploadFile(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), "", tempVerFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fileTwoGeneration2, err := gcsClient.UploadFile(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), "", tempVerFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fakeZipFileGeneration, err := gcsClient.UploadFile(versionedBucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"), "application/zip", tempVerFile.Name(), "")
			Expect(err).ToNot(HaveOccurred())

			fakeZipFileObject, err := gcsClient.GetBucketObjectInfo(versionedBucketName, filepath.Join(directoryPrefix, "zip-to-upload.zip"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fakeZipFileObject.ContentType).To(Equal("application/zip"))
			Expect(fakeZipFileGeneration).To(Equal(fakeZipFileObject.Generation))

			files, err := gcsClient.BucketObjects(versionedBucketName, directoryPrefix)
			Expect(err).ToNot(HaveOccurred())
			Expect(files).To(ConsistOf([]string{filepath.Join(directoryPrefix, "file-to-upload-1"), filepath.Join(directoryPrefix, "file-to-upload-2"), filepath.Join(directoryPrefix, "zip-to-upload.zip")}))

			fileOneGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneGenerations).To(ConsistOf([]int64{fileOneGeneration}))

			fileOneGenerationsObject, err := gcsClient.GetBucketObjectInfo(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneGenerations).To(ConsistOf([]int64{fileOneGenerationsObject.Generation}))

			fileOneURL, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneURL).To(Equal(fmt.Sprintf("gs://%s/%s", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"))))

			fileOneURLGeneration, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), fileOneGeneration)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileOneURLGeneration).To(Equal(fmt.Sprintf("gs://%s/%s#%d", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), fileOneGeneration)))

			fileTwoGenerations, err := gcsClient.ObjectGenerations(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoGenerations).To(ConsistOf([]int64{fileTwoGeneration1, fileTwoGeneration2}))

			fileTwoURL, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), 0)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoURL).To(Equal(fmt.Sprintf("gs://%s/%s", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"))))

			fileTwoURLGeneration1, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration1)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoURLGeneration1).To(Equal(fmt.Sprintf("gs://%s/%s#%d", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration1)))

			fileTwoURLGeneration2, err := gcsClient.URL(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration2)
			Expect(err).ToNot(HaveOccurred())
			Expect(fileTwoURLGeneration2).To(Equal(fmt.Sprintf("gs://%s/%s#%d", versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-2"), fileTwoGeneration2)))

			tempFile, err := gcsClient.DownloadFile(versionedBucketName, filepath.Join(directoryPrefix, "file-to-upload-1"), 0)
			Expect(err).ToNot(HaveOccurred())

			read, err := ioutil.ReadFile(tempFile)
			Expect(err).ToNot(HaveOccurred())
			Expect(read).To(Equal([]byte("hello-" + runtime)))
		})
	})
})
<|endoftext|>


<commit_before>package integration_test

import (
	"os/exec"

	"github.com/concourse/atc"
	"github.com/concourse/fly/ui"
	"github.com/fatih/color"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/onsi/gomega/ghttp"
)

var _ = Describe("Fly CLI", func() {
	Describe("pipelines", func() {
		var (
			flyCmd *exec.Cmd
		)

		Context("when pipelines are returned from the API", func() {
			Context("when no --all flag is given", func() {

				BeforeEach(func() {
					flyCmd = exec.Command(flyPath, "-t", targetName, "pipelines")
					atcServer.AppendHandlers(
						ghttp.CombineHandlers(
							ghttp.VerifyRequest("GET", "/api/v1/teams/main/pipelines"),
							ghttp.RespondWithJSONEncoded(200, []atc.Pipeline{
								{Name: "pipeline-1-longer", URL: "/pipelines/pipeline-1", Paused: false, Public: false},
								{Name: "pipeline-2", URL: "/pipelines/pipeline-2", Paused: true, Public: false},
								{Name: "pipeline-3", URL: "/pipelines/pipeline-3", Paused: false, Public: true},
							}),
						),
					)
				})

				It("only shows the team's pipelines", func() {
					sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
					Expect(err).NotTo(HaveOccurred())
					Eventually(sess).Should(gexec.Exit(0))

					Expect(sess.Out).To(PrintTable(ui.Table{
						Headers: ui.TableRow{
							{Contents: "name", Color: color.New(color.Bold)},
							{Contents: "paused", Color: color.New(color.Bold)},
							{Contents: "public", Color: color.New(color.Bold)},
						},
						Data: []ui.TableRow{
							{{Contents: "pipeline-1-longer"}, {Contents: "no"}, {Contents: "no"}},
							{{Contents: "pipeline-2"}, {Contents: "yes", Color: color.New(color.FgCyan)}, {Contents: "no"}},
							{{Contents: "pipeline-3"}, {Contents: "no"}, {Contents: "yes", Color: color.New(color.FgCyan)}},
						},
					}))
				})
			})

			Context("when --all is specified", func() {
				BeforeEach(func() {
					flyCmd = exec.Command(flyPath, "-t", targetName, "pipelines", "--all")
					atcServer.AppendHandlers(
						ghttp.CombineHandlers(
							ghttp.VerifyRequest("GET", "/api/v1/pipelines"),
							ghttp.RespondWithJSONEncoded(200, []atc.Pipeline{
								{Name: "pipeline-1-longer", URL: "/pipelines/pipeline-1", Paused: false, Public: false, TeamName: "main"},
								{Name: "pipeline-2", URL: "/pipelines/pipeline-2", Paused: true, Public: false, TeamName: "main"},
								{Name: "pipeline-3", URL: "/pipelines/pipeline-3", Paused: false, Public: true, TeamName: "main"},
								{Name: "foreign-pipeline-1", URL: "/pipelines/foreign-pipeline-1", Paused: false, Public: true, TeamName: "other"},
								{Name: "foreign-pipeline-2", URL: "/pipelines/foreign-pipeline-2", Paused: false, Public: true, TeamName: "other"},
							}),
						),
					)
				})

				It("includes team and shared pipelines, with a team name column", func() {
					sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
					Expect(err).NotTo(HaveOccurred())
					Eventually(sess).Should(gexec.Exit(0))

					Expect(sess.Out).To(PrintTable(ui.Table{
						Headers: ui.TableRow{
							{Contents: "name", Color: color.New(color.Bold)},
							{Contents: "team", Color: color.New(color.Bold)},
							{Contents: "paused", Color: color.New(color.Bold)},
							{Contents: "public", Color: color.New(color.Bold)},
						},
						Data: []ui.TableRow{
							{{Contents: "pipeline-1-longer"}, {Contents: "main"}, {Contents: "no"}, {Contents: "no"}},
							{{Contents: "pipeline-2"}, {Contents: "main"}, {Contents: "yes", Color: color.New(color.FgCyan)}, {Contents: "no"}},
							{{Contents: "pipeline-3"}, {Contents: "main"}, {Contents: "no"}, {Contents: "yes", Color: color.New(color.FgCyan)}},
							{{Contents: "foreign-pipeline-1"}, {Contents: "other"}, {Contents: "no"}, {Contents: "yes", Color: color.New(color.FgCyan)}},
							{{Contents: "foreign-pipeline-2"}, {Contents: "other"}, {Contents: "no"}, {Contents: "yes", Color: color.New(color.FgCyan)}},
						},
					}))
				})
			})
		})

		Context("and the api returns an internal server error", func() {
			BeforeEach(func() {
				flyCmd = exec.Command(flyPath, "-t", targetName, "pipelines")
				atcServer.AppendHandlers(
					ghttp.CombineHandlers(
						ghttp.VerifyRequest("GET", "/api/v1/teams/main/pipelines"),
						ghttp.RespondWith(500, ""),
					),
				)
			})

			It("writes an error message to stderr", func() {
				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(sess).Should(gexec.Exit(1))
				Eventually(sess.Err).Should(gbytes.Say("Unexpected Response"))
			})
		})
	})
})
<commit_msg>Test pipeline completion.<commit_after>package integration_test

import (
	"os"
	"os/exec"

	"github.com/concourse/atc"
	"github.com/concourse/fly/ui"
	"github.com/fatih/color"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/onsi/gomega/ghttp"
)

var _ = Describe("Fly CLI", func() {
	Describe("pipelines", func() {
		var (
			flyCmd *exec.Cmd
		)

		Context("when pipelines are returned from the API", func() {
			Context("when no --all flag is given", func() {

				BeforeEach(func() {
					flyCmd = exec.Command(flyPath, "-t", targetName, "pipelines")
					atcServer.AppendHandlers(
						ghttp.CombineHandlers(
							ghttp.VerifyRequest("GET", "/api/v1/teams/main/pipelines"),
							ghttp.RespondWithJSONEncoded(200, []atc.Pipeline{
								{Name: "pipeline-1-longer", URL: "/pipelines/pipeline-1", Paused: false, Public: false},
								{Name: "pipeline-2", URL: "/pipelines/pipeline-2", Paused: true, Public: false},
								{Name: "pipeline-3", URL: "/pipelines/pipeline-3", Paused: false, Public: true},
							}),
						),
					)
				})

				It("only shows the team's pipelines", func() {
					sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
					Expect(err).NotTo(HaveOccurred())
					Eventually(sess).Should(gexec.Exit(0))

					Expect(sess.Out).To(PrintTable(ui.Table{
						Headers: ui.TableRow{
							{Contents: "name", Color: color.New(color.Bold)},
							{Contents: "paused", Color: color.New(color.Bold)},
							{Contents: "public", Color: color.New(color.Bold)},
						},
						Data: []ui.TableRow{
							{{Contents: "pipeline-1-longer"}, {Contents: "no"}, {Contents: "no"}},
							{{Contents: "pipeline-2"}, {Contents: "yes", Color: color.New(color.FgCyan)}, {Contents: "no"}},
							{{Contents: "pipeline-3"}, {Contents: "no"}, {Contents: "yes", Color: color.New(color.FgCyan)}},
						},
					}))
				})
			})

			Context("when --all is specified", func() {
				BeforeEach(func() {
					flyCmd = exec.Command(flyPath, "-t", targetName, "pipelines", "--all")
					atcServer.AppendHandlers(
						ghttp.CombineHandlers(
							ghttp.VerifyRequest("GET", "/api/v1/pipelines"),
							ghttp.RespondWithJSONEncoded(200, []atc.Pipeline{
								{Name: "pipeline-1-longer", URL: "/pipelines/pipeline-1", Paused: false, Public: false, TeamName: "main"},
								{Name: "pipeline-2", URL: "/pipelines/pipeline-2", Paused: true, Public: false, TeamName: "main"},
								{Name: "pipeline-3", URL: "/pipelines/pipeline-3", Paused: false, Public: true, TeamName: "main"},
								{Name: "foreign-pipeline-1", URL: "/pipelines/foreign-pipeline-1", Paused: false, Public: true, TeamName: "other"},
								{Name: "foreign-pipeline-2", URL: "/pipelines/foreign-pipeline-2", Paused: false, Public: true, TeamName: "other"},
							}),
						),
					)
				})

				It("includes team and shared pipelines, with a team name column", func() {
					sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
					Expect(err).NotTo(HaveOccurred())
					Eventually(sess).Should(gexec.Exit(0))

					Expect(sess.Out).To(PrintTable(ui.Table{
						Headers: ui.TableRow{
							{Contents: "name", Color: color.New(color.Bold)},
							{Contents: "team", Color: color.New(color.Bold)},
							{Contents: "paused", Color: color.New(color.Bold)},
							{Contents: "public", Color: color.New(color.Bold)},
						},
						Data: []ui.TableRow{
							{{Contents: "pipeline-1-longer"}, {Contents: "main"}, {Contents: "no"}, {Contents: "no"}},
							{{Contents: "pipeline-2"}, {Contents: "main"}, {Contents: "yes", Color: color.New(color.FgCyan)}, {Contents: "no"}},
							{{Contents: "pipeline-3"}, {Contents: "main"}, {Contents: "no"}, {Contents: "yes", Color: color.New(color.FgCyan)}},
							{{Contents: "foreign-pipeline-1"}, {Contents: "other"}, {Contents: "no"}, {Contents: "yes", Color: color.New(color.FgCyan)}},
							{{Contents: "foreign-pipeline-2"}, {Contents: "other"}, {Contents: "no"}, {Contents: "yes", Color: color.New(color.FgCyan)}},
						},
					}))
				})
			})

			Context("completion", func() {
				BeforeEach(func() {
					os.Setenv("GO_FLAGS_COMPLETION", "1")
					atcServer.AppendHandlers(
						ghttp.CombineHandlers(
							ghttp.VerifyRequest("GET", "/api/v1/teams/main/pipelines"),
							ghttp.RespondWithJSONEncoded(200, []atc.Pipeline{
								{Name: "some-pipeline-1", URL: "/pipelines/some-pipeline-1", Paused: false, Public: false},
								{Name: "some-pipeline-2", URL: "/pipelines/some-pipeline-2", Paused: false, Public: false},
								{Name: "another-pipeline", URL: "/pipelines/another-pipeline", Paused: false, Public: false},
							}),
						),
					)
				})

				AfterEach(func() {
					os.Unsetenv("GO_FLAGS_COMPLETION")
				})

				It("returns all matching pipelines", func() {
					flyCmd := exec.Command(flyPath, "-t", targetName, "get-pipeline", "-p", "some-")
					sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
					Expect(err).NotTo(HaveOccurred())
					Eventually(sess).Should(gexec.Exit(0))
					Eventually(sess.Out).Should(gbytes.Say("some-pipeline-1"))
					Eventually(sess.Out).Should(gbytes.Say("some-pipeline-2"))
					Eventually(sess.Out).ShouldNot(gbytes.Say("another-pipeline"))
				})
			})
		})

		Context("and the api returns an internal server error", func() {
			BeforeEach(func() {
				flyCmd = exec.Command(flyPath, "-t", targetName, "pipelines")
				atcServer.AppendHandlers(
					ghttp.CombineHandlers(
						ghttp.VerifyRequest("GET", "/api/v1/teams/main/pipelines"),
						ghttp.RespondWith(500, ""),
					),
				)
			})

			It("writes an error message to stderr", func() {
				sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter)
				Expect(err).NotTo(HaveOccurred())

				Eventually(sess).Should(gexec.Exit(1))
				Eventually(sess.Err).Should(gbytes.Say("Unexpected Response"))
			})
		})
	})
})
<|endoftext|>


<commit_before>//
// Copyright 2019 Google Inc. All Rights Reserved.
//
// 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 schedbt

import (
	"bufio"
	"strings"
	"testing"

	"github.com/golang/protobuf/proto"
	"github.com/google/go-cmp/cmp"
	eventpb "github.com/google/schedviz/tracedata/schedviz_events_go_proto"
	"github.com/google/schedviz/tracedata/testeventsetbuilder"
)

func TestParsing(t *testing.T) {
	tests := []struct {
		description string
		input       string
		want        *eventpb.EventSet
	}{{
		"Valid trace",
		`Attaching 5 probes...
ST:0:beef
P:a:64:70:Thread 1
P:a:c8:70:Thread 2
S:a:0:64:0:c8
M:14:0:0:1:64
W:1e:0:1:64`,
		testeventsetbuilder.TestProtobuf(t, emptyEventSet().
			WithEvent("sched_switch", 0, 0xbeef+10, false,
				100, "Thread 1", 112, 0,
				200, "Thread 2", 112).
			WithEvent("sched_migrate_task", 0, 0xbeef+20, false,
				100, "Thread 1", 112,
				0, 1).
			WithEvent("sched_wakeup", 0, 0xbeef+30, false,
				100, "Thread 1", 112, 1)),
	}, {
		"Process name with colons",
		`Attaching 5 probes...
ST:0:beef
P:a:64:70:Thread:1
M:a:0:0:1:64`,
		testeventsetbuilder.TestProtobuf(t, emptyEventSet().
			WithEvent("sched_migrate_task", 0, 0xbeef+10, false,
				100, "Thread:1", 112,
				0, 1)),
	}}
	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			p := NewParser()
			r := strings.NewReader(test.input)
			bufr := bufio.NewReader(r)
			if err := p.Parse(bufr); err != nil {
				t.Fatalf("Parse() yielded unexpected error %v", err)
			}
			got, err := p.EventSet()
			if err != nil {
				t.Fatalf("EventSet() yielded unexpected error %v", err)
			}
			if d := cmp.Diff(test.want, got); d != "" {
				t.Errorf("Parser produced %s, diff(want->got) %s", proto.MarshalTextString(got), d)
			}
		})
	}
}
<commit_msg>Internal change<commit_after>//
// Copyright 2019 Google Inc. All Rights Reserved.
//
// 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 schedbt

import (
	"bufio"
	"strings"
	"testing"

	"github.com/golang/protobuf/proto"
	"github.com/google/go-cmp/cmp"
	eventpb "github.com/google/schedviz/tracedata/schedviz_events_go_proto"
	"github.com/google/schedviz/tracedata/testeventsetbuilder"
)

func TestParsing(t *testing.T) {
	tests := []struct {
		description string
		input       string
		want        *eventpb.EventSet
	}{{
		"Valid trace",
		`Attaching 5 probes...
ST:0:beef
P:a:64:70:Thread 1
P:a:c8:70:Thread 2
S:a:0:64:0:c8
M:14:0:0:1:64
W:1e:0:1:64`,
		testeventsetbuilder.TestProtobuf(t, emptyEventSet().
			WithEvent("sched_switch", 0, 0xbeef+10, false,
				100, "Thread 1", 112, 0,
				200, "Thread 2", 112).
			WithEvent("sched_migrate_task", 0, 0xbeef+20, false,
				100, "Thread 1", 112,
				0, 1).
			WithEvent("sched_wakeup", 0, 0xbeef+30, false,
				100, "Thread 1", 112, 1)),
	}, {
		"Process name with colons",
		`Attaching 5 probes...
ST:0:beef
P:a:64:70:Thread:1
M:a:0:0:1:64`,
		testeventsetbuilder.TestProtobuf(t, emptyEventSet().
			WithEvent("sched_migrate_task", 0, 0xbeef+10, false,
				100, "Thread:1", 112,
				0, 1)),
	}}
	for _, test := range tests {
		t.Run(test.description, func(t *testing.T) {
			p := NewParser()
			r := strings.NewReader(test.input)
			bufr := bufio.NewReader(r)
			if err := p.Parse(bufr); err != nil {
				t.Fatalf("Parse() yielded unexpected error %v", err)
			}
			got, err := p.EventSet()
			if err != nil {
				t.Fatalf("EventSet() yielded unexpected error %v", err)
			}
			if d := cmp.Diff(test.want, got, cmp.Comparer(proto.Equal)); d != "" {
				t.Errorf("Parser produced %s, diff(want->got) %s", proto.MarshalTextString(got), d)
			}
		})
	}
}
<|endoftext|>