<commit_before>package docker

import (
	"archive/tar"
	"bufio"
	"bytes"
	"errors"
	"io"
	"strings"
	"sync"
	"time"

	"github.com/NetSys/quilt/util"

	log "github.com/Sirupsen/logrus"
	dkc "github.com/fsouza/go-dockerclient"
)

const (
	// The root namespace for all labels
	labelBase = "q."

	// This is the namespace for user defined labels
	userLabelPrefix = labelBase + "user.label."

	// This is the namespace for system defined labels
	systemLabelPrefix = labelBase + "system.label."

	// LabelTrueValue is needed because a label has to be a key/value pair, hence
	// this is the value that will be used if we're only interested in the key
	LabelTrueValue = "1"

	// SchedulerLabelKey is the key, used by the scheduler.
	SchedulerLabelKey = systemLabelPrefix + "Quilt"

	// SchedulerLabelValue is the value, used by the scheduler.
	SchedulerLabelValue = "Scheduler"

	// SchedulerLabelPair is the key/value pair, used by the scheduler.
	SchedulerLabelPair = SchedulerLabelKey + "=" + SchedulerLabelValue
)

var errNoSuchContainer = errors.New("container does not exist")

// A Container as returned by the docker client API.
type Container struct {
	ID     string
	Name   string
	Image  string
	IP     string
	Path   string
	Args   []string
	Pid    int
	Env    map[string]string
	Labels map[string]string
}

// ContainerSlice is an alias for []Container to allow for joins
type ContainerSlice []Container

// A Client to the local docker daemon.
type Client interface {
	Run(opts RunOptions) (string, error)
	Exec(name string, cmd ...string) error
	ExecVerbose(name string, cmd ...string) ([]byte, error)
	Remove(name string) error
	RemoveID(id string) error
	Pull(image string) error
	List(filters map[string][]string) ([]Container, error)
	Get(id string) (Container, error)
	WriteToContainer(id, src, dst, archiveName string, permission int) error
	GetFromContainer(id string, src string) (string, error)
	IsRunning(name string) (bool, error)
}

// RunOptions changes the behavior of the Run function.
type RunOptions struct {
	Name   string
	Image  string
	Args   []string
	Labels map[string]string
	Env    map[string]struct{}

	NetworkMode string
	PidMode     string
	Privileged  bool
	VolumesFrom []string
}

type docker struct {
	*dkc.Client
	*sync.Mutex
	imageCache map[string]struct{}
}

// New creates client to the docker daemon.
func New(sock string) Client {
	var client *dkc.Client
	for {
		var err error
		client, err = dkc.NewClient(sock)
		if err != nil {
			log.WithError(err).Warn("Failed to create docker client.")
			time.Sleep(10 * time.Second)
			continue
		}
		break
	}

	return docker{client, &sync.Mutex{}, map[string]struct{}{}}
}

func (dk docker) Run(opts RunOptions) (string, error) {
	hc := dkc.HostConfig{
		NetworkMode: opts.NetworkMode,
		PidMode:     opts.PidMode,
		Privileged:  opts.Privileged,
		VolumesFrom: opts.VolumesFrom,
	}
	id, err := dk.create(opts.Name, opts.Image, opts.Args, opts.Labels, opts.Env, &hc)
	if err != nil {
		return "", err
	}

	if err = dk.StartContainer(id, &hc); err != nil {
		dk.removeID(id) // Remove the container to avoid a zombie.
		return "", err
	}

	return id, nil
}

func (dk docker) Exec(name string, cmd ...string) error {
	_, err := dk.ExecVerbose(name, cmd...)
	return err
}

func (dk docker) ExecVerbose(name string, cmd ...string) ([]byte, error) {
	id, err := dk.getID(name)
	if err != nil {
		return nil, err
	}

	var inBuff, outBuff bytes.Buffer
	exec, err := dk.CreateExec(dkc.CreateExecOptions{
		Container:    id,
		Cmd:          cmd,
		AttachStdout: true})

	if err != nil {
		return nil, err
	}

	err = dk.StartExec(exec.ID, dkc.StartExecOptions{
		OutputStream: &inBuff,
	})

	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(bytes.NewReader(inBuff.Bytes()))
	for scanner.Scan() {
		outBuff.WriteString(scanner.Text() + "\n")
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return outBuff.Bytes(), nil
}

// WriteToContainer writes the contents of SRC into the file at path DST on the
// container with id ID. Overwrites DST if it already exists.
func (dk docker) WriteToContainer(id, src, dst, archiveName string,
	permission int) error {

	tarBuf, err := util.ToTar(archiveName, permission, src)

	if err != nil {
		return err
	}

	err = dk.UploadToContainer(id, dkc.UploadToContainerOptions{
		InputStream: tarBuf,
		Path:        dst,
	})
	if err != nil {
		return err
	}

	return nil
}

// GetFromContainer returns a string containing the content of the file named
// SRC on the container with id ID.
func (dk docker) GetFromContainer(id string, src string) (string, error) {
	var buffIn bytes.Buffer
	var buffOut bytes.Buffer
	err := dk.DownloadFromContainer(id, dkc.DownloadFromContainerOptions{
		OutputStream: &buffIn,
		Path:         src,
	})
	if err != nil {
		return "", err
	}

	writer := io.Writer(&buffOut)

	for tr := tar.NewReader(&buffIn); err != io.EOF; _, err = tr.Next() {

		if err != nil {
			return "", err
		}

		_, err = io.Copy(writer, tr)
		if err != nil {
			return "", err
		}
	}

	return buffOut.String(), nil
}

func (dk docker) Remove(name string) error {
	id, err := dk.getID(name)
	if err != nil {
		return nil // Can't remove a non-existent container.
	}

	log.WithFields(log.Fields{
		"name": name,
		"id":   id,
	}).Info("Remove container.")
	return dk.removeID(id)
}

func (dk docker) RemoveID(id string) error {
	log.WithField("id", id).Info("Remove Container.")
	return dk.removeID(id)
}

func (dk docker) removeID(id string) error {
	err := dk.RemoveContainer(dkc.RemoveContainerOptions{ID: id, Force: true})
	if err != nil {
		return err
	}

	return nil
}

func (dk docker) Pull(image string) error {
	dk.Lock()
	defer dk.Unlock()

	if _, ok := dk.imageCache[image]; ok {
		return nil
	}

	log.Infof("Pulling docker image %s.", image)
	opts := dkc.PullImageOptions{Repository: image}
	if err := dk.PullImage(opts, dkc.AuthConfiguration{}); err != nil {
		return err
	}

	dk.imageCache[image] = struct{}{}
	return nil
}

func (dk docker) List(filters map[string][]string) ([]Container, error) {
	return dk.list(filters, false)
}

func (dk docker) list(filters map[string][]string, all bool) ([]Container, error) {
	opts := dkc.ListContainersOptions{All: all, Filters: filters}
	apics, err := dk.ListContainers(opts)
	if err != nil {
		return nil, err
	}

	var containers []Container
	for _, apic := range apics {
		c, err := dk.Get(apic.ID)
		if err != nil {
			log.WithError(err).Warnf("Failed to inspect container: %s",
				apic.ID)
			continue
		}

		containers = append(containers, c)
	}

	return containers, nil
}

func (dk docker) Get(id string) (Container, error) {
	c, err := dk.InspectContainer(id)
	if err != nil {
		return Container{}, err
	}

	env := make(map[string]string)
	for _, value := range c.Config.Env {
		e := strings.Split(value, "=")
		if len(e) > 1 {
			env[e[0]] = e[1]
		}
	}

	return Container{
		Name:   c.Name,
		ID:     c.ID,
		IP:     c.NetworkSettings.IPAddress,
		Image:  c.Config.Image,
		Path:   c.Path,
		Args:   c.Args,
		Pid:    c.State.Pid,
		Env:    env,
		Labels: c.Config.Labels,
	}, nil
}

func (dk docker) IsRunning(name string) (bool, error) {
	containers, err := dk.List(map[string][]string{
		"name": {name},
	})
	if err != nil {
		return false, err
	}
	return len(containers) != 0, nil
}

func (dk docker) create(name, image string, args []string, labels map[string]string,
	env map[string]struct{}, hc *dkc.HostConfig) (string, error) {
	if err := dk.Pull(image); err != nil {
		return "", err
	}

	envList := make([]string, len(env))
	for k := range env {
		envList = append(envList, k)
	}

	container, err := dk.CreateContainer(dkc.CreateContainerOptions{
		Name: name,
		Config: &dkc.Config{
			Image:  string(image),
			Cmd:    args,
			Labels: labels,
			Env:    envList},
		HostConfig: hc,
	})
	if err != nil {
		return "", err
	}

	return container.ID, nil
}

func (dk docker) getID(name string) (string, error) {
	containers, err := dk.list(nil, true)
	if err != nil {
		return "", err
	}

	name = "/" + name
	for _, c := range containers {
		if name == c.Name {
			return c.ID, nil
		}
	}

	return "", errNoSuchContainer
}

// UserLabel returns the supplied label tagged with the user prefix.
func UserLabel(label string) string {
	return userLabelPrefix + label
}

// IsUserLabel returns whether the supplied label represents a Quilt user label.
func IsUserLabel(label string) bool {
	return strings.HasPrefix(label, userLabelPrefix)
}

// ParseUserLabel returns the supplied label with the user prefix stripped.
func ParseUserLabel(label string) string {
	return strings.TrimPrefix(label, userLabelPrefix)
}

// SystemLabel returns the supplied label tagged with the system prefix.
func SystemLabel(label string) string {
	return systemLabelPrefix + label
}

// Get returns the value contained at the given index
func (cs ContainerSlice) Get(ii int) interface{} {
	return cs[ii]
}

// Len returns the number of items in the slice
func (cs ContainerSlice) Len() int {
	return len(cs)
}
<commit_msg>docker: Use a filtered list for getID()<commit_after>package docker

import (
	"archive/tar"
	"bufio"
	"bytes"
	"errors"
	"io"
	"strings"
	"sync"
	"time"

	"github.com/NetSys/quilt/util"

	log "github.com/Sirupsen/logrus"
	dkc "github.com/fsouza/go-dockerclient"
)

const (
	// The root namespace for all labels
	labelBase = "q."

	// This is the namespace for user defined labels
	userLabelPrefix = labelBase + "user.label."

	// This is the namespace for system defined labels
	systemLabelPrefix = labelBase + "system.label."

	// LabelTrueValue is needed because a label has to be a key/value pair, hence
	// this is the value that will be used if we're only interested in the key
	LabelTrueValue = "1"

	// SchedulerLabelKey is the key, used by the scheduler.
	SchedulerLabelKey = systemLabelPrefix + "Quilt"

	// SchedulerLabelValue is the value, used by the scheduler.
	SchedulerLabelValue = "Scheduler"

	// SchedulerLabelPair is the key/value pair, used by the scheduler.
	SchedulerLabelPair = SchedulerLabelKey + "=" + SchedulerLabelValue
)

var errNoSuchContainer = errors.New("container does not exist")

// A Container as returned by the docker client API.
type Container struct {
	ID     string
	Name   string
	Image  string
	IP     string
	Path   string
	Args   []string
	Pid    int
	Env    map[string]string
	Labels map[string]string
}

// ContainerSlice is an alias for []Container to allow for joins
type ContainerSlice []Container

// A Client to the local docker daemon.
type Client interface {
	Run(opts RunOptions) (string, error)
	Exec(name string, cmd ...string) error
	ExecVerbose(name string, cmd ...string) ([]byte, error)
	Remove(name string) error
	RemoveID(id string) error
	Pull(image string) error
	List(filters map[string][]string) ([]Container, error)
	Get(id string) (Container, error)
	WriteToContainer(id, src, dst, archiveName string, permission int) error
	GetFromContainer(id string, src string) (string, error)
	IsRunning(name string) (bool, error)
}

// RunOptions changes the behavior of the Run function.
type RunOptions struct {
	Name   string
	Image  string
	Args   []string
	Labels map[string]string
	Env    map[string]struct{}

	NetworkMode string
	PidMode     string
	Privileged  bool
	VolumesFrom []string
}

type docker struct {
	*dkc.Client
	*sync.Mutex
	imageCache map[string]struct{}
}

// New creates client to the docker daemon.
func New(sock string) Client {
	var client *dkc.Client
	for {
		var err error
		client, err = dkc.NewClient(sock)
		if err != nil {
			log.WithError(err).Warn("Failed to create docker client.")
			time.Sleep(10 * time.Second)
			continue
		}
		break
	}

	return docker{client, &sync.Mutex{}, map[string]struct{}{}}
}

func (dk docker) Run(opts RunOptions) (string, error) {
	hc := dkc.HostConfig{
		NetworkMode: opts.NetworkMode,
		PidMode:     opts.PidMode,
		Privileged:  opts.Privileged,
		VolumesFrom: opts.VolumesFrom,
	}
	id, err := dk.create(opts.Name, opts.Image, opts.Args, opts.Labels, opts.Env, &hc)
	if err != nil {
		return "", err
	}

	if err = dk.StartContainer(id, &hc); err != nil {
		dk.removeID(id) // Remove the container to avoid a zombie.
		return "", err
	}

	return id, nil
}

func (dk docker) Exec(name string, cmd ...string) error {
	_, err := dk.ExecVerbose(name, cmd...)
	return err
}

func (dk docker) ExecVerbose(name string, cmd ...string) ([]byte, error) {
	id, err := dk.getID(name)
	if err != nil {
		return nil, err
	}

	var inBuff, outBuff bytes.Buffer
	exec, err := dk.CreateExec(dkc.CreateExecOptions{
		Container:    id,
		Cmd:          cmd,
		AttachStdout: true})

	if err != nil {
		return nil, err
	}

	err = dk.StartExec(exec.ID, dkc.StartExecOptions{
		OutputStream: &inBuff,
	})

	if err != nil {
		return nil, err
	}

	scanner := bufio.NewScanner(bytes.NewReader(inBuff.Bytes()))
	for scanner.Scan() {
		outBuff.WriteString(scanner.Text() + "\n")
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return outBuff.Bytes(), nil
}

// WriteToContainer writes the contents of SRC into the file at path DST on the
// container with id ID. Overwrites DST if it already exists.
func (dk docker) WriteToContainer(id, src, dst, archiveName string,
	permission int) error {

	tarBuf, err := util.ToTar(archiveName, permission, src)

	if err != nil {
		return err
	}

	err = dk.UploadToContainer(id, dkc.UploadToContainerOptions{
		InputStream: tarBuf,
		Path:        dst,
	})
	if err != nil {
		return err
	}

	return nil
}

// GetFromContainer returns a string containing the content of the file named
// SRC on the container with id ID.
func (dk docker) GetFromContainer(id string, src string) (string, error) {
	var buffIn bytes.Buffer
	var buffOut bytes.Buffer
	err := dk.DownloadFromContainer(id, dkc.DownloadFromContainerOptions{
		OutputStream: &buffIn,
		Path:         src,
	})
	if err != nil {
		return "", err
	}

	writer := io.Writer(&buffOut)

	for tr := tar.NewReader(&buffIn); err != io.EOF; _, err = tr.Next() {

		if err != nil {
			return "", err
		}

		_, err = io.Copy(writer, tr)
		if err != nil {
			return "", err
		}
	}

	return buffOut.String(), nil
}

func (dk docker) Remove(name string) error {
	id, err := dk.getID(name)
	if err != nil {
		return nil // Can't remove a non-existent container.
	}

	log.WithFields(log.Fields{
		"name": name,
		"id":   id,
	}).Info("Remove container.")
	return dk.removeID(id)
}

func (dk docker) RemoveID(id string) error {
	log.WithField("id", id).Info("Remove Container.")
	return dk.removeID(id)
}

func (dk docker) removeID(id string) error {
	err := dk.RemoveContainer(dkc.RemoveContainerOptions{ID: id, Force: true})
	if err != nil {
		return err
	}

	return nil
}

func (dk docker) Pull(image string) error {
	dk.Lock()
	defer dk.Unlock()

	if _, ok := dk.imageCache[image]; ok {
		return nil
	}

	log.Infof("Pulling docker image %s.", image)
	opts := dkc.PullImageOptions{Repository: image}
	if err := dk.PullImage(opts, dkc.AuthConfiguration{}); err != nil {
		return err
	}

	dk.imageCache[image] = struct{}{}
	return nil
}

func (dk docker) List(filters map[string][]string) ([]Container, error) {
	return dk.list(filters, false)
}

func (dk docker) list(filters map[string][]string, all bool) ([]Container, error) {
	opts := dkc.ListContainersOptions{All: all, Filters: filters}
	apics, err := dk.ListContainers(opts)
	if err != nil {
		return nil, err
	}

	var containers []Container
	for _, apic := range apics {
		c, err := dk.Get(apic.ID)
		if err != nil {
			log.WithError(err).Warnf("Failed to inspect container: %s",
				apic.ID)
			continue
		}

		containers = append(containers, c)
	}

	return containers, nil
}

func (dk docker) Get(id string) (Container, error) {
	c, err := dk.InspectContainer(id)
	if err != nil {
		return Container{}, err
	}

	env := make(map[string]string)
	for _, value := range c.Config.Env {
		e := strings.Split(value, "=")
		if len(e) > 1 {
			env[e[0]] = e[1]
		}
	}

	return Container{
		Name:   c.Name,
		ID:     c.ID,
		IP:     c.NetworkSettings.IPAddress,
		Image:  c.Config.Image,
		Path:   c.Path,
		Args:   c.Args,
		Pid:    c.State.Pid,
		Env:    env,
		Labels: c.Config.Labels,
	}, nil
}

func (dk docker) IsRunning(name string) (bool, error) {
	containers, err := dk.List(map[string][]string{
		"name": {name},
	})
	if err != nil {
		return false, err
	}
	return len(containers) != 0, nil
}

func (dk docker) create(name, image string, args []string, labels map[string]string,
	env map[string]struct{}, hc *dkc.HostConfig) (string, error) {
	if err := dk.Pull(image); err != nil {
		return "", err
	}

	envList := make([]string, len(env))
	for k := range env {
		envList = append(envList, k)
	}

	container, err := dk.CreateContainer(dkc.CreateContainerOptions{
		Name: name,
		Config: &dkc.Config{
			Image:  string(image),
			Cmd:    args,
			Labels: labels,
			Env:    envList},
		HostConfig: hc,
	})
	if err != nil {
		return "", err
	}

	return container.ID, nil
}

func (dk docker) getID(name string) (string, error) {
	containers, err := dk.list(map[string][]string{"name": {name}}, true)
	if err != nil {
		return "", err
	}

	if len(containers) > 0 {
		return containers[0].ID, nil
	}

	return "", errNoSuchContainer
}

// UserLabel returns the supplied label tagged with the user prefix.
func UserLabel(label string) string {
	return userLabelPrefix + label
}

// IsUserLabel returns whether the supplied label represents a Quilt user label.
func IsUserLabel(label string) bool {
	return strings.HasPrefix(label, userLabelPrefix)
}

// ParseUserLabel returns the supplied label with the user prefix stripped.
func ParseUserLabel(label string) string {
	return strings.TrimPrefix(label, userLabelPrefix)
}

// SystemLabel returns the supplied label tagged with the system prefix.
func SystemLabel(label string) string {
	return systemLabelPrefix + label
}

// Get returns the value contained at the given index
func (cs ContainerSlice) Get(ii int) interface{} {
	return cs[ii]
}

// Len returns the number of items in the slice
func (cs ContainerSlice) Len() int {
	return len(cs)
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package quick implements utility functions to help with black box testing.
package quick

import (
	"flag"
	"fmt"
	"math"
	"math/rand"
	"reflect"
	"strings"
)

var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")

// A Generator can generate random values of its own type.
type Generator interface {
	// Generate returns a random instance of the type on which it is a
	// method using the size as a size hint.
	Generate(rand *rand.Rand, size int) reflect.Value
}

// randFloat32 generates a random float taking the full range of a float32.
func randFloat32(rand *rand.Rand) float32 {
	f := rand.Float64() * math.MaxFloat32
	if rand.Int()&1 == 1 {
		f = -f
	}
	return float32(f)
}

// randFloat64 generates a random float taking the full range of a float64.
func randFloat64(rand *rand.Rand) float64 {
	f := rand.Float64() * math.MaxFloat64
	if rand.Int()&1 == 1 {
		f = -f
	}
	return f
}

// randInt64 returns a random integer taking half the range of an int64.
func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }

// complexSize is the maximum length of arbitrary values that contain other
// values.
const complexSize = 50

// Value returns an arbitrary value of the given type.
// If the type implements the Generator interface, that will be used.
// Note: To create arbitrary values for structs, all the fields must be exported.
func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
	if m, ok := reflect.Zero(t).Interface().(Generator); ok {
		return m.Generate(rand, complexSize), true
	}

	v := reflect.New(t).Elem()
	switch concrete := t; concrete.Kind() {
	case reflect.Bool:
		v.SetBool(rand.Int()&1 == 0)
	case reflect.Float32:
		v.SetFloat(float64(randFloat32(rand)))
	case reflect.Float64:
		v.SetFloat(randFloat64(rand))
	case reflect.Complex64:
		v.SetComplex(complex(float64(randFloat32(rand)), float64(randFloat32(rand))))
	case reflect.Complex128:
		v.SetComplex(complex(randFloat64(rand), randFloat64(rand)))
	case reflect.Int16:
		v.SetInt(randInt64(rand))
	case reflect.Int32:
		v.SetInt(randInt64(rand))
	case reflect.Int64:
		v.SetInt(randInt64(rand))
	case reflect.Int8:
		v.SetInt(randInt64(rand))
	case reflect.Int:
		v.SetInt(randInt64(rand))
	case reflect.Uint16:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uint32:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uint64:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uint8:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uint:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uintptr:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Map:
		numElems := rand.Intn(complexSize)
		v.Set(reflect.MakeMap(concrete))
		for i := 0; i < numElems; i++ {
			key, ok1 := Value(concrete.Key(), rand)
			value, ok2 := Value(concrete.Elem(), rand)
			if !ok1 || !ok2 {
				return reflect.Value{}, false
			}
			v.SetMapIndex(key, value)
		}
	case reflect.Ptr:
		elem, ok := Value(concrete.Elem(), rand)
		if !ok {
			return reflect.Value{}, false
		}
		v.Set(reflect.New(concrete.Elem()))
		v.Elem().Set(elem)
	case reflect.Slice:
		numElems := rand.Intn(complexSize)
		v.Set(reflect.MakeSlice(concrete, numElems, numElems))
		for i := 0; i < numElems; i++ {
			elem, ok := Value(concrete.Elem(), rand)
			if !ok {
				return reflect.Value{}, false
			}
			v.Index(i).Set(elem)
		}
	case reflect.Array:
		for i := 0; i < v.Len(); i++ {
			elem, ok := Value(concrete.Elem(), rand)
			if !ok {
				return reflect.Value{}, false
			}
			v.Index(i).Set(elem)
		}
	case reflect.String:
		numChars := rand.Intn(complexSize)
		codePoints := make([]rune, numChars)
		for i := 0; i < numChars; i++ {
			codePoints[i] = rune(rand.Intn(0x10ffff))
		}
		v.SetString(string(codePoints))
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			elem, ok := Value(concrete.Field(i).Type, rand)
			if !ok {
				return reflect.Value{}, false
			}
			v.Field(i).Set(elem)
		}
	default:
		return reflect.Value{}, false
	}

	return v, true
}

// A Config structure contains options for running a test.
type Config struct {
	// MaxCount sets the maximum number of iterations. If zero,
	// MaxCountScale is used.
	MaxCount int
	// MaxCountScale is a non-negative scale factor applied to the default
	// maximum. If zero, the default is unchanged.
	MaxCountScale float64
	// If non-nil, rand is a source of random numbers. Otherwise a default
	// pseudo-random source will be used.
	Rand *rand.Rand
	// If non-nil, the Values function generates a slice of arbitrary
	// reflect.Values that are congruent with the arguments to the function
	// being tested. Otherwise, the top-level Values function is used
	// to generate them.
	Values func([]reflect.Value, *rand.Rand)
}

var defaultConfig Config

// getRand returns the *rand.Rand to use for a given Config.
func (c *Config) getRand() *rand.Rand {
	if c.Rand == nil {
		return rand.New(rand.NewSource(0))
	}
	return c.Rand
}

// getMaxCount returns the maximum number of iterations to run for a given
// Config.
func (c *Config) getMaxCount() (maxCount int) {
	maxCount = c.MaxCount
	if maxCount == 0 {
		if c.MaxCountScale != 0 {
			maxCount = int(c.MaxCountScale * float64(*defaultMaxCount))
		} else {
			maxCount = *defaultMaxCount
		}
	}

	return
}

// A SetupError is the result of an error in the way that check is being
// used, independent of the functions being tested.
type SetupError string

func (s SetupError) Error() string { return string(s) }

// A CheckError is the result of Check finding an error.
type CheckError struct {
	Count int
	In    []interface{}
}

func (s *CheckError) Error() string {
	return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
}

// A CheckEqualError is the result CheckEqual finding an error.
type CheckEqualError struct {
	CheckError
	Out1 []interface{}
	Out2 []interface{}
}

func (s *CheckEqualError) Error() string {
	return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
}

// Check looks for an input to f, any function that returns bool,
// such that f returns false.  It calls f repeatedly, with arbitrary
// values for each argument.  If f returns false on a given input,
// Check returns that input as a *CheckError.
// For example:
//
// 	func TestOddMultipleOfThree(t *testing.T) {
// 		f := func(x int) bool {
// 			y := OddMultipleOfThree(x)
// 			return y%2 == 1 && y%3 == 0
// 		}
// 		if err := quick.Check(f, nil); err != nil {
// 			t.Error(err)
// 		}
// 	}
func Check(f interface{}, config *Config) (err error) {
	if config == nil {
		config = &defaultConfig
	}

	fVal, fType, ok := functionAndType(f)
	if !ok {
		err = SetupError("argument is not a function")
		return
	}

	if fType.NumOut() != 1 {
		err = SetupError("function returns more than one value.")
		return
	}
	if fType.Out(0).Kind() != reflect.Bool {
		err = SetupError("function does not return a bool")
		return
	}

	arguments := make([]reflect.Value, fType.NumIn())
	rand := config.getRand()
	maxCount := config.getMaxCount()

	for i := 0; i < maxCount; i++ {
		err = arbitraryValues(arguments, fType, config, rand)
		if err != nil {
			return
		}

		if !fVal.Call(arguments)[0].Bool() {
			err = &CheckError{i + 1, toInterfaces(arguments)}
			return
		}
	}

	return
}

// CheckEqual looks for an input on which f and g return different results.
// It calls f and g repeatedly with arbitrary values for each argument.
// If f and g return different answers, CheckEqual returns a *CheckEqualError
// describing the input and the outputs.
func CheckEqual(f, g interface{}, config *Config) (err error) {
	if config == nil {
		config = &defaultConfig
	}

	x, xType, ok := functionAndType(f)
	if !ok {
		err = SetupError("f is not a function")
		return
	}
	y, yType, ok := functionAndType(g)
	if !ok {
		err = SetupError("g is not a function")
		return
	}

	if xType != yType {
		err = SetupError("functions have different types")
		return
	}

	arguments := make([]reflect.Value, xType.NumIn())
	rand := config.getRand()
	maxCount := config.getMaxCount()

	for i := 0; i < maxCount; i++ {
		err = arbitraryValues(arguments, xType, config, rand)
		if err != nil {
			return
		}

		xOut := toInterfaces(x.Call(arguments))
		yOut := toInterfaces(y.Call(arguments))

		if !reflect.DeepEqual(xOut, yOut) {
			err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
			return
		}
	}

	return
}

// arbitraryValues writes Values to args such that args contains Values
// suitable for calling f.
func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err error) {
	if config.Values != nil {
		config.Values(args, rand)
		return
	}

	for j := 0; j < len(args); j++ {
		var ok bool
		args[j], ok = Value(f.In(j), rand)
		if !ok {
			err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
			return
		}
	}

	return
}

func functionAndType(f interface{}) (v reflect.Value, t reflect.Type, ok bool) {
	v = reflect.ValueOf(f)
	ok = v.Kind() == reflect.Func
	if !ok {
		return
	}
	t = v.Type()
	return
}

func toInterfaces(values []reflect.Value) []interface{} {
	ret := make([]interface{}, len(values))
	for i, v := range values {
		ret[i] = v.Interface()
	}
	return ret
}

func toString(interfaces []interface{}) string {
	s := make([]string, len(interfaces))
	for i, v := range interfaces {
		s[i] = fmt.Sprintf("%#v", v)
	}
	return strings.Join(s, ", ")
}
<commit_msg>testing/quick: fix comment<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package quick implements utility functions to help with black box testing.
package quick

import (
	"flag"
	"fmt"
	"math"
	"math/rand"
	"reflect"
	"strings"
)

var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check")

// A Generator can generate random values of its own type.
type Generator interface {
	// Generate returns a random instance of the type on which it is a
	// method using the size as a size hint.
	Generate(rand *rand.Rand, size int) reflect.Value
}

// randFloat32 generates a random float taking the full range of a float32.
func randFloat32(rand *rand.Rand) float32 {
	f := rand.Float64() * math.MaxFloat32
	if rand.Int()&1 == 1 {
		f = -f
	}
	return float32(f)
}

// randFloat64 generates a random float taking the full range of a float64.
func randFloat64(rand *rand.Rand) float64 {
	f := rand.Float64() * math.MaxFloat64
	if rand.Int()&1 == 1 {
		f = -f
	}
	return f
}

// randInt64 returns a random integer taking half the range of an int64.
func randInt64(rand *rand.Rand) int64 { return rand.Int63() - 1<<62 }

// complexSize is the maximum length of arbitrary values that contain other
// values.
const complexSize = 50

// Value returns an arbitrary value of the given type.
// If the type implements the Generator interface, that will be used.
// Note: To create arbitrary values for structs, all the fields must be exported.
func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
	if m, ok := reflect.Zero(t).Interface().(Generator); ok {
		return m.Generate(rand, complexSize), true
	}

	v := reflect.New(t).Elem()
	switch concrete := t; concrete.Kind() {
	case reflect.Bool:
		v.SetBool(rand.Int()&1 == 0)
	case reflect.Float32:
		v.SetFloat(float64(randFloat32(rand)))
	case reflect.Float64:
		v.SetFloat(randFloat64(rand))
	case reflect.Complex64:
		v.SetComplex(complex(float64(randFloat32(rand)), float64(randFloat32(rand))))
	case reflect.Complex128:
		v.SetComplex(complex(randFloat64(rand), randFloat64(rand)))
	case reflect.Int16:
		v.SetInt(randInt64(rand))
	case reflect.Int32:
		v.SetInt(randInt64(rand))
	case reflect.Int64:
		v.SetInt(randInt64(rand))
	case reflect.Int8:
		v.SetInt(randInt64(rand))
	case reflect.Int:
		v.SetInt(randInt64(rand))
	case reflect.Uint16:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uint32:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uint64:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uint8:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uint:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Uintptr:
		v.SetUint(uint64(randInt64(rand)))
	case reflect.Map:
		numElems := rand.Intn(complexSize)
		v.Set(reflect.MakeMap(concrete))
		for i := 0; i < numElems; i++ {
			key, ok1 := Value(concrete.Key(), rand)
			value, ok2 := Value(concrete.Elem(), rand)
			if !ok1 || !ok2 {
				return reflect.Value{}, false
			}
			v.SetMapIndex(key, value)
		}
	case reflect.Ptr:
		elem, ok := Value(concrete.Elem(), rand)
		if !ok {
			return reflect.Value{}, false
		}
		v.Set(reflect.New(concrete.Elem()))
		v.Elem().Set(elem)
	case reflect.Slice:
		numElems := rand.Intn(complexSize)
		v.Set(reflect.MakeSlice(concrete, numElems, numElems))
		for i := 0; i < numElems; i++ {
			elem, ok := Value(concrete.Elem(), rand)
			if !ok {
				return reflect.Value{}, false
			}
			v.Index(i).Set(elem)
		}
	case reflect.Array:
		for i := 0; i < v.Len(); i++ {
			elem, ok := Value(concrete.Elem(), rand)
			if !ok {
				return reflect.Value{}, false
			}
			v.Index(i).Set(elem)
		}
	case reflect.String:
		numChars := rand.Intn(complexSize)
		codePoints := make([]rune, numChars)
		for i := 0; i < numChars; i++ {
			codePoints[i] = rune(rand.Intn(0x10ffff))
		}
		v.SetString(string(codePoints))
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			elem, ok := Value(concrete.Field(i).Type, rand)
			if !ok {
				return reflect.Value{}, false
			}
			v.Field(i).Set(elem)
		}
	default:
		return reflect.Value{}, false
	}

	return v, true
}

// A Config structure contains options for running a test.
type Config struct {
	// MaxCount sets the maximum number of iterations. If zero,
	// MaxCountScale is used.
	MaxCount int
	// MaxCountScale is a non-negative scale factor applied to the default
	// maximum. If zero, the default is unchanged.
	MaxCountScale float64
	// If non-nil, rand is a source of random numbers. Otherwise a default
	// pseudo-random source will be used.
	Rand *rand.Rand
	// If non-nil, the Values function generates a slice of arbitrary
	// reflect.Values that are congruent with the arguments to the function
	// being tested. Otherwise, the top-level Value function is used
	// to generate them.
	Values func([]reflect.Value, *rand.Rand)
}

var defaultConfig Config

// getRand returns the *rand.Rand to use for a given Config.
func (c *Config) getRand() *rand.Rand {
	if c.Rand == nil {
		return rand.New(rand.NewSource(0))
	}
	return c.Rand
}

// getMaxCount returns the maximum number of iterations to run for a given
// Config.
func (c *Config) getMaxCount() (maxCount int) {
	maxCount = c.MaxCount
	if maxCount == 0 {
		if c.MaxCountScale != 0 {
			maxCount = int(c.MaxCountScale * float64(*defaultMaxCount))
		} else {
			maxCount = *defaultMaxCount
		}
	}

	return
}

// A SetupError is the result of an error in the way that check is being
// used, independent of the functions being tested.
type SetupError string

func (s SetupError) Error() string { return string(s) }

// A CheckError is the result of Check finding an error.
type CheckError struct {
	Count int
	In    []interface{}
}

func (s *CheckError) Error() string {
	return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In))
}

// A CheckEqualError is the result CheckEqual finding an error.
type CheckEqualError struct {
	CheckError
	Out1 []interface{}
	Out2 []interface{}
}

func (s *CheckEqualError) Error() string {
	return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2))
}

// Check looks for an input to f, any function that returns bool,
// such that f returns false.  It calls f repeatedly, with arbitrary
// values for each argument.  If f returns false on a given input,
// Check returns that input as a *CheckError.
// For example:
//
// 	func TestOddMultipleOfThree(t *testing.T) {
// 		f := func(x int) bool {
// 			y := OddMultipleOfThree(x)
// 			return y%2 == 1 && y%3 == 0
// 		}
// 		if err := quick.Check(f, nil); err != nil {
// 			t.Error(err)
// 		}
// 	}
func Check(f interface{}, config *Config) (err error) {
	if config == nil {
		config = &defaultConfig
	}

	fVal, fType, ok := functionAndType(f)
	if !ok {
		err = SetupError("argument is not a function")
		return
	}

	if fType.NumOut() != 1 {
		err = SetupError("function returns more than one value.")
		return
	}
	if fType.Out(0).Kind() != reflect.Bool {
		err = SetupError("function does not return a bool")
		return
	}

	arguments := make([]reflect.Value, fType.NumIn())
	rand := config.getRand()
	maxCount := config.getMaxCount()

	for i := 0; i < maxCount; i++ {
		err = arbitraryValues(arguments, fType, config, rand)
		if err != nil {
			return
		}

		if !fVal.Call(arguments)[0].Bool() {
			err = &CheckError{i + 1, toInterfaces(arguments)}
			return
		}
	}

	return
}

// CheckEqual looks for an input on which f and g return different results.
// It calls f and g repeatedly with arbitrary values for each argument.
// If f and g return different answers, CheckEqual returns a *CheckEqualError
// describing the input and the outputs.
func CheckEqual(f, g interface{}, config *Config) (err error) {
	if config == nil {
		config = &defaultConfig
	}

	x, xType, ok := functionAndType(f)
	if !ok {
		err = SetupError("f is not a function")
		return
	}
	y, yType, ok := functionAndType(g)
	if !ok {
		err = SetupError("g is not a function")
		return
	}

	if xType != yType {
		err = SetupError("functions have different types")
		return
	}

	arguments := make([]reflect.Value, xType.NumIn())
	rand := config.getRand()
	maxCount := config.getMaxCount()

	for i := 0; i < maxCount; i++ {
		err = arbitraryValues(arguments, xType, config, rand)
		if err != nil {
			return
		}

		xOut := toInterfaces(x.Call(arguments))
		yOut := toInterfaces(y.Call(arguments))

		if !reflect.DeepEqual(xOut, yOut) {
			err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
			return
		}
	}

	return
}

// arbitraryValues writes Values to args such that args contains Values
// suitable for calling f.
func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err error) {
	if config.Values != nil {
		config.Values(args, rand)
		return
	}

	for j := 0; j < len(args); j++ {
		var ok bool
		args[j], ok = Value(f.In(j), rand)
		if !ok {
			err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j))
			return
		}
	}

	return
}

func functionAndType(f interface{}) (v reflect.Value, t reflect.Type, ok bool) {
	v = reflect.ValueOf(f)
	ok = v.Kind() == reflect.Func
	if !ok {
		return
	}
	t = v.Type()
	return
}

func toInterfaces(values []reflect.Value) []interface{} {
	ret := make([]interface{}, len(values))
	for i, v := range values {
		ret[i] = v.Interface()
	}
	return ret
}

func toString(interfaces []interface{}) string {
	s := make([]string, len(interfaces))
	for i, v := range interfaces {
		s[i] = fmt.Sprintf("%#v", v)
	}
	return strings.Join(s, ", ")
}
<|endoftext|>


<commit_before>package shell

import (
	"fmt"

	"github.com/kardianos/osext"
)

const template = `#!/usr/bin/env zsh
ANTIBODY_BINARY="%s"
antibody() {
	case "$1" in
	bundle|update)
		tmp_dir=$(mktemp -d)
		while read -u 3 bundle; do
			source "$bundle" 2&> ${temp_dir}/antibody-log
		done 3< <( $ANTIBODY_BINARY $@ )
		;;
	*)
		$ANTIBODY_BINARY $@
		;;
	esac
}

_antibody() {
	IFS=' ' read -A reply <<< "$(echo "bundle update list help")"
}
compctl -K _antibody antibody
`

// Init returns the shell that should be loaded to antibody to work correctly.
func Init() string {
	executable, _ := osext.Executable()
	return fmt.Sprintf(template, executable)
}
<commit_msg>Save log to /tmp/$USER-antibody-log<commit_after>package shell

import (
	"fmt"

	"github.com/kardianos/osext"
)

const template = `#!/usr/bin/env zsh
ANTIBODY_BINARY="%s"
antibody() {
	case "$1" in
	bundle|update)
		while read -u 3 bundle; do
			source "$bundle" 2&> /tmp/${USER}-antibody-log
		done 3< <( $ANTIBODY_BINARY $@ )
		;;
	*)
		$ANTIBODY_BINARY $@
		;;
	esac
}

_antibody() {
	IFS=' ' read -A reply <<< "$(echo "bundle update list help")"
}
compctl -K _antibody antibody
`

// Init returns the shell that should be loaded to antibody to work correctly.
func Init() string {
	executable, _ := osext.Executable()
	return fmt.Sprintf(template, executable)
}
<|endoftext|>


<commit_before>package crawler

import (
	"context"
	"time"

	"go.opentelemetry.io/otel/label"

	index_types "github.com/ipfs-search/ipfs-search/components/index/types"
	t "github.com/ipfs-search/ipfs-search/types"
)

func appendReference(refs index_types.References, r *t.Reference) (index_types.References, bool) {
	if r.Parent == nil {
		// No new reference, not updating
		return refs, false
	}

	for _, indexedRef := range refs {
		if indexedRef.ParentHash == r.Parent.ID && indexedRef.Name == r.Name {
			// Existing reference, not updating
			return refs, false
		}
	}

	return append(refs, index_types.Reference{
		ParentHash: r.Parent.ID,
		Name:       r.Name,
	}), true
}

// updateExisting updates known existing items.
func (c *Crawler) updateExisting(ctx context.Context, i *existingItem) error {
	ctx, span := c.Tracer.Start(ctx, "crawler.updateExisting")
	defer span.End()

	refs, refsUpdated := appendReference(i.References, &i.AnnotatedResource.Reference)

	now := time.Now()
	isRecent := now.Sub(i.LastSeen) > c.config.MinUpdateAge

	if refsUpdated || isRecent {
		if span.IsRecording() {
			var reason string

			if refsUpdated {
				reason = "reference-added"
			}

			if isRecent {
				reason = "is-recent"
			}
			span.AddEvent(ctx, "Updating",
				label.String("reason", reason),
				label.Any("new-reference", i.AnnotatedResource.Reference),
				label.Stringer("last-seen", i.LastSeen),
			)
		}

		return i.Index.Update(ctx, i.AnnotatedResource.ID, &index_types.Update{
			LastSeen:   now,
			References: refs,
		})
	} else {
		span.AddEvent(ctx, "Not updating")
	}

	return nil
}

// updateMaybeExisting updates an item when it exists and returnes true when item exists.
func (c *Crawler) updateMaybeExisting(ctx context.Context, r *t.AnnotatedResource) (bool, error) {
	ctx, span := c.Tracer.Start(ctx, "crawler.updateMaybeExisting")
	defer span.End()

	existing, err := c.getExistingItem(ctx, r)
	if err != nil {
		return false, err
	}

	// Process existing item
	if existing != nil {
		if span.IsRecording() {
			span.AddEvent(ctx, "existing", label.Any("index", existing.Index))
		}

		if existing.Index == c.indexes.Invalids {
			// Already indexed as invalid; we're done
			return true, nil
		}

		// Update item and we're done.
		if err = c.updateExisting(ctx, existing); err != nil {
			return true, err
		}

		return true, nil
	}

	return false, nil
}
<commit_msg>Make sure to also truncate LastSeen on updates.<commit_after>package crawler

import (
	"context"
	"time"

	"go.opentelemetry.io/otel/label"

	index_types "github.com/ipfs-search/ipfs-search/components/index/types"
	t "github.com/ipfs-search/ipfs-search/types"
)

func appendReference(refs index_types.References, r *t.Reference) (index_types.References, bool) {
	if r.Parent == nil {
		// No new reference, not updating
		return refs, false
	}

	for _, indexedRef := range refs {
		if indexedRef.ParentHash == r.Parent.ID && indexedRef.Name == r.Name {
			// Existing reference, not updating
			return refs, false
		}
	}

	return append(refs, index_types.Reference{
		ParentHash: r.Parent.ID,
		Name:       r.Name,
	}), true
}

// updateExisting updates known existing items.
func (c *Crawler) updateExisting(ctx context.Context, i *existingItem) error {
	ctx, span := c.Tracer.Start(ctx, "crawler.updateExisting")
	defer span.End()

	refs, refsUpdated := appendReference(i.References, &i.AnnotatedResource.Reference)

	now := time.Now()

	// Strip milliseconds to cater to legacy ES index format.
	// This can be safely removed after the next reindex with _nomillis removed from time format.
	now = now.Truncate(time.Second)

	isRecent := now.Sub(i.LastSeen) > c.config.MinUpdateAge

	if refsUpdated || isRecent {
		if span.IsRecording() {
			var reason string

			if refsUpdated {
				reason = "reference-added"
			}

			if isRecent {
				reason = "is-recent"
			}
			span.AddEvent(ctx, "Updating",
				label.String("reason", reason),
				label.Any("new-reference", i.AnnotatedResource.Reference),
				label.Stringer("last-seen", i.LastSeen),
			)
		}

		return i.Index.Update(ctx, i.AnnotatedResource.ID, &index_types.Update{
			LastSeen:   now,
			References: refs,
		})
	} else {
		span.AddEvent(ctx, "Not updating")
	}

	return nil
}

// updateMaybeExisting updates an item when it exists and returnes true when item exists.
func (c *Crawler) updateMaybeExisting(ctx context.Context, r *t.AnnotatedResource) (bool, error) {
	ctx, span := c.Tracer.Start(ctx, "crawler.updateMaybeExisting")
	defer span.End()

	existing, err := c.getExistingItem(ctx, r)
	if err != nil {
		return false, err
	}

	// Process existing item
	if existing != nil {
		if span.IsRecording() {
			span.AddEvent(ctx, "existing", label.Any("index", existing.Index))
		}

		if existing.Index == c.indexes.Invalids {
			// Already indexed as invalid; we're done
			return true, nil
		}

		// Update item and we're done.
		if err = c.updateExisting(ctx, existing); err != nil {
			return true, err
		}

		return true, nil
	}

	return false, nil
}
<|endoftext|>


<commit_before>package scipipe

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	t "testing"
)

func TestShellHasInOutPorts(t *t.T) {
	tt := Sh("echo {i:in1} {o:out1}")
	tt.OutPathFuncs["out1"] = func() string {
		return fmt.Sprint(tt.InPaths["in1"], ".bar")
	}

	tt.InPorts["in1"] = make(chan *FileTarget, BUFSIZE)
	go func() { tt.InPorts["in1"] <- NewFileTarget("foo.txt") }()
	go tt.Run()
	<-tt.OutPorts["out1"]

	assert.NotNil(t, tt.InPorts["in1"], "InPorts are nil!")
	assert.NotNil(t, tt.OutPorts["out1"], "OutPorts are nil!")

	cleanFiles("foo.txt", "foo.txt.bar")
}

func TestShellCloseOutPortOnInPortClose(t *t.T) {
	fooTask := Sh("echo foo > {o:out1}")
	fooTask.OutPathFuncs["out1"] = func() string {
		return "foo.txt"
	}

	barReplacer := Sh("sed 's/foo/bar/g' {i:foo} > {o:bar}")
	barReplacer.OutPathFuncs["bar"] = func() string {
		return barReplacer.GetInPath("foo") + ".bar"
	}

	barReplacer.InPorts["foo"] = fooTask.OutPorts["out1"]

	go fooTask.Run()
	go barReplacer.Run()
	<-barReplacer.OutPorts["bar"]

	// Assert no more content coming on channels
	assert.Nil(t, <-fooTask.OutPorts["out1"])
	assert.Nil(t, <-barReplacer.OutPorts["bar"])

	_, fooErr := os.Stat("foo.txt")
	assert.Nil(t, fooErr)
	_, barErr := os.Stat("foo.txt.bar")
	assert.Nil(t, barErr)

	cleanFiles("foo.txt", "foo.txt.bar")
}

func TestReplacePlaceholdersInCmd(t *t.T) {
	rawCmd := "echo {i:in1} > {o:out1}"
	tt := Sh(rawCmd)
	tt.OutPathFuncs["out1"] = func() string {
		return fmt.Sprint(tt.InPaths["in1"], ".bar")
	}

	tt.InPorts["in1"] = make(chan *FileTarget, BUFSIZE)
	ift := NewFileTarget("foo.txt")
	go func() {
		defer close(tt.InPorts["in1"])
		tt.InPorts["in1"] <- ift
	}()

	// Assert inport is still open after first read
	inPortsClosed := tt.receiveInputs()
	assert.Equal(t, false, inPortsClosed)

	// Assert inport is closed after second read
	inPortsClosed = tt.receiveInputs()
	assert.Equal(t, true, inPortsClosed)

	// Assert InPath is correct
	assert.Equal(t, "foo.txt", tt.InPaths["in1"], "foo.txt")

	// Assert placeholders are correctly replaced in command
	cmd := tt.replacePlaceholdersInCmd(rawCmd)
	assert.EqualValues(t, "echo foo.txt > foo.txt.bar", cmd)
}

func TestParameterCommand(t *t.T) {
	// An abc file printer
	abc := Sh("echo {p:a} {p:b} {p:c} > {o:out}")
	abc.OutPathFuncs["out"] = func() string {
		return fmt.Sprintf(
			"%s_%s_%s.txt",
			abc.Params["a"],
			abc.Params["b"],
			abc.Params["c"],
		)
	}

	// A printer task
	prt := Sh("cat {i:in} >> /tmp/log.txt; rm {i:in}")

	// Connection info
	prt.InPorts["in"] = abc.OutPorts["out"]

	// Feed the task with multiple combinations
	go func() {
		defer close(abc.ParamPorts["a"])
		defer close(abc.ParamPorts["b"])
		defer close(abc.ParamPorts["c"])

		for _, a := range SS("a1", "a2", "a3") {
			for _, b := range SS("b1", "b2", "b3") {
				for _, c := range SS("c1", "c2", "c3") {
					abc.ParamPorts["a"] <- a
					abc.ParamPorts["b"] <- b
					abc.ParamPorts["c"] <- c
				}
			}
		}
	}()

	go abc.Run()
	prt.Run()
	fmt.Println("Finished TestParameterCommand")

	_, err := os.Stat("/tmp/log.txt")
	assert.Nil(t, err)

	cleanFiles("/tmp/log.txt")
}

func cleanFiles(fileNames ...string) {
	for _, fileName := range fileNames {
		if _, err := os.Stat(fileName); err == nil {
			fmt.Println("Removing file", fileName)
			os.Remove(fileName)
			fmt.Println("Successfully removed file", fileName)
		}
	}
}
<commit_msg>Use pipeline and combinatorics task in shell test<commit_after>package scipipe

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"os"
	t "testing"
)

func TestShellHasInOutPorts(t *t.T) {
	tt := Sh("echo {i:in1} {o:out1}")
	tt.OutPathFuncs["out1"] = func() string {
		return fmt.Sprint(tt.InPaths["in1"], ".bar")
	}

	tt.InPorts["in1"] = make(chan *FileTarget, BUFSIZE)
	go func() { tt.InPorts["in1"] <- NewFileTarget("foo.txt") }()
	go tt.Run()
	<-tt.OutPorts["out1"]

	assert.NotNil(t, tt.InPorts["in1"], "InPorts are nil!")
	assert.NotNil(t, tt.OutPorts["out1"], "OutPorts are nil!")

	cleanFiles("foo.txt", "foo.txt.bar")
}

func TestShellCloseOutPortOnInPortClose(t *t.T) {
	fooTask := Sh("echo foo > {o:out1}")
	fooTask.OutPathFuncs["out1"] = func() string {
		return "foo.txt"
	}

	barReplacer := Sh("sed 's/foo/bar/g' {i:foo} > {o:bar}")
	barReplacer.OutPathFuncs["bar"] = func() string {
		return barReplacer.GetInPath("foo") + ".bar"
	}

	barReplacer.InPorts["foo"] = fooTask.OutPorts["out1"]

	go fooTask.Run()
	go barReplacer.Run()
	<-barReplacer.OutPorts["bar"]

	// Assert no more content coming on channels
	assert.Nil(t, <-fooTask.OutPorts["out1"])
	assert.Nil(t, <-barReplacer.OutPorts["bar"])

	_, fooErr := os.Stat("foo.txt")
	assert.Nil(t, fooErr)
	_, barErr := os.Stat("foo.txt.bar")
	assert.Nil(t, barErr)

	cleanFiles("foo.txt", "foo.txt.bar")
}

func TestReplacePlaceholdersInCmd(t *t.T) {
	rawCmd := "echo {i:in1} > {o:out1}"
	tt := Sh(rawCmd)
	tt.OutPathFuncs["out1"] = func() string {
		return fmt.Sprint(tt.InPaths["in1"], ".bar")
	}

	tt.InPorts["in1"] = make(chan *FileTarget, BUFSIZE)
	ift := NewFileTarget("foo.txt")
	go func() {
		defer close(tt.InPorts["in1"])
		tt.InPorts["in1"] <- ift
	}()

	// Assert inport is still open after first read
	inPortsClosed := tt.receiveInputs()
	assert.Equal(t, false, inPortsClosed)

	// Assert inport is closed after second read
	inPortsClosed = tt.receiveInputs()
	assert.Equal(t, true, inPortsClosed)

	// Assert InPath is correct
	assert.Equal(t, "foo.txt", tt.InPaths["in1"], "foo.txt")

	// Assert placeholders are correctly replaced in command
	cmd := tt.replacePlaceholdersInCmd(rawCmd)
	assert.EqualValues(t, "echo foo.txt > foo.txt.bar", cmd)
}

func TestParameterCommand(t *t.T) {
	cmb := NewCombinatoricsTask()

	// An abc file printer
	abc := Sh("echo {p:a} {p:b} {p:c} > {o:out}")
	abc.OutPathFuncs["out"] = func() string {
		return fmt.Sprintf(
			"%s_%s_%s.txt",
			abc.Params["a"],
			abc.Params["b"],
			abc.Params["c"],
		)
	}

	// A printer task
	prt := Sh("cat {i:in} >> /tmp/log.txt; rm {i:in}")

	// Connection info
	abc.ParamPorts["a"] = cmb.A
	abc.ParamPorts["b"] = cmb.B
	abc.ParamPorts["c"] = cmb.C
	prt.InPorts["in"] = abc.OutPorts["out"]

	pl := NewPipeline()
	pl.AddTasks(cmb, abc, prt)
	pl.Run()

	// Run tests
	_, err := os.Stat("/tmp/log.txt")
	assert.Nil(t, err)

	cleanFiles("/tmp/log.txt")
}

// Helper functions

func cleanFiles(fileNames ...string) {
	for _, fileName := range fileNames {
		if _, err := os.Stat(fileName); err == nil {
			fmt.Println("Removing file", fileName)
			os.Remove(fileName)
			fmt.Println("Successfully removed file", fileName)
		}
	}
}

// Helper tasks

type CombinatoricsTask struct {
	BaseTask
	A chan string
	B chan string
	C chan string
}

func NewCombinatoricsTask() *CombinatoricsTask {
	return &CombinatoricsTask{
		A: make(chan string, BUFSIZE),
		B: make(chan string, BUFSIZE),
		C: make(chan string, BUFSIZE),
	}
}

func (proc *CombinatoricsTask) Run() {
	defer close(proc.A)
	defer close(proc.B)
	defer close(proc.C)

	for _, a := range SS("a1", "a2", "a3") {
		for _, b := range SS("b1", "b2", "b3") {
			for _, c := range SS("c1", "c2", "c3") {
				proc.A <- a
				proc.B <- b
				proc.C <- c
			}
		}
	}
}
<|endoftext|>


<commit_before>package postgres

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"path"
	"path/filepath"
	gotemplate "text/template"

	"github.com/nuveo/log"
	"github.com/prest/prest/adapters"
	"github.com/prest/prest/adapters/postgres/internal/connection"
	"github.com/prest/prest/adapters/scanner"
	"github.com/prest/prest/config"
	"github.com/prest/prest/template"
)

// GetScript get SQL template file
func (adapter *Postgres) GetScript(verb, folder, scriptName string) (script string, err error) {
	verbs := map[string]string{
		"GET":    ".read.sql",
		"POST":   ".write.sql",
		"PATCH":  ".update.sql",
		"PUT":    ".update.sql",
		"DELETE": ".delete.sql",
	}

	sufix, ok := verbs[verb]
	if !ok {
		err = fmt.Errorf("invalid http method %s", verb)
		return
	}

	script = filepath.Join(config.PrestConf.QueriesPath, folder, fmt.Sprint(scriptName, sufix))

	if _, err = os.Stat(script); os.IsNotExist(err) {
		err = fmt.Errorf("could not load %s", script)
		return
	}

	return
}

// ParseScript use values sent by users and add on script
func (adapter *Postgres) ParseScript(scriptPath string, templateData map[string]interface{}) (sqlQuery string, values []interface{}, err error) {
	_, tplName := path.Split(scriptPath)

	funcs := &template.FuncRegistry{TemplateData: templateData}
	tpl := gotemplate.New(tplName).Funcs(funcs.RegistryAllFuncs())

	tpl, err = tpl.ParseFiles(scriptPath)
	if err != nil {
		err = fmt.Errorf("could not parse file %s: %+v", scriptPath, err)
		return
	}

	var buff bytes.Buffer
	err = tpl.Execute(&buff, funcs.TemplateData)
	if err != nil {
		err = fmt.Errorf("could not execute template %v", err)
		return
	}

	sqlQuery = buff.String()
	return
}

// WriteSQL perform INSERT's, UPDATE's, DELETE's operations
func WriteSQL(sql string, values []interface{}) (sc adapters.Scanner) {
	db, err := connection.Get()
	if err != nil {
		log.Println(err)
		sc = &scanner.PrestScanner{Error: err}
		return
	}
	stmt, err := Prepare(db, sql)
	if err != nil {
		log.Printf("could not prepare sql: %s\n Error: %v\n", sql, err)
		sc = &scanner.PrestScanner{Error: err}
		return
	}
	valuesAux := make([]interface{}, 0, len(values))

	for i := 0; i < len(values); i++ {
		valuesAux = append(valuesAux, values[i])
	}

	result, err := stmt.Exec(valuesAux...)
	if err != nil {
		log.Printf("sql = %+v\n", sql)
		err = fmt.Errorf("could not peform sql: %v", err)
		sc = &scanner.PrestScanner{Error: err}
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		err = fmt.Errorf("could not rows affected: %v", err)
		sc = &scanner.PrestScanner{Error: err}
		return
	}

	data := make(map[string]interface{})
	data["rows_affected"] = rowsAffected
	var resultByte []byte
	resultByte, err = json.Marshal(data)
	sc = &scanner.PrestScanner{
		Error: err,
		Buff:  bytes.NewBuffer(resultByte),
	}
	return
}

// ExecuteScripts run sql templates created by users
func (adapter *Postgres) ExecuteScripts(method, sql string, values []interface{}) (sc adapters.Scanner) {
	switch method {
	case "GET":
		sc = adapter.Query(sql, values...)
	case "POST", "PUT", "PATCH", "DELETE":
		sc = WriteSQL(sql, values)
	default:
		sc = &scanner.PrestScanner{Error: fmt.Errorf("invalid method %s", method)}
	}

	return
}
<commit_msg>Fixed: The problem that the sql template path cannot be parsed correctly on the windows system.<commit_after>package postgres

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	gotemplate "text/template"

	"github.com/nuveo/log"
	"github.com/prest/prest/adapters"
	"github.com/prest/prest/adapters/postgres/internal/connection"
	"github.com/prest/prest/adapters/scanner"
	"github.com/prest/prest/config"
	"github.com/prest/prest/template"
)

// GetScript get SQL template file
func (adapter *Postgres) GetScript(verb, folder, scriptName string) (script string, err error) {
	verbs := map[string]string{
		"GET":    ".read.sql",
		"POST":   ".write.sql",
		"PATCH":  ".update.sql",
		"PUT":    ".update.sql",
		"DELETE": ".delete.sql",
	}

	sufix, ok := verbs[verb]
	if !ok {
		err = fmt.Errorf("invalid http method %s", verb)
		return
	}

	script = filepath.Join(config.PrestConf.QueriesPath, folder, fmt.Sprint(scriptName, sufix))

	if _, err = os.Stat(script); os.IsNotExist(err) {
		err = fmt.Errorf("could not load %s", script)
		return
	}

	return
}

// ParseScript use values sent by users and add on script
func (adapter *Postgres) ParseScript(scriptPath string, templateData map[string]interface{}) (sqlQuery string, values []interface{}, err error) {
	_, tplName := filepath.Split(scriptPath)

	funcs := &template.FuncRegistry{TemplateData: templateData}
	tpl := gotemplate.New(tplName).Funcs(funcs.RegistryAllFuncs())

	tpl, err = tpl.ParseFiles(scriptPath)
	if err != nil {
		err = fmt.Errorf("could not parse file %s: %+v", scriptPath, err)
		return
	}

	var buff bytes.Buffer
	err = tpl.Execute(&buff, funcs.TemplateData)
	if err != nil {
		err = fmt.Errorf("could not execute template %v", err)
		return
	}

	sqlQuery = buff.String()
	return
}

// WriteSQL perform INSERT's, UPDATE's, DELETE's operations
func WriteSQL(sql string, values []interface{}) (sc adapters.Scanner) {
	db, err := connection.Get()
	if err != nil {
		log.Println(err)
		sc = &scanner.PrestScanner{Error: err}
		return
	}
	stmt, err := Prepare(db, sql)
	if err != nil {
		log.Printf("could not prepare sql: %s\n Error: %v\n", sql, err)
		sc = &scanner.PrestScanner{Error: err}
		return
	}
	valuesAux := make([]interface{}, 0, len(values))

	for i := 0; i < len(values); i++ {
		valuesAux = append(valuesAux, values[i])
	}

	result, err := stmt.Exec(valuesAux...)
	if err != nil {
		log.Printf("sql = %+v\n", sql)
		err = fmt.Errorf("could not peform sql: %v", err)
		sc = &scanner.PrestScanner{Error: err}
		return
	}

	rowsAffected, err := result.RowsAffected()
	if err != nil {
		err = fmt.Errorf("could not rows affected: %v", err)
		sc = &scanner.PrestScanner{Error: err}
		return
	}

	data := make(map[string]interface{})
	data["rows_affected"] = rowsAffected
	var resultByte []byte
	resultByte, err = json.Marshal(data)
	sc = &scanner.PrestScanner{
		Error: err,
		Buff:  bytes.NewBuffer(resultByte),
	}
	return
}

// ExecuteScripts run sql templates created by users
func (adapter *Postgres) ExecuteScripts(method, sql string, values []interface{}) (sc adapters.Scanner) {
	switch method {
	case "GET":
		sc = adapter.Query(sql, values...)
	case "POST", "PUT", "PATCH", "DELETE":
		sc = WriteSQL(sql, values)
	default:
		sc = &scanner.PrestScanner{Error: fmt.Errorf("invalid method %s", method)}
	}

	return
}
<|endoftext|>


<commit_before>package flags_test

import (
	"github.com/jessevdk/go-flags"
	"testing"
)

func assertString(t *testing.T, a string, b string) {
	if a != b {
		t.Errorf("Expected %#v, but got %#v", b, a)
	}
}
func assertStringArray(t *testing.T, a []string, b []string) {
	if len(a) != len(b) {
		t.Errorf("Expected %#v, but got %#v", b, a)
		return
	}

	for i, v := range a {
		if b[i] != v {
			t.Errorf("Expected %#v, but got %#v", b, a)
			return
		}
	}
}

func assertBoolArray(t *testing.T, a []bool, b []bool) {
	if len(a) != len(b) {
		t.Errorf("Expected %#v, but got %#v", b, a)
		return
	}

	for i, v := range a {
		if b[i] != v {
			t.Errorf("Expected %#v, but got %#v", b, a)
			return
		}
	}
}

func assertParseSuccess(t *testing.T, data interface{}, args ...string) []string {
	parser := flags.NewParser(data, flags.Default &^ flags.PrintErrors)
	ret, err := parser.ParseArgs(args)

	if err != nil {
		t.Fatalf("Unexpected parse error: %s", err)
		return nil
	}

	return ret
}

func assertParseFail(t *testing.T, typ flags.ErrorType, msg string, data interface{}, args ...string) {
	parser := flags.NewParser(data, flags.Default &^ flags.PrintErrors)
	_, err := parser.ParseArgs(args)

	if err == nil {
		t.Fatalf("Expected error: %s", msg)
		return
	}

	if e, ok := err.(*flags.Error); !ok {
		t.Fatalf("Expected Error type, but got %#v", err)
		return
	} else {
		if e.Type != typ {
			t.Errorf("Expected error type {%s}, but got {%s}", typ, e.Type)
		}

		if e.Message != msg {
			t.Errorf("Expected error message %#v, but got %#v", msg, e.Message)
		}
	}
}

func TestShort(t *testing.T) {
	var opts = struct {
		Value bool `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-v")

	assertStringArray(t, ret, []string{})

	if !opts.Value {
		t.Errorf("Expected Value to be true")
	}
}

func TestShortMultiConcat(t *testing.T) {
	var opts = struct {
		V bool `short:"v"`
		O bool `short:"o"`
		F bool `short:"f"`
	}{}

	ret := assertParseSuccess(t, &opts, "-vo", "-f")

	assertStringArray(t, ret, []string{})

	if !opts.V {
		t.Errorf("Expected V to be true")
	}

	if !opts.O {
		t.Errorf("Expected O to be true")
	}

	if !opts.F {
		t.Errorf("Expected F to be true")
	}
}

func TestShortMultiSlice(t *testing.T) {
	var opts = struct {
		Values []bool `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-v", "-v")

	assertStringArray(t, ret, []string{})
	assertBoolArray(t, opts.Values, []bool{true, true})
}

func TestShortMultiSliceConcat(t *testing.T) {
	var opts = struct {
		Values []bool `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-vvv")

	assertStringArray(t, ret, []string{})
	assertBoolArray(t, opts.Values, []bool{true, true, true})
}

func TestShortWithEqualArg(t *testing.T) {
	var opts = struct {
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-v=value")

	assertStringArray(t, ret, []string{})
	assertString(t, opts.Value, "value")
}

func TestShortWithArg(t *testing.T) {
	var opts = struct {
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-vvalue")

	assertStringArray(t, ret, []string{})
	assertString(t, opts.Value, "value")
}

func TestShortArg(t *testing.T) {
	var opts = struct {
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-v", "value")

	assertStringArray(t, ret, []string{})
	assertString(t, opts.Value, "value")
}

func TestShortMultiWithEqualArg(t *testing.T) {
	var opts = struct {
		F []bool `short:"f"`
		Value string `short:"v"`
	}{}

	assertParseFail(t, flags.ErrUnknownFlag, "unknown flag `='", &opts, "-ffv=value")
}

func TestShortMultiArg(t *testing.T) {
	var opts = struct {
		F []bool `short:"f"`
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-ffv", "value")

	assertStringArray(t, ret, []string{})
	assertBoolArray(t, opts.F, []bool{true, true})
	assertString(t, opts.Value, "value")
}

func TestShortMultiArgConcatFail(t *testing.T) {
	var opts = struct {
		F []bool `short:"f"`
		Value string `short:"v"`
	}{}

	assertParseFail(t, flags.ErrUnknownFlag, "unknown flag `a'", &opts, "-ffvvalue")
}

func TestShortMultiArgConcat(t *testing.T) {
	var opts = struct {
		F []bool `short:"f"`
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-vff")

	assertStringArray(t, ret, []string{})
	assertString(t, opts.Value, "ff")
}
<commit_msg>Fix test for error in failing short tests<commit_after>package flags_test

import (
	"github.com/jessevdk/go-flags"
	"testing"
)

func assertString(t *testing.T, a string, b string) {
	if a != b {
		t.Errorf("Expected %#v, but got %#v", b, a)
	}
}
func assertStringArray(t *testing.T, a []string, b []string) {
	if len(a) != len(b) {
		t.Errorf("Expected %#v, but got %#v", b, a)
		return
	}

	for i, v := range a {
		if b[i] != v {
			t.Errorf("Expected %#v, but got %#v", b, a)
			return
		}
	}
}

func assertBoolArray(t *testing.T, a []bool, b []bool) {
	if len(a) != len(b) {
		t.Errorf("Expected %#v, but got %#v", b, a)
		return
	}

	for i, v := range a {
		if b[i] != v {
			t.Errorf("Expected %#v, but got %#v", b, a)
			return
		}
	}
}

func assertParseSuccess(t *testing.T, data interface{}, args ...string) []string {
	parser := flags.NewParser(data, flags.Default &^ flags.PrintErrors)
	ret, err := parser.ParseArgs(args)

	if err != nil {
		t.Fatalf("Unexpected parse error: %s", err)
		return nil
	}

	return ret
}

func assertParseFail(t *testing.T, typ flags.ErrorType, msg string, data interface{}, args ...string) {
	parser := flags.NewParser(data, flags.Default &^ flags.PrintErrors)
	_, err := parser.ParseArgs(args)

	if err == nil {
		t.Fatalf("Expected error: %s", msg)
		return
	}

	if e, ok := err.(*flags.Error); !ok {
		t.Fatalf("Expected Error type, but got %#v", err)
		return
	} else {
		if e.Type != typ {
			t.Errorf("Expected error type {%s}, but got {%s}", typ, e.Type)
		}

		if e.Message != msg {
			t.Errorf("Expected error message %#v, but got %#v", msg, e.Message)
		}
	}
}

func TestShort(t *testing.T) {
	var opts = struct {
		Value bool `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-v")

	assertStringArray(t, ret, []string{})

	if !opts.Value {
		t.Errorf("Expected Value to be true")
	}
}

func TestShortMultiConcat(t *testing.T) {
	var opts = struct {
		V bool `short:"v"`
		O bool `short:"o"`
		F bool `short:"f"`
	}{}

	ret := assertParseSuccess(t, &opts, "-vo", "-f")

	assertStringArray(t, ret, []string{})

	if !opts.V {
		t.Errorf("Expected V to be true")
	}

	if !opts.O {
		t.Errorf("Expected O to be true")
	}

	if !opts.F {
		t.Errorf("Expected F to be true")
	}
}

func TestShortMultiSlice(t *testing.T) {
	var opts = struct {
		Values []bool `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-v", "-v")

	assertStringArray(t, ret, []string{})
	assertBoolArray(t, opts.Values, []bool{true, true})
}

func TestShortMultiSliceConcat(t *testing.T) {
	var opts = struct {
		Values []bool `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-vvv")

	assertStringArray(t, ret, []string{})
	assertBoolArray(t, opts.Values, []bool{true, true, true})
}

func TestShortWithEqualArg(t *testing.T) {
	var opts = struct {
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-v=value")

	assertStringArray(t, ret, []string{})
	assertString(t, opts.Value, "value")
}

func TestShortWithArg(t *testing.T) {
	var opts = struct {
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-vvalue")

	assertStringArray(t, ret, []string{})
	assertString(t, opts.Value, "value")
}

func TestShortArg(t *testing.T) {
	var opts = struct {
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-v", "value")

	assertStringArray(t, ret, []string{})
	assertString(t, opts.Value, "value")
}

func TestShortMultiWithEqualArg(t *testing.T) {
	var opts = struct {
		F []bool `short:"f"`
		Value string `short:"v"`
	}{}

	assertParseFail(t, flags.ErrExpectedArgument, "expected argument for flag `-v'", &opts, "-ffv=value")
}

func TestShortMultiArg(t *testing.T) {
	var opts = struct {
		F []bool `short:"f"`
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-ffv", "value")

	assertStringArray(t, ret, []string{})
	assertBoolArray(t, opts.F, []bool{true, true})
	assertString(t, opts.Value, "value")
}

func TestShortMultiArgConcatFail(t *testing.T) {
	var opts = struct {
		F []bool `short:"f"`
		Value string `short:"v"`
	}{}

	assertParseFail(t, flags.ErrExpectedArgument, "expected argument for flag `-v'", &opts, "-ffvvalue")
}

func TestShortMultiArgConcat(t *testing.T) {
	var opts = struct {
		F []bool `short:"f"`
		Value string `short:"v"`
	}{}

	ret := assertParseSuccess(t, &opts, "-vff")

	assertStringArray(t, ret, []string{})
	assertString(t, opts.Value, "ff")
}
<|endoftext|>


<commit_before>// autogenerated code

package main

import "testing"
import "gflow"
import "regexp"

var tests = []testing.InternalTest{
	testing.InternalTest{"gflow.TestIT", gflow.TestIT},
}

var benchmarks = []testing.InternalBenchmark{}

func main() {
	testing.Main(regexp.MatchString, tests, benchmarks)
}
<commit_msg>Refactored project structure, fixed bugs with THEN and OR, moved tests from main into test file<commit_after><|endoftext|>


<commit_before>// Copyright 2017-2018 Authors of Cilium
//
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/cilium/cilium/pkg/defaults"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/test/helpers"

	"github.com/sirupsen/logrus"
)

// BugtoolConfiguration creates and loads the configuration file used to run
// the commands. The only commands not managed by the configuration is initial
// setup, for ex. searching for Cilium daemonset pods or running uname.
type BugtoolConfiguration struct {
	// Commands is the exact commands that will be run by the bugtool
	Commands []string `json:"commands"`
}

func setupDefaultConfig(path string, k8sPods []string, confDir, cmdDir string) (*BugtoolConfiguration, error) {
	c := BugtoolConfiguration{defaultCommands(confDir, cmdDir, k8sPods)}
	return &c, save(&c, path)
}

func defaultCommands(confDir string, cmdDir string, k8sPods []string) []string {
	var commands []string
	// Not expecting all of the commands to be available
	commands = []string{
		// Host and misc
		"ps auxfw",
		"hostname",
		"ip a",
		"ip r",
		"ip link",
		"uname -a",
		"dig",
		"netstat -a",
		"pidstat",
		"arp",
		"top -b -n 1",
		"uptime",
		"dmesg --time-format=iso",
		"bpftool map show",
		"bpftool prog show",
		// Versions
		"docker version",
		"docker info",
		// Docker and Kubernetes logs from systemd
		"journalctl -u cilium*",
		"journalctl -u kubelet",
		// iptables
		"iptables-save",
		"iptables -S",
		"ip6tables -S",
		"iptables -L -v",
		"ip rule",
		// gops
		fmt.Sprintf("gops memstats $(pidof %s)", helpers.AgentDaemon),
		fmt.Sprintf("gops stack $(pidof %s)", helpers.AgentDaemon),
		fmt.Sprintf("gops stats $(pidof %s)", helpers.AgentDaemon),
		// Get list of open file descriptors managed by the agent
		fmt.Sprintf("ls -la /proc/$(pidof %s)/fd", helpers.AgentDaemon),
	}

	// Commands that require variables and / or more configuration are added
	// separately below
	commands = append(commands, catCommands()...)
	commands = append(commands, ethoolCommands()...)
	commands = append(commands, copyConfigCommands(confDir, k8sPods)...)
	commands = append(commands, copyCiliumInfoCommands(cmdDir, k8sPods)...)

	return k8sCommands(commands, k8sPods)
}

func save(c *BugtoolConfiguration, path string) error {
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("Failed to open file %s for writing: %s", path, err)
	}
	defer f.Close()

	data, err := json.MarshalIndent(c, "", "\t")
	if err != nil {
		return fmt.Errorf("Cannot marshal config %s", err)
	}
	err = ioutil.WriteFile(path, data, 0644)
	if err != nil {
		return fmt.Errorf("Cannot write config %s", err)
	}
	return nil
}

func loadConfigFile(path string) (*BugtoolConfiguration, error) {
	var content []byte
	var err error
	logrus.WithField(logfields.Path, path).Debug("Loading file")

	content, err = ioutil.ReadFile(path)

	if err != nil {
		return nil, err
	}

	var c BugtoolConfiguration
	err = json.Unmarshal(content, &c)
	return &c, err
}

func catCommands() []string {
	files := []string{
		"/proc/sys/net/core/bpf_jit_enable",
		"/proc/kallsyms",
		"/etc/resolv.conf",
		"/var/log/docker.log",
		"/var/log/daemon.log",
		"/var/log/messages",
	}
	// Only print the files that do exist to reduce number of errors in
	// archive
	commands := []string{}
	for _, f := range files {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			continue
		}
		commands = append(commands, fmt.Sprintf("cat %s", f))
	}
	// TODO: handle K8s case as well.
	return commands
}

func copyConfigCommands(confDir string, k8sPods []string) []string {
	commands := []string{}
	// Location is a convenience structure to avoid too many long lines
	type Location struct {
		Src string
		Dst string
	}

	// These locations don't depend on the kernel version for running so we
	// can add them in this scope.
	locations := []Location{
		{"/proc/config", fmt.Sprintf("%s/kernel-config", confDir)},
		{"/proc/config.gz", fmt.Sprintf("%s/kernel-config.gz", confDir)},
	}

	// The following lines copy the kernel configuration. This code is
	// duplicated for the non Kubernetes case. The variables preventing
	// them to be one block is the pod prefix and namespace used in the
	// path. This should be refactored.
	if len(k8sPods) == 0 {
		kernel, _ := execCommand("uname -r")
		kernel = strings.TrimSpace(kernel)
		// Append the boot config for the current kernel
		l := Location{fmt.Sprintf("/boot/config-%s", kernel),
			fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
		locations = append(locations, l)

		// Use the locations to create command strings
		for _, location := range locations {
			if _, err := os.Stat(location.Src); os.IsNotExist(err) {
				continue
			}
			commands = append(commands, fmt.Sprintf("cp %s %s", location.Src, location.Dst))
		}
	} else {
		// If there are multiple pods, we want to get all of the kernel
		// configs. Therefore we need copy commands for all the pods.
		for _, pod := range k8sPods {
			prompt := podPrefix(pod, "uname -r")
			kernel, _ := execCommand(prompt)
			kernel = strings.TrimSpace(kernel)
			l := Location{fmt.Sprintf("/boot/config-%s", kernel),
				fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
			locations = append(locations, l)

			// The location is mostly the same but the command is
			// prepended with 'kubectl` and the path contains the
			// namespace and pod. For ex:
			// kubectl cp kube-system/cilium-kg8lv:/tmp/cilium-bugtool-243785589.tar /tmp/cilium-bugtool-243785589.tar
			for _, location := range locations {
				kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, location.Src)
				cmd := fmt.Sprintf("%s %s %s %s", "kubectl", "cp", kubectlArg, location.Dst)
				commands = append(commands, cmd)
			}
		}
	}
	return commands
}

func copyCiliumInfoCommands(cmdDir string, k8sPods []string) []string {
	// Most of the output should come via debuginfo but also adding
	// these ones for skimming purposes
	ciliumCommands := []string{
		"cilium debuginfo",
		"cilium config",
		"cilium bpf tunnel list",
		"cilium bpf lb list",
		"cilium bpf endpoint list",
		"cilium bpf ct list global",
		"cilium bpf proxy list",
		"cilium bpf ipcache list",
		"cilium status --verbose",
		"cilium identity list",
		"cilium map list --verbose",
		"cilium-health status",
	}
	var commands []string

	stateDir := filepath.Join(defaults.RuntimePath, defaults.StateDir)
	if len(k8sPods) == 0 { // Assuming this is a non k8s deployment
		dst := filepath.Join(cmdDir, defaults.StateDir)
		commands = append(commands, fmt.Sprintf("cp -r %s %s", stateDir, dst))
		for _, cmd := range ciliumCommands {
			// Add the host flag if set
			if len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}
			commands = append(commands, cmd)
		}
	} else { // Found k8s pods
		for _, pod := range k8sPods {
			dst := filepath.Join(cmdDir, fmt.Sprintf("%s-%s", pod, defaults.StateDir))
			kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, stateDir)
			// kubectl cp kube-system/cilium-xrzwr:/var/run/cilium/state cilium-xrzwr-state
			commands = append(commands, fmt.Sprintf("kubectl cp %s %s", kubectlArg, dst))
			for _, cmd := range ciliumCommands {
				// Add the host flag if set
				if len(host) > 0 {
					cmd = fmt.Sprintf("%s -H %s", cmd, host)
				}
				commands = append(commands, podPrefix(pod, cmd))
			}
		}
	}

	return commands
}

func k8sCommands(allCommands []string, pods []string) []string {
	// These commands do not require a pod argument
	var commands = []string{
		"kubectl get nodes -o wide",
		"kubectl describe nodes",
		"kubectl get pods,svc --all-namespaces",
		"kubectl version",
	}

	// Prepare to run all the commands inside of the pod(s)
	for _, pod := range pods {
		for _, cmd := range allCommands {
			// Add the host flag if set
			if strings.HasPrefix(cmd, "cilium") &&
				!strings.Contains(cmd, "-H") && len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}

			if !strings.Contains(cmd, "kubectl exec") {
				cmd = podPrefix(pod, cmd)
			}
			commands = append(commands, cmd)
		}

		// Retrieve current version of pod logs
		cmd := fmt.Sprintf("kubectl -n %s logs --timestamps %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		// Retrieve previous version of pod logs
		cmd = fmt.Sprintf("kubectl -n %s logs --timestamps -p %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		cmd = fmt.Sprintf("kubectl -n %s describe pod %s", k8sNamespace, pod)
		commands = append(commands, cmd)
	}

	if len(pods) == 0 {
		allCommands = append(allCommands, commands...)
		return allCommands
	}

	return commands
}
<commit_msg>Revert "bugtool: Include cilium map list --verbose"<commit_after>// Copyright 2017-2018 Authors of Cilium
//
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/cilium/cilium/pkg/defaults"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/test/helpers"

	"github.com/sirupsen/logrus"
)

// BugtoolConfiguration creates and loads the configuration file used to run
// the commands. The only commands not managed by the configuration is initial
// setup, for ex. searching for Cilium daemonset pods or running uname.
type BugtoolConfiguration struct {
	// Commands is the exact commands that will be run by the bugtool
	Commands []string `json:"commands"`
}

func setupDefaultConfig(path string, k8sPods []string, confDir, cmdDir string) (*BugtoolConfiguration, error) {
	c := BugtoolConfiguration{defaultCommands(confDir, cmdDir, k8sPods)}
	return &c, save(&c, path)
}

func defaultCommands(confDir string, cmdDir string, k8sPods []string) []string {
	var commands []string
	// Not expecting all of the commands to be available
	commands = []string{
		// Host and misc
		"ps auxfw",
		"hostname",
		"ip a",
		"ip r",
		"ip link",
		"uname -a",
		"dig",
		"netstat -a",
		"pidstat",
		"arp",
		"top -b -n 1",
		"uptime",
		"dmesg --time-format=iso",
		"bpftool map show",
		"bpftool prog show",
		// Versions
		"docker version",
		"docker info",
		// Docker and Kubernetes logs from systemd
		"journalctl -u cilium*",
		"journalctl -u kubelet",
		// iptables
		"iptables-save",
		"iptables -S",
		"ip6tables -S",
		"iptables -L -v",
		"ip rule",
		// gops
		fmt.Sprintf("gops memstats $(pidof %s)", helpers.AgentDaemon),
		fmt.Sprintf("gops stack $(pidof %s)", helpers.AgentDaemon),
		fmt.Sprintf("gops stats $(pidof %s)", helpers.AgentDaemon),
		// Get list of open file descriptors managed by the agent
		fmt.Sprintf("ls -la /proc/$(pidof %s)/fd", helpers.AgentDaemon),
	}

	// Commands that require variables and / or more configuration are added
	// separately below
	commands = append(commands, catCommands()...)
	commands = append(commands, ethoolCommands()...)
	commands = append(commands, copyConfigCommands(confDir, k8sPods)...)
	commands = append(commands, copyCiliumInfoCommands(cmdDir, k8sPods)...)

	return k8sCommands(commands, k8sPods)
}

func save(c *BugtoolConfiguration, path string) error {
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("Failed to open file %s for writing: %s", path, err)
	}
	defer f.Close()

	data, err := json.MarshalIndent(c, "", "\t")
	if err != nil {
		return fmt.Errorf("Cannot marshal config %s", err)
	}
	err = ioutil.WriteFile(path, data, 0644)
	if err != nil {
		return fmt.Errorf("Cannot write config %s", err)
	}
	return nil
}

func loadConfigFile(path string) (*BugtoolConfiguration, error) {
	var content []byte
	var err error
	logrus.WithField(logfields.Path, path).Debug("Loading file")

	content, err = ioutil.ReadFile(path)

	if err != nil {
		return nil, err
	}

	var c BugtoolConfiguration
	err = json.Unmarshal(content, &c)
	return &c, err
}

func catCommands() []string {
	files := []string{
		"/proc/sys/net/core/bpf_jit_enable",
		"/proc/kallsyms",
		"/etc/resolv.conf",
		"/var/log/docker.log",
		"/var/log/daemon.log",
		"/var/log/messages",
	}
	// Only print the files that do exist to reduce number of errors in
	// archive
	commands := []string{}
	for _, f := range files {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			continue
		}
		commands = append(commands, fmt.Sprintf("cat %s", f))
	}
	// TODO: handle K8s case as well.
	return commands
}

func copyConfigCommands(confDir string, k8sPods []string) []string {
	commands := []string{}
	// Location is a convenience structure to avoid too many long lines
	type Location struct {
		Src string
		Dst string
	}

	// These locations don't depend on the kernel version for running so we
	// can add them in this scope.
	locations := []Location{
		{"/proc/config", fmt.Sprintf("%s/kernel-config", confDir)},
		{"/proc/config.gz", fmt.Sprintf("%s/kernel-config.gz", confDir)},
	}

	// The following lines copy the kernel configuration. This code is
	// duplicated for the non Kubernetes case. The variables preventing
	// them to be one block is the pod prefix and namespace used in the
	// path. This should be refactored.
	if len(k8sPods) == 0 {
		kernel, _ := execCommand("uname -r")
		kernel = strings.TrimSpace(kernel)
		// Append the boot config for the current kernel
		l := Location{fmt.Sprintf("/boot/config-%s", kernel),
			fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
		locations = append(locations, l)

		// Use the locations to create command strings
		for _, location := range locations {
			if _, err := os.Stat(location.Src); os.IsNotExist(err) {
				continue
			}
			commands = append(commands, fmt.Sprintf("cp %s %s", location.Src, location.Dst))
		}
	} else {
		// If there are multiple pods, we want to get all of the kernel
		// configs. Therefore we need copy commands for all the pods.
		for _, pod := range k8sPods {
			prompt := podPrefix(pod, "uname -r")
			kernel, _ := execCommand(prompt)
			kernel = strings.TrimSpace(kernel)
			l := Location{fmt.Sprintf("/boot/config-%s", kernel),
				fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
			locations = append(locations, l)

			// The location is mostly the same but the command is
			// prepended with 'kubectl` and the path contains the
			// namespace and pod. For ex:
			// kubectl cp kube-system/cilium-kg8lv:/tmp/cilium-bugtool-243785589.tar /tmp/cilium-bugtool-243785589.tar
			for _, location := range locations {
				kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, location.Src)
				cmd := fmt.Sprintf("%s %s %s %s", "kubectl", "cp", kubectlArg, location.Dst)
				commands = append(commands, cmd)
			}
		}
	}
	return commands
}

func copyCiliumInfoCommands(cmdDir string, k8sPods []string) []string {
	// Most of the output should come via debuginfo but also adding
	// these ones for skimming purposes
	ciliumCommands := []string{
		"cilium debuginfo",
		"cilium config",
		"cilium bpf tunnel list",
		"cilium bpf lb list",
		"cilium bpf endpoint list",
		"cilium bpf ct list global",
		"cilium bpf proxy list",
		"cilium bpf ipcache list",
		"cilium status --verbose",
		"cilium identity list",
		"cilium-health status",
	}
	var commands []string

	stateDir := filepath.Join(defaults.RuntimePath, defaults.StateDir)
	if len(k8sPods) == 0 { // Assuming this is a non k8s deployment
		dst := filepath.Join(cmdDir, defaults.StateDir)
		commands = append(commands, fmt.Sprintf("cp -r %s %s", stateDir, dst))
		for _, cmd := range ciliumCommands {
			// Add the host flag if set
			if len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}
			commands = append(commands, cmd)
		}
	} else { // Found k8s pods
		for _, pod := range k8sPods {
			dst := filepath.Join(cmdDir, fmt.Sprintf("%s-%s", pod, defaults.StateDir))
			kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, stateDir)
			// kubectl cp kube-system/cilium-xrzwr:/var/run/cilium/state cilium-xrzwr-state
			commands = append(commands, fmt.Sprintf("kubectl cp %s %s", kubectlArg, dst))
			for _, cmd := range ciliumCommands {
				// Add the host flag if set
				if len(host) > 0 {
					cmd = fmt.Sprintf("%s -H %s", cmd, host)
				}
				commands = append(commands, podPrefix(pod, cmd))
			}
		}
	}

	return commands
}

func k8sCommands(allCommands []string, pods []string) []string {
	// These commands do not require a pod argument
	var commands = []string{
		"kubectl get nodes -o wide",
		"kubectl describe nodes",
		"kubectl get pods,svc --all-namespaces",
		"kubectl version",
	}

	// Prepare to run all the commands inside of the pod(s)
	for _, pod := range pods {
		for _, cmd := range allCommands {
			// Add the host flag if set
			if strings.HasPrefix(cmd, "cilium") &&
				!strings.Contains(cmd, "-H") && len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}

			if !strings.Contains(cmd, "kubectl exec") {
				cmd = podPrefix(pod, cmd)
			}
			commands = append(commands, cmd)
		}

		// Retrieve current version of pod logs
		cmd := fmt.Sprintf("kubectl -n %s logs --timestamps %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		// Retrieve previous version of pod logs
		cmd = fmt.Sprintf("kubectl -n %s logs --timestamps -p %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		cmd = fmt.Sprintf("kubectl -n %s describe pod %s", k8sNamespace, pod)
		commands = append(commands, cmd)
	}

	if len(pods) == 0 {
		allCommands = append(allCommands, commands...)
		return allCommands
	}

	return commands
}
<|endoftext|>


<commit_before>// Copyright Banrai LLC. All rights reserved. Use of this source code is
// governed by the license that can be found in the LICENSE file.

package database

import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
	"log"
)

type DBConnection struct {
	DBName  string
	User    string
	Pass    string
	SSLMode bool
}

// Connect to the database with the given coordinates, and invoke the
// function, which gets passed a map of all the prepared statements
func WithDatabase(dbCoords DBConnection, fn func(map[string]*sql.Stmt)) {
	preparedStatements := []string{PERSON_INSERT,
		PERSON_UPDATE,
		PERSON_DELETE,
		PERSON_LOOKUP_BY_ID,
		PERSON_LOOKUP_BY_EMAIL,
		SESSION_INSERT,
		SESSION_UPDATE,
		SESSION_CLEANUP,
		SESSION_LOOKUP_BY_CODE,
		SESSION_LOOKUP_BY_ACCOUNT,
		PK_INSERT,
		PK_UPDATE,
		PK_DELETE,
		PK_LOOKUP}

	sslMode := "disable"
	if dbCoords.SSLMode {
		sslMode = "enable"
	}

	db, dbErr := sql.Open("postgres",
		fmt.Sprintf("user=%s dbname=%s password=%s sslmode=%s",
			dbCoords.User,
			dbCoords.DBName,
			dbCoords.Pass,
			sslMode))
	if dbErr != nil {
		log.Fatal(dbErr)
	}
	defer db.Close()

	statements := map[string]*sql.Stmt{}
	for _, p := range preparedStatements {
		stmt, err := db.Prepare(p)
		if err != nil {
			log.Fatal(err)
		} else {
			statements[p] = stmt
		}
	}

	fn(statements)
}
<commit_msg>Added the message and recipient prepared statements to the core database module<commit_after>// Copyright Banrai LLC. All rights reserved. Use of this source code is
// governed by the license that can be found in the LICENSE file.

package database

import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
	"log"
)

type DBConnection struct {
	DBName  string
	User    string
	Pass    string
	SSLMode bool
}

// Connect to the database with the given coordinates, and invoke the
// function, which gets passed a map of all the prepared statements
func WithDatabase(dbCoords DBConnection, fn func(map[string]*sql.Stmt)) {
	preparedStatements := []string{PERSON_INSERT,
		PERSON_UPDATE,
		PERSON_DELETE,
		PERSON_LOOKUP_BY_ID,
		PERSON_LOOKUP_BY_EMAIL,
		SESSION_INSERT,
		SESSION_UPDATE,
		SESSION_CLEANUP,
		SESSION_LOOKUP_BY_CODE,
		SESSION_LOOKUP_BY_ACCOUNT,
		PK_INSERT,
		PK_UPDATE,
		PK_DELETE,
		PK_LOOKUP,
		MESSAGE_INSERT,
		MESSAGE_DELETE,
		MESSAGE_CLEANUP,
		RECIPIENT_INSERT,
		RECIPIENT_DELETE,
		RECIPIENT_CLEANUP,
		MESSAGES_BY_AUTHOR,
		MESSAGES_BY_RECIPIENT,
		RECIPIENTS_BY_MESSAGE}

	sslMode := "disable"
	if dbCoords.SSLMode {
		sslMode = "enable"
	}

	db, dbErr := sql.Open("postgres",
		fmt.Sprintf("user=%s dbname=%s password=%s sslmode=%s",
			dbCoords.User,
			dbCoords.DBName,
			dbCoords.Pass,
			sslMode))
	if dbErr != nil {
		log.Fatal(dbErr)
	}
	defer db.Close()

	statements := map[string]*sql.Stmt{}
	for _, p := range preparedStatements {
		stmt, err := db.Prepare(p)
		if err != nil {
			log.Fatal(err)
		} else {
			statements[p] = stmt
		}
	}

	fn(statements)
}
<|endoftext|>