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

// This file defines an API entrypoint for the refactoring engine.  It provides
// functions that enumerate the available refactorings, and it provides a short
// name for each refactoring (which is used by tests, among other things).

// Contributors: Reed Allman, Josh Kane, Jeff Overbey

package doctor

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

var refactorings map[string]Refactoring

func init() {
	refactorings = map[string]Refactoring{
		"null":        new(NullRefactoring),
		"rename":      new(RenameRefactoring),
		"shortassign": new(ShortAssignRefactoring),
		"fiximports":  new(FixImportsTransformation),
	}
}

func GetAllRefactorings() map[string]Refactoring {
	return refactorings
}

func GetRefactoring(shortName string) Refactoring {
	return refactorings[shortName]
}

//TODO is this what util is for?
//e.g. 302,6
func parseLineCol(linecol string) (int, int) {
	lc := strings.Split(linecol, ",")
	if l, err := strconv.ParseInt(lc[0], 10, 32); err == nil {
		if c, err := strconv.ParseInt(lc[1], 10, 32); err == nil {
			return int(l), int(c)
		}
	}

	return -1, -1
}

//pos=3,6:3,9
func parsePositionToTextSelection(pos string) (t TextSelection, err error) {
	args := strings.Split(pos, ":")

	if len(args) < 2 {
		err = fmt.Errorf("invalid -pos")
		return
	}

	sl, sc := parseLineCol(args[0])
	el, ec := parseLineCol(args[1])

	if sl < 0 || sc < 0 || el < 0 || ec < 0 {
		err = fmt.Errorf("invalid -pos line, col")
		return
	}

	t = TextSelection{startLine: sl, startCol: sc,
		endLine: el, endCol: ec}

	return
}

//TODO (reed / josh) scope here?
//
//This will do all of the configuration and execution for
//a refactoring (@op), returning the edits to be made and log.
//For use with the CLI, but have at it.
//
func Query(file string, args []string, r Refactoring, pos string, scope string) (*Log, EditSet) {
	if r == nil {
		fmt.Errorf("Invalid refactoring")
		os.Exit(2)
	}

	ts, err := parsePositionToTextSelection(pos)
	if err != nil {
		fmt.Println(err)
		os.Exit(2)
	}
	ts.filename = file

	r.SetSelection(ts)
	r.Configure(args)
	r.Run()
	return r.GetResult()
}
<commit_msg>pos default to 0,0:0,0, tbd if desired<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file defines an API entrypoint for the refactoring engine.  It provides
// functions that enumerate the available refactorings, and it provides a short
// name for each refactoring (which is used by tests, among other things).

// Contributors: Reed Allman, Josh Kane, Jeff Overbey

package doctor

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

var refactorings map[string]Refactoring

func init() {
	refactorings = map[string]Refactoring{
		"null":        new(NullRefactoring),
		"rename":      new(RenameRefactoring),
		"shortassign": new(ShortAssignRefactoring),
		"fiximports":  new(FixImportsTransformation),
	}
}

func GetAllRefactorings() map[string]Refactoring {
	return refactorings
}

func GetRefactoring(shortName string) Refactoring {
	return refactorings[shortName]
}

//TODO is this what util is for?
//e.g. 302,6
func parseLineCol(linecol string) (int, int) {
	lc := strings.Split(linecol, ",")
	if l, err := strconv.ParseInt(lc[0], 10, 32); err == nil {
		if c, err := strconv.ParseInt(lc[1], 10, 32); err == nil {
			return int(l), int(c)
		}
	}

	return -1, -1
}

//pos=3,6:3,9
func parsePositionToTextSelection(pos string) (t TextSelection, err error) {
	args := strings.Split(pos, ":")

	if len(args) < 2 {
		err = fmt.Errorf("invalid -pos")
		return
	}

	sl, sc := parseLineCol(args[0])
	el, ec := parseLineCol(args[1])

	if sl < 0 || sc < 0 || el < 0 || ec < 0 {
		err = fmt.Errorf("invalid -pos line, col")
		return
	}

	t = TextSelection{startLine: sl, startCol: sc,
		endLine: el, endCol: ec}

	return
}

//TODO (reed / josh) scope here?
//
//This will do all of the configuration and execution for
//a refactoring (@op), returning the edits to be made and log.
//For use with the CLI, but have at it.
//
func Query(file string, args []string, r Refactoring, pos string, scope string) (*Log, EditSet) {
	if r == nil {
		fmt.Errorf("Invalid refactoring")
		os.Exit(2)
	}

	if pos == "" {
		pos = "0,0:0,0"
	}
	ts, err := parsePositionToTextSelection(pos)
	if err != nil {
		fmt.Println(err)
		os.Exit(2)
	}
	ts.filename = file

	r.SetSelection(ts)
	r.Configure(args)
	r.Run()
	return r.GetResult()
}
<|endoftext|>


<commit_before>package vizzini_test

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/routing-info/cfroutes"

	. "code.cloudfoundry.org/vizzini/matchers"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const HealthyCheckInterval = 30 * time.Second
const ConvergerInterval = 30 * time.Second
const CrashRestartTimeout = 30 * time.Second

const GraceTarballURL = "https://storage.googleapis.com/diego-assets-bucket/grace.tar.gz"
const GraceTarballURLSHAChecksum = "3d91a77e18b34a4844fb92695581c4d83bd87ce0"
const GraceBusyboxImageURL = "docker:///cfdiegodocker/grace"

//Tasks

func TaskGetter(logger lager.Logger, guid string) func() (*models.Task, error) {
	return func() (*models.Task, error) {
		return bbsClient.TaskByGuid(logger, guid)
	}
}

func TasksByDomainGetter(logger lager.Logger, domain string) func() ([]*models.Task, error) {
	return func() ([]*models.Task, error) {
		return bbsClient.TasksByDomain(logger, domain)
	}
}

func ClearOutTasksInDomain(domain string) {
	tasks, err := bbsClient.TasksByDomain(logger, domain)
	Expect(err).NotTo(HaveOccurred())
	for _, task := range tasks {
		if task.State != models.Task_Completed {
			bbsClient.CancelTask(logger, task.TaskGuid)
			Eventually(TaskGetter(logger, task.TaskGuid)).Should(HaveTaskState(models.Task_Completed))
		}
		Expect(bbsClient.ResolvingTask(logger, task.TaskGuid)).To(Succeed())
		Expect(bbsClient.DeleteTask(logger, task.TaskGuid)).To(Succeed())
	}
	Eventually(TasksByDomainGetter(logger, domain)).Should(BeEmpty())
}

func Task() *models.TaskDefinition {
	return &models.TaskDefinition{
		Action: models.WrapAction(&models.RunAction{
			Path: "bash",
			Args: []string{"-c", "echo 'some output' > /tmp/bar"},
			User: "vcap",
		}),
		RootFs:        defaultRootFS,
		MemoryMb:      128,
		DiskMb:        128,
		CpuWeight:     100,
		LogGuid:       guid,
		LogSource:     "VIZ",
		ResultFile:    "/tmp/bar",
		Annotation:    "arbitrary-data",
		PlacementTags: PlacementTags(),
	}
}

//LRPs

func LRPGetter(logger lager.Logger, guid string) func() (*models.DesiredLRP, error) {
	return func() (*models.DesiredLRP, error) {
		return bbsClient.DesiredLRPByProcessGuid(logger, guid)
	}
}

func ActualLRPByProcessGuidAndIndex(logger lager.Logger, guid string, index int) (models.ActualLRP, error) {
	actualLRPGroup, err := bbsClient.ActualLRPGroupByProcessGuidAndIndex(logger, guid, index)
	if err != nil {
		return models.ActualLRP{}, err
	}
	actualLRP, _ := actualLRPGroup.Resolve()
	return *actualLRP, nil
}

func ActualsByProcessGuid(logger lager.Logger, guid string) ([]models.ActualLRP, error) {
	actualLRPGroups, err := bbsClient.ActualLRPGroupsByProcessGuid(logger, guid)
	if err != nil {
		return nil, err
	}

	return resolveActuals(actualLRPGroups), nil
}

func ActualsByDomain(logger lager.Logger, domain string) ([]models.ActualLRP, error) {
	actualLRPGroups, err := bbsClient.ActualLRPGroups(logger, models.ActualLRPFilter{Domain: domain})
	if err != nil {
		return nil, err
	}

	return resolveActuals(actualLRPGroups), nil
}

func resolveActuals(actualLRPGroups []*models.ActualLRPGroup) []models.ActualLRP {
	actualLRPs := make([]models.ActualLRP, 0, len(actualLRPGroups))
	for _, actualLRPGroup := range actualLRPGroups {
		actualLRP, _ := actualLRPGroup.Resolve()
		actualLRPs = append(actualLRPs, *actualLRP)
	}

	return actualLRPs
}

func ActualGetter(logger lager.Logger, guid string, index int) func() (models.ActualLRP, error) {
	return func() (models.ActualLRP, error) {
		return ActualLRPByProcessGuidAndIndex(logger, guid, index)
	}
}

func ActualByProcessGuidGetter(logger lager.Logger, guid string) func() ([]models.ActualLRP, error) {
	return func() ([]models.ActualLRP, error) {
		return ActualsByProcessGuid(logger, guid)
	}
}

func ActualByDomainGetter(logger lager.Logger, domain string) func() ([]models.ActualLRP, error) {
	return func() ([]models.ActualLRP, error) {
		return ActualsByDomain(logger, domain)
	}
}

func ClearOutDesiredLRPsInDomain(domain string) {
	lrps, err := bbsClient.DesiredLRPs(logger, models.DesiredLRPFilter{Domain: domain})
	Expect(err).NotTo(HaveOccurred())
	for _, lrp := range lrps {
		Expect(bbsClient.RemoveDesiredLRP(logger, lrp.ProcessGuid)).To(Succeed())
	}
	// Wait enough time for the Grace app to exit if it was run with -catchTerminate
	Eventually(ActualByDomainGetter(logger, domain), timeout+time.Second).Should(BeEmpty())
}

func EndpointCurler(endpoint string) func() (int, error) {
	return func() (int, error) {
		resp, err := http.Get(endpoint)
		if err != nil {
			return 0, err
		}
		resp.Body.Close()
		return resp.StatusCode, nil
	}
}

func EndpointContentCurler(endpoint string) func() (string, error) {
	return func() (string, error) {
		resp, err := http.Get(endpoint)
		if err != nil {
			return "", err
		}
		defer resp.Body.Close()
		content, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return "", err
		}
		return string(content), nil
	}
}

func IndexCounter(guid string, optionalHttpClient ...*http.Client) func() (int, error) {
	return IndexCounterWithAttempts(guid, 100, optionalHttpClient...)
}

func IndexCounterWithAttempts(guid string, attempts int, optionalHttpClient ...*http.Client) func() (int, error) {
	return func() (int, error) {
		counts := map[int]bool{}
		for i := 0; i < attempts; i++ {
			index, err := GetIndexFromEndpointFor(guid, optionalHttpClient...)
			if err != nil {
				return 0, err
			}
			if index == -1 {
				continue
			}
			counts[index] = true
		}
		return len(counts), nil
	}
}

func GetIndexFromEndpointFor(guid string, optionalHttpClient ...*http.Client) (int, error) {
	httpClient := http.DefaultClient
	if len(optionalHttpClient) == 1 {
		httpClient = optionalHttpClient[0]
	}
	url := "http://" + RouteForGuid(guid) + "/index"
	resp, err := httpClient.Get(url)
	if err != nil {
		return 0, err
	}
	if resp.StatusCode != http.StatusOK {
		resp.Body.Close()
		return -1, nil
	}
	content, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return 0, err
	}

	return strconv.Atoi(string(content))
}

func GraceCounterGetter(guid string) func() (int, error) {
	return func() (int, error) {
		resp, err := http.Get("http://" + RouteForGuid(guid) + "/counter")
		if err != nil {
			return 0, err
		}
		defer resp.Body.Close()
		content, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return 0, err
		}
		return strconv.Atoi(string(content))
	}
}

func StartedAtGetter(guid string) func() (int64, error) {
	url := "http://" + RouteForGuid(guid) + "/started-at"
	return func() (int64, error) {
		resp, err := http.Get(url)
		if err != nil {
			return 0, err
		}
		if resp.StatusCode != http.StatusOK {
			resp.Body.Close()
			return 0, errors.New(fmt.Sprintf("invalid status code: %d", resp.StatusCode))
		}
		content, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			return 0, err
		}
		return strconv.ParseInt(string(content), 10, 64)
	}
}

func RouteForGuid(guid string) string {
	return fmt.Sprintf("%s.%s", guid, routableDomainSuffix)
}

func DirectAddressFor(guid string, index int, containerPort uint32) string {
	actualLRP, err := ActualGetter(logger, guid, index)()
	Expect(err).NotTo(HaveOccurred())
	Expect(actualLRP).NotTo(BeZero())

	for _, portMapping := range actualLRP.Ports {
		if portMapping.ContainerPort == containerPort {
			return fmt.Sprintf("%s:%d", actualLRP.Address, portMapping.HostPort)
		}
	}

	ginkgo.Fail(fmt.Sprintf("could not find port %d for ActualLRP %d with ProcessGuid %s", containerPort, index, guid))
	return ""
}

func TLSDirectAddressFor(guid string, index int, containerPort uint32) string {
	actualLRP, err := ActualGetter(logger, guid, index)()
	Expect(err).NotTo(HaveOccurred())
	Expect(actualLRP).NotTo(BeZero())

	for _, portMapping := range actualLRP.Ports {
		if portMapping.ContainerPort == containerPort {
			return fmt.Sprintf("%s:%d", actualLRP.Address, portMapping.HostTlsProxyPort)
		}
	}

	ginkgo.Fail(fmt.Sprintf("could not find port %d for ActualLRP %d with ProcessGuid %s", containerPort, index, guid))
	return ""
}

func DesiredLRPWithGuid(guid string) *models.DesiredLRP {
	routingInfo := cfroutes.CFRoutes{
		{Port: 8080, Hostnames: []string{RouteForGuid(guid)}},
	}.RoutingInfo()

	return &models.DesiredLRP{
		ProcessGuid:   guid,
		PlacementTags: PlacementTags(),
		Domain:        domain,
		Instances:     1,
		CachedDependencies: []*models.CachedDependency{
			&models.CachedDependency{
				From:              GraceTarballURL,
				To:                "/tmp/grace",
				CacheKey:          "grace",
				ChecksumAlgorithm: "sha1",
				ChecksumValue:     GraceTarballURLSHAChecksum,
			},
		},
		LegacyDownloadUser: "vcap",
		Action: models.WrapAction(&models.RunAction{
			Path: "/tmp/grace/grace",
			User: "vcap",
			Env:  []*models.EnvironmentVariable{{Name: "PORT", Value: "8080"}, {"ACTION_LEVEL", "COYOTE"}, {"OVERRIDE", "DAQUIRI"}},
		}),
		Monitor: models.WrapAction(&models.RunAction{
			Path: "nc",
			Args: []string{"-z", "0.0.0.0", "8080"},
			User: "vcap",
		}),
		RootFs:     defaultRootFS,
		MemoryMb:   128,
		DiskMb:     128,
		CpuWeight:  100,
		Ports:      []uint32{8080},
		Routes:     &routingInfo,
		LogGuid:    guid,
		LogSource:  "VIZ",
		Annotation: "arbitrary-data",
	}
}

func PlacementTags() []string {
	return repPlacementTags
}
<commit_msg>update grace checksum<commit_after>package vizzini_test

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/lager"
	"code.cloudfoundry.org/routing-info/cfroutes"

	. "code.cloudfoundry.org/vizzini/matchers"
	"github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const HealthyCheckInterval = 30 * time.Second
const ConvergerInterval = 30 * time.Second
const CrashRestartTimeout = 30 * time.Second

const GraceTarballURL = "https://storage.googleapis.com/diego-assets-bucket/grace.tar.gz"
const GraceTarballURLSHAChecksum = "a34f8e417a8593f3ebca18a70084daf7359b4965"
const GraceBusyboxImageURL = "docker:///cfdiegodocker/grace"

//Tasks

func TaskGetter(logger lager.Logger, guid string) func() (*models.Task, error) {
	return func() (*models.Task, error) {
		return bbsClient.TaskByGuid(logger, guid)
	}
}

func TasksByDomainGetter(logger lager.Logger, domain string) func() ([]*models.Task, error) {
	return func() ([]*models.Task, error) {
		return bbsClient.TasksByDomain(logger, domain)
	}
}

func ClearOutTasksInDomain(domain string) {
	tasks, err := bbsClient.TasksByDomain(logger, domain)
	Expect(err).NotTo(HaveOccurred())
	for _, task := range tasks {
		if task.State != models.Task_Completed {
			bbsClient.CancelTask(logger, task.TaskGuid)
			Eventually(TaskGetter(logger, task.TaskGuid)).Should(HaveTaskState(models.Task_Completed))
		}
		Expect(bbsClient.ResolvingTask(logger, task.TaskGuid)).To(Succeed())
		Expect(bbsClient.DeleteTask(logger, task.TaskGuid)).To(Succeed())
	}
	Eventually(TasksByDomainGetter(logger, domain)).Should(BeEmpty())
}

func Task() *models.TaskDefinition {
	return &models.TaskDefinition{
		Action: models.WrapAction(&models.RunAction{
			Path: "bash",
			Args: []string{"-c", "echo 'some output' > /tmp/bar"},
			User: "vcap",
		}),
		RootFs:        defaultRootFS,
		MemoryMb:      128,
		DiskMb:        128,
		CpuWeight:     100,
		LogGuid:       guid,
		LogSource:     "VIZ",
		ResultFile:    "/tmp/bar",
		Annotation:    "arbitrary-data",
		PlacementTags: PlacementTags(),
	}
}

//LRPs

func LRPGetter(logger lager.Logger, guid string) func() (*models.DesiredLRP, error) {
	return func() (*models.DesiredLRP, error) {
		return bbsClient.DesiredLRPByProcessGuid(logger, guid)
	}
}

func ActualLRPByProcessGuidAndIndex(logger lager.Logger, guid string, index int) (models.ActualLRP, error) {
	actualLRPGroup, err := bbsClient.ActualLRPGroupByProcessGuidAndIndex(logger, guid, index)
	if err != nil {
		return models.ActualLRP{}, err
	}
	actualLRP, _ := actualLRPGroup.Resolve()
	return *actualLRP, nil
}

func ActualsByProcessGuid(logger lager.Logger, guid string) ([]models.ActualLRP, error) {
	actualLRPGroups, err := bbsClient.ActualLRPGroupsByProcessGuid(logger, guid)
	if err != nil {
		return nil, err
	}

	return resolveActuals(actualLRPGroups), nil
}

func ActualsByDomain(logger lager.Logger, domain string) ([]models.ActualLRP, error) {
	actualLRPGroups, err := bbsClient.ActualLRPGroups(logger, models.ActualLRPFilter{Domain: domain})
	if err != nil {
		return nil, err
	}

	return resolveActuals(actualLRPGroups), nil
}

func resolveActuals(actualLRPGroups []*models.ActualLRPGroup) []models.ActualLRP {
	actualLRPs := make([]models.ActualLRP, 0, len(actualLRPGroups))
	for _, actualLRPGroup := range actualLRPGroups {
		actualLRP, _ := actualLRPGroup.Resolve()
		actualLRPs = append(actualLRPs, *actualLRP)
	}

	return actualLRPs
}

func ActualGetter(logger lager.Logger, guid string, index int) func() (models.ActualLRP, error) {
	return func() (models.ActualLRP, error) {
		return ActualLRPByProcessGuidAndIndex(logger, guid, index)
	}
}

func ActualByProcessGuidGetter(logger lager.Logger, guid string) func() ([]models.ActualLRP, error) {
	return func() ([]models.ActualLRP, error) {
		return ActualsByProcessGuid(logger, guid)
	}
}

func ActualByDomainGetter(logger lager.Logger, domain string) func() ([]models.ActualLRP, error) {
	return func() ([]models.ActualLRP, error) {
		return ActualsByDomain(logger, domain)
	}
}

func ClearOutDesiredLRPsInDomain(domain string) {
	lrps, err := bbsClient.DesiredLRPs(logger, models.DesiredLRPFilter{Domain: domain})
	Expect(err).NotTo(HaveOccurred())
	for _, lrp := range lrps {
		Expect(bbsClient.RemoveDesiredLRP(logger, lrp.ProcessGuid)).To(Succeed())
	}
	// Wait enough time for the Grace app to exit if it was run with -catchTerminate
	Eventually(ActualByDomainGetter(logger, domain), timeout+time.Second).Should(BeEmpty())
}

func EndpointCurler(endpoint string) func() (int, error) {
	return func() (int, error) {
		resp, err := http.Get(endpoint)
		if err != nil {
			return 0, err
		}
		resp.Body.Close()
		return resp.StatusCode, nil
	}
}

func EndpointContentCurler(endpoint string) func() (string, error) {
	return func() (string, error) {
		resp, err := http.Get(endpoint)
		if err != nil {
			return "", err
		}
		defer resp.Body.Close()
		content, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return "", err
		}
		return string(content), nil
	}
}

func IndexCounter(guid string, optionalHttpClient ...*http.Client) func() (int, error) {
	return IndexCounterWithAttempts(guid, 100, optionalHttpClient...)
}

func IndexCounterWithAttempts(guid string, attempts int, optionalHttpClient ...*http.Client) func() (int, error) {
	return func() (int, error) {
		counts := map[int]bool{}
		for i := 0; i < attempts; i++ {
			index, err := GetIndexFromEndpointFor(guid, optionalHttpClient...)
			if err != nil {
				return 0, err
			}
			if index == -1 {
				continue
			}
			counts[index] = true
		}
		return len(counts), nil
	}
}

func GetIndexFromEndpointFor(guid string, optionalHttpClient ...*http.Client) (int, error) {
	httpClient := http.DefaultClient
	if len(optionalHttpClient) == 1 {
		httpClient = optionalHttpClient[0]
	}
	url := "http://" + RouteForGuid(guid) + "/index"
	resp, err := httpClient.Get(url)
	if err != nil {
		return 0, err
	}
	if resp.StatusCode != http.StatusOK {
		resp.Body.Close()
		return -1, nil
	}
	content, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return 0, err
	}

	return strconv.Atoi(string(content))
}

func GraceCounterGetter(guid string) func() (int, error) {
	return func() (int, error) {
		resp, err := http.Get("http://" + RouteForGuid(guid) + "/counter")
		if err != nil {
			return 0, err
		}
		defer resp.Body.Close()
		content, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return 0, err
		}
		return strconv.Atoi(string(content))
	}
}

func StartedAtGetter(guid string) func() (int64, error) {
	url := "http://" + RouteForGuid(guid) + "/started-at"
	return func() (int64, error) {
		resp, err := http.Get(url)
		if err != nil {
			return 0, err
		}
		if resp.StatusCode != http.StatusOK {
			resp.Body.Close()
			return 0, errors.New(fmt.Sprintf("invalid status code: %d", resp.StatusCode))
		}
		content, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			return 0, err
		}
		return strconv.ParseInt(string(content), 10, 64)
	}
}

func RouteForGuid(guid string) string {
	return fmt.Sprintf("%s.%s", guid, routableDomainSuffix)
}

func DirectAddressFor(guid string, index int, containerPort uint32) string {
	actualLRP, err := ActualGetter(logger, guid, index)()
	Expect(err).NotTo(HaveOccurred())
	Expect(actualLRP).NotTo(BeZero())

	for _, portMapping := range actualLRP.Ports {
		if portMapping.ContainerPort == containerPort {
			return fmt.Sprintf("%s:%d", actualLRP.Address, portMapping.HostPort)
		}
	}

	ginkgo.Fail(fmt.Sprintf("could not find port %d for ActualLRP %d with ProcessGuid %s", containerPort, index, guid))
	return ""
}

func TLSDirectAddressFor(guid string, index int, containerPort uint32) string {
	actualLRP, err := ActualGetter(logger, guid, index)()
	Expect(err).NotTo(HaveOccurred())
	Expect(actualLRP).NotTo(BeZero())

	for _, portMapping := range actualLRP.Ports {
		if portMapping.ContainerPort == containerPort {
			return fmt.Sprintf("%s:%d", actualLRP.Address, portMapping.HostTlsProxyPort)
		}
	}

	ginkgo.Fail(fmt.Sprintf("could not find port %d for ActualLRP %d with ProcessGuid %s", containerPort, index, guid))
	return ""
}

func DesiredLRPWithGuid(guid string) *models.DesiredLRP {
	routingInfo := cfroutes.CFRoutes{
		{Port: 8080, Hostnames: []string{RouteForGuid(guid)}},
	}.RoutingInfo()

	return &models.DesiredLRP{
		ProcessGuid:   guid,
		PlacementTags: PlacementTags(),
		Domain:        domain,
		Instances:     1,
		CachedDependencies: []*models.CachedDependency{
			&models.CachedDependency{
				From:              GraceTarballURL,
				To:                "/tmp/grace",
				CacheKey:          "grace",
				ChecksumAlgorithm: "sha1",
				ChecksumValue:     GraceTarballURLSHAChecksum,
			},
		},
		LegacyDownloadUser: "vcap",
		Action: models.WrapAction(&models.RunAction{
			Path: "/tmp/grace/grace",
			User: "vcap",
			Env:  []*models.EnvironmentVariable{{Name: "PORT", Value: "8080"}, {"ACTION_LEVEL", "COYOTE"}, {"OVERRIDE", "DAQUIRI"}},
		}),
		Monitor: models.WrapAction(&models.RunAction{
			Path: "nc",
			Args: []string{"-z", "0.0.0.0", "8080"},
			User: "vcap",
		}),
		RootFs:     defaultRootFS,
		MemoryMb:   128,
		DiskMb:     128,
		CpuWeight:  100,
		Ports:      []uint32{8080},
		Routes:     &routingInfo,
		LogGuid:    guid,
		LogSource:  "VIZ",
		Annotation: "arbitrary-data",
	}
}

func PlacementTags() []string {
	return repPlacementTags
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"sync"
	"syscall"
	"testing"
	"time"

	"github.com/peferron/alternate/testbin"
)

const (
	zero  time.Duration = 0
	one                 = 50 * time.Millisecond
	two                 = 2 * one
	three               = 3 * one
)

func init() {
	fmt.Println("Initializing testKill channel")
	testKill = make(chan struct{})
}

func newNilWriter() *nilWriter {
	return &nilWriter{}
}

type nilWriter struct{}

func (w *nilWriter) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func newLineWriter(log bool) *lineWriter {
	return &lineWriter{
		"",
		[]string{},
		&sync.Mutex{},
		log,
	}
}

type lineWriter struct {
	buf   string
	lines []string
	mutex *sync.Mutex
	log   bool
}

func (w *lineWriter) Write(p []byte) (n int, err error) {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	n = len(p)

	w.buf += string(p)
	a := strings.Split(w.buf, "\n")
	for _, s := range a {
		if s == "" {
			continue
		}
		w.lines = append(w.lines, s)
		if w.log {
			fmt.Printf("LineWriter received: %q\n", s)
		}
	}
	w.buf = a[len(a)-1]

	return
}

func (w *lineWriter) reset() {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	w.buf = ""
	w.lines = []string{}
}

func (w *lineWriter) getLines() []string {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	clone := make([]string, len(w.lines))
	for i, s := range w.lines {
		clone[i] = s
	}
	return clone
}

type test struct {
	t           *testing.T
	cmdStdout   *lineWriter
	cmdStderr   *lineWriter
	params      []string
	expectIndex int
}

func (test *test) reset() {
	test.cmdStdout.reset()
	test.cmdStderr.reset()
}

func (test *test) expect(d time.Duration, lines []string) {
	expectIndex := test.expectIndex
	test.expectIndex++

	time.Sleep(d)

	stdoutLines := test.cmdStdout.getLines()
	if !sameStrings(lines, stdoutLines) {
		fmt.Printf("For parameters %q expect #%d, within %v expected lines %q in stdout, was %q\n",
			test.params, expectIndex, d, lines, stdoutLines)
		test.t.Errorf("For parameters %q expect #%d, within %v expected lines %q in stdout, was %q",
			test.params, expectIndex, d, lines, stdoutLines)
	}
	stderrLines := test.cmdStderr.getLines()
	if !sameStrings(lines, stderrLines) {
		fmt.Printf("For parameters %q expect #%d, within %v expected lines %q in stderr, was %q\n",
			test.params, expectIndex, d, lines, stderrLines)
		test.t.Errorf("For parameters %q expect #%d, within %v expected lines %q in stderr, was %q",
			test.params, expectIndex, d, lines, stderrLines)
	}
}

// sameStrings makes an unordered comparison of two slices of strings, and returns true if they
// contain the same strings, or false otherwise.
func sameStrings(a []string, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	if len(a) == 0 {
		return true
	}
	aa := clone(a)
	bb := clone(b)
	sort.Strings(aa)
	sort.Strings(bb)
	for i := range aa {
		if aa[i] != bb[i] {
			return false
		}
	}
	return true
}

// clone returns a deep copy of a slice of strings.
func clone(a []string) []string {
	b := make([]string, len(a))
	for i := range a {
		b[i] = a[i]
	}
	return b
}

func start(t *testing.T, params []string, overlap time.Duration) *test {
	test := &test{
		t,
		newLineWriter(false),
		newLineWriter(false),
		params,
		0,
	}
	c := testbin.Build() + " " + placeholder
	go alternate(c, placeholder, params, overlap, newNilWriter(), test.cmdStdout, test.cmdStderr)
	return test
}

func sendUsr1() {
	process().Signal(syscall.SIGUSR1)
}

func stop() {
	testKill <- struct{}{}
	time.Sleep(one)
}

func process() *os.Process {
	p, err := os.FindProcess(os.Getpid())
	if err != nil {
		panic(err)
	}
	return p
}

func TestSameStrings(t *testing.T) {
	tests := []struct {
		a    []string
		b    []string
		same bool
	}{
		{[]string{"a", "b"}, []string{"a", "b"}, true},
		{[]string{"b", "a"}, []string{"a", "b"}, true},
		{[]string{"a", "b", "c"}, []string{"a", "b"}, false},
	}

	for _, test := range tests {
		same := sameStrings(test.a, test.b)
		if test.same != same {
			t.Errorf("For values %q and %q, expected same to be %t, was %t",
				test.a, test.b, test.same, same)
		}
	}
}

func TestLineWriter(t *testing.T) {
	type action struct {
		reset bool
		write string
	}
	tests := []struct {
		actions []action
		lines   []string
	}{
		{
			[]action{
				{false, "abc\nde\n\nf"},
			},
			[]string{"abc", "de", "f"},
		},
	}

	for i, test := range tests {
		writer := newLineWriter(false)
		for _, a := range test.actions {
			if a.reset {
				writer.reset()
			}
			if a.write != "" {
				writer.Write([]byte(a.write))
			}
		}

		lines := writer.getLines()

		same := true
		if len(test.lines) != len(lines) {
			same = false
		} else {
			for j := range test.lines {
				if test.lines[j] != lines[j] {
					same = false
					break
				}
			}
		}

		if !same {
			t.Errorf("For test #%d, expected lines to be %q, but was %q", i, test.lines, lines)
		}
	}
}

func TestNoOverlapNoConflict(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := zero

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, zero, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
			"param0 " + a + " | exit",
		})

		c := testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param0 " + c + " | start",
			"param1 " + b + " | exit",
		})

		stop()
	}
}

func TestOverlapNoConflict(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := two

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, zero, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
		})
		test.reset()
		test.expect(two, []string{
			"param0 " + a + " | exit",
		})

		c := testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param0 " + c + " | start",
		})
		test.reset()
		test.expect(two, []string{
			"param1 " + b + " | exit",
		})

		stop()
	}
}

func TestNoOverlapConflict(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := zero

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, -one, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
		})

		testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(one, []string{})

		stop()
	}
}

func TestOverlapConflict(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := two

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, -one, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
		})
		test.reset()
		test.expect(two, []string{})

		testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(three, []string{})

		stop()
	}
}

func TestPrematureCmdExit(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := two

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, zero, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(zero, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
			"param1 " + b + " | exit",
		})
		test.reset()
		test.expect(two, []string{})

		c := testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + c + " | start",
		})
		test.reset()
		test.expect(two, []string{
			"param0 " + a + " | exit",
		})

		stop()
	}
}

func TestCmdRunError(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := zero

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, zero, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		testbin.Clean()
		sendUsr1()
		test.expect(one, []string{})

		test.reset()
		sendUsr1()
		test.expect(one, []string{})

		testbin.Build()
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
			"param0 " + a + " | exit",
		})

		stop()
	}
}

func TestAlternateExit(t *testing.T) {
	c := testbin.Build() + " " + placeholder
	v := []string{"param0"}
	o := zero

	testbin.SetBehavior(two, zero, "a")

	exited := false
	go func() {
		alternate(c, placeholder, v, o, newNilWriter(), newNilWriter(), newNilWriter())
		exited = true
	}()

	time.Sleep(one)
	if exited {
		t.Error("Was expecting exited to be false, was true")
	}

	time.Sleep(two)
	if !exited {
		t.Error("Was expecting exited to be true, was false")
	}
}
<commit_msg>Add test for SIGTERM forwarding<commit_after>package main

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"sync"
	"syscall"
	"testing"
	"time"

	"github.com/peferron/alternate/testbin"
)

const (
	zero  time.Duration = 0
	one                 = 50 * time.Millisecond
	two                 = 2 * one
	three               = 3 * one
)

func init() {
	fmt.Println("Initializing testKill channel")
	testKill = make(chan struct{})
}

func newNilWriter() *nilWriter {
	return &nilWriter{}
}

type nilWriter struct{}

func (w *nilWriter) Write(p []byte) (n int, err error) {
	return len(p), nil
}

func newLineWriter(log bool) *lineWriter {
	return &lineWriter{
		"",
		[]string{},
		&sync.Mutex{},
		log,
	}
}

type lineWriter struct {
	buf   string
	lines []string
	mutex *sync.Mutex
	log   bool
}

func (w *lineWriter) Write(p []byte) (n int, err error) {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	n = len(p)

	w.buf += string(p)
	a := strings.Split(w.buf, "\n")
	for _, s := range a {
		if s == "" {
			continue
		}
		w.lines = append(w.lines, s)
		if w.log {
			fmt.Printf("LineWriter received: %q\n", s)
		}
	}
	w.buf = a[len(a)-1]

	return
}

func (w *lineWriter) reset() {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	w.buf = ""
	w.lines = []string{}
}

func (w *lineWriter) getLines() []string {
	w.mutex.Lock()
	defer w.mutex.Unlock()

	clone := make([]string, len(w.lines))
	for i, s := range w.lines {
		clone[i] = s
	}
	return clone
}

type test struct {
	t           *testing.T
	cmdStdout   *lineWriter
	cmdStderr   *lineWriter
	params      []string
	exited      bool
	expectIndex int
}

func (test *test) reset() {
	test.cmdStdout.reset()
	test.cmdStderr.reset()
}

func (test *test) expect(d time.Duration, lines []string) {
	expectIndex := test.expectIndex
	test.expectIndex++

	time.Sleep(d)

	stdoutLines := test.cmdStdout.getLines()
	if !sameStrings(lines, stdoutLines) {
		fmt.Printf("For parameters %q expect #%d, within %v expected lines %q in stdout, was %q\n",
			test.params, expectIndex, d, lines, stdoutLines)
		test.t.Errorf("For parameters %q expect #%d, within %v expected lines %q in stdout, was %q",
			test.params, expectIndex, d, lines, stdoutLines)
	}
	stderrLines := test.cmdStderr.getLines()
	if !sameStrings(lines, stderrLines) {
		fmt.Printf("For parameters %q expect #%d, within %v expected lines %q in stderr, was %q\n",
			test.params, expectIndex, d, lines, stderrLines)
		test.t.Errorf("For parameters %q expect #%d, within %v expected lines %q in stderr, was %q",
			test.params, expectIndex, d, lines, stderrLines)
	}
}

// sameStrings makes an unordered comparison of two slices of strings, and returns true if they
// contain the same strings, or false otherwise.
func sameStrings(a []string, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	if len(a) == 0 {
		return true
	}
	aa := clone(a)
	bb := clone(b)
	sort.Strings(aa)
	sort.Strings(bb)
	for i := range aa {
		if aa[i] != bb[i] {
			return false
		}
	}
	return true
}

// clone returns a deep copy of a slice of strings.
func clone(a []string) []string {
	b := make([]string, len(a))
	for i := range a {
		b[i] = a[i]
	}
	return b
}

func start(t *testing.T, params []string, overlap time.Duration) *test {
	test := &test{
		t,
		newLineWriter(false),
		newLineWriter(false),
		params,
		false,
		0,
	}
	c := testbin.Build() + " " + placeholder
	go func() {
		alternate(c, placeholder, params, overlap, newNilWriter(), test.cmdStdout, test.cmdStderr)
		test.exited = true
	}()
	return test
}

func sendUsr1() {
	process().Signal(syscall.SIGUSR1)
}

func sendTerm() {
	process().Signal(syscall.SIGTERM)
}

func kill() {
	testKill <- struct{}{}
	time.Sleep(one)
}

func process() *os.Process {
	p, err := os.FindProcess(os.Getpid())
	if err != nil {
		panic(err)
	}
	return p
}

func TestSameStrings(t *testing.T) {
	tests := []struct {
		a    []string
		b    []string
		same bool
	}{
		{[]string{"a", "b"}, []string{"a", "b"}, true},
		{[]string{"b", "a"}, []string{"a", "b"}, true},
		{[]string{"a", "b", "c"}, []string{"a", "b"}, false},
	}

	for _, test := range tests {
		same := sameStrings(test.a, test.b)
		if test.same != same {
			t.Errorf("For values %q and %q, expected same to be %t, was %t",
				test.a, test.b, test.same, same)
		}
	}
}

func TestLineWriter(t *testing.T) {
	type action struct {
		reset bool
		write string
	}
	tests := []struct {
		actions []action
		lines   []string
	}{
		{
			[]action{
				{false, "abc\nde\n\nf"},
			},
			[]string{"abc", "de", "f"},
		},
	}

	for i, test := range tests {
		writer := newLineWriter(false)
		for _, a := range test.actions {
			if a.reset {
				writer.reset()
			}
			if a.write != "" {
				writer.Write([]byte(a.write))
			}
		}

		lines := writer.getLines()

		same := true
		if len(test.lines) != len(lines) {
			same = false
		} else {
			for j := range test.lines {
				if test.lines[j] != lines[j] {
					same = false
					break
				}
			}
		}

		if !same {
			t.Errorf("For test #%d, expected lines to be %q, but was %q", i, test.lines, lines)
		}
	}
}

func TestNoOverlapNoConflict(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := zero

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, zero, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
			"param0 " + a + " | exit",
		})

		c := testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param0 " + c + " | start",
			"param1 " + b + " | exit",
		})

		kill()
	}
}

func TestOverlapNoConflict(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := two

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, zero, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
		})
		test.reset()
		test.expect(two, []string{
			"param0 " + a + " | exit",
		})

		c := testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param0 " + c + " | start",
		})
		test.reset()
		test.expect(two, []string{
			"param1 " + b + " | exit",
		})

		kill()
	}
}

func TestNoOverlapConflict(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := zero

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, -one, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
		})

		testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(one, []string{})

		kill()
	}
}

func TestOverlapConflict(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := two

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, -one, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
		})
		test.reset()
		test.expect(two, []string{})

		testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(three, []string{})

		kill()
	}
}

func TestPrematureCmdExit(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := two

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, zero, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(zero, zero, "b")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
			"param1 " + b + " | exit",
		})
		test.reset()
		test.expect(two, []string{})

		c := testbin.SetBehavior(-one, zero, "c")
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + c + " | start",
		})
		test.reset()
		test.expect(two, []string{
			"param0 " + a + " | exit",
		})

		kill()
	}
}

func TestCmdRunError(t *testing.T) {
	paramSets := [][]string{
		{"param0", "param1"},
		{"param0", "param1", "param0"},
	}
	o := zero

	for _, v := range paramSets {
		a := testbin.SetBehavior(-one, zero, "a")
		test := start(t, v, o)
		test.expect(one, []string{
			"param0 " + a + " | start",
		})

		b := testbin.SetBehavior(-one, zero, "b")
		test.reset()
		testbin.Clean()
		sendUsr1()
		test.expect(one, []string{})

		test.reset()
		sendUsr1()
		test.expect(one, []string{})

		testbin.Build()
		test.reset()
		sendUsr1()
		test.expect(one, []string{
			"param1 " + b + " | start",
			"param0 " + a + " | exit",
		})

		kill()
	}
}

func TestAllCmdsExit(t *testing.T) {
	v := []string{"param0"}
	o := zero

	a := testbin.SetBehavior(two, zero, "a")
	test := start(t, v, o)
	test.expect(one, []string{
		"param0 " + a + " | start",
	})
	if test.exited {
		t.Error("Was expecting exited to be false, was true")
	}

	test.reset()
	test.expect(two, []string{
		"param0 " + a + " | exit",
	})
	if !test.exited {
		t.Error("Was expecting exited to be true, was false")
	}
}

func TestTermForwarding(t *testing.T) {
	v := []string{"param0"}
	o := zero

	a := testbin.SetBehavior(-one, two, "a")
	test := start(t, v, o)
	test.expect(one, []string{
		"param0 " + a + " | start",
	})
	if test.exited {
		t.Error("Was expecting exited to be false, was true")
	}

	test.reset()
	sendTerm()
	test.expect(one, []string{})
	if test.exited {
		t.Error("Was expecting exited to be false, was true")
	}

	test.reset()
	test.expect(two, []string{
		"param0 " + a + " | exit",
	})
	if !test.exited {
		t.Error("Was expecting exited to be true, was false")
	}
}
<|endoftext|>


<commit_before><commit_msg>test(internal/errs): 修正测试用例行号错误<commit_after><|endoftext|>


<commit_before>// Package pinata is a utility to beat data out of interface{}, []interface{}
// and map[string]interface{}. It was origally designed for use with the
// encoding/json package but can be generally useful.
//
// Unlike other packages most methods do not return an error type. They become
// a no-op when the first error is found so the error can be checked after a
// series of operations instead of at each operation seperately. Because of
// this "late" error handling design special care is taken to return good
// errors so you can still find out where things went wrong.
//
// This API is not thread safe.
package pinata

import (
	"bytes"
	"fmt"
	"strings"
)

// Stick offers methods of hitting the Pinata and extracting its goodness.
type Stick interface {
	// Error returns the first error encountered or nil if all operations so far
	// were successful.
	Error() error

	// ClearError clears the error. If there is no error the method has no effect.
	ClearError()

	// PathString gets the string value at the given path within the Pinata. The
	// last element in the path must be a string, the rest must be a
	// map[string]interface{}. The input Pinata must hold a
	// map[string]interface{} as well.
	PathString(Pinata, ...string) string

	// String returns the Pinata as a string if it is one.
	String(Pinata) string

	// IndexString gets the string value at the given index within the Pinata.
	// The input Pinata must hold a []interface{}.
	IndexString(Pinata, int) string

	// PathPinata gets the Pinata value at the given path within the Pinata. All
	// elements in the path must be of type map[string]interface{}. The input
	// Pinata must hold a map[string]interface{} as well.
	PathPinata(Pinata, ...string) Pinata

	// IndexString gets the Pinata value at the given index within the Pinata.
	// The input Pinata must hold a []interface{}.
	IndexPinata(Pinata, int) Pinata
}

// ErrorContext contains information about the circumstances of an error.
type ErrorContext struct {
	method      string
	methodInput []interface{}
	next        *ErrorContext
}

// MethodName returns the name of the method that caused the error.
func (ec ErrorContext) MethodName() string {
	return ec.method
}

// MethodArgs returns the input parameters of the method that caused the error.
func (ec ErrorContext) MethodArgs() []interface{} {
	return ec.methodInput
}

// Next gets additional context linked to this one.
func (ec ErrorContext) Next() ErrorContext {
	if ec.next != nil {
		return *ec.next
	}
	return ErrorContext{}
}

// Pinata holds the data.
type Pinata struct {
	context  *ErrorContext
	contents contents
}

// Value returns the raw Pinata value.
func (p Pinata) Value() interface{} {
	return p.contents.Value()
}

// Map returns the Pinata value as a map if it is one (the bool indicates
// success).
func (p Pinata) Map() (map[string]interface{}, bool) {
	return p.contents.Map()
}

// Slice returns the Pinata value as a slice if it is one (the bool indicates
// success).
func (p Pinata) Slice() ([]interface{}, bool) {
	return p.contents.Slice()
}

type contents interface {
	Value() interface{}
	Map() (map[string]interface{}, bool)
	Slice() ([]interface{}, bool)
}

type otherPinata struct {
	value interface{}
}

func (p otherPinata) Value() interface{} {
	return p.value
}

func (p otherPinata) Map() (map[string]interface{}, bool) {
	return nil, false
}

func (p otherPinata) Slice() ([]interface{}, bool) {
	return nil, false
}

var _ = contents(mapPinata{})

type mapPinata struct {
	otherPinata
	value map[string]interface{}
}

func (p mapPinata) Map() (map[string]interface{}, bool) {
	return p.value, true
}

type slicePinata struct {
	otherPinata
	value []interface{}
}

func (p slicePinata) Slice() ([]interface{}, bool) {
	return p.value, true
}

// New is a starting point for a pinata celebration.
func New(contents interface{}) (Stick, Pinata) {
	return NewStick(), NewPinata(contents)
}

// NewStick returns a new Stick to hit a Pinata with.
func NewStick() Stick {
	return &stick{}
}

// NewPinata creates a new Pinata holding the specified value.
func NewPinata(contents interface{}) Pinata {
	return newPinataWithContext(contents, nil)
}

func newPinataWithContext(contents interface{}, context *ErrorContext) Pinata {
	switch t := contents.(type) {
	case map[string]interface{}:
		return Pinata{contents: &mapPinata{value: t}, context: context}
	case []interface{}:
		return Pinata{contents: &slicePinata{value: t}, context: context}
	default:
		return Pinata{contents: &otherPinata{value: t}, context: context}
	}
}

var _ = error(Error{})

// ErrorReason describes the reason for returning an Error.
type ErrorReason string

const (
	// ErrorReasonIncompatibleType indicates the contents of the Pinata is not compatible with the invoked method.
	ErrorReasonIncompatibleType ErrorReason = "incompatible type"
	// ErrorReasonNotFound indicates the input has not been found in the Pinata.
	ErrorReasonNotFound = "not found"
	// ErrorReasonInvalidInput indicates the input is not in the expected range or format.
	ErrorReasonInvalidInput = "invalid input"
)

// Error is set on the Pinata if something goes wrong.
type Error struct {
	reason  ErrorReason
	context *ErrorContext
	advice  string
}

// Reason indicates why the error occurred.
func (p Error) Reason() ErrorReason {
	return p.reason
}

// Context returns more information about the circumstances of the error.
func (p Error) Context() ErrorContext {
	if p.context != nil {
		return *p.context
	}
	return ErrorContext{}
}

// Advice contains a human readable hint detailing how to remedy this error.
func (p Error) Advice() string {
	return p.advice
}

// Error returns a summary of the problem.
func (p Error) Error() string {
	var summaries []string
	current := p.context
	for current != nil {
		var methodInput = current.MethodArgs()
		var summary string
		if len(methodInput) > 0 {
			var buf bytes.Buffer
			_, _ = buf.WriteString(current.MethodName())
			_ = buf.WriteByte('(')
			for i := range methodInput {
				_, _ = buf.WriteString("%#v")
				if i < len(methodInput)-1 {
					_, _ = buf.WriteString(", ")
				}
			}
			_ = buf.WriteByte(')')
			summary = fmt.Sprintf(buf.String(), methodInput...)
			summaries = append(summaries, summary)
		}
		current = current.next
	}
	return fmt.Sprintf("pinata: %s (%s): \n\t%v", p.Reason(), p.Advice(), strings.Join(summaries, " :: "))
}

type stick struct {
	err error
}

func (s *stick) ClearError() {
	s.err = nil
}

func (s *stick) Error() error {
	return s.err
}

// this method assumes s.err != nil
func (s *stick) stringUnsupported(errCtx *ErrorContext, method string, input []interface{}, advice string) string {
	s.err = &Error{
		context: &ErrorContext{
			method:      method,
			methodInput: input,
			next:        errCtx,
		},
		reason: ErrorReasonIncompatibleType,
		advice: advice,
	}
	return ""
}

// this method assumes s.err != nil
func (s *stick) indexUnsupported(errCtx *ErrorContext, method string, index int) {
	s.err = &Error{
		context: &ErrorContext{
			method:      method,
			methodInput: []interface{}{index},
			next:        errCtx,
		},
		reason: ErrorReasonIncompatibleType,
		advice: "call this method on a slice pinata",
	}
}

// this method assumes s.err != nil
func (s *stick) pathUnsupported(errCtx *ErrorContext, method string, path []string) {
	s.err = &Error{
		context: &ErrorContext{
			method:      method,
			methodInput: toInterfaceSlice(path),
			next:        errCtx,
		},
		reason: ErrorReasonIncompatibleType,
		advice: "call this method on a map pinata",
	}
}

// this method assumes s.err != nil
func (s *stick) internalString(p Pinata, method string, input []interface{}) string {
	if _, ok := p.Map(); ok {
		return s.stringUnsupported(p.context, method, input, "this is a map")
	}
	if _, ok := p.Slice(); ok {
		return s.stringUnsupported(p.context, method, input, "this is a slice")
	}
	if v, ok := p.Value().(string); ok {
		return v
	}
	return s.stringUnsupported(p.context, method, input, "this is not a string")
}

func (s *stick) String(p Pinata) string {
	if s.err != nil {
		return ""
	}
	return s.internalString(p, "String", nil)
}

// this method assumes s.err != nil
func (s *stick) internalIndexPinata(p Pinata, method string, index int) Pinata {
	if slice, ok := p.Slice(); ok {
		if index < 0 || index >= len(slice) {
			s.err = &Error{
				context: &ErrorContext{
					method:      method,
					methodInput: []interface{}{index},
					next:        p.context,
				},
				reason: ErrorReasonInvalidInput,
				advice: fmt.Sprintf("specify an index from 0 to %d", len(slice)-1),
			}
			return Pinata{}
		}
		return newPinataWithContext(slice[index], &ErrorContext{
			method:      method,
			methodInput: []interface{}{index},
			next:        p.context,
		})
	}
	s.indexUnsupported(p.context, method, index)
	return Pinata{}
}

func (s *stick) IndexPinata(p Pinata, index int) Pinata {
	if s.err != nil {
		return Pinata{}
	}
	return s.internalIndexPinata(p, "IndexPinata", index)
}

func (s *stick) IndexString(p Pinata, index int) string {
	if s.err != nil {
		return ""
	}
	const method = "IndexString"
	pinata := s.internalIndexPinata(p, method, index)
	if s.err != nil {
		return ""
	}
	pinata.context = p.context
	return s.internalString(pinata, method, []interface{}{index})
}

// this method assumes s.err != nil
func (s *stick) internalPathPinata(p Pinata, method string, path ...string) Pinata {
	contents, ok := p.Map()

	if !ok {
		s.pathUnsupported(p.context, method, path)
		return Pinata{}
	}

	if len(path) == 0 {
		s.err = &Error{
			context: &ErrorContext{
				method:      method,
				methodInput: toInterfaceSlice(path),
				next:        p.context,
			},
			reason: ErrorReasonInvalidInput,
			advice: "specify a path",
		}
		return Pinata{}
	}

	for i := 0; i < len(path)-1; i++ {
		current := path[i]
		if v, ok := contents[current]; ok {
			if v, ok := v.(map[string]interface{}); ok {
				contents = v
			} else {
				s.err = &Error{
					context: &ErrorContext{
						method:      method,
						methodInput: toInterfaceSlice(path),
						next:        p.context,
					},
					reason: ErrorReasonIncompatibleType,
					advice: fmt.Sprintf(`"%s" does not hold a pinata`, strings.Join(path[:i+1], `", "`)),
				}
				return Pinata{}
			}
		} else {
			s.err = &Error{
				context: &ErrorContext{
					method:      method,
					methodInput: toInterfaceSlice(path),
					next:        p.context,
				},
				reason: ErrorReasonNotFound,
				advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path[:i+1], `", "`)),
			}
			return Pinata{}
		}
	}

	if v, ok := contents[path[len(path)-1]]; ok {
		return newPinataWithContext(v, &ErrorContext{
			method:      method,
			methodInput: toInterfaceSlice(path),
			next:        p.context,
		})
	}

	s.err = &Error{
		context: &ErrorContext{
			method:      method,
			methodInput: toInterfaceSlice(path),
			next:        p.context,
		},
		reason: ErrorReasonNotFound,
		advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path, `", "`)),
	}
	return Pinata{}
}

func (s *stick) PathPinata(p Pinata, path ...string) Pinata {
	if s.err != nil {
		return Pinata{}
	}
	return s.internalPathPinata(p, "PathPinata", path...)
}

func (s *stick) PathString(p Pinata, path ...string) string {
	if s.err != nil {
		return ""
	}
	const method = "PathString"
	pinata := s.internalPathPinata(p, method, path...)
	if s.err != nil {
		return ""
	}
	pinata.context = p.context
	return s.internalString(pinata, method, toInterfaceSlice(path))
}

func toInterfaceSlice(c []string) []interface{} {
	ifaces := make([]interface{}, len(c))
	for i := range c {
		ifaces[i] = c[i]
	}
	return ifaces
}
<commit_msg>bring less optimism about errors<commit_after>// Package pinata is a utility to beat data out of interface{}, []interface{}
// and map[string]interface{}. It was origally designed for use with the
// encoding/json package but can be generally useful.
//
// Unlike other packages most methods do not return an error type. They become
// a no-op when the first error is found so the error can be checked after a
// series of operations instead of at each operation seperately. Because of
// this "late" error handling design special care is taken to return good
// errors so you can still find out where things went wrong.
//
// This API is not thread safe.
package pinata

import (
	"bytes"
	"fmt"
	"strings"
)

// Stick offers methods of hitting the Pinata and extracting its goodness.
type Stick interface {
	// Error returns the first error encountered or nil if all operations so far
	// were successful.
	Error() error

	// ClearError clears the error. If there is no error the method has no effect.
	ClearError()

	// PathString gets the string value at the given path within the Pinata. The
	// last element in the path must be a string, the rest must be a
	// map[string]interface{}. The input Pinata must hold a
	// map[string]interface{} as well.
	PathString(Pinata, ...string) string

	// String returns the Pinata as a string if it is one.
	String(Pinata) string

	// IndexString gets the string value at the given index within the Pinata.
	// The input Pinata must hold a []interface{}.
	IndexString(Pinata, int) string

	// PathPinata gets the Pinata value at the given path within the Pinata. All
	// elements in the path must be of type map[string]interface{}. The input
	// Pinata must hold a map[string]interface{} as well.
	PathPinata(Pinata, ...string) Pinata

	// IndexString gets the Pinata value at the given index within the Pinata.
	// The input Pinata must hold a []interface{}.
	IndexPinata(Pinata, int) Pinata
}

// ErrorContext contains information about the circumstances of an error.
type ErrorContext struct {
	method      string
	methodInput []interface{}
	next        *ErrorContext
}

// MethodName returns the name of the method that caused the error.
func (ec ErrorContext) MethodName() string {
	return ec.method
}

// MethodArgs returns the input parameters of the method that caused the error.
func (ec ErrorContext) MethodArgs() []interface{} {
	return ec.methodInput
}

// Next gets additional context linked to this one.
func (ec ErrorContext) Next() ErrorContext {
	if ec.next != nil {
		return *ec.next
	}
	return ErrorContext{}
}

// Pinata holds the data.
type Pinata struct {
	context  *ErrorContext
	contents contents
}

// Value returns the raw Pinata value.
func (p Pinata) Value() interface{} {
	return p.contents.Value()
}

// Map returns the Pinata value as a map if it is one (the bool indicates
// success).
func (p Pinata) Map() (map[string]interface{}, bool) {
	return p.contents.Map()
}

// Slice returns the Pinata value as a slice if it is one (the bool indicates
// success).
func (p Pinata) Slice() ([]interface{}, bool) {
	return p.contents.Slice()
}

type contents interface {
	Value() interface{}
	Map() (map[string]interface{}, bool)
	Slice() ([]interface{}, bool)
}

type otherPinata struct {
	value interface{}
}

func (p otherPinata) Value() interface{} {
	return p.value
}

func (p otherPinata) Map() (map[string]interface{}, bool) {
	return nil, false
}

func (p otherPinata) Slice() ([]interface{}, bool) {
	return nil, false
}

var _ = contents(mapPinata{})

type mapPinata struct {
	otherPinata
	value map[string]interface{}
}

func (p mapPinata) Map() (map[string]interface{}, bool) {
	return p.value, true
}

type slicePinata struct {
	otherPinata
	value []interface{}
}

func (p slicePinata) Slice() ([]interface{}, bool) {
	return p.value, true
}

// New is a starting point for a pinata celebration.
func New(contents interface{}) (Stick, Pinata) {
	return NewStick(), NewPinata(contents)
}

// NewStick returns a new Stick to hit a Pinata with.
func NewStick() Stick {
	return &stick{}
}

// NewPinata creates a new Pinata holding the specified value.
func NewPinata(contents interface{}) Pinata {
	return newPinataWithContext(contents, nil)
}

func newPinataWithContext(contents interface{}, context *ErrorContext) Pinata {
	switch t := contents.(type) {
	case map[string]interface{}:
		return Pinata{contents: &mapPinata{value: t}, context: context}
	case []interface{}:
		return Pinata{contents: &slicePinata{value: t}, context: context}
	default:
		return Pinata{contents: &otherPinata{value: t}, context: context}
	}
}

var _ = error(Error{})

// ErrorReason describes the reason for returning an Error.
type ErrorReason string

const (
	// ErrorReasonIncompatibleType indicates the contents of the Pinata is not compatible with the invoked method.
	ErrorReasonIncompatibleType ErrorReason = "incompatible type"
	// ErrorReasonNotFound indicates the input has not been found in the Pinata.
	ErrorReasonNotFound = "not found"
	// ErrorReasonInvalidInput indicates the input is not in the expected range or format.
	ErrorReasonInvalidInput = "invalid input"
)

// Error is set on the Pinata when something goes wrong.
type Error struct {
	reason  ErrorReason
	context *ErrorContext
	advice  string
}

// Reason indicates why the error occurred.
func (p Error) Reason() ErrorReason {
	return p.reason
}

// Context returns more information about the circumstances of the error.
func (p Error) Context() ErrorContext {
	if p.context != nil {
		return *p.context
	}
	return ErrorContext{}
}

// Advice contains a human readable hint detailing how to remedy this error.
func (p Error) Advice() string {
	return p.advice
}

// Error returns a summary of the problem.
func (p Error) Error() string {
	var summaries []string
	current := p.context
	for current != nil {
		var methodInput = current.MethodArgs()
		var summary string
		if len(methodInput) > 0 {
			var buf bytes.Buffer
			_, _ = buf.WriteString(current.MethodName())
			_ = buf.WriteByte('(')
			for i := range methodInput {
				_, _ = buf.WriteString("%#v")
				if i < len(methodInput)-1 {
					_, _ = buf.WriteString(", ")
				}
			}
			_ = buf.WriteByte(')')
			summary = fmt.Sprintf(buf.String(), methodInput...)
			summaries = append(summaries, summary)
		}
		current = current.next
	}
	return fmt.Sprintf("pinata: %s (%s): \n\t%v", p.Reason(), p.Advice(), strings.Join(summaries, " :: "))
}

type stick struct {
	err error
}

func (s *stick) ClearError() {
	s.err = nil
}

func (s *stick) Error() error {
	return s.err
}

// this method assumes s.err != nil
func (s *stick) stringUnsupported(errCtx *ErrorContext, method string, input []interface{}, advice string) string {
	s.err = &Error{
		context: &ErrorContext{
			method:      method,
			methodInput: input,
			next:        errCtx,
		},
		reason: ErrorReasonIncompatibleType,
		advice: advice,
	}
	return ""
}

// this method assumes s.err != nil
func (s *stick) indexUnsupported(errCtx *ErrorContext, method string, index int) {
	s.err = &Error{
		context: &ErrorContext{
			method:      method,
			methodInput: []interface{}{index},
			next:        errCtx,
		},
		reason: ErrorReasonIncompatibleType,
		advice: "call this method on a slice pinata",
	}
}

// this method assumes s.err != nil
func (s *stick) pathUnsupported(errCtx *ErrorContext, method string, path []string) {
	s.err = &Error{
		context: &ErrorContext{
			method:      method,
			methodInput: toInterfaceSlice(path),
			next:        errCtx,
		},
		reason: ErrorReasonIncompatibleType,
		advice: "call this method on a map pinata",
	}
}

// this method assumes s.err != nil
func (s *stick) internalString(p Pinata, method string, input []interface{}) string {
	if _, ok := p.Map(); ok {
		return s.stringUnsupported(p.context, method, input, "this is a map")
	}
	if _, ok := p.Slice(); ok {
		return s.stringUnsupported(p.context, method, input, "this is a slice")
	}
	if v, ok := p.Value().(string); ok {
		return v
	}
	return s.stringUnsupported(p.context, method, input, "this is not a string")
}

func (s *stick) String(p Pinata) string {
	if s.err != nil {
		return ""
	}
	return s.internalString(p, "String", nil)
}

// this method assumes s.err != nil
func (s *stick) internalIndexPinata(p Pinata, method string, index int) Pinata {
	if slice, ok := p.Slice(); ok {
		if index < 0 || index >= len(slice) {
			s.err = &Error{
				context: &ErrorContext{
					method:      method,
					methodInput: []interface{}{index},
					next:        p.context,
				},
				reason: ErrorReasonInvalidInput,
				advice: fmt.Sprintf("specify an index from 0 to %d", len(slice)-1),
			}
			return Pinata{}
		}
		return newPinataWithContext(slice[index], &ErrorContext{
			method:      method,
			methodInput: []interface{}{index},
			next:        p.context,
		})
	}
	s.indexUnsupported(p.context, method, index)
	return Pinata{}
}

func (s *stick) IndexPinata(p Pinata, index int) Pinata {
	if s.err != nil {
		return Pinata{}
	}
	return s.internalIndexPinata(p, "IndexPinata", index)
}

func (s *stick) IndexString(p Pinata, index int) string {
	if s.err != nil {
		return ""
	}
	const method = "IndexString"
	pinata := s.internalIndexPinata(p, method, index)
	if s.err != nil {
		return ""
	}
	pinata.context = p.context
	return s.internalString(pinata, method, []interface{}{index})
}

// this method assumes s.err != nil
func (s *stick) internalPathPinata(p Pinata, method string, path ...string) Pinata {
	contents, ok := p.Map()

	if !ok {
		s.pathUnsupported(p.context, method, path)
		return Pinata{}
	}

	if len(path) == 0 {
		s.err = &Error{
			context: &ErrorContext{
				method:      method,
				methodInput: toInterfaceSlice(path),
				next:        p.context,
			},
			reason: ErrorReasonInvalidInput,
			advice: "specify a path",
		}
		return Pinata{}
	}

	for i := 0; i < len(path)-1; i++ {
		current := path[i]
		if v, ok := contents[current]; ok {
			if v, ok := v.(map[string]interface{}); ok {
				contents = v
			} else {
				s.err = &Error{
					context: &ErrorContext{
						method:      method,
						methodInput: toInterfaceSlice(path),
						next:        p.context,
					},
					reason: ErrorReasonIncompatibleType,
					advice: fmt.Sprintf(`"%s" does not hold a pinata`, strings.Join(path[:i+1], `", "`)),
				}
				return Pinata{}
			}
		} else {
			s.err = &Error{
				context: &ErrorContext{
					method:      method,
					methodInput: toInterfaceSlice(path),
					next:        p.context,
				},
				reason: ErrorReasonNotFound,
				advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path[:i+1], `", "`)),
			}
			return Pinata{}
		}
	}

	if v, ok := contents[path[len(path)-1]]; ok {
		return newPinataWithContext(v, &ErrorContext{
			method:      method,
			methodInput: toInterfaceSlice(path),
			next:        p.context,
		})
	}

	s.err = &Error{
		context: &ErrorContext{
			method:      method,
			methodInput: toInterfaceSlice(path),
			next:        p.context,
		},
		reason: ErrorReasonNotFound,
		advice: fmt.Sprintf(`"%s" does not exist`, strings.Join(path, `", "`)),
	}
	return Pinata{}
}

func (s *stick) PathPinata(p Pinata, path ...string) Pinata {
	if s.err != nil {
		return Pinata{}
	}
	return s.internalPathPinata(p, "PathPinata", path...)
}

func (s *stick) PathString(p Pinata, path ...string) string {
	if s.err != nil {
		return ""
	}
	const method = "PathString"
	pinata := s.internalPathPinata(p, method, path...)
	if s.err != nil {
		return ""
	}
	pinata.context = p.context
	return s.internalString(pinata, method, toInterfaceSlice(path))
}

func toInterfaceSlice(c []string) []interface{} {
	ifaces := make([]interface{}, len(c))
	for i := range c {
		ifaces[i] = c[i]
	}
	return ifaces
}
<|endoftext|>


<commit_before>package main

import (
	"time"
)

type Pinger struct {
	interval time.Duration
	ticker   *time.Ticker
	cmd      chan string
	count    uint32
}

func NewPinger(interval time.Duration) *Pinger {
	return &Pinger{count: 0, interval: interval, cmd: make(chan string)}
}

func (p *Pinger) run() {
	p.ticker = time.NewTicker(p.interval)
	defer p.ticker.Stop()

	for {
		select {
		case <-p.ticker.C:
			if p.count > 0 {
				log.Debugf("Ping will be sent to %v", p.count)
				app.BroadcastAll((&Reply{Type: "ping", Message: time.Now().Unix()}).toJSON())
				log.Debugf("Ping was sent to %v", p.count)
			}
		case cmd := <-p.cmd:
			if cmd == "incr" {
				p.count += 1
			} else {
				p.count -= 1
			}
			log.Debugf("Ping count %v", p.count)
		}
	}
}

func (p *Pinger) Increment() {
	log.Debugf("Increment ping")
	p.cmd <- "incr"
}

func (p *Pinger) Decrement() {
	log.Debugf("Decrement ping")
	p.cmd <- "decr"
}
<commit_msg>Fix Ping. Delete Identifier<commit_after>package main

import (
	"time"
	"encoding/json"
)

type Pinger struct {
	interval time.Duration
	ticker   *time.Ticker
	cmd      chan string
	count    uint32
}

type PingReply struct {
	Type       string      `json:"type"`
	Message    interface{} `json:"message"`
}

func (p *PingReply) toJSON() []byte {
	jsonStr, err := json.Marshal(&p)
	if err != nil {
		panic("Failed to build JSON")
	}
	return jsonStr
}

func NewPinger(interval time.Duration) *Pinger {
	return &Pinger{count: 0, interval: interval, cmd: make(chan string)}
}

func (p *Pinger) run() {
	p.ticker = time.NewTicker(p.interval)
	defer p.ticker.Stop()

	for {
		select {
		case <-p.ticker.C:
			if p.count > 0 {
				log.Debugf("Ping will be sent to %v", p.count)
				app.BroadcastAll((&PingReply{Type: "ping", Message: time.Now().Unix()}).toJSON())
				log.Debugf("Ping was sent to %v", p.count)
			}
		case cmd := <-p.cmd:
			if cmd == "incr" {
				p.count += 1
			} else {
				p.count -= 1
			}
			log.Debugf("Ping count %v", p.count)
		}
	}
}

func (p *Pinger) Increment() {
	log.Debugf("Increment ping")
	p.cmd <- "incr"
}

func (p *Pinger) Decrement() {
	log.Debugf("Decrement ping")
	p.cmd <- "decr"
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp 2016 All Rights Reserved.

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

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

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

package main

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

// Grower example simple Chaincode implementation
type Grower struct {
}

type Error struct{
  Err string
}

var ddispensary = NewDispensary()
var ccustomer = NewCustomer()

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

// Init resets all the things
func (t *Grower) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    if len(args) != 1 {
        return nil, errors.New("Incorrect number of arguments. Expecting 1")
    }

    err := stub.PutState("hello_world", []byte(args[0]))
    if err != nil {
        return nil, err
    }

    return nil, nil
}

// Invoke is our entry point to invoke a chaincode function
func (t *Grower) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    fmt.Println("********************************Invoke****************************************")

    //   Handle different functions
    if function == "receiveOrder" {
        // Receive Order from Dispensary
        return t.receiveOrder(stub, args)
    } else if function == "shipOrder" {
        // Transfer product to Dispensary
        return t.shipOrder(stub,args)
    }else if function == "dispensaryPlacedOrder" {
        // Order Placed from Dispensary
        return t.dispensaryPlacedOrder(stub, args)
    }else if function == "shipmentReceivedBygrower" {
        // Grower shippment to Dispensary
        return t.shipmentReceivedBygrower(stub, args)
    }else if function == "customerPurchase" {
        // Purchased by Customer
        return t.customerPurchase(stub,args)
    }
    return nil, errors.New("Received unknown function invocation")
}

func (t *Grower) receiveOrder(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
 if len(args) != 3 {
    error := Error{"Incorrect number of arguments. Expecting 3"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("receiveOrderError", errorMarshal)
    return nil, errors.New("Incorrect number of arguments. Expecting 3")
  }
  // ==== Input sanitation ====
  fmt.Println("- start Receiving Order")
  if len(args[0]) <= 0 {
    error := Error{"1st argument must be a non-empty string"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("receiveOrderError", errorMarshal)
    return nil, errors.New("1st argument must be a non-empty string")
  }
  if len(args[1]) <= 0 {
    error := Error{"2nd argument must be a non-empty string"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("receiveOrderError", errorMarshal)
    return nil, errors.New("2nd argument must be a non-empty string")
  }
  if len(args[2]) <= 0 {
    error := Error{"3rd argument must be a non-empty string"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("receiveOrderError", errorMarshal)
    return nil, errors.New("3rd argument must be a non-empty string")
  }

id:= args[0]
    /*product:= args[1]
    quantity:= args[2]*/

    /*var data = {"dispensaryDetails":id,"product":product,"quantity":quantity}
    orderAsJson,err = json.Marshal(data)*/
    stub.PutState(id,[]byte("Grower Received Order"))
    return nil,nil
}

func (t *Grower) dispensaryPlacedOrder(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
         ddispensary.placedOrder(stub, args)
        return nil,nil
}

func (t *Grower) shipmentReceivedBygrower(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
      ddispensary.receivedShippmentOrder(stub,args)
        return nil,nil
}

func (t *Grower) customerPurchase(stub shim.ChaincodeStubInterface,args []string) ([]byte, error) {
      ccustomer.purchase(stub,args)
        return nil,nil
}

func (t *Grower) getOrder(stub shim.ChaincodeStubInterface, args []string) ([]byte,error) {
    fmt.Println("getCircle called")
    if len(args) !=1{
        return nil,errors.New("Incorrect number of arguments. Expecting 1")
    }
    Id := args[0]
    order, err := stub.GetState(Id)
    if err != nil {
        return nil,err
    }

    return order,nil
}

func (t *Grower) shipOrder(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {

if len(args) != 2 {
    error := Error{"Incorrect number of arguments. Expecting 2"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("transferOrderError", errorMarshal)
    return nil, errors.New("Incorrect number of arguments. Expecting 2")
  }
    id:= args[0]
    orderAsJson,err := stub.GetState(id)
if err != nil {
        return nil,err
    }
    if len(orderAsJson)==0{
        fmt.Println("Order doesnt exists")
        error := Error{"Order doesnt exists"}
        errorMarshal, _ := json.Marshal(error)
        stub.SetEvent("transferOrderError", errorMarshal)
        return nil, errors.New("Order doesnt exists")
    }

    /*var order
    json.Unmarshal(orderAsJson,&order)*/
    stub.PutState(id,[]byte("Shipped By Grower"))
    return nil,nil
}

// Query is our entry point for queries
func (t *Grower) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    fmt.Println("Query is running " + function)

    if function =="getOrder"{
            return t.getOrder(stub,args)
        }
    return nil,errors.New("Received unknown function query")
}<commit_msg>Update the folders<commit_after>/*
Copyright IBM Corp 2016 All Rights Reserved.

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

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

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

package main

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

// Grower example simple Chaincode implementation
type Grower struct {
}

type Error struct{
  Err string
}

var ddispensary = NewDispensary()
var ccustomer = NewCustomer()

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

// Init resets all the things
func (t *Grower) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    if len(args) != 1 {
        return nil, errors.New("Incorrect number of arguments. Expecting 1")
    }

    err := stub.PutState("hello_world", []byte(args[0]))
    if err != nil {
        return nil, err
    }

    return nil, nil
}

// Invoke is our entry point to invoke a chaincode function
func (t *Grower) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    fmt.Println("********************************Invoke****************************************")

    //   Handle different functions
    if function == "receiveOrder" {
        // Receive Order from Dispensary
        return t.receiveOrder(stub, args)
    } else if function == "shipOrder" {
        // Transfer product to Dispensary
        return t.shipOrder(stub,args)
    }else if function == "dispensaryPlacedOrder" {
        // Order Placed from Dispensary
        return t.dispensaryPlacedOrder(stub, args)
    }else if function == "shipmentReceivedByDispensary" {
        // Grower shippment to Dispensary
        return t.shipmentReceivedByDispensary(stub, args)
    }else if function == "customerPurchase" {
        // Purchased by Customer
        return t.customerPurchase(stub,args)
    }
    return nil, errors.New("Received unknown function invocation")
}

func (t *Grower) receiveOrder(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
 if len(args) != 3 {
    error := Error{"Incorrect number of arguments. Expecting 3"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("receiveOrderError", errorMarshal)
    return nil, errors.New("Incorrect number of arguments. Expecting 3")
  }
  // ==== Input sanitation ====
  fmt.Println("- start Receiving Order")
  if len(args[0]) <= 0 {
    error := Error{"1st argument must be a non-empty string"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("receiveOrderError", errorMarshal)
    return nil, errors.New("1st argument must be a non-empty string")
  }
  if len(args[1]) <= 0 {
    error := Error{"2nd argument must be a non-empty string"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("receiveOrderError", errorMarshal)
    return nil, errors.New("2nd argument must be a non-empty string")
  }
  if len(args[2]) <= 0 {
    error := Error{"3rd argument must be a non-empty string"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("receiveOrderError", errorMarshal)
    return nil, errors.New("3rd argument must be a non-empty string")
  }

id:= args[0]
    /*product:= args[1]
    quantity:= args[2]*/

    /*var data = {"dispensaryDetails":id,"product":product,"quantity":quantity}
    orderAsJson,err = json.Marshal(data)*/
    stub.PutState(id,[]byte("Grower Received Order"))
    return nil,nil
}

func (t *Grower) dispensaryPlacedOrder(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
         ddispensary.placedOrder(stub, args)
        return nil,nil
}

func (t *Grower) shipmentReceivedByDispensary(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
      ddispensary.receivedShippmentOrder(stub,args)
        return nil,nil
}

func (t *Grower) customerPurchase(stub shim.ChaincodeStubInterface,args []string) ([]byte, error) {
      ccustomer.purchase(stub,args)
        return nil,nil
}

func (t *Grower) getOrder(stub shim.ChaincodeStubInterface, args []string) ([]byte,error) {
    fmt.Println("getCircle called")
    if len(args) !=1{
        return nil,errors.New("Incorrect number of arguments. Expecting 1")
    }
    Id := args[0]
    order, err := stub.GetState(Id)
    if err != nil {
        return nil,err
    }

    return order,nil
}

func (t *Grower) shipOrder(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {

if len(args) != 2 {
    error := Error{"Incorrect number of arguments. Expecting 2"}
    errorMarshal, _ := json.Marshal(error)
    stub.SetEvent("transferOrderError", errorMarshal)
    return nil, errors.New("Incorrect number of arguments. Expecting 2")
  }
    id:= args[0]
    orderAsJson,err := stub.GetState(id)
if err != nil {
        return nil,err
    }
    if len(orderAsJson)==0{
        fmt.Println("Order doesnt exists")
        error := Error{"Order doesnt exists"}
        errorMarshal, _ := json.Marshal(error)
        stub.SetEvent("transferOrderError", errorMarshal)
        return nil, errors.New("Order doesnt exists")
    }

    /*var order
    json.Unmarshal(orderAsJson,&order)*/
    stub.PutState(id,[]byte("Shipped By Grower"))
    return nil,nil
}

// Query is our entry point for queries
func (t *Grower) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    fmt.Println("Query is running " + function)

    if function =="getOrder"{
            return t.getOrder(stub,args)
        }
    return nil,errors.New("Received unknown function query")
}<|endoftext|>


<commit_before>package vlc

// #cgo LDFLAGS: -lvlc
// #include <vlc/vlc.h>
// #include <stdlib.h>
import "C"
import (
	"errors"
	"unsafe"
)

// Player is a media player used to play a single media file.
// For playing media lists (playlists) use ListPlayer instead.
type Player struct {
	player *C.libvlc_media_player_t
}

// NewPlayer creates an instance of a single-media player.
func NewPlayer() (*Player, error) {
	if instance == nil {
		return nil, errors.New("Module must be initialized first")
	}

	if player := C.libvlc_media_player_new(instance); player != nil {
		return &Player{player: player}, nil
	}

	return nil, getError()
}

// Release destroys the media player instance.
func (p *Player) Release() error {
	if p.player == nil {
		return nil
	}

	C.libvlc_media_player_release(p.player)
	p.player = nil

	return getError()
}

// Play plays the current media.
func (p *Player) Play() error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}
	if p.IsPlaying() {
		return nil
	}

	if C.libvlc_media_player_play(p.player) < 0 {
		return getError()
	}

	return nil
}

// IsPlaying returns a boolean value specifying if the player is currently
// playing.
func (p *Player) IsPlaying() bool {
	if p.player == nil {
		return false
	}

	return C.libvlc_media_player_is_playing(p.player) != 0
}

// Stop cancels the currently playing media, if there is one.
func (p *Player) Stop() error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}
	if !p.IsPlaying() {
		return nil
	}

	C.libvlc_media_player_stop(p.player)
	return getError()
}

// SetPause sets the pause state of the media player.
// Pass in true to pause the current media, or false to resume it.
func (p *Player) SetPause(pause bool) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_media_player_set_pause(p.player, C.int(boolToInt(pause)))
	return getError()
}

// TogglePause pauses/resumes the player.
// Calling this method has no effect if there is no media.
func (p *Player) TogglePause() error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_media_player_pause(p.player)
	return getError()
}

// SetFullScreen sets the fullscreen state of the media player.
// Pass in true to enable fullscreen, or false to disable it.
func (p *Player) SetFullScreen(fullscreen bool) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_set_fullscreen(p.player, C.int(boolToInt(fullscreen)))
	return getError()
}

// ToggleFullScreen toggles the fullscreen status of the player,
// on non-embedded video outputs.
func (p *Player) ToggleFullScreen() error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_toggle_fullscreen(p.player)
	return getError()
}

// IsFullScreen gets the fullscreen status of the current player.
func (p *Player) IsFullScreen() (bool, error) {
	if p.player == nil {
		return false, errors.New("A player must be initialized first")
	}

	return (C.libvlc_get_fullscreen(p.player) != C.int(0)), getError()
}

// Volume returns the volume of the player.
func (p *Player) Volume() (int, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	return int(C.libvlc_audio_get_volume(p.player)), getError()
}

// SetVolume sets the volume of the player.
func (p *Player) SetVolume(volume int) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_audio_set_volume(p.player, C.int(volume))
	return getError()
}

// Media returns the current media of the player, if one exists.
func (p *Player) Media() (*Media, error) {
	if p.player == nil {
		return nil, errors.New("A player must be initialized first")
	}

	media := C.libvlc_media_player_get_media(p.player)
	if media == nil {
		return nil, nil
	}

	// This call will not release the media. Instead, it will decrement
	// the reference count increased by libvlc_media_player_get_media.
	C.libvlc_media_release(media)

	return &Media{media}, nil
}

// SetMedia sets the provided media as the current media of the player.
func (p *Player) SetMedia(m *Media) error {
	return p.setMedia(m)
}

// LoadMediaFromPath loads the media from the specified path and adds it as the
// current media of the player.
func (p *Player) LoadMediaFromPath(path string) (*Media, error) {
	return p.loadMedia(path, true)
}

// LoadMediaFromURL loads the media from the specified URL and adds it as the
// current media of the player.
func (p *Player) LoadMediaFromURL(url string) (*Media, error) {
	return p.loadMedia(url, false)
}

// SetAudioOutput selects an audio output module.
// Any change will take be effect only after playback is stopped and restarted.
// Audio output cannot be changed while playing.
func (p *Player) SetAudioOutput(output string) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	cOutput := C.CString(output)
	defer C.free(unsafe.Pointer(cOutput))

	if C.libvlc_audio_output_set(p.player, cOutput) != 0 {
		return getError()
	}

	return nil
}

// MediaLength returns media length in milliseconds.
func (p *Player) MediaLength() (int, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	return int(C.libvlc_media_player_get_length(p.player)), getError()
}

// MediaState returns the state of the current media.
func (p *Player) MediaState() (MediaState, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	state := int(C.libvlc_media_player_get_state(p.player))
	return MediaState(state), getError()
}

// MediaPosition returns media position as a
// float percentage between 0.0 and 1.0.
func (p *Player) MediaPosition() (float32, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	return float32(C.libvlc_media_player_get_position(p.player)), getError()
}

// SetMediaPosition sets media position as percentage between 0.0 and 1.0.
// Some formats and protocols do not support this.
func (p *Player) SetMediaPosition(pos float32) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_media_player_set_position(p.player, C.float(pos))
	return getError()
}

// MediaTime returns media time in milliseconds.
func (p *Player) MediaTime() (int, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	return int(C.libvlc_media_player_get_time(p.player)), getError()
}

// SetMediaTime sets the media time in milliseconds.
// Some formats and protocals do not support this.
func (p *Player) SetMediaTime(t int) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_media_player_set_time(p.player, C.libvlc_time_t(int64(t)))
	return getError()
}

// WillPlay returns true if the current media is not in a
// finished or error state.
func (p *Player) WillPlay() bool {
	if p.player == nil {
		return false
	}

	return C.libvlc_media_player_will_play(p.player) != 0
}

func (p *Player) loadMedia(path string, local bool) (*Media, error) {
	m, err := newMedia(path, local)
	if err != nil {
		return nil, err
	}

	if err = p.setMedia(m); err != nil {
		m.Release()
		return nil, err
	}

	return m, nil
}

func (p *Player) setMedia(m *Media) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}
	if m.media == nil {
		return errors.New("The media must be initialized first")
	}

	C.libvlc_media_player_set_media(p.player, m.media)
	return getError()
}

func (p *Player) setXWindow(uint32 XID) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}
	C.libvlc_media_player_set_xwindow(XID)
	return getError()
}
<commit_msg>Correct function declaration<commit_after>package vlc

// #cgo LDFLAGS: -lvlc
// #include <vlc/vlc.h>
// #include <stdlib.h>
import "C"
import (
	"errors"
	"unsafe"
)

// Player is a media player used to play a single media file.
// For playing media lists (playlists) use ListPlayer instead.
type Player struct {
	player *C.libvlc_media_player_t
}

// NewPlayer creates an instance of a single-media player.
func NewPlayer() (*Player, error) {
	if instance == nil {
		return nil, errors.New("Module must be initialized first")
	}

	if player := C.libvlc_media_player_new(instance); player != nil {
		return &Player{player: player}, nil
	}

	return nil, getError()
}

// Release destroys the media player instance.
func (p *Player) Release() error {
	if p.player == nil {
		return nil
	}

	C.libvlc_media_player_release(p.player)
	p.player = nil

	return getError()
}

// Play plays the current media.
func (p *Player) Play() error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}
	if p.IsPlaying() {
		return nil
	}

	if C.libvlc_media_player_play(p.player) < 0 {
		return getError()
	}

	return nil
}

// IsPlaying returns a boolean value specifying if the player is currently
// playing.
func (p *Player) IsPlaying() bool {
	if p.player == nil {
		return false
	}

	return C.libvlc_media_player_is_playing(p.player) != 0
}

// Stop cancels the currently playing media, if there is one.
func (p *Player) Stop() error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}
	if !p.IsPlaying() {
		return nil
	}

	C.libvlc_media_player_stop(p.player)
	return getError()
}

// SetPause sets the pause state of the media player.
// Pass in true to pause the current media, or false to resume it.
func (p *Player) SetPause(pause bool) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_media_player_set_pause(p.player, C.int(boolToInt(pause)))
	return getError()
}

// TogglePause pauses/resumes the player.
// Calling this method has no effect if there is no media.
func (p *Player) TogglePause() error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_media_player_pause(p.player)
	return getError()
}

// SetFullScreen sets the fullscreen state of the media player.
// Pass in true to enable fullscreen, or false to disable it.
func (p *Player) SetFullScreen(fullscreen bool) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_set_fullscreen(p.player, C.int(boolToInt(fullscreen)))
	return getError()
}

// ToggleFullScreen toggles the fullscreen status of the player,
// on non-embedded video outputs.
func (p *Player) ToggleFullScreen() error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_toggle_fullscreen(p.player)
	return getError()
}

// IsFullScreen gets the fullscreen status of the current player.
func (p *Player) IsFullScreen() (bool, error) {
	if p.player == nil {
		return false, errors.New("A player must be initialized first")
	}

	return (C.libvlc_get_fullscreen(p.player) != C.int(0)), getError()
}

// Volume returns the volume of the player.
func (p *Player) Volume() (int, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	return int(C.libvlc_audio_get_volume(p.player)), getError()
}

// SetVolume sets the volume of the player.
func (p *Player) SetVolume(volume int) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_audio_set_volume(p.player, C.int(volume))
	return getError()
}

// Media returns the current media of the player, if one exists.
func (p *Player) Media() (*Media, error) {
	if p.player == nil {
		return nil, errors.New("A player must be initialized first")
	}

	media := C.libvlc_media_player_get_media(p.player)
	if media == nil {
		return nil, nil
	}

	// This call will not release the media. Instead, it will decrement
	// the reference count increased by libvlc_media_player_get_media.
	C.libvlc_media_release(media)

	return &Media{media}, nil
}

// SetMedia sets the provided media as the current media of the player.
func (p *Player) SetMedia(m *Media) error {
	return p.setMedia(m)
}

// LoadMediaFromPath loads the media from the specified path and adds it as the
// current media of the player.
func (p *Player) LoadMediaFromPath(path string) (*Media, error) {
	return p.loadMedia(path, true)
}

// LoadMediaFromURL loads the media from the specified URL and adds it as the
// current media of the player.
func (p *Player) LoadMediaFromURL(url string) (*Media, error) {
	return p.loadMedia(url, false)
}

// SetAudioOutput selects an audio output module.
// Any change will take be effect only after playback is stopped and restarted.
// Audio output cannot be changed while playing.
func (p *Player) SetAudioOutput(output string) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	cOutput := C.CString(output)
	defer C.free(unsafe.Pointer(cOutput))

	if C.libvlc_audio_output_set(p.player, cOutput) != 0 {
		return getError()
	}

	return nil
}

// MediaLength returns media length in milliseconds.
func (p *Player) MediaLength() (int, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	return int(C.libvlc_media_player_get_length(p.player)), getError()
}

// MediaState returns the state of the current media.
func (p *Player) MediaState() (MediaState, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	state := int(C.libvlc_media_player_get_state(p.player))
	return MediaState(state), getError()
}

// MediaPosition returns media position as a
// float percentage between 0.0 and 1.0.
func (p *Player) MediaPosition() (float32, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	return float32(C.libvlc_media_player_get_position(p.player)), getError()
}

// SetMediaPosition sets media position as percentage between 0.0 and 1.0.
// Some formats and protocols do not support this.
func (p *Player) SetMediaPosition(pos float32) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_media_player_set_position(p.player, C.float(pos))
	return getError()
}

// MediaTime returns media time in milliseconds.
func (p *Player) MediaTime() (int, error) {
	if p.player == nil {
		return 0, errors.New("A player must be initialized first")
	}

	return int(C.libvlc_media_player_get_time(p.player)), getError()
}

// SetMediaTime sets the media time in milliseconds.
// Some formats and protocals do not support this.
func (p *Player) SetMediaTime(t int) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}

	C.libvlc_media_player_set_time(p.player, C.libvlc_time_t(int64(t)))
	return getError()
}

// WillPlay returns true if the current media is not in a
// finished or error state.
func (p *Player) WillPlay() bool {
	if p.player == nil {
		return false
	}

	return C.libvlc_media_player_will_play(p.player) != 0
}

func (p *Player) loadMedia(path string, local bool) (*Media, error) {
	m, err := newMedia(path, local)
	if err != nil {
		return nil, err
	}

	if err = p.setMedia(m); err != nil {
		m.Release()
		return nil, err
	}

	return m, nil
}

func (p *Player) setMedia(m *Media) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}
	if m.media == nil {
		return errors.New("The media must be initialized first")
	}

	C.libvlc_media_player_set_media(p.player, m.media)
	return getError()
}

func (p *Player) setXWindow(XID uint32) error {
	if p.player == nil {
		return errors.New("A player must be initialized first")
	}
	C.libvlc_media_player_set_xwindow(XID)
	return getError()
}
<|endoftext|>


<commit_before>package app

import "github.com/robfig/revel"
import "github.com/jgraham909/revmgo"

func init() {
	revel.OnAppStart(func() { revmgo.AppInit() })
	revel.Filters = []revel.Filter{
		revel.PanicFilter,             // Recover from panics and display an error page instead.
		revel.RouterFilter,            // Use the routing table to select the right Action
		revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
		revel.ParamsFilter,            // Parse parameters into Controller.Params.
		revel.SessionFilter,           // Restore and write the session cookie.
		revel.FlashFilter,             // Restore and write the flash cookie.
		revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
		revel.I18nFilter,              // Resolve the requested language
		revel.InterceptorFilter,       // Run interceptors around the action.
		revel.ActionInvoker,           // Invoke the action.
	}

	revel.TemplateFuncs["nil"] = func(a interface{}) bool {
		return a == nil
	}
}
<commit_msg>Updating revmgo instantiation<commit_after>package app

import "github.com/robfig/revel"
import "github.com/jgraham909/revmgo"

func init() {
	revel.OnAppStart(revmgo.AppInit)
	revel.Filters = []revel.Filter{
		revel.PanicFilter,             // Recover from panics and display an error page instead.
		revel.RouterFilter,            // Use the routing table to select the right Action
		revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
		revel.ParamsFilter,            // Parse parameters into Controller.Params.
		revel.SessionFilter,           // Restore and write the session cookie.
		revel.FlashFilter,             // Restore and write the flash cookie.
		revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
		revel.I18nFilter,              // Resolve the requested language
		revel.InterceptorFilter,       // Run interceptors around the action.
		revel.ActionInvoker,           // Invoke the action.
	}

	revel.TemplateFuncs["nil"] = func(a interface{}) bool {
		return a == nil
	}
}
<|endoftext|>