<commit_before>package server

import (
	"bytes"
	"fmt"
	"io"
	"sync"

	"github.com/golang/snappy"

	"github.com/gogo/protobuf/types"
	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/admin"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
	"github.com/pachyderm/pachyderm/src/client/pkg/pbutil"
	"github.com/pachyderm/pachyderm/src/client/pps"
	"github.com/pachyderm/pachyderm/src/server/pkg/log"
	"github.com/pachyderm/pachyderm/src/server/pkg/obj"
)

type apiServer struct {
	log.Logger
	address        string
	pachClient     *client.APIClient
	pachClientOnce sync.Once
}

func (a *apiServer) Extract(request *admin.ExtractRequest, extractServer admin.API_ExtractServer) (retErr error) {
	pachClient, err := a.getPachClient()
	if err != nil {
		return err
	}
	pachClient = pachClient.WithCtx(extractServer.Context())
	handleOp := extractServer.Send
	if request.URL != "" {
		url, err := obj.ParseURL(request.URL)
		if err != nil {
			return fmt.Errorf("error parsing url %v: %v", request.URL, err)
		}
		objClient, err := obj.NewClientFromURLAndSecret(extractServer.Context(), url)
		if err != nil {
			return err
		}
		objW, err := objClient.Writer(url.Object)
		if err != nil {
			return err
		}
		snappyW := snappy.NewBufferedWriter(objW)
		defer func() {
			if err := snappyW.Close(); err != nil && retErr == nil {
				retErr = err
			}
		}()
		w := pbutil.NewWriter(snappyW)
		handleOp = func(op *admin.Op) error { return w.Write(op) }
	}
	v, err := pachClient.VersionAPIClient.GetVersion(pachClient.Ctx(), &types.Empty{})
	if err != nil {
		return err
	}
	if err := handleOp(&admin.Op{
		Version: v,
	}); err != nil {
		return err
	}
	if !request.NoObjects {
		w := &extractObjectWriter{extractServer}
		if err := pachClient.ListObject(func(object *pfs.Object) error {
			if err := pachClient.GetObject(object.Hash, w); err != nil {
				return err
			}
			// empty PutObjectRequest to indicate EOF
			return handleOp(&admin.Op{Object: &pfs.PutObjectRequest{}})
		}); err != nil {
			return err
		}
		if err := pachClient.ListTag(func(resp *pfs.ListTagsResponse) error {
			return handleOp(&admin.Op{
				Tag: &pfs.TagObjectRequest{
					Object: resp.Object,
					Tags:   []*pfs.Tag{resp.Tag},
				},
			})
		}); err != nil {
			return err
		}
	}
	if !request.NoRepos {
		ris, err := pachClient.ListRepo(nil)
		if err != nil {
			return err
		}
		for _, ri := range ris {
			if len(ri.Provenance) > 0 {
				continue
			}
			if err := handleOp(&admin.Op{
				Repo: &pfs.CreateRepoRequest{
					Repo:        ri.Repo,
					Provenance:  ri.Provenance,
					Description: ri.Description,
				},
			}); err != nil {
				return err
			}
			cis, err := pachClient.ListCommit(ri.Repo.Name, "", "", 0)
			if err != nil {
				return err
			}
			for _, ci := range sortCommitInfos(cis) {
				// Even without a parent, ParentCommit is used to indicate which
				// repo to make the commit in.
				if ci.ParentCommit == nil {
					ci.ParentCommit = client.NewCommit(ri.Repo.Name, "")
				}
				if err := handleOp(&admin.Op{
					Commit: &pfs.BuildCommitRequest{
						Parent: ci.ParentCommit,
						Tree:   ci.Tree,
						ID:     ci.Commit.ID,
					},
				}); err != nil {
					return err
				}
			}
			bis, err := pachClient.ListBranch(ri.Repo.Name)
			if err != nil {
				return err
			}
			for _, bi := range bis {
				if err := handleOp(&admin.Op{
					Branch: &pfs.SetBranchRequest{
						Commit: bi.Head,
						Branch: bi.Name,
					},
				},
				); err != nil {
					return err
				}
			}
		}
	}
	if !request.NoPipelines {
		pis, err := pachClient.ListPipeline()
		if err != nil {
			return err
		}
		for _, pi := range pis {
			if err := handleOp(&admin.Op{
				Pipeline: &pps.CreatePipelineRequest{
					Pipeline:           pi.Pipeline,
					Transform:          pi.Transform,
					ParallelismSpec:    pi.ParallelismSpec,
					Egress:             pi.Egress,
					OutputBranch:       pi.OutputBranch,
					ScaleDownThreshold: pi.ScaleDownThreshold,
					ResourceRequests:   pi.ResourceRequests,
					ResourceLimits:     pi.ResourceLimits,
					Input:              pi.Input,
					Description:        pi.Description,
					Incremental:        pi.Incremental,
					CacheSize:          pi.CacheSize,
					EnableStats:        pi.EnableStats,
					Batch:              pi.Batch,
					MaxQueueSize:       pi.MaxQueueSize,
					Service:            pi.Service,
					ChunkSpec:          pi.ChunkSpec,
					DatumTimeout:       pi.DatumTimeout,
					JobTimeout:         pi.JobTimeout,
					Salt:               pi.Salt,
				},
			}); err != nil {
				return err
			}
		}
	}
	return nil
}

func sortCommitInfos(cis []*pfs.CommitInfo) []*pfs.CommitInfo {
	commitMap := make(map[string]*pfs.CommitInfo)
	for _, ci := range cis {
		commitMap[ci.Commit.ID] = ci
	}
	var result []*pfs.CommitInfo
	for _, ci := range cis {
		if commitMap[ci.Commit.ID] == nil {
			continue
		}
		var localResult []*pfs.CommitInfo
		for ci != nil {
			localResult = append(localResult, ci)
			delete(commitMap, ci.Commit.ID)
			if ci.ParentCommit != nil {
				ci = commitMap[ci.ParentCommit.ID]
			} else {
				ci = nil
			}
		}
		for i := range localResult {
			result = append(result, localResult[len(localResult)-i-1])
		}
	}
	return result
}

func (a *apiServer) Restore(restoreServer admin.API_RestoreServer) (retErr error) {
	ctx := restoreServer.Context()
	pachClient, err := a.getPachClient()
	if err != nil {
		return err
	}
	defer func() {
		for {
			_, err := restoreServer.Recv()
			if err != nil {
				break
			}
		}
		if err := restoreServer.SendAndClose(&types.Empty{}); err != nil && retErr == nil {
			retErr = err
		}
	}()
	var r pbutil.Reader
	for {
		var op *admin.Op
		if r == nil {
			req, err := restoreServer.Recv()
			if err != nil {
				if err == io.EOF {
					return nil
				}
				return err
			}
			if req.URL != "" {
				url, err := obj.ParseURL(req.URL)
				if err != nil {
					return fmt.Errorf("error parsing url %v: %v", req.URL, err)
				}
				objClient, err := obj.NewClientFromURLAndSecret(restoreServer.Context(), url)
				if err != nil {
					return err
				}
				objR, err := objClient.Reader(url.Object, 0, 0)
				if err != nil {
					return err
				}
				snappyR := snappy.NewReader(objR)
				r = pbutil.NewReader(snappyR)
				continue
			} else {
				op = req.Op
			}
		} else {
			op = &admin.Op{}
			if err := r.Read(op); err != nil {
				if err == io.EOF {
					return nil
				}
				return err
			}
		}
		switch {
		case op.Version != nil:
		case op.Object != nil:
			r := &extractObjectReader{adminAPIRestoreServer: restoreServer}
			r.buf.Write(op.Object.Value)
			if _, _, err := pachClient.PutObject(r); err != nil {
				return fmt.Errorf("error putting object: %v", err)
			}
		case op.Tag != nil:
			if _, err := pachClient.ObjectAPIClient.TagObject(ctx, op.Tag); err != nil {
				return fmt.Errorf("error tagging object: %v", grpcutil.ScrubGRPC(err))
			}
		case op.Repo != nil:
			if _, err := pachClient.PfsAPIClient.CreateRepo(ctx, op.Repo); err != nil {
				return fmt.Errorf("error creating repo: %v", grpcutil.ScrubGRPC(err))
			}
		case op.Commit != nil:
			if _, err := pachClient.PfsAPIClient.BuildCommit(ctx, op.Commit); err != nil {
				return fmt.Errorf("error creating commit: %v", grpcutil.ScrubGRPC(err))
			}
		case op.Branch != nil:
			if _, err := pachClient.PfsAPIClient.SetBranch(ctx, op.Branch); err != nil {
				return fmt.Errorf("error creating branch: %v", grpcutil.ScrubGRPC(err))
			}
		case op.Pipeline != nil:
			if _, err := pachClient.PpsAPIClient.CreatePipeline(ctx, op.Pipeline); err != nil {
				return fmt.Errorf("error creating pipeline: %v", grpcutil.ScrubGRPC(err))
			}
		}
	}
}

func (a *apiServer) getPachClient() (*client.APIClient, error) {
	if a.pachClient == nil {
		var onceErr error
		a.pachClientOnce.Do(func() {
			a.pachClient, onceErr = client.NewFromAddress(a.address)
		})
		if onceErr != nil {
			return nil, onceErr
		}
	}
	return a.pachClient, nil
}

type extractObjectWriter struct {
	admin.API_ExtractServer
}

func (w *extractObjectWriter) Write(p []byte) (int, error) {
	chunkSize := grpcutil.MaxMsgSize / 2
	var n int
	for i := 0; i*(chunkSize) < len(p); i++ {
		value := p[i*chunkSize:]
		if len(value) > chunkSize {
			value = value[:chunkSize]
		}
		if err := w.Send(&admin.Op{Object: &pfs.PutObjectRequest{Value: value}}); err != nil {
			return n, err
		}
		n += len(value)
	}
	return n, nil
}

type adminAPIRestoreServer admin.API_RestoreServer

type extractObjectReader struct {
	adminAPIRestoreServer
	buf bytes.Buffer
	eof bool
}

func (r *extractObjectReader) Read(p []byte) (int, error) {
	for len(p) > r.buf.Len() && !r.eof {
		request, err := r.Recv()
		if err != nil {
			return 0, grpcutil.ScrubGRPC(err)
		}
		op := request.Op
		if op.Object == nil {
			return 0, fmt.Errorf("expected an object, but got: %v", op)
		}
		r.buf.Write(op.Object.Value)
		if len(op.Object.Value) == 0 {
			r.eof = true
		}
	}
	return r.buf.Read(p)
}
<commit_msg>Panic when we can't connect pach client.<commit_after>package server

import (
	"bytes"
	"fmt"
	"io"
	"sync"

	"github.com/golang/snappy"

	"github.com/gogo/protobuf/types"
	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/admin"
	"github.com/pachyderm/pachyderm/src/client/pfs"
	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
	"github.com/pachyderm/pachyderm/src/client/pkg/pbutil"
	"github.com/pachyderm/pachyderm/src/client/pps"
	"github.com/pachyderm/pachyderm/src/server/pkg/log"
	"github.com/pachyderm/pachyderm/src/server/pkg/obj"
)

type apiServer struct {
	log.Logger
	address        string
	pachClient     *client.APIClient
	pachClientOnce sync.Once
}

func (a *apiServer) Extract(request *admin.ExtractRequest, extractServer admin.API_ExtractServer) (retErr error) {
	pachClient := a.getPachClient()
	pachClient = pachClient.WithCtx(extractServer.Context())
	handleOp := extractServer.Send
	if request.URL != "" {
		url, err := obj.ParseURL(request.URL)
		if err != nil {
			return fmt.Errorf("error parsing url %v: %v", request.URL, err)
		}
		objClient, err := obj.NewClientFromURLAndSecret(extractServer.Context(), url)
		if err != nil {
			return err
		}
		objW, err := objClient.Writer(url.Object)
		if err != nil {
			return err
		}
		snappyW := snappy.NewBufferedWriter(objW)
		defer func() {
			if err := snappyW.Close(); err != nil && retErr == nil {
				retErr = err
			}
		}()
		w := pbutil.NewWriter(snappyW)
		handleOp = func(op *admin.Op) error { return w.Write(op) }
	}
	v, err := pachClient.VersionAPIClient.GetVersion(pachClient.Ctx(), &types.Empty{})
	if err != nil {
		return err
	}
	if err := handleOp(&admin.Op{
		Version: v,
	}); err != nil {
		return err
	}
	if !request.NoObjects {
		w := &extractObjectWriter{extractServer}
		if err := pachClient.ListObject(func(object *pfs.Object) error {
			if err := pachClient.GetObject(object.Hash, w); err != nil {
				return err
			}
			// empty PutObjectRequest to indicate EOF
			return handleOp(&admin.Op{Object: &pfs.PutObjectRequest{}})
		}); err != nil {
			return err
		}
		if err := pachClient.ListTag(func(resp *pfs.ListTagsResponse) error {
			return handleOp(&admin.Op{
				Tag: &pfs.TagObjectRequest{
					Object: resp.Object,
					Tags:   []*pfs.Tag{resp.Tag},
				},
			})
		}); err != nil {
			return err
		}
	}
	if !request.NoRepos {
		ris, err := pachClient.ListRepo(nil)
		if err != nil {
			return err
		}
		for _, ri := range ris {
			if len(ri.Provenance) > 0 {
				continue
			}
			if err := handleOp(&admin.Op{
				Repo: &pfs.CreateRepoRequest{
					Repo:        ri.Repo,
					Provenance:  ri.Provenance,
					Description: ri.Description,
				},
			}); err != nil {
				return err
			}
			cis, err := pachClient.ListCommit(ri.Repo.Name, "", "", 0)
			if err != nil {
				return err
			}
			for _, ci := range sortCommitInfos(cis) {
				// Even without a parent, ParentCommit is used to indicate which
				// repo to make the commit in.
				if ci.ParentCommit == nil {
					ci.ParentCommit = client.NewCommit(ri.Repo.Name, "")
				}
				if err := handleOp(&admin.Op{
					Commit: &pfs.BuildCommitRequest{
						Parent: ci.ParentCommit,
						Tree:   ci.Tree,
						ID:     ci.Commit.ID,
					},
				}); err != nil {
					return err
				}
			}
			bis, err := pachClient.ListBranch(ri.Repo.Name)
			if err != nil {
				return err
			}
			for _, bi := range bis {
				if err := handleOp(&admin.Op{
					Branch: &pfs.SetBranchRequest{
						Commit: bi.Head,
						Branch: bi.Name,
					},
				},
				); err != nil {
					return err
				}
			}
		}
	}
	if !request.NoPipelines {
		pis, err := pachClient.ListPipeline()
		if err != nil {
			return err
		}
		for _, pi := range pis {
			if err := handleOp(&admin.Op{
				Pipeline: &pps.CreatePipelineRequest{
					Pipeline:           pi.Pipeline,
					Transform:          pi.Transform,
					ParallelismSpec:    pi.ParallelismSpec,
					Egress:             pi.Egress,
					OutputBranch:       pi.OutputBranch,
					ScaleDownThreshold: pi.ScaleDownThreshold,
					ResourceRequests:   pi.ResourceRequests,
					ResourceLimits:     pi.ResourceLimits,
					Input:              pi.Input,
					Description:        pi.Description,
					Incremental:        pi.Incremental,
					CacheSize:          pi.CacheSize,
					EnableStats:        pi.EnableStats,
					Batch:              pi.Batch,
					MaxQueueSize:       pi.MaxQueueSize,
					Service:            pi.Service,
					ChunkSpec:          pi.ChunkSpec,
					DatumTimeout:       pi.DatumTimeout,
					JobTimeout:         pi.JobTimeout,
					Salt:               pi.Salt,
				},
			}); err != nil {
				return err
			}
		}
	}
	return nil
}

func sortCommitInfos(cis []*pfs.CommitInfo) []*pfs.CommitInfo {
	commitMap := make(map[string]*pfs.CommitInfo)
	for _, ci := range cis {
		commitMap[ci.Commit.ID] = ci
	}
	var result []*pfs.CommitInfo
	for _, ci := range cis {
		if commitMap[ci.Commit.ID] == nil {
			continue
		}
		var localResult []*pfs.CommitInfo
		for ci != nil {
			localResult = append(localResult, ci)
			delete(commitMap, ci.Commit.ID)
			if ci.ParentCommit != nil {
				ci = commitMap[ci.ParentCommit.ID]
			} else {
				ci = nil
			}
		}
		for i := range localResult {
			result = append(result, localResult[len(localResult)-i-1])
		}
	}
	return result
}

func (a *apiServer) Restore(restoreServer admin.API_RestoreServer) (retErr error) {
	ctx := restoreServer.Context()
	pachClient := a.getPachClient()
	defer func() {
		for {
			_, err := restoreServer.Recv()
			if err != nil {
				break
			}
		}
		if err := restoreServer.SendAndClose(&types.Empty{}); err != nil && retErr == nil {
			retErr = err
		}
	}()
	var r pbutil.Reader
	for {
		var op *admin.Op
		if r == nil {
			req, err := restoreServer.Recv()
			if err != nil {
				if err == io.EOF {
					return nil
				}
				return err
			}
			if req.URL != "" {
				url, err := obj.ParseURL(req.URL)
				if err != nil {
					return fmt.Errorf("error parsing url %v: %v", req.URL, err)
				}
				objClient, err := obj.NewClientFromURLAndSecret(restoreServer.Context(), url)
				if err != nil {
					return err
				}
				objR, err := objClient.Reader(url.Object, 0, 0)
				if err != nil {
					return err
				}
				snappyR := snappy.NewReader(objR)
				r = pbutil.NewReader(snappyR)
				continue
			} else {
				op = req.Op
			}
		} else {
			op = &admin.Op{}
			if err := r.Read(op); err != nil {
				if err == io.EOF {
					return nil
				}
				return err
			}
		}
		switch {
		case op.Version != nil:
		case op.Object != nil:
			r := &extractObjectReader{adminAPIRestoreServer: restoreServer}
			r.buf.Write(op.Object.Value)
			if _, _, err := pachClient.PutObject(r); err != nil {
				return fmt.Errorf("error putting object: %v", err)
			}
		case op.Tag != nil:
			if _, err := pachClient.ObjectAPIClient.TagObject(ctx, op.Tag); err != nil {
				return fmt.Errorf("error tagging object: %v", grpcutil.ScrubGRPC(err))
			}
		case op.Repo != nil:
			if _, err := pachClient.PfsAPIClient.CreateRepo(ctx, op.Repo); err != nil {
				return fmt.Errorf("error creating repo: %v", grpcutil.ScrubGRPC(err))
			}
		case op.Commit != nil:
			if _, err := pachClient.PfsAPIClient.BuildCommit(ctx, op.Commit); err != nil {
				return fmt.Errorf("error creating commit: %v", grpcutil.ScrubGRPC(err))
			}
		case op.Branch != nil:
			if _, err := pachClient.PfsAPIClient.SetBranch(ctx, op.Branch); err != nil {
				return fmt.Errorf("error creating branch: %v", grpcutil.ScrubGRPC(err))
			}
		case op.Pipeline != nil:
			if _, err := pachClient.PpsAPIClient.CreatePipeline(ctx, op.Pipeline); err != nil {
				return fmt.Errorf("error creating pipeline: %v", grpcutil.ScrubGRPC(err))
			}
		}
	}
}

func (a *apiServer) getPachClient() *client.APIClient {
	a.pachClientOnce.Do(func() {
		var err error
		a.pachClient, err = client.NewFromAddress(a.address)
		if err != nil {
			panic(fmt.Sprintf("pps failed to initialize pach client: %v", err))
		}
	})
	return a.pachClient
}

type extractObjectWriter struct {
	admin.API_ExtractServer
}

func (w *extractObjectWriter) Write(p []byte) (int, error) {
	chunkSize := grpcutil.MaxMsgSize / 2
	var n int
	for i := 0; i*(chunkSize) < len(p); i++ {
		value := p[i*chunkSize:]
		if len(value) > chunkSize {
			value = value[:chunkSize]
		}
		if err := w.Send(&admin.Op{Object: &pfs.PutObjectRequest{Value: value}}); err != nil {
			return n, err
		}
		n += len(value)
	}
	return n, nil
}

type adminAPIRestoreServer admin.API_RestoreServer

type extractObjectReader struct {
	adminAPIRestoreServer
	buf bytes.Buffer
	eof bool
}

func (r *extractObjectReader) Read(p []byte) (int, error) {
	for len(p) > r.buf.Len() && !r.eof {
		request, err := r.Recv()
		if err != nil {
			return 0, grpcutil.ScrubGRPC(err)
		}
		op := request.Op
		if op.Object == nil {
			return 0, fmt.Errorf("expected an object, but got: %v", op)
		}
		r.buf.Write(op.Object.Value)
		if len(op.Object.Value) == 0 {
			r.eof = true
		}
	}
	return r.buf.Read(p)
}
<|endoftext|>


<commit_before>package process

// Logic for this file is largely based on:
// https://github.com/jarib/childprocess/blob/783f7a00a1678b5d929062564ef5ae76822dfd62/lib/childprocess/unix/process.rb

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/buildkite/agent/logger"
	"github.com/buildkite/agent/shell"
)

type Process struct {
	Pid        int
	PTY        bool
	Script     string
	Env        []string
	ExitStatus string

	buffer bytes.Buffer

	command *exec.Cmd

	// This callback is called when the process offically starts
	StartCallback func()

	// For every line in the process output, this callback will be called
	// with the contents of the line
	LineCallback func(string)

	// Running is stored as an int32 so we can use atomic operations to
	// set/get it (it's accessed by multiple goroutines)
	running int32
}

func (p *Process) Start() error {
	c, err := shell.CommandFromString(p.Script)
	if err != nil {
		return err
	}

	p.command = exec.Command(c.Command, c.Args...)

	// Copy the current processes ENV and merge in the new ones. We do this
	// so the sub process gets PATH and stuff. We merge our path in over
	// the top of the current one so the ENV from Buildkite and the agent
	// take precedence over the agent
	currentEnv := os.Environ()
	p.command.Env = append(currentEnv, p.Env...)

	var waitGroup sync.WaitGroup

	lineReaderPipe, lineWriterPipe := io.Pipe()

	multiWriter := io.MultiWriter(&p.buffer, lineWriterPipe)

	logger.Info("Starting to run: %s", c.String())

	// Toggle between running in a pty
	if p.PTY {
		pty, err := StartPTY(p.command)
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.setRunning(true)

		waitGroup.Add(1)

		go func() {
			logger.Debug("[Process] Starting to copy PTY to the buffer")

			// Copy the pty to our buffer. This will block until it
			// EOF's or something breaks.
			_, err = io.Copy(multiWriter, pty)
			if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
				// We can safely ignore this error, because
				// it's just the PTY telling us that it closed
				// successfully.  See:
				// https://github.com/buildkite/agent/pull/34#issuecomment-46080419
				err = nil
			}

			if err != nil {
				logger.Error("[Process] PTY output copy failed with error: %T: %v", err, err)
			} else {
				logger.Debug("[Process] PTY has finished being copied to the buffer")
			}

			waitGroup.Done()
		}()
	} else {
		p.command.Stdout = multiWriter
		p.command.Stderr = multiWriter
		p.command.Stdin = nil

		err := p.command.Start()
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.setRunning(true)
	}

	logger.Info("[Process] Process is running with PID: %d", p.Pid)

	// Add the line callback routine to the waitGroup
	waitGroup.Add(1)

	go func() {
		logger.Debug("[LineScanner] Starting to read lines")

		reader := bufio.NewReader(lineReaderPipe)

		var appending []byte

		for {
			line, isPrefix, err := reader.ReadLine()
			if err != nil {
				if err == io.EOF {
					logger.Debug("[LineScanner] Encountered EOF")
					break
				}

				logger.Error("[LineScanner] Failed to read: (%T: %v)", err, err)
			}

			// If isPrefix is true, that means we've got a really
			// long line incoming, and we'll keep appending to it
			// until isPrefix is false (which means the long line
			// has ended.
			if isPrefix && appending == nil {
				logger.Debug("[LineScanner] Line is too long to read, going to buffer it until it finishes")
				appending = line

				continue
			}

			// Should we be appending?
			if appending != nil {
				appending = append(appending, line...)

				// No more isPrefix! Line is finished!
				if !isPrefix {
					logger.Debug("[LineScanner] Finished buffering long line")
					line = appending

					// Reset appending back to nil
					appending = nil
				} else {
					continue
				}
			}

			go p.LineCallback(string(line))
		}

		logger.Debug("[LineScanner] Finished")

		waitGroup.Done()
	}()

	// Call the StartCallback
	go p.StartCallback()

	// Wait until the process has finished. The returned error is nil if the command runs,
	// has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.
	waitResult := p.command.Wait()

	// Close the line writer pipe
	lineWriterPipe.Close()

	// The process is no longer running at this point
	p.setRunning(false)

	// Find the exit status of the script
	p.ExitStatus = getExitStatus(waitResult)

	logger.Info("Process with PID: %d finished with Exit Status: %s", p.Pid, p.ExitStatus)

	// Sometimes (in docker containers) io.Copy never seems to finish. This is a mega
	// hack around it. If it doesn't finish after 1 second, just continue.
	logger.Debug("[Process] Waiting for routines to finish")
	err = timeoutWait(&waitGroup)
	if err != nil {
		logger.Debug("[Process] Timed out waiting for wait group: (%T: %v)", err, err)
	}

	// No error occurred so we can return nil
	return nil
}

func (p *Process) Output() string {
	return p.buffer.String()
}

func (p *Process) Kill() error {
	// Send a sigterm
	err := p.signal(syscall.SIGTERM)
	if err != nil {
		return err
	}

	// Make a channel that we'll use as a timeout
	c := make(chan int, 1)
	checking := true

	// Start a routine that checks to see if the process
	// is still alive.
	go func() {
		for checking {
			logger.Debug("[Process] Checking to see if PID: %d is still alive", p.Pid)

			foundProcess, err := os.FindProcess(p.Pid)

			// Can't find the process at all
			if err != nil {
				logger.Debug("[Process] Could not find process with PID: %d", p.Pid)

				break
			}

			// We have some information about the process
			if foundProcess != nil {
				processState, err := foundProcess.Wait()

				if err != nil || processState.Exited() {
					logger.Debug("[Process] Process with PID: %d has exited.", p.Pid)

					break
				}
			}

			// Retry in a moment
			sleepTime := time.Duration(1 * time.Second)
			time.Sleep(sleepTime)
		}

		c <- 1
	}()

	// Timeout this process after 3 seconds
	select {
	case _ = <-c:
		// Was successfully terminated
	case <-time.After(10 * time.Second):
		// Stop checking in the routine above
		checking = false

		// Forcefully kill the thing
		err = p.signal(syscall.SIGKILL)

		if err != nil {
			return err
		}
	}

	return nil
}

func (p *Process) signal(sig os.Signal) error {
	if p.command != nil && p.command.Process != nil {
		logger.Debug("[Process] Sending signal: %s to PID: %d", sig.String(), p.Pid)

		err := p.command.Process.Signal(sig)
		if err != nil {
			logger.Error("[Process] Failed to send signal: %s to PID: %d (%T: %v)", sig.String(), p.Pid, err, err)
			return err
		}
	} else {
		logger.Debug("[Process] No process to signal yet")
	}

	return nil
}

// Returns whether or not the process is running
func (p *Process) IsRunning() bool {
	return atomic.LoadInt32(&p.running) != 0
}

// Sets the running flag of the process
func (p *Process) setRunning(r bool) {
	// Use the atomic package to avoid race conditions when setting the
	// `running` value from multiple routines
	if r {
		atomic.StoreInt32(&p.running, 1)
	} else {
		atomic.StoreInt32(&p.running, 0)
	}
}

// https://github.com/hnakamur/commango/blob/fe42b1cf82bf536ce7e24dceaef6656002e03743/os/executil/executil.go#L29
// TODO: Can this be better?
func getExitStatus(waitResult error) string {
	exitStatus := -1

	if waitResult != nil {
		if err, ok := waitResult.(*exec.ExitError); ok {
			if s, ok := err.Sys().(syscall.WaitStatus); ok {
				exitStatus = s.ExitStatus()
			} else {
				logger.Error("[Process] Unimplemented for system where exec.ExitError.Sys() is not syscall.WaitStatus.")
			}
		} else {
			logger.Error("[Process] Unexpected error type in getExitStatus: %#v", waitResult)
		}
	} else {
		exitStatus = 0
	}

	return fmt.Sprintf("%d", exitStatus)
}

func timeoutWait(waitGroup *sync.WaitGroup) error {
	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)

	// Start waiting for the routines to finish
	go func() {
		waitGroup.Wait()
		c <- 1
	}()

	select {
	case _ = <-c:
		return nil
	case <-time.After(10 * time.Second):
		return errors.New("Timeout")
	}

	return nil
}
<commit_msg>Wait for all line callbacks to finish before finishing the process<commit_after>package process

// Logic for this file is largely based on:
// https://github.com/jarib/childprocess/blob/783f7a00a1678b5d929062564ef5ae76822dfd62/lib/childprocess/unix/process.rb

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/buildkite/agent/logger"
	"github.com/buildkite/agent/shell"
)

type Process struct {
	Pid        int
	PTY        bool
	Script     string
	Env        []string
	ExitStatus string

	buffer bytes.Buffer

	command *exec.Cmd

	// This callback is called when the process offically starts
	StartCallback func()

	// For every line in the process output, this callback will be called
	// with the contents of the line
	LineCallback func(string)

	// Running is stored as an int32 so we can use atomic operations to
	// set/get it (it's accessed by multiple goroutines)
	running int32
}

func (p *Process) Start() error {
	c, err := shell.CommandFromString(p.Script)
	if err != nil {
		return err
	}

	p.command = exec.Command(c.Command, c.Args...)

	// Copy the current processes ENV and merge in the new ones. We do this
	// so the sub process gets PATH and stuff. We merge our path in over
	// the top of the current one so the ENV from Buildkite and the agent
	// take precedence over the agent
	currentEnv := os.Environ()
	p.command.Env = append(currentEnv, p.Env...)

	var waitGroup sync.WaitGroup
	var lineCallbackWaitGroup sync.WaitGroup

	lineReaderPipe, lineWriterPipe := io.Pipe()

	multiWriter := io.MultiWriter(&p.buffer, lineWriterPipe)

	logger.Info("Starting to run: %s", c.String())

	// Toggle between running in a pty
	if p.PTY {
		pty, err := StartPTY(p.command)
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.setRunning(true)

		waitGroup.Add(1)

		go func() {
			logger.Debug("[Process] Starting to copy PTY to the buffer")

			// Copy the pty to our buffer. This will block until it
			// EOF's or something breaks.
			_, err = io.Copy(multiWriter, pty)
			if e, ok := err.(*os.PathError); ok && e.Err == syscall.EIO {
				// We can safely ignore this error, because
				// it's just the PTY telling us that it closed
				// successfully.  See:
				// https://github.com/buildkite/agent/pull/34#issuecomment-46080419
				err = nil
			}

			if err != nil {
				logger.Error("[Process] PTY output copy failed with error: %T: %v", err, err)
			} else {
				logger.Debug("[Process] PTY has finished being copied to the buffer")
			}

			waitGroup.Done()
		}()
	} else {
		p.command.Stdout = multiWriter
		p.command.Stderr = multiWriter
		p.command.Stdin = nil

		err := p.command.Start()
		if err != nil {
			p.ExitStatus = "1"
			return err
		}

		p.Pid = p.command.Process.Pid
		p.setRunning(true)
	}

	logger.Info("[Process] Process is running with PID: %d", p.Pid)

	// Add the line callback routine to the waitGroup
	waitGroup.Add(1)

	go func() {
		logger.Debug("[LineScanner] Starting to read lines")

		reader := bufio.NewReader(lineReaderPipe)

		var appending []byte

		for {
			line, isPrefix, err := reader.ReadLine()
			if err != nil {
				if err == io.EOF {
					logger.Debug("[LineScanner] Encountered EOF")
					break
				}

				logger.Error("[LineScanner] Failed to read: (%T: %v)", err, err)
			}

			// If isPrefix is true, that means we've got a really
			// long line incoming, and we'll keep appending to it
			// until isPrefix is false (which means the long line
			// has ended.
			if isPrefix && appending == nil {
				logger.Debug("[LineScanner] Line is too long to read, going to buffer it until it finishes")
				appending = line

				continue
			}

			// Should we be appending?
			if appending != nil {
				appending = append(appending, line...)

				// No more isPrefix! Line is finished!
				if !isPrefix {
					logger.Debug("[LineScanner] Finished buffering long line")
					line = appending

					// Reset appending back to nil
					appending = nil
				} else {
					continue
				}
			}

			lineCallbackWaitGroup.Add(1)
			go func(line string) {
				defer lineCallbackWaitGroup.Done()
				p.LineCallback(line)
			}(string(line))
		}

		logger.Debug("[LineScanner] Finished")

		waitGroup.Done()
	}()

	// Call the StartCallback
	go p.StartCallback()

	// Wait until the process has finished. The returned error is nil if the command runs,
	// has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.
	waitResult := p.command.Wait()

	// Close the line writer pipe
	lineWriterPipe.Close()

	// The process is no longer running at this point
	p.setRunning(false)

	// Find the exit status of the script
	p.ExitStatus = getExitStatus(waitResult)

	logger.Info("Process with PID: %d finished with Exit Status: %s", p.Pid, p.ExitStatus)

	// Sometimes (in docker containers) io.Copy never seems to finish. This is a mega
	// hack around it. If it doesn't finish after 1 second, just continue.
	logger.Debug("[Process] Waiting for routines to finish")
	err = timeoutWait(&waitGroup)
	if err != nil {
		logger.Debug("[Process] Timed out waiting for wait group: (%T: %v)", err, err)
	}

	// We need to make sure all the line callbacks have finish before
	// finish up the process
	logger.Debug("[Process] Waiting for line callbacks to finish")
	lineCallbackWaitGroup.Wait()

	// No error occurred so we can return nil
	return nil
}

func (p *Process) Output() string {
	return p.buffer.String()
}

func (p *Process) Kill() error {
	// Send a sigterm
	err := p.signal(syscall.SIGTERM)
	if err != nil {
		return err
	}

	// Make a channel that we'll use as a timeout
	c := make(chan int, 1)
	checking := true

	// Start a routine that checks to see if the process
	// is still alive.
	go func() {
		for checking {
			logger.Debug("[Process] Checking to see if PID: %d is still alive", p.Pid)

			foundProcess, err := os.FindProcess(p.Pid)

			// Can't find the process at all
			if err != nil {
				logger.Debug("[Process] Could not find process with PID: %d", p.Pid)

				break
			}

			// We have some information about the process
			if foundProcess != nil {
				processState, err := foundProcess.Wait()

				if err != nil || processState.Exited() {
					logger.Debug("[Process] Process with PID: %d has exited.", p.Pid)

					break
				}
			}

			// Retry in a moment
			sleepTime := time.Duration(1 * time.Second)
			time.Sleep(sleepTime)
		}

		c <- 1
	}()

	// Timeout this process after 3 seconds
	select {
	case _ = <-c:
		// Was successfully terminated
	case <-time.After(10 * time.Second):
		// Stop checking in the routine above
		checking = false

		// Forcefully kill the thing
		err = p.signal(syscall.SIGKILL)

		if err != nil {
			return err
		}
	}

	return nil
}

func (p *Process) signal(sig os.Signal) error {
	if p.command != nil && p.command.Process != nil {
		logger.Debug("[Process] Sending signal: %s to PID: %d", sig.String(), p.Pid)

		err := p.command.Process.Signal(sig)
		if err != nil {
			logger.Error("[Process] Failed to send signal: %s to PID: %d (%T: %v)", sig.String(), p.Pid, err, err)
			return err
		}
	} else {
		logger.Debug("[Process] No process to signal yet")
	}

	return nil
}

// Returns whether or not the process is running
func (p *Process) IsRunning() bool {
	return atomic.LoadInt32(&p.running) != 0
}

// Sets the running flag of the process
func (p *Process) setRunning(r bool) {
	// Use the atomic package to avoid race conditions when setting the
	// `running` value from multiple routines
	if r {
		atomic.StoreInt32(&p.running, 1)
	} else {
		atomic.StoreInt32(&p.running, 0)
	}
}

// https://github.com/hnakamur/commango/blob/fe42b1cf82bf536ce7e24dceaef6656002e03743/os/executil/executil.go#L29
// TODO: Can this be better?
func getExitStatus(waitResult error) string {
	exitStatus := -1

	if waitResult != nil {
		if err, ok := waitResult.(*exec.ExitError); ok {
			if s, ok := err.Sys().(syscall.WaitStatus); ok {
				exitStatus = s.ExitStatus()
			} else {
				logger.Error("[Process] Unimplemented for system where exec.ExitError.Sys() is not syscall.WaitStatus.")
			}
		} else {
			logger.Error("[Process] Unexpected error type in getExitStatus: %#v", waitResult)
		}
	} else {
		exitStatus = 0
	}

	return fmt.Sprintf("%d", exitStatus)
}

func timeoutWait(waitGroup *sync.WaitGroup) error {
	// Make a chanel that we'll use as a timeout
	c := make(chan int, 1)

	// Start waiting for the routines to finish
	go func() {
		waitGroup.Wait()
		c <- 1
	}()

	select {
	case _ = <-c:
		return nil
	case <-time.After(10 * time.Second):
		return errors.New("Timeout")
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

type Chaincode struct { }

type ChaincodeFunctions struct {
	stub shim.ChaincodeStubInterface
}

func main() {
	err := shim.Start(new(Chaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

func (t Chaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	//fns := ChaincodeFunctions{stub}
	configJson := args[0]
	_ = args[1] // nonce to stop existing deal being returned
	_ = stub.PutState("dealConfig", []byte(configJson))
	_ = stub.PutState("dealStatus", []byte("draft")) // Possible Values [draft, open, closed, allocated]
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

func (t Chaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AddOrder(investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AllocateOrder(investor, alloc)
	} else if function == "updateDealStatus" {
		status := args[0]
		return fns.UpdateDealStatus(status)
	} else if function == "confirmOrder" {
		investor := args[0]
		return fns.ConfirmOrder(investor)
	}
	fmt.Println("invoke did not find func: " + function)

	return nil, errors.New("Received unknown function invocation: " + function)
}

func (t Chaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "ping" {
		return fns.Ping()
	} else if function == "getDealConfig" {
		return fns.GetDealConfig()
	} else if function == "getOrder" {
		investor := args[0]
		return fns.GetOrder(investor)
	} else if function == "getOrderbook" {
		return fns.GetOrderbook()
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type DealConfig struct {
	Issuer 		string 		`json:"issuer"`
	Banks 		[]string 	`json:"banks"`
	BookStatus 	string 		`json:"bookStatus"`
	RequireQib	bool		`json:"requireQib"`
	DocRegAddress string 	`json:"docRegAddress"`
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
	Confirmed	bool		`json:"confirmed"`
}

// Public Functions

func (c ChaincodeFunctions) Ping() ([]byte, error) {
    return []byte("pong"), nil
}

func (c ChaincodeFunctions) GetDealConfig() ([]byte, error) {
	dealConfig, _ := c.stub.GetState("dealConfig")
	return dealConfig, nil
}

func (c ChaincodeFunctions) UpdateDealStatus(dealStatus string) ([]byte, error)  {
	dealConfig := c.getDealConfigFromBlockchain()
	dealConfig.BookStatus = dealStatus
	c.saveDealConfigToBlockchain(dealConfig)
	c.stub.SetEvent("Book Status Change", []byte("{\"status\":\"" + dealStatus + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) AddOrder(investor string, ioi float64) ([]byte, error)  {
	dealConfig := c.getDealConfigFromBlockchain()
	if dealConfig.BookStatus != "open" {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not open\"}"))
		return nil, errors.New("Orders cannot be placed unless deal status is 'Open'")
	}
	if dealConfig.RequireQib && !c.checkInvestorQib(dealConfig.DocRegAddress, investor) {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":" + investor + "\" is not a QIB\"}"))
		return nil, errors.New("Order's cannot be placed without QIB status")
	}
	order := c.getOrderFromBlockChain(investor)
	if order.Investor == "" {
		order = Order{Investor: investor, Ioi: ioi, Alloc: 0.0, Confirmed: false}
	} else {
		order.Ioi = ioi
	}
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Added", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) ConfirmOrder(investor string) ([]byte, error) {
	dealConfig := c.getDealConfigFromBlockchain()
	if dealConfig.BookStatus != "allocated" {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not allocated\"}"))
		return nil, nil
	}
	order := c.getOrderFromBlockChain(investor)
	order.Confirmed = true
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Confirmed", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) GetOrder(investor string) ([]byte, error) {
	orderJson := c.getOrderAsJsonFromBlockchain(investor)
	return []byte(orderJson), nil
}

func (c ChaincodeFunctions) GetOrderbook() ([]byte, error) {
	orderbookJson, _ := c.stub.GetState("orderbook")
	return []byte(orderbookJson), nil
}

func (c ChaincodeFunctions) AllocateOrder(investor string, alloc float64) ([]byte, error) {
	order := c.getOrderFromBlockChain(investor)
	order.Alloc = alloc
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Allocated", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

// Private Functions

func (c ChaincodeFunctions) getDealConfigFromBlockchain() DealConfig {
	dealConfigJson, _ := c.stub.GetState("dealConfig")
	var dealConfig DealConfig
	_ = json.Unmarshal(dealConfigJson, &dealConfig)
	return dealConfig
}

func (c ChaincodeFunctions) saveDealConfigToBlockchain(dealConfig DealConfig) {
	dealConfigJson, _ := json.Marshal(dealConfig)
	_ = c.stub.PutState("dealConfig", []byte(dealConfigJson))
}

func (c ChaincodeFunctions) getOrderAsJsonFromBlockchain(investor string) string {
	order := c.getOrderFromBlockChain(investor)
	orderJson, _ := json.Marshal(order)
	return string(orderJson)
}

func (c ChaincodeFunctions) getOrderFromBlockChain(investor string) Order {
	orderbook := c.getOrderbookFromBlockChain()
	return orderbook[investor]
}

func (c ChaincodeFunctions) saveOrderToBlockChain(order Order) {
	orderbook := c.getOrderbookFromBlockChain()
	orderbook[order.Investor] = order
	c.saveOrderbookToBlockChain(orderbook)
}

func (c ChaincodeFunctions) getOrderbookFromBlockChain() map[string]Order {
	orderbookJson, _ := c.stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	return orderbook
}

func (c ChaincodeFunctions) saveOrderbookToBlockChain(orderbook map[string]Order) {
	orderbookJson, _ := json.Marshal(orderbook)
	_ = c.stub.PutState("orderbook", []byte(orderbookJson))
}

func (c ChaincodeFunctions) checkInvestorQib(address string, company string) bool {
	invokeArgs := util.ToChaincodeArgs("getDocsFor", company)
	docsJson, _ := c.stub.QueryChaincode(address, invokeArgs)
	var docs []string
	_ = json.Unmarshal(docsJson, &docs)
	return stringInSlice("qib", docs)
}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}<commit_msg>batch check-in<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/core/util"
)

type Chaincode struct { }

type ChaincodeFunctions struct {
	stub shim.ChaincodeStubInterface
}

func main() {
	err := shim.Start(new(Chaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

func (t Chaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	//fns := ChaincodeFunctions{stub}
	configJson := args[0]
	_ = args[1] // nonce to stop existing deal being returned
	_ = stub.PutState("dealConfig", []byte(configJson))
	_ = stub.PutState("dealStatus", []byte("draft")) // Possible Values [draft, open, closed, allocated]
	_ = stub.PutState("orderbook", []byte("{}"))
	return nil, nil
}

func (t Chaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "addOrder" {
		investor := args[0]
		ioi, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AddOrder(investor, ioi)
	} else if function == "allocateOrder" {
		investor := args[0]
		alloc, err := strconv.ParseFloat(args[1], 64)
		if err != nil {
	        return nil, errors.New("Failed to parse " + args[1] + " as a float64")
    	}
		return fns.AllocateOrder(investor, alloc)
	} else if function == "updateDealStatus" {
		status := args[0]
		return fns.UpdateDealStatus(status)
	} else if function == "confirmOrder" {
		investor := args[0]
		return fns.ConfirmOrder(investor)
	}
	fmt.Println("invoke did not find func: " + function)

	return nil, errors.New("Received unknown function invocation: " + function)
}

func (t Chaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("query is running " + function)
	fns := ChaincodeFunctions{stub}
	if function == "ping" {
		return fns.Ping()
	} else if function == "getDealConfig" {
		return fns.GetDealConfig()
	} else if function == "getOrder" {
		investor := args[0]
		return fns.GetOrder(investor)
	} else if function == "getOrderbook" {
		return fns.GetOrderbook()
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

type DealConfig struct {
	Issuer 		string 		`json:"issuer"`
	Banks 		[]string 	`json:"banks"`
	BookStatus 	string 		`json:"bookStatus"`
	RequireQib	bool		`json:"requireQib"`
	DocRegAddress string 	`json:"docRegAddress"`
}

type Order struct {
	Investor	string 		`json:"investor"`
	Ioi 		float64 	`json:"ioi"`
	Alloc 		float64		`json:"alloc"`
	Confirmed	bool		`json:"confirmed"`
}

// Public Functions

func (c ChaincodeFunctions) Ping() ([]byte, error) {
    return []byte("pong"), nil
}

func (c ChaincodeFunctions) GetDealConfig() ([]byte, error) {
	dealConfig, _ := c.stub.GetState("dealConfig")
	return dealConfig, nil
}

func (c ChaincodeFunctions) UpdateDealStatus(dealStatus string) ([]byte, error)  {
	dealConfig := c.getDealConfigFromBlockchain()
	dealConfig.BookStatus = dealStatus
	c.saveDealConfigToBlockchain(dealConfig)
	c.stub.SetEvent("Book Status Change", []byte("{\"status\":\"" + dealStatus + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) AddOrder(investor string, ioi float64) ([]byte, error)  {
	dealConfig := c.getDealConfigFromBlockchain()
	if dealConfig.BookStatus != "open" {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not open\"}"))
		return nil, errors.New("Orders cannot be placed unless deal status is 'Open'")
	}
	if dealConfig.RequireQib && !c.checkInvestorQib(dealConfig.DocRegAddress, investor) {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":" + investor + "\" is not a QIB\"}"))
		return nil, errors.New("Order's cannot be placed without QIB status")
	}
	order := c.getOrderFromBlockChain(investor)
	if order.Investor == "" {
		order = Order{Investor: investor, Ioi: ioi, Alloc: 0.0, Confirmed: false}
	} else {
		order.Ioi = ioi
	}
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Added", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) ConfirmOrder(investor string) ([]byte, error) {
	dealConfig := c.getDealConfigFromBlockchain()
	if dealConfig.BookStatus != "allocated" {
		c.stub.SetEvent("Permission Denied", []byte("{\"reason\":\"book is not allocated\"}"))
		return nil, nil
	}
	order := c.getOrderFromBlockChain(investor)
	order.Confirmed = true
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Confirmed", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

func (c ChaincodeFunctions) GetOrder(investor string) ([]byte, error) {
	orderJson := c.getOrderAsJsonFromBlockchain(investor)
	return []byte(orderJson), nil
}

func (c ChaincodeFunctions) GetOrderbook() ([]byte, error) {
	orderbookJson, _ := c.stub.GetState("orderbook")
	return []byte(orderbookJson), nil
}

func (c ChaincodeFunctions) AllocateOrder(investor string, alloc float64) ([]byte, error) {
	order := c.getOrderFromBlockChain(investor)
	order.Alloc = alloc
	c.saveOrderToBlockChain(order)
	c.stub.SetEvent("Order Allocated", []byte("{\"investor\":\"" + investor + "\"}"))
	return nil, nil
}

// Private Functions

func (c ChaincodeFunctions) getDealConfigFromBlockchain() DealConfig {
	dealConfigJson, _ := c.stub.GetState("dealConfig")
	var dealConfig DealConfig
	_ = json.Unmarshal(dealConfigJson, &dealConfig)
	return dealConfig
}

func (c ChaincodeFunctions) saveDealConfigToBlockchain(dealConfig DealConfig) {
	dealConfigJson, _ := json.Marshal(dealConfig)
	_ = c.stub.PutState("dealConfig", []byte(dealConfigJson))
}

func (c ChaincodeFunctions) getOrderAsJsonFromBlockchain(investor string) string {
	order := c.getOrderFromBlockChain(investor)
	orderJson, _ := json.Marshal(order)
	return string(orderJson)
}

func (c ChaincodeFunctions) getOrderFromBlockChain(investor string) Order {
	orderbook := c.getOrderbookFromBlockChain()
	return orderbook[investor]
}

func (c ChaincodeFunctions) saveOrderToBlockChain(order Order) {
	orderbook := c.getOrderbookFromBlockChain()
	orderbook[order.Investor] = order
	c.saveOrderbookToBlockChain(orderbook)
}

func (c ChaincodeFunctions) getOrderbookFromBlockChain() map[string]Order {
	orderbookJson, _ := c.stub.GetState("orderbook")
	var orderbook map[string]Order
	_ = json.Unmarshal(orderbookJson, &orderbook)
	return orderbook
}

func (c ChaincodeFunctions) saveOrderbookToBlockChain(orderbook map[string]Order) {
	orderbookJson, _ := json.Marshal(orderbook)
	_ = c.stub.PutState("orderbook", []byte(orderbookJson))
}

func (c ChaincodeFunctions) checkInvestorQib(address string, company string) bool {
	invokeArgs := util.ToChaincodeArgs("getDocs", company)
	docsJson, _ := c.stub.QueryChaincode(address, invokeArgs)
	var docs []string
	_ = json.Unmarshal(docsJson, &docs)
	return stringInSlice("qib", docs)
}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}<|endoftext|>


<commit_before>// Copyright 2016 FullStory, Inc.
//
// 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 solrmonitor

import (
	"encoding/json"
	"errors"
	"math"
	"reflect"
	"testing"
)

func TestComputeBounds(t *testing.T) {
	assertBounds(t, bounds{lo: math.MinInt32, hi: math.MaxInt32}, computeBounds("80000000-7fffffff"))
	assertBounds(t, bounds{lo: 0, hi: 0x6eeeeee}, computeBounds("00000000-06eeeeee"))
	assertBounds(t, bounds{lo: 0, hi: 0x5dddddd}, computeBounds("0-5dddddd"))
	assertBounds(t, bounds{lo: -1, hi: 0}, computeBounds("ffffffff-0"))
	assertBounds(t, bounds{lo: 3, hi: 3}, computeBounds("3-3"))
	assertBounds(t, bounds{err: errors.New(`failed to split "omg"`)}, computeBounds("omg"))
	assertBounds(t, bounds{err: errors.New(`failed to parse "wtf"`)}, computeBounds("80000000-wtf"))
	assertBounds(t, bounds{err: errors.New(`failed to parse "lol"`)}, computeBounds("lol-7fffffff"))
	assertBounds(t, bounds{err: errors.New(`low should be <= high "4-0"`)}, computeBounds("4-0"))
}

func TestUnmarshal(t *testing.T) {
	tcs := []ShardState{
		{Parent: "parent", Range: "80000000-7fffffff", State: "active"},
		{Parent: "parent", Range: "80000000-b332ffff", State: "active"},
		{Parent: "parent", Range: "80000000-wtf", State: "active"},
		{Parent: "parent", Range: "lol-7fffffff", State: "active"},
		{Parent: "parent", Range: "4-0", State: "active"},
	}

	for i := range tcs {
		// bounds not precomputed
		original := tcs[i]

		expected := original.WithRangeBounds()

		var actual ShardState
		jsonUnmarshal(jsonMarshal(&original), &actual)

		if !reflect.DeepEqual(expected, actual) {
			t.Errorf("case %d; expected: %+v, actual: %+v", i, expected, actual)
		}

		assertBounds(t, rangeBounds(expected), rangeBounds(original))
		assertBounds(t, rangeBounds(expected), rangeBounds(actual))

		// Sanity check the internal values
		if original.rangeInitialized {
			t.Error("expected !original.rangeInitialized")
		}
		if !expected.rangeInitialized {
			t.Error("expected expected.rangeInitialized")
		}
		if !actual.rangeInitialized {
			t.Error("expected actual.rangeInitialized")
		}
	}
}

func rangeBounds(v ShardState) bounds {
	var ret bounds
	ret.lo, ret.hi, ret.err = v.RangeBounds()
	return ret
}

func assertBounds(t *testing.T, expected bounds, actual bounds) {
	if expected.err != nil {
		if actual.err == nil {
			t.Errorf("Expected err: %s, actual: nil", expected.err.Error())
		} else if expected.err.Error() != actual.err.Error() {
			t.Errorf("Expected err: %s, actual: %s", expected.err.Error(), actual.err.Error())
		}
		return
	}

	if actual.err != nil {
		t.Errorf("Expected no err, actual: %s", actual.err.Error())
		return
	}

	if expected.lo != actual.lo {
		t.Errorf("Expected low: %d, actual: %d", expected.lo, actual.lo)
	}

	if expected.hi != actual.hi {
		t.Errorf("Expected hi: %d, actual: %d", expected.hi, actual.hi)
	}
}

func jsonMarshal(val interface{}) string {
	b, err := json.MarshalIndent(val, "", "  ")
	if err != nil {
		panic(err.Error())
	}
	return string(b)
}

func jsonUnmarshal(data string, val interface{}) {
	err := json.Unmarshal([]byte(data), val)
	if err != nil {
		panic(err.Error())
	}
}
<commit_msg>fix broken solrmonitor test (#17822)<commit_after>// Copyright 2016 FullStory, Inc.
//
// 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 solrmonitor

import (
	"encoding/json"
	"errors"
	"math"
	"reflect"
	"testing"
)

func computeBounds(rangeStr string) bounds {
	lo, hi, err := ComputeHashBounds(rangeStr)
	return bounds{lo, hi, err}
}

func TestComputeBounds(t *testing.T) {
	assertBounds(t, bounds{lo: math.MinInt32, hi: math.MaxInt32}, computeBounds("80000000-7fffffff"))
	assertBounds(t, bounds{lo: 0, hi: 0x6eeeeee}, computeBounds("00000000-06eeeeee"))
	assertBounds(t, bounds{lo: 0, hi: 0x5dddddd}, computeBounds("0-5dddddd"))
	assertBounds(t, bounds{lo: -1, hi: 0}, computeBounds("ffffffff-0"))
	assertBounds(t, bounds{lo: 3, hi: 3}, computeBounds("3-3"))
	assertBounds(t, bounds{err: errors.New(`failed to split "omg"`)}, computeBounds("omg"))
	assertBounds(t, bounds{err: errors.New(`failed to parse "wtf"`)}, computeBounds("80000000-wtf"))
	assertBounds(t, bounds{err: errors.New(`failed to parse "lol"`)}, computeBounds("lol-7fffffff"))
	assertBounds(t, bounds{err: errors.New(`low should be <= high "4-0"`)}, computeBounds("4-0"))
}

func TestUnmarshal(t *testing.T) {
	tcs := []ShardState{
		{Parent: "parent", Range: "80000000-7fffffff", State: "active"},
		{Parent: "parent", Range: "80000000-b332ffff", State: "active"},
		{Parent: "parent", Range: "80000000-wtf", State: "active"},
		{Parent: "parent", Range: "lol-7fffffff", State: "active"},
		{Parent: "parent", Range: "4-0", State: "active"},
	}

	for i := range tcs {
		// bounds not precomputed
		original := tcs[i]

		expected := original.WithRangeBounds()

		var actual ShardState
		jsonUnmarshal(jsonMarshal(&original), &actual)

		if !reflect.DeepEqual(expected, actual) {
			t.Errorf("case %d; expected: %+v, actual: %+v", i, expected, actual)
		}

		assertBounds(t, rangeBounds(expected), rangeBounds(original))
		assertBounds(t, rangeBounds(expected), rangeBounds(actual))

		// Sanity check the internal values
		if original.rangeInitialized {
			t.Error("expected !original.rangeInitialized")
		}
		if !expected.rangeInitialized {
			t.Error("expected expected.rangeInitialized")
		}
		if !actual.rangeInitialized {
			t.Error("expected actual.rangeInitialized")
		}
	}
}

func rangeBounds(v ShardState) bounds {
	var ret bounds
	ret.lo, ret.hi, ret.err = v.RangeBounds()
	return ret
}

func assertBounds(t *testing.T, expected bounds, actual bounds) {
	if expected.err != nil {
		if actual.err == nil {
			t.Errorf("Expected err: %s, actual: nil", expected.err.Error())
		} else if expected.err.Error() != actual.err.Error() {
			t.Errorf("Expected err: %s, actual: %s", expected.err.Error(), actual.err.Error())
		}
		return
	}

	if actual.err != nil {
		t.Errorf("Expected no err, actual: %s", actual.err.Error())
		return
	}

	if expected.lo != actual.lo {
		t.Errorf("Expected low: %d, actual: %d", expected.lo, actual.lo)
	}

	if expected.hi != actual.hi {
		t.Errorf("Expected hi: %d, actual: %d", expected.hi, actual.hi)
	}
}

func jsonMarshal(val interface{}) string {
	b, err := json.MarshalIndent(val, "", "  ")
	if err != nil {
		panic(err.Error())
	}
	return string(b)
}

func jsonUnmarshal(data string, val interface{}) {
	err := json.Unmarshal([]byte(data), val)
	if err != nil {
		panic(err.Error())
	}
}
<|endoftext|>


<commit_before>package service

import (
	"fmt"

	"github.com/juju/errors"

	"github.com/juju/juju/service/common"
	"github.com/juju/juju/service/systemd"
	"github.com/juju/juju/service/upstart"
	"github.com/juju/juju/service/windows"
	"github.com/juju/juju/version"
)

// These are the names of the init systems regognized by juju.
const (
	InitSystemWindows = "windows"
	InitSystemUpstart = "upstart"
	InitSystemSystemd = "systemd"
)

var _ Service = (*upstart.Service)(nil)
var _ Service = (*windows.Service)(nil)

// TODO(ericsnow) bug #1426461
// Running, Installed, and Exists should return errors.

// Service represents a service in the init system running on a host.
type Service interface {
	// Name returns the service's name.
	Name() string

	// Conf returns the service's conf data.
	Conf() common.Conf

	// UpdateConfig adds a config to the service, overwriting the current one.
	UpdateConfig(conf common.Conf)

	// Running returns a boolean value that denotes
	// whether or not the service is running.
	Running() bool

	// Start will try to start the service.
	Start() error

	// Stop will try to stop the service.
	Stop() error

	// TODO(ericsnow) Eliminate StopAndRemove.

	// StopAndRemove will stop the service and remove it.
	StopAndRemove() error

	// Exists returns whether the service configuration exists in the
	// init directory with the same content that this Service would have
	// if installed.
	Exists() bool

	// Installed will return a boolean value that denotes
	// whether or not the service is installed.
	Installed() bool

	// Install installs a service.
	Install() error

	// Remove will remove the service.
	Remove() error

	// InstallCommands returns the list of commands to run on a
	// (remote) host to install the service.
	InstallCommands() ([]string, error)
}

// TODO(ericsnow) bug #1426458
// Eliminate the need to pass an empty conf for most service methods
// and several helper functions.

// NewService returns a new Service based on the provided info.
func NewService(name string, conf common.Conf, initSystem string) (Service, error) {
	switch initSystem {
	case InitSystemWindows:
		return windows.NewService(name, conf), nil
	case InitSystemUpstart:
		return upstart.NewService(name, conf), nil
	case InitSystemSystemd:
		svc, err := systemd.NewService(name, conf)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return svc, nil
	default:
		return nil, errors.NotFoundf("init system %q", initSystem)
	}
}

// DiscoverService returns an interface to a service apropriate
// for the current system
func DiscoverService(name string, conf common.Conf) (Service, error) {
	initName, ok := VersionInitSystem(version.Current)
	if !ok {
		return nil, errors.NotFoundf("init system on local host")
	}

	service, err := NewService(name, conf, initName)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return service, nil
}

// VersionInitSystem returns an init system name based on the provided
// version info. If one cannot be identified then false if returned
// for the second return value.
func VersionInitSystem(vers version.Binary) (string, bool) {
	switch vers.OS {
	case version.Windows:
		return InitSystemWindows, true
	case version.Ubuntu:
		switch vers.Series {
		case "precise", "quantal", "raring", "saucy", "trusty", "utopic":
			return InitSystemUpstart, true
		// TODO(ericsnow) the explicit vivid case should be removed once
		// vivid switches over to systemd (for PID 1).
		case "vivid":
			return InitSystemUpstart, true
		default:
			// vivid and later
			return InitSystemSystemd, true
		}
		// TODO(ericsnow) Support other OSes, like version.CentOS.
	default:
		return "", false
	}
}

// ListServices lists all installed services on the running system
func ListServices(initDir string) ([]string, error) {
	initName, ok := VersionInitSystem(version.Current)
	if !ok {
		return nil, errors.NotFoundf("init system on local host")
	}

	switch initName {
	case InitSystemWindows:
		services, err := windows.ListServices()
		if err != nil {
			return nil, err
		}
		return services, nil
	case InitSystemUpstart:
		services, err := upstart.ListServices(initDir)
		if err != nil {
			return nil, err
		}
		return services, nil
	case InitSystemSystemd:
		services, err := systemd.ListServices()
		if err != nil {
			return nil, err
		}
		return services, nil
	default:
		return nil, errors.NotFoundf("init system %q", initName)
	}
}

var linuxExecutables = map[string]string{
	// Note that some systems link /sbin/init to whatever init system
	// is supported, so in the future we may need some other way to
	// identify upstart uniquely.
	"/sbin/init":    InitSystemUpstart,
	"/sbin/upstart": InitSystemUpstart,
	// TODO(ericsnow) Disabled for lp-1427210.
	//"/sbin/systemd":        InitSystemSystemd,
	//"/bin/systemd":         InitSystemSystemd,
	//"/lib/systemd/systemd": InitSystemSystemd,
}

// TODO(ericsnow) Is it too much to cat once for each executable?
const initSystemTest = `[[ "$(cat /proc/1/cmdline)" == "%s" ]]`

// ListServicesCommand returns the command that should be run to get
// a list of service names on a host.
func ListServicesCommand() string {
	// TODO(ericsnow) Allow passing in "initSystems ...string".
	executables := linuxExecutables

	// TODO(ericsnow) build the command in a better way?

	cmdAll := ""
	for executable, initSystem := range executables {
		cmd, ok := listServicesCommand(initSystem)
		if !ok {
			continue
		}

		test := fmt.Sprintf(initSystemTest, executable)
		cmd = fmt.Sprintf("if %s; then %s\n", test, cmd)
		if cmdAll != "" {
			cmd = "el" + cmd
		}
		cmdAll += cmd
	}
	if cmdAll != "" {
		cmdAll += "" +
			"else exit 1\n" +
			"fi"
	}
	return cmdAll
}

func listServicesCommand(initSystem string) (string, bool) {
	switch initSystem {
	case InitSystemWindows:
		return windows.ListCommand(), true
	case InitSystemUpstart:
		return upstart.ListCommand(), true
	case InitSystemSystemd:
		return systemd.ListCommand(), true
	default:
		return "", false
	}
}
<commit_msg>service: predictable ListServicesCommand output<commit_after>package service

import (
	"fmt"

	"github.com/juju/errors"
	"github.com/juju/utils/set"

	"github.com/juju/juju/service/common"
	"github.com/juju/juju/service/systemd"
	"github.com/juju/juju/service/upstart"
	"github.com/juju/juju/service/windows"
	"github.com/juju/juju/version"
)

// These are the names of the init systems regognized by juju.
const (
	InitSystemWindows = "windows"
	InitSystemUpstart = "upstart"
	InitSystemSystemd = "systemd"
)

var _ Service = (*upstart.Service)(nil)
var _ Service = (*windows.Service)(nil)

// TODO(ericsnow) bug #1426461
// Running, Installed, and Exists should return errors.

// Service represents a service in the init system running on a host.
type Service interface {
	// Name returns the service's name.
	Name() string

	// Conf returns the service's conf data.
	Conf() common.Conf

	// UpdateConfig adds a config to the service, overwriting the current one.
	UpdateConfig(conf common.Conf)

	// Running returns a boolean value that denotes
	// whether or not the service is running.
	Running() bool

	// Start will try to start the service.
	Start() error

	// Stop will try to stop the service.
	Stop() error

	// TODO(ericsnow) Eliminate StopAndRemove.

	// StopAndRemove will stop the service and remove it.
	StopAndRemove() error

	// Exists returns whether the service configuration exists in the
	// init directory with the same content that this Service would have
	// if installed.
	Exists() bool

	// Installed will return a boolean value that denotes
	// whether or not the service is installed.
	Installed() bool

	// Install installs a service.
	Install() error

	// Remove will remove the service.
	Remove() error

	// InstallCommands returns the list of commands to run on a
	// (remote) host to install the service.
	InstallCommands() ([]string, error)
}

// TODO(ericsnow) bug #1426458
// Eliminate the need to pass an empty conf for most service methods
// and several helper functions.

// NewService returns a new Service based on the provided info.
func NewService(name string, conf common.Conf, initSystem string) (Service, error) {
	switch initSystem {
	case InitSystemWindows:
		return windows.NewService(name, conf), nil
	case InitSystemUpstart:
		return upstart.NewService(name, conf), nil
	case InitSystemSystemd:
		svc, err := systemd.NewService(name, conf)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return svc, nil
	default:
		return nil, errors.NotFoundf("init system %q", initSystem)
	}
}

// DiscoverService returns an interface to a service apropriate
// for the current system
func DiscoverService(name string, conf common.Conf) (Service, error) {
	initName, ok := VersionInitSystem(version.Current)
	if !ok {
		return nil, errors.NotFoundf("init system on local host")
	}

	service, err := NewService(name, conf, initName)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return service, nil
}

// VersionInitSystem returns an init system name based on the provided
// version info. If one cannot be identified then false if returned
// for the second return value.
func VersionInitSystem(vers version.Binary) (string, bool) {
	switch vers.OS {
	case version.Windows:
		return InitSystemWindows, true
	case version.Ubuntu:
		switch vers.Series {
		case "precise", "quantal", "raring", "saucy", "trusty", "utopic":
			return InitSystemUpstart, true
		// TODO(ericsnow) the explicit vivid case should be removed once
		// vivid switches over to systemd (for PID 1).
		case "vivid":
			return InitSystemUpstart, true
		default:
			// vivid and later
			return InitSystemSystemd, true
		}
		// TODO(ericsnow) Support other OSes, like version.CentOS.
	default:
		return "", false
	}
}

// ListServices lists all installed services on the running system
func ListServices(initDir string) ([]string, error) {
	initName, ok := VersionInitSystem(version.Current)
	if !ok {
		return nil, errors.NotFoundf("init system on local host")
	}

	switch initName {
	case InitSystemWindows:
		services, err := windows.ListServices()
		if err != nil {
			return nil, err
		}
		return services, nil
	case InitSystemUpstart:
		services, err := upstart.ListServices(initDir)
		if err != nil {
			return nil, err
		}
		return services, nil
	case InitSystemSystemd:
		services, err := systemd.ListServices()
		if err != nil {
			return nil, err
		}
		return services, nil
	default:
		return nil, errors.NotFoundf("init system %q", initName)
	}
}

var linuxExecutables = map[string]string{
	// Note that some systems link /sbin/init to whatever init system
	// is supported, so in the future we may need some other way to
	// identify upstart uniquely.
	"/sbin/init":    InitSystemUpstart,
	"/sbin/upstart": InitSystemUpstart,
	// TODO(ericsnow) Disabled for lp-1427210.
	//"/sbin/systemd":        InitSystemSystemd,
	//"/bin/systemd":         InitSystemSystemd,
	//"/lib/systemd/systemd": InitSystemSystemd,
}

// TODO(ericsnow) Is it too much to cat once for each executable?
const initSystemTest = `[[ "$(cat /proc/1/cmdline)" == "%s" ]]`

// ListServicesCommand returns the command that should be run to get
// a list of service names on a host.
func ListServicesCommand() string {
	// TODO(ericsnow) Allow passing in "initSystems ...string".
	executables := linuxExecutables

	// Sort executable names for predictable commands, simplifying testing.
	sortedExecutables := make(set.Strings)
	for executable := range executables {
		sortedExecutables.Add(executable)
	}

	// TODO(ericsnow) build the command in a better way?

	cmdAll := ""
	for _, executable := range sortedExecutables.SortedValues() {
		initSystem := executables[executable]
		cmd, ok := listServicesCommand(initSystem)
		if !ok {
			continue
		}

		test := fmt.Sprintf(initSystemTest, executable)
		cmd = fmt.Sprintf("if %s; then %s\n", test, cmd)
		if cmdAll != "" {
			cmd = "el" + cmd
		}
		cmdAll += cmd
	}
	if cmdAll != "" {
		cmdAll += "" +
			"else exit 1\n" +
			"fi"
	}
	return cmdAll
}

func listServicesCommand(initSystem string) (string, bool) {
	switch initSystem {
	case InitSystemWindows:
		return windows.ListCommand(), true
	case InitSystemUpstart:
		return upstart.ListCommand(), true
	case InitSystemSystemd:
		return systemd.ListCommand(), true
	default:
		return "", false
	}
}
<|endoftext|>


<commit_before>package service

import (
	"fmt"
	"html/template"
	"os"
	"os/exec"
	"strings"

	"github.com/bpowell/brocker/container"
)

var nginxConfig *template.Template

func init() {
	nginxConfig = template.Must(template.ParseFiles("/etc/brocker/nginx.conf.tmpl", "/etc/brocker/myapp.conf.tmpl"))
}

type Service struct {
	ContainterName  string
	Name            string `json:"name"`
	BridgeName      string
	BridgeIP        string `json:"bridge-ip"`
	Pid             int
	Containers      map[string]container.Container
	LoadBalanceType string
	Servers         []string
}

func (s *Service) Reload() {
	c, ok := s.Containers[s.ContainterName]
	if !ok {
		fmt.Println("Not a container", s.ContainterName)
		return
	}

	if err := c.Exec("/usr/sbin/nginx -s reload -c /app/nginx.conf"); err != nil {
		fmt.Println("Cannot reload nginx: ", err)
		return
	}
}

func (s *Service) Stop() {
	c, ok := s.Containers[s.ContainterName]
	if !ok {
		fmt.Println("Not a container", s.ContainterName)
		return
	}

	if err := c.Exec("/usr/sbin/nginx -s stop -c /app/nginx.conf"); err != nil {
		fmt.Println(err)
	}

	for _, c := range s.Containers {
		c.Close()
	}

	deleteBridge := strings.Split(fmt.Sprintf("ip link delete %s type bridge", s.BridgeName), " ")
	if err := exec.Command(deleteBridge[0], deleteBridge[1:]...).Run(); err != nil {
		fmt.Printf("Cannot delete bridge %s", s.BridgeName)
	}
}

func (s *Service) WriteConfig(path string) {
	nginxconffile, err := os.Create(fmt.Sprintf("%s/%s/nginx.conf", path, s.ContainterName))
	if err != nil {
		fmt.Println(err)
		return
	}
	defer nginxconffile.Close()

	if err := nginxConfig.ExecuteTemplate(nginxconffile, "nginx.conf.tmpl", s); err != nil {
		fmt.Println(err)
		nginxconffile.Close()
		return
	}

	myappconffile, err := os.Create(fmt.Sprintf("%s/%s/myapp.conf", path, s.ContainterName))
	if err != nil {
		fmt.Println(err)
		return
	}
	defer myappconffile.Close()

	if err := nginxConfig.ExecuteTemplate(myappconffile, "myapp.conf.tmpl", s); err != nil {
		fmt.Println(err)
		return
	}
}
<commit_msg>more docs<commit_after>package service

import (
	"fmt"
	"html/template"
	"os"
	"os/exec"
	"strings"

	"github.com/bpowell/brocker/container"
)

var nginxConfig *template.Template

func init() {
	nginxConfig = template.Must(template.ParseFiles("/etc/brocker/nginx.conf.tmpl", "/etc/brocker/myapp.conf.tmpl"))
}

// Service contains all things to run a service
type Service struct {
	ContainterName  string
	Name            string `json:"name"`
	BridgeName      string
	BridgeIP        string `json:"bridge-ip"`
	Pid             int
	Containers      map[string]container.Container
	LoadBalanceType string
	Servers         []string
}

// Reload reloads all the nginx configs
func (s *Service) Reload() {
	c, ok := s.Containers[s.ContainterName]
	if !ok {
		fmt.Println("Not a container", s.ContainterName)
		return
	}

	if err := c.Exec("/usr/sbin/nginx -s reload -c /app/nginx.conf"); err != nil {
		fmt.Println("Cannot reload nginx: ", err)
		return
	}
}

// Stop stops all containers and the service
func (s *Service) Stop() {
	c, ok := s.Containers[s.ContainterName]
	if !ok {
		fmt.Println("Not a container", s.ContainterName)
		return
	}

	if err := c.Exec("/usr/sbin/nginx -s stop -c /app/nginx.conf"); err != nil {
		fmt.Println(err)
	}

	for _, c := range s.Containers {
		c.Close()
	}

	deleteBridge := strings.Split(fmt.Sprintf("ip link delete %s type bridge", s.BridgeName), " ")
	if err := exec.Command(deleteBridge[0], deleteBridge[1:]...).Run(); err != nil {
		fmt.Printf("Cannot delete bridge %s", s.BridgeName)
	}
}

// WriteConfig writes all the nginx configs
func (s *Service) WriteConfig(path string) {
	nginxconffile, err := os.Create(fmt.Sprintf("%s/%s/nginx.conf", path, s.ContainterName))
	if err != nil {
		fmt.Println(err)
		return
	}
	defer nginxconffile.Close()

	if err := nginxConfig.ExecuteTemplate(nginxconffile, "nginx.conf.tmpl", s); err != nil {
		fmt.Println(err)
		nginxconffile.Close()
		return
	}

	myappconffile, err := os.Create(fmt.Sprintf("%s/%s/myapp.conf", path, s.ContainterName))
	if err != nil {
		fmt.Println(err)
		return
	}
	defer myappconffile.Close()

	if err := nginxConfig.ExecuteTemplate(myappconffile, "myapp.conf.tmpl", s); err != nil {
		fmt.Println(err)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"os"

	"github.com/kurin/tgt/packet"
)

func main() {
	for {
		m, err := packet.Next(os.Stdin)

		if err == io.EOF {
			return
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(m)
	}
}
<commit_msg>No longer used.<commit_after><|endoftext|>


<commit_before>package protocol

import (
	"github.com/AutogrowSystems/faye-go/utils"
	"reflect"
	"sync"
	"time"
)

type MsgStore interface {
	EnqueueMessages([]Message)
	GetAndClearMessages() []Message
}

// Connect requests starts a session
type Session struct {
	conn     Connection
	timeout  int
	response Message
	client   *Client
	started  time.Time
	logger   utils.Logger
}

func NewSession(client *Client, conn Connection, timeout int, response Message, logger utils.Logger) *Session {
	session := Session{conn, timeout, response, client, time.Now(), logger}
	if timeout > 0 {
		go func() {
			time.Sleep(time.Duration(timeout) * time.Millisecond)
			session.End()
		}()
	}
	return &session
}

func (s Session) End() {
	// c.mutex.Lock()
	// defer c.mutex.Unlock()

	if s.conn.IsConnected() {
		s.conn.Send([]Message{s.response})
	} else {
		s.logger.Debugf("No longer connected %s", s.client.clientId)
	}
}

type Client struct {
	clientId    string
	connection  Connection
	msgStore    MsgStore
	isConnected bool
	responseMsg Message
	mutex       sync.Mutex
	lastSession *Session
	created     time.Time
	logger      utils.Logger
}

func NewClient(clientId string, msgStore MsgStore, logger utils.Logger) Client {
	client := Client{
		clientId:    clientId,
		msgStore:    msgStore,
		isConnected: false,
		created:     time.Now(),
		logger:      logger,
	}

	return client
}

func (c Client) Id() string {
	return c.clientId
}

func (c *Client) Connect(timeout int, interval int, responseMsg Message, connection Connection) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.lastSession = NewSession(c, connection, timeout, responseMsg, c.logger)
	c.responseMsg = responseMsg

	c.flushMsgs()
}

func (c *Client) SetConnection(connection Connection) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if c.connection == nil || connection.Priority() > c.connection.Priority() {
		c.connection = connection
		c.isConnected = true
	}
}

func (c Client) Queue(msg Message) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.msgStore.EnqueueMessages([]Message{msg})
	c.flushMsgs()
}

func (c Client) QueueMany(msgs []Message) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.msgStore.EnqueueMessages(msgs)
	c.flushMsgs()
}

func (c Client) IsExpired() bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if time.Now().Sub(c.created) > time.Duration(1*time.Minute) {
		if c.lastSession != nil &&
			time.Now().Sub(c.lastSession.started) > time.Duration(2*time.Hour) {
			return true
		}
	}
	return false
}

func (c Client) flushMsgs() {
	if c.isConnected && c.connection != nil && c.connection.IsConnected() {
		msgs := c.msgStore.GetAndClearMessages()
		if len(msgs) > 0 {

			var msgsWithConnect []Message
			if c.connection.IsSingleShot() {
				msgsWithConnect = append(msgs, c.responseMsg)

			} else {
				msgsWithConnect = msgs
			}
			c.logger.Debugf("Sending %d msgs to %s on %s", len(msgsWithConnect), c.clientId, reflect.TypeOf(c.connection))

			err := c.connection.Send(msgsWithConnect)

			// failed, so requeue
			if err != nil {
				c.logger.Debugf("Was unable to send to %s requeued %d messages", c.clientId, len(msgs))
				c.msgStore.EnqueueMessages(msgs)
			} else {
				c.responseMsg = nil
				c.isConnected = false
			}
		}
	} else {
		c.logger.Debugf("Not connected for %s", c.clientId)
	}
}
<commit_msg>made sure to set the client ID on any messages being queued on a client<commit_after>package protocol

import (
	"github.com/AutogrowSystems/faye-go/utils"
	"reflect"
	"sync"
	"time"
)

type MsgStore interface {
	EnqueueMessages([]Message)
	GetAndClearMessages() []Message
}

// Connect requests starts a session
type Session struct {
	conn     Connection
	timeout  int
	response Message
	client   *Client
	started  time.Time
	logger   utils.Logger
}

func NewSession(client *Client, conn Connection, timeout int, response Message, logger utils.Logger) *Session {
	session := Session{conn, timeout, response, client, time.Now(), logger}
	if timeout > 0 {
		go func() {
			time.Sleep(time.Duration(timeout) * time.Millisecond)
			session.End()
		}()
	}
	return &session
}

func (s Session) End() {
	// c.mutex.Lock()
	// defer c.mutex.Unlock()

	if s.conn.IsConnected() {
		s.conn.Send([]Message{s.response})
	} else {
		s.logger.Debugf("No longer connected %s", s.client.clientId)
	}
}

type Client struct {
	clientId    string
	connection  Connection
	msgStore    MsgStore
	isConnected bool
	responseMsg Message
	mutex       sync.Mutex
	lastSession *Session
	created     time.Time
	logger      utils.Logger
}

func NewClient(clientId string, msgStore MsgStore, logger utils.Logger) Client {
	client := Client{
		clientId:    clientId,
		msgStore:    msgStore,
		isConnected: false,
		created:     time.Now(),
		logger:      logger,
	}

	return client
}

func (c Client) Id() string {
	return c.clientId
}

func (c *Client) Connect(timeout int, interval int, responseMsg Message, connection Connection) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.lastSession = NewSession(c, connection, timeout, responseMsg, c.logger)
	c.responseMsg = responseMsg

	c.flushMsgs()
}

func (c *Client) SetConnection(connection Connection) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if c.connection == nil || connection.Priority() > c.connection.Priority() {
		c.connection = connection
		c.isConnected = true
	}
}

func (c Client) Queue(msg Message) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	msg.SetClientId(c.clientId)
	c.msgStore.EnqueueMessages([]Message{msg})
	c.flushMsgs()
}

func (c Client) QueueMany(msgs []Message) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.msgStore.EnqueueMessages(msgs)
	c.flushMsgs()
}

func (c Client) IsExpired() bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if time.Now().Sub(c.created) > time.Duration(1*time.Minute) {
		if c.lastSession != nil &&
			time.Now().Sub(c.lastSession.started) > time.Duration(2*time.Hour) {
			return true
		}
	}
	return false
}

func (c Client) flushMsgs() {
	if c.isConnected && c.connection != nil && c.connection.IsConnected() {
		msgs := c.msgStore.GetAndClearMessages()
		if len(msgs) > 0 {

			var msgsWithConnect []Message
			if c.connection.IsSingleShot() {
				msgsWithConnect = append(msgs, c.responseMsg)

			} else {
				msgsWithConnect = msgs
			}
			c.logger.Debugf("Sending %d msgs to %s on %s", len(msgsWithConnect), c.clientId, reflect.TypeOf(c.connection))

			err := c.connection.Send(msgsWithConnect)

			// failed, so requeue
			if err != nil {
				c.logger.Debugf("Was unable to send to %s requeued %d messages", c.clientId, len(msgs))
				c.msgStore.EnqueueMessages(msgs)
			} else {
				c.responseMsg = nil
				c.isConnected = false
			}
		}
	} else {
		c.logger.Debugf("Not connected for %s", c.clientId)
	}
}
<|endoftext|>


<commit_before>package protocol

import (
	"github.com/AutogrowSystems/faye-go/utils"
	"reflect"
	"sync"
	"time"
)

type MsgStore interface {
	EnqueueMessages([]Message)
	GetAndClearMessages() []Message
}

// Connect requests starts a session
type Session struct {
	conn     Connection
	timeout  int
	response Message
	client   *Client
	started  time.Time
	logger   utils.Logger
}

func NewSession(client *Client, conn Connection, timeout int, response Message, logger utils.Logger) *Session {
	session := Session{conn, timeout, response, client, time.Now(), logger}
	if timeout > 0 {
		go func() {
			time.Sleep(time.Duration(timeout) * time.Millisecond)
			session.End()
		}()
	}
	return &session
}

func (s Session) End() {
	// c.mutex.Lock()
	// defer c.mutex.Unlock()

	if s.conn.IsConnected() {
		s.conn.Send([]Message{s.response})
	} else {
		s.logger.Debugf("No longer connected %s", s.client.clientId)
	}
}

type Client struct {
	clientId    string
	connection  Connection
	msgStore    MsgStore
	isConnected bool
	responseMsg Message
	mutex       sync.Mutex
	lastSession *Session
	created     time.Time
	logger      utils.Logger
}

func NewClient(clientId string, msgStore MsgStore, logger utils.Logger) Client {
	client := Client{
		clientId:    clientId,
		msgStore:    msgStore,
		isConnected: false,
		created:     time.Now(),
		logger:      logger,
	}

	return client
}

func (c Client) Id() string {
	return c.clientId
}

func (c *Client) Connect(timeout int, interval int, responseMsg Message, connection Connection) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.lastSession = NewSession(c, connection, timeout, responseMsg, c.logger)
	c.responseMsg = responseMsg

	c.flushMsgs()
}

func (c *Client) SetConnection(connection Connection) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if c.connection == nil || connection.Priority() > c.connection.Priority() {
		c.connection = connection
		c.isConnected = true
	}
}

func (c Client) Queue(msg Message) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	msg.SetClientId(c.clientId)
	c.msgStore.EnqueueMessages([]Message{msg})
	c.flushMsgs()
}

func (c Client) QueueMany(msgs []Message) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.msgStore.EnqueueMessages(msgs)
	c.flushMsgs()
}

func (c Client) IsExpired() bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if time.Now().Sub(c.created) > time.Duration(1*time.Minute) {
		if c.lastSession != nil &&
			time.Now().Sub(c.lastSession.started) > time.Duration(2*time.Hour) {
			return true
		}
	}
	return false
}

func (c Client) flushMsgs() {
	if c.isConnected && c.connection != nil && c.connection.IsConnected() {
		msgs := c.msgStore.GetAndClearMessages()
		if len(msgs) > 0 {

			var msgsWithConnect []Message
			if c.connection.IsSingleShot() {
				msgsWithConnect = append(msgs, c.responseMsg)

			} else {
				msgsWithConnect = msgs
			}
			c.logger.Debugf("Sending %d msgs to %s on %s", len(msgsWithConnect), c.clientId, reflect.TypeOf(c.connection))

			err := c.connection.Send(msgsWithConnect)

			// failed, so requeue
			if err != nil {
				c.logger.Debugf("Was unable to send to %s requeued %d messages", c.clientId, len(msgs))
				c.msgStore.EnqueueMessages(msgs)
			} else {
				c.responseMsg = nil
				c.isConnected = false
			}
		}
	} else {
		c.logger.Debugf("Not connected for %s", c.clientId)
	}
}
<commit_msg>made connect response come before messages<commit_after>package protocol

import (
	"github.com/AutogrowSystems/faye-go/utils"
	"reflect"
	"sync"
	"time"
)

type MsgStore interface {
	EnqueueMessages([]Message)
	GetAndClearMessages() []Message
}

// Connect requests starts a session
type Session struct {
	conn     Connection
	timeout  int
	response Message
	client   *Client
	started  time.Time
	logger   utils.Logger
}

func NewSession(client *Client, conn Connection, timeout int, response Message, logger utils.Logger) *Session {
	session := Session{conn, timeout, response, client, time.Now(), logger}
	if timeout > 0 {
		go func() {
			time.Sleep(time.Duration(timeout) * time.Millisecond)
			session.End()
		}()
	}
	return &session
}

func (s Session) End() {
	// c.mutex.Lock()
	// defer c.mutex.Unlock()

	if s.conn.IsConnected() {
		s.conn.Send([]Message{s.response})
	} else {
		s.logger.Debugf("No longer connected %s", s.client.clientId)
	}
}

type Client struct {
	clientId    string
	connection  Connection
	msgStore    MsgStore
	isConnected bool
	responseMsg Message
	mutex       sync.Mutex
	lastSession *Session
	created     time.Time
	logger      utils.Logger
}

func NewClient(clientId string, msgStore MsgStore, logger utils.Logger) Client {
	client := Client{
		clientId:    clientId,
		msgStore:    msgStore,
		isConnected: false,
		created:     time.Now(),
		logger:      logger,
	}

	return client
}

func (c Client) Id() string {
	return c.clientId
}

func (c *Client) Connect(timeout int, interval int, responseMsg Message, connection Connection) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.lastSession = NewSession(c, connection, timeout, responseMsg, c.logger)
	c.responseMsg = responseMsg

	c.flushMsgs()
}

func (c *Client) SetConnection(connection Connection) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if c.connection == nil || connection.Priority() > c.connection.Priority() {
		c.connection = connection
		c.isConnected = true
	}
}

func (c Client) Queue(msg Message) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	msg.SetClientId(c.clientId)
	c.msgStore.EnqueueMessages([]Message{msg})
	c.flushMsgs()
}

func (c Client) QueueMany(msgs []Message) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.msgStore.EnqueueMessages(msgs)
	c.flushMsgs()
}

func (c Client) IsExpired() bool {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if time.Now().Sub(c.created) > time.Duration(1*time.Minute) {
		if c.lastSession != nil &&
			time.Now().Sub(c.lastSession.started) > time.Duration(2*time.Hour) {
			return true
		}
	}
	return false
}

func (c Client) IsConnected() bool {
	c.logger.Debugf("Client %s connected?: %t, %t", c.clientId, c.isConnected, c.connection.IsConnected())
	return c.isConnected && c.connection != nil && c.connection.IsConnected()
}

func (c Client) flushMsgs() {
	if c.IsConnected() {

		msgs := c.msgStore.GetAndClearMessages()
		if len(msgs) > 0 {

			var msgsToSend []Message

			if c.responseMsg != nil {
				msgsToSend = append(msgsToSend, c.responseMsg)
				msgsToSend = append(msgsToSend, msgs...)
			} else {
				msgsToSend = msgs
			}

			c.logger.Debugf("Sending %d msgs to %s on %s", len(msgsToSend), c.clientId, reflect.TypeOf(c.connection))
			err := c.connection.Send(msgsToSend)

			// failed, so requeue
			if err != nil {
				c.logger.Errorf("ERROR: %+v", err)
				c.logger.Debugf("Was unable to send to %s, requeued %d messages", c.clientId, len(msgs))
				c.msgStore.EnqueueMessages(msgs)
			} else {
				c.responseMsg = nil
				c.isConnected = false
			}
		}
	} else {
		c.logger.Debugf("Not connected to %s", c.clientId)
	}
}
<|endoftext|>


<commit_before>package commands_test

import (
	"cf"
	"cf/api"
	. "cf/commands"
	"github.com/stretchr/testify/assert"
	"testhelpers"
	"testing"
)

func TestBindCommand(t *testing.T) {
	app := cf.Application{Name: "my-app", Guid: "my-app-guid"}
	serviceInstance := cf.ServiceInstance{Name: "my-service", Guid: "my-service-guid"}
	reqFactory := &testhelpers.FakeReqFactory{
		Application:     app,
		ServiceInstance: serviceInstance,
	}
	serviceRepo := &testhelpers.FakeServiceRepo{}
	fakeUI := callBindService([]string{"my-app", "my-service"}, reqFactory, serviceRepo)

	assert.Equal(t, reqFactory.ApplicationName, "my-app")
	assert.Equal(t, reqFactory.ServiceInstanceName, "my-service")

	assert.Contains(t, fakeUI.Outputs[0], "Binding service")
	assert.Contains(t, fakeUI.Outputs[0], "my-service")
	assert.Contains(t, fakeUI.Outputs[0], "my-app")

	assert.Equal(t, serviceRepo.BindServiceServiceInstance, serviceInstance)
	assert.Equal(t, serviceRepo.BindServiceApplication, app)

	assert.Contains(t, fakeUI.Outputs[1], "OK")
}

func TestBindCommandIfServiceIsAlreadyBound(t *testing.T) {
	app := cf.Application{Name: "my-app", Guid: "my-app-guid"}
	serviceInstance := cf.ServiceInstance{Name: "my-service", Guid: "my-service-guid"}
	reqFactory := &testhelpers.FakeReqFactory{
		Application:     app,
		ServiceInstance: serviceInstance,
	}
	serviceRepo := &testhelpers.FakeServiceRepo{BindServiceErrorCode: "90003"}
	fakeUI := callBindService([]string{"my-app", "my-service"}, reqFactory, serviceRepo)

	assert.Contains(t, fakeUI.Outputs[0], "Binding service")
	assert.Contains(t, fakeUI.Outputs[1], "OK")
	assert.Contains(t, fakeUI.Outputs[2], "is already bound")
}

func TestBindCommandFailsWithUsage(t *testing.T) {
	reqFactory := &testhelpers.FakeReqFactory{}
	serviceRepo := &testhelpers.FakeServiceRepo{}

	fakeUI := callBindService([]string{"my-service"}, reqFactory, serviceRepo)
	assert.True(t, fakeUI.FailedWithUsage)

	fakeUI = callBindService([]string{"my-app"}, reqFactory, serviceRepo)
	assert.True(t, fakeUI.FailedWithUsage)

	fakeUI = callBindService([]string{"my-app", "my-service"}, reqFactory, serviceRepo)
	assert.False(t, fakeUI.FailedWithUsage)
}

func callBindService(args []string, reqFactory *testhelpers.FakeReqFactory, serviceRepo api.ServiceRepository) (fakeUI *testhelpers.FakeUI) {
	fakeUI = new(testhelpers.FakeUI)
	ctxt := testhelpers.NewContext("bind-service", args)
	cmd := NewBindService(fakeUI, serviceRepo)
	testhelpers.RunCommand(cmd, ctxt, reqFactory)
	return
}
<commit_msg>Make tests a little better.<commit_after>package commands_test

import (
	"cf"
	"cf/api"
	. "cf/commands"
	"github.com/stretchr/testify/assert"
	"testhelpers"
	"testing"
)

func TestBindCommand(t *testing.T) {
	app := cf.Application{Name: "my-app", Guid: "my-app-guid"}
	serviceInstance := cf.ServiceInstance{Name: "my-service", Guid: "my-service-guid"}
	reqFactory := &testhelpers.FakeReqFactory{
		Application:     app,
		ServiceInstance: serviceInstance,
	}
	serviceRepo := &testhelpers.FakeServiceRepo{}
	fakeUI := callBindService([]string{"my-app", "my-service"}, reqFactory, serviceRepo)

	assert.Equal(t, reqFactory.ApplicationName, "my-app")
	assert.Equal(t, reqFactory.ServiceInstanceName, "my-service")

	assert.Contains(t, fakeUI.Outputs[0], "Binding service")
	assert.Contains(t, fakeUI.Outputs[0], "my-service")
	assert.Contains(t, fakeUI.Outputs[0], "my-app")

	assert.Equal(t, serviceRepo.BindServiceServiceInstance, serviceInstance)
	assert.Equal(t, serviceRepo.BindServiceApplication, app)

	assert.Contains(t, fakeUI.Outputs[1], "OK")
}

func TestBindCommandIfServiceIsAlreadyBound(t *testing.T) {
	app := cf.Application{Name: "my-app", Guid: "my-app-guid"}
	serviceInstance := cf.ServiceInstance{Name: "my-service", Guid: "my-service-guid"}
	reqFactory := &testhelpers.FakeReqFactory{
		Application:     app,
		ServiceInstance: serviceInstance,
	}
	serviceRepo := &testhelpers.FakeServiceRepo{BindServiceErrorCode: "90003"}
	fakeUI := callBindService([]string{"my-app", "my-service"}, reqFactory, serviceRepo)

	assert.Contains(t, fakeUI.Outputs[0], "Binding service")
	assert.Contains(t, fakeUI.Outputs[1], "OK")
	assert.Contains(t, fakeUI.Outputs[2], "my-app")
	assert.Contains(t, fakeUI.Outputs[2], "is already bound")
	assert.Contains(t, fakeUI.Outputs[2], "my-service")
}

func TestBindCommandFailsWithUsage(t *testing.T) {
	reqFactory := &testhelpers.FakeReqFactory{}
	serviceRepo := &testhelpers.FakeServiceRepo{}

	fakeUI := callBindService([]string{"my-service"}, reqFactory, serviceRepo)
	assert.True(t, fakeUI.FailedWithUsage)

	fakeUI = callBindService([]string{"my-app"}, reqFactory, serviceRepo)
	assert.True(t, fakeUI.FailedWithUsage)

	fakeUI = callBindService([]string{"my-app", "my-service"}, reqFactory, serviceRepo)
	assert.False(t, fakeUI.FailedWithUsage)
}

func callBindService(args []string, reqFactory *testhelpers.FakeReqFactory, serviceRepo api.ServiceRepository) (fakeUI *testhelpers.FakeUI) {
	fakeUI = new(testhelpers.FakeUI)
	ctxt := testhelpers.NewContext("bind-service", args)
	cmd := NewBindService(fakeUI, serviceRepo)
	testhelpers.RunCommand(cmd, ctxt, reqFactory)
	return
}
<|endoftext|>