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

package main

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"text/tabwriter"
	"time"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/prometheus/client_golang/api"
	promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
	"github.com/prometheus/common/model"
	"github.com/spf13/cobra"
	"k8s.io/api/core/v1"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/portforward"
	"k8s.io/client-go/transport/spdy"

	"istio.io/istio/pkg/log"
)

var (
	metricsCmd = &cobra.Command{
		Use:   "metrics <service name>...",
		Short: "Prints the metrics for the specified service(s) when running in Kubernetes.",
		Long: `
Prints the metrics for the specified service(s) when running in Kubernetes.

This command finds a Prometheus pod running in the specified istio system
namespace. It then executes a series of queries per requested service to
find the following top-level service metrics: total requests per second,
error rate, and request latency at p50, p90, and p99 percentiles. The
query results are printed to the console, organized by service name.

All metrics returned are from server-side reports. This means that latencies
and error rates are from the perspective of the service itself and not of an
individual client (or aggregate set of clients). Rates and latencies are
calculated over a time interval of 1 minute.
`,
		Example: `
# Retrieve service metrics for productpage service
istioctl experimental metrics productpage

# Retrieve service metrics for various services in the different namespaces
istioctl experimental metrics productpage.foo reviews.bar ratings.baz
`,
		Aliases: []string{"m"},
		Args:    cobra.MinimumNArgs(1),
		RunE:    run,
		DisableFlagsInUseLine: true,
	}
)

func init() {
	experimentalCmd.AddCommand(metricsCmd)
}

type serviceMetrics struct {
	service                            string
	totalRPS, errorRPS                 float64
	p50Latency, p90Latency, p99Latency time.Duration
}

func run(c *cobra.Command, args []string) error {
	log.Debugf("metrics command invoked for service(s): %v", args)

	config, _ := defaultRestConfig()
	client, err := createCoreV1Client()
	if err != nil {
		return fmt.Errorf("failed to create k8s client: %v", err)
	}

	pl, err := prometheusPods(client)
	if err != nil {
		return fmt.Errorf("not able to locate prometheus pod: %v", err)
	}

	if len(pl.Items) < 1 {
		return errors.New("no prometheus pods found")
	}

	port, err := availablePort()
	if err != nil {
		return fmt.Errorf("not able to find available port: %v", err)
	}
	log.Debugf("Using local port: %d", port)

	// only use the first pod in the list
	promPod := pl.Items[0]
	fw, readyCh, err := buildPortForwarder(client, config, promPod.Name, port)
	if err != nil {
		return fmt.Errorf("could not build port forwarder for prometheus: %v", err)
	}

	errCh := make(chan error)
	go func() {
		errCh <- fw.ForwardPorts()
	}()

	select {
	case err := <-errCh:
		return fmt.Errorf("failure running port forward process: %v", err)
	case <-readyCh:
		log.Debugf("port-forward to prometheus pod ready")
		defer fw.Close()

		promAPI, err := prometheusAPI(port)
		if err != nil {
			return err
		}

		services := args
		for _, service := range services {
			sm, err := metrics(promAPI, service)
			if err != nil {
				return fmt.Errorf("could not build metrics for service '%s': %v", service, err)
			}

			printMetrics(sm)
		}
		return nil
	}
}

func prometheusPods(client cache.Getter) (*v1.PodList, error) {
	podGet := client.Get().Resource("pods").Namespace(istioNamespace).Param("labelSelector", "app=prometheus")
	obj, err := podGet.Do().Get()
	if err != nil {
		return nil, fmt.Errorf("failed retrieving pod: %v", err)
	}
	return obj.(*v1.PodList), nil
}

func buildPortForwarder(client *rest.RESTClient, config *rest.Config, podName string, port int) (*portforward.PortForwarder, <-chan struct{}, error) {
	req := client.Post().Resource("pods").Namespace(istioNamespace).Name(podName).SubResource("portforward")

	transport, upgrader, err := spdy.RoundTripperFor(config)
	if err != nil {
		return nil, nil, fmt.Errorf("failure creating roundtripper: %v", err)
	}

	dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", req.URL())

	stop := make(chan struct{})
	ready := make(chan struct{})
	fw, err := portforward.New(dialer, []string{fmt.Sprintf("%d:9090", port)}, stop, ready, ioutil.Discard, os.Stderr)
	if err != nil {
		return nil, nil, fmt.Errorf("failed establishing port-forward: %v", err)
	}

	return fw, ready, nil
}

func availablePort() (int, error) {
	addr, err := net.ResolveTCPAddr("tcp", ":0")
	if err != nil {
		return 0, err
	}

	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return 0, err
	}
	port := l.Addr().(*net.TCPAddr).Port
	l.Close()
	return port, nil
}

func prometheusAPI(port int) (promv1.API, error) {
	promClient, err := api.NewClient(api.Config{Address: fmt.Sprintf("http://localhost:%d", port)})
	if err != nil {
		return nil, fmt.Errorf("could not build prometheus client: %v", err)
	}
	return promv1.NewAPI(promClient), nil
}

func metrics(promAPI promv1.API, service string) (serviceMetrics, error) {
	rpsQuery := fmt.Sprintf(`sum(rate(istio_request_count{destination_service=~"%s.*"}[1m]))`, service)
	errRPSQuery := fmt.Sprintf(`sum(rate(istio_request_count{destination_service=~"%s.*",response_code!="200"}[1m]))`, service)
	p50LatencyQuery := fmt.Sprintf(`histogram_quantile(%f, sum(rate(istio_request_duration_bucket{destination_service=~"%s.*"}[1m])) by (le))`, 0.5, service)
	p90LatencyQuery := fmt.Sprintf(`histogram_quantile(%f, sum(rate(istio_request_duration_bucket{destination_service=~"%s.*"}[1m])) by (le))`, 0.9, service)
	p99LatencyQuery := fmt.Sprintf(`histogram_quantile(%f, sum(rate(istio_request_duration_bucket{destination_service=~"%s.*"}[1m])) by (le))`, 0.99, service)

	var me *multierror.Error
	var err error
	sm := serviceMetrics{service: service}
	sm.totalRPS, err = vectorValue(promAPI, rpsQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}

	sm.errorRPS, err = vectorValue(promAPI, errRPSQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}

	p50Latency, err := vectorValue(promAPI, p50LatencyQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}
	sm.p50Latency = time.Duration(p50Latency*1000) * time.Millisecond

	p90Latency, err := vectorValue(promAPI, p90LatencyQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}
	sm.p90Latency = time.Duration(p90Latency*1000) * time.Millisecond

	p99Latency, err := vectorValue(promAPI, p99LatencyQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}
	sm.p99Latency = time.Duration(p99Latency*1000) * time.Millisecond

	if me.ErrorOrNil() != nil {
		return sm, fmt.Errorf("error retrieving some metrics: %v", me.Error())
	}

	return sm, nil
}

func vectorValue(promAPI promv1.API, query string) (float64, error) {
	log.Debugf("executing query: %s", query)
	val, err := promAPI.Query(context.Background(), query, time.Now())
	if err != nil {
		return 0, fmt.Errorf("query() failure for '%s': %v", query, err)
	}

	switch v := val.(type) {
	case model.Vector:
		if v.Len() < 1 {
			log.Debugf("no values for query: %s", query)
			return 0, nil
		}
		return float64(v[0].Value), nil
	default:
		return 0, errors.New("bad metric value type returned for query")
	}
}

func printMetrics(sm serviceMetrics) {
	w := tabwriter.NewWriter(os.Stdout, 0, 1, 2, ' ', 0)
	fmt.Fprintf(w, "%s:\n", sm.service)
	fmt.Fprintf(w, "\tTotal RPS: \t%f\n", sm.totalRPS)
	fmt.Fprintf(w, "\tError RPS: \t%f\n", sm.errorRPS)
	fmt.Fprintf(w, "\tP50 Latency: \t%s\n", sm.p50Latency)
	fmt.Fprintf(w, "\tP90 Latency: \t%s\n", sm.p90Latency)
	fmt.Fprintf(w, "\tP99 Latency: \t%s\n", sm.p99Latency)
	w.Flush()
}
<commit_msg>Make metrics command ready for web scale. (#5289)<commit_after>// Copyright 2018 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"text/tabwriter"
	"time"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/prometheus/client_golang/api"
	promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
	"github.com/prometheus/common/model"
	"github.com/spf13/cobra"
	"k8s.io/api/core/v1"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/portforward"
	"k8s.io/client-go/transport/spdy"

	"istio.io/istio/pkg/log"
)

var (
	metricsCmd = &cobra.Command{
		Use:   "metrics <service name>...",
		Short: "Prints the metrics for the specified service(s) when running in Kubernetes.",
		Long: `
Prints the metrics for the specified service(s) when running in Kubernetes.

This command finds a Prometheus pod running in the specified istio system
namespace. It then executes a series of queries per requested service to
find the following top-level service metrics: total requests per second,
error rate, and request latency at p50, p90, and p99 percentiles. The
query results are printed to the console, organized by service name.

All metrics returned are from server-side reports. This means that latencies
and error rates are from the perspective of the service itself and not of an
individual client (or aggregate set of clients). Rates and latencies are
calculated over a time interval of 1 minute.
`,
		Example: `
# Retrieve service metrics for productpage service
istioctl experimental metrics productpage

# Retrieve service metrics for various services in the different namespaces
istioctl experimental metrics productpage.foo reviews.bar ratings.baz
`,
		Aliases: []string{"m"},
		Args:    cobra.MinimumNArgs(1),
		RunE:    run,
		DisableFlagsInUseLine: true,
	}
)

func init() {
	experimentalCmd.AddCommand(metricsCmd)
}

type serviceMetrics struct {
	service                            string
	totalRPS, errorRPS                 float64
	p50Latency, p90Latency, p99Latency time.Duration
}

func run(c *cobra.Command, args []string) error {
	log.Debugf("metrics command invoked for service(s): %v", args)

	config, _ := defaultRestConfig()
	client, err := createCoreV1Client()
	if err != nil {
		return fmt.Errorf("failed to create k8s client: %v", err)
	}

	pl, err := prometheusPods(client)
	if err != nil {
		return fmt.Errorf("not able to locate prometheus pod: %v", err)
	}

	if len(pl.Items) < 1 {
		return errors.New("no prometheus pods found")
	}

	port, err := availablePort()
	if err != nil {
		return fmt.Errorf("not able to find available port: %v", err)
	}
	log.Debugf("Using local port: %d", port)

	// only use the first pod in the list
	promPod := pl.Items[0]
	fw, readyCh, err := buildPortForwarder(client, config, promPod.Name, port)
	if err != nil {
		return fmt.Errorf("could not build port forwarder for prometheus: %v", err)
	}

	errCh := make(chan error)
	go func() {
		errCh <- fw.ForwardPorts()
	}()

	select {
	case err := <-errCh:
		return fmt.Errorf("failure running port forward process: %v", err)
	case <-readyCh:
		log.Debugf("port-forward to prometheus pod ready")
		defer fw.Close()

		promAPI, err := prometheusAPI(port)
		if err != nil {
			return err
		}

		printHeader()

		services := args
		for _, service := range services {
			sm, err := metrics(promAPI, service)
			if err != nil {
				return fmt.Errorf("could not build metrics for service '%s': %v", service, err)
			}

			printMetrics(sm)
		}
		return nil
	}
}

func prometheusPods(client cache.Getter) (*v1.PodList, error) {
	podGet := client.Get().Resource("pods").Namespace(istioNamespace).Param("labelSelector", "app=prometheus")
	obj, err := podGet.Do().Get()
	if err != nil {
		return nil, fmt.Errorf("failed retrieving pod: %v", err)
	}
	return obj.(*v1.PodList), nil
}

func buildPortForwarder(client *rest.RESTClient, config *rest.Config, podName string, port int) (*portforward.PortForwarder, <-chan struct{}, error) {
	req := client.Post().Resource("pods").Namespace(istioNamespace).Name(podName).SubResource("portforward")

	transport, upgrader, err := spdy.RoundTripperFor(config)
	if err != nil {
		return nil, nil, fmt.Errorf("failure creating roundtripper: %v", err)
	}

	dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", req.URL())

	stop := make(chan struct{})
	ready := make(chan struct{})
	fw, err := portforward.New(dialer, []string{fmt.Sprintf("%d:9090", port)}, stop, ready, ioutil.Discard, os.Stderr)
	if err != nil {
		return nil, nil, fmt.Errorf("failed establishing port-forward: %v", err)
	}

	return fw, ready, nil
}

func availablePort() (int, error) {
	addr, err := net.ResolveTCPAddr("tcp", ":0")
	if err != nil {
		return 0, err
	}

	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return 0, err
	}
	port := l.Addr().(*net.TCPAddr).Port
	l.Close()
	return port, nil
}

func prometheusAPI(port int) (promv1.API, error) {
	promClient, err := api.NewClient(api.Config{Address: fmt.Sprintf("http://localhost:%d", port)})
	if err != nil {
		return nil, fmt.Errorf("could not build prometheus client: %v", err)
	}
	return promv1.NewAPI(promClient), nil
}

func metrics(promAPI promv1.API, service string) (serviceMetrics, error) {
	rpsQuery := fmt.Sprintf(`sum(rate(istio_request_count{destination_service=~"%s.*"}[1m]))`, service)
	errRPSQuery := fmt.Sprintf(`sum(rate(istio_request_count{destination_service=~"%s.*",response_code!="200"}[1m]))`, service)
	p50LatencyQuery := fmt.Sprintf(`histogram_quantile(%f, sum(rate(istio_request_duration_bucket{destination_service=~"%s.*"}[1m])) by (le))`, 0.5, service)
	p90LatencyQuery := fmt.Sprintf(`histogram_quantile(%f, sum(rate(istio_request_duration_bucket{destination_service=~"%s.*"}[1m])) by (le))`, 0.9, service)
	p99LatencyQuery := fmt.Sprintf(`histogram_quantile(%f, sum(rate(istio_request_duration_bucket{destination_service=~"%s.*"}[1m])) by (le))`, 0.99, service)

	var me *multierror.Error
	var err error
	sm := serviceMetrics{service: service}
	sm.totalRPS, err = vectorValue(promAPI, rpsQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}

	sm.errorRPS, err = vectorValue(promAPI, errRPSQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}

	p50Latency, err := vectorValue(promAPI, p50LatencyQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}
	sm.p50Latency = time.Duration(p50Latency*1000) * time.Millisecond

	p90Latency, err := vectorValue(promAPI, p90LatencyQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}
	sm.p90Latency = time.Duration(p90Latency*1000) * time.Millisecond

	p99Latency, err := vectorValue(promAPI, p99LatencyQuery)
	if err != nil {
		me = multierror.Append(me, err)
	}
	sm.p99Latency = time.Duration(p99Latency*1000) * time.Millisecond

	if me.ErrorOrNil() != nil {
		return sm, fmt.Errorf("error retrieving some metrics: %v", me.Error())
	}

	return sm, nil
}

func vectorValue(promAPI promv1.API, query string) (float64, error) {
	log.Debugf("executing query: %s", query)
	val, err := promAPI.Query(context.Background(), query, time.Now())
	if err != nil {
		return 0, fmt.Errorf("query() failure for '%s': %v", query, err)
	}

	switch v := val.(type) {
	case model.Vector:
		if v.Len() < 1 {
			log.Debugf("no values for query: %s", query)
			return 0, nil
		}
		return float64(v[0].Value), nil
	default:
		return 0, errors.New("bad metric value type returned for query")
	}
}

func printHeader() {
	w := tabwriter.NewWriter(os.Stdout, 13, 1, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintf(w, "%13sSERVICE\tTOTAL RPS\tERROR RPS\tP50 LATENCY\tP90 LATENCY\tP99 LATENCY\t\n", "")
	w.Flush()
}

func printMetrics(sm serviceMetrics) {
	w := tabwriter.NewWriter(os.Stdout, 13, 1, 2, ' ', tabwriter.AlignRight)
	fmt.Fprintf(w, "%20s\t", sm.service)
	fmt.Fprintf(w, "%.3f\t", sm.totalRPS)
	fmt.Fprintf(w, "%.3f\t", sm.errorRPS)
	fmt.Fprintf(w, "%s\t", sm.p50Latency)
	fmt.Fprintf(w, "%s\t", sm.p90Latency)
	fmt.Fprintf(w, "%s\t\n", sm.p99Latency)
	w.Flush()
}
<|endoftext|>


<commit_before>package stripe

import (
	"encoding/json"
	"strconv"

	"github.com/stripe/stripe-go/form"
)

// cardSource is a string that's used to build card form parameters. It's a
// constant just to make mistakes less likely.
const cardSource = "source"

// CardBrand is the list of allowed values for the card's brand.
// Allowed values are "Unknown", "Visa", "American Express", "MasterCard", "Discover"
// "JCB", "Diners Club".
type CardBrand string

// CardFunding is the list of allowed values for the card's funding.
// Allowed values are "credit", "debit", "prepaid", "unknown".
type CardFunding string

// TokenizationMethod is the list of allowed values for the card's tokenization method.
// Allowed values are "apple_pay", "android_pay".
type TokenizationMethod string

// Verification is the list of allowed verification responses.
// Allowed values are "pass", "fail", "unchecked", "unavailable".
type Verification string

// CardParams is the set of parameters that can be used when creating or updating a card.
// For more details see https://stripe.com/docs/api#create_card and https://stripe.com/docs/api#update_card.
//
// Note that while form annotations are used for tokenization and updates,
// cards have some unusual logic on creates that necessitates manual handling
// of all parameters. See AppendToAsCardSourceOrExternalAccount.
type CardParams struct {
	Params    `form:"*"`
	Account   string `form:"-"`
	Address1  string `form:"address_line1"`
	Address2  string `form:"address_line2"`
	CVC       string `form:"cvc"`
	City      string `form:"address_city"`
	Country   string `form:"address_country"`
	Currency  string `form:"currency"`
	Customer  string `form:"-"`
	Default   bool   `form:"default_for_currency"`
	Month     string `form:"exp_month"`
	Name      string `form:"name"`
	Number    string `form:"number"`
	Recipient string `form:"-"`
	State     string `form:"address_state"`
	Token     string `form:"-"`
	Year      string `form:"exp_year"`
	Zip       string `form:"address_zip"`
}

// AppendToAsCardSourceOrExternalAccount appends the given CardParams as either a
// card or external account.
//
// It may look like an AppendTo from the form package, but it's not, and is
// only used in the special case where we use `card.New`. It's needed because
// we have some weird encoding logic here that can't be handled by the form
// package (and it's special enough that it wouldn't be desirable to have it do
// so).
//
// This is not a pattern that we want to push forward, and this largely exists
// because the cards endpoint is a little unusual. There is one other resource
// like it, which is bank account.
func (c *CardParams) AppendToAsCardSourceOrExternalAccount(body *form.Values, keyParts []string) {
	if len(c.Token) > 0 && len(c.Account) > 0 {
		body.Add(form.FormatKey(append(keyParts, "external_account")), c.Token)

	}

	if c.Default {
		body.Add(form.FormatKey(append(keyParts, "default_for_currency")), strconv.FormatBool(c.Default))
	}

	if len(c.Token) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource)), c.Token)
	}

	if len(c.Number) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "object")), "card")
		body.Add(form.FormatKey(append(keyParts, cardSource, "number")), c.Number)
	}

	if len(c.CVC) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "cvc")), c.CVC)
	}

	if len(c.Currency) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "currency")), c.Currency)
	}

	if c.Default {
		body.Add(form.FormatKey(append(keyParts, cardSource, "default_for_currency")), strconv.FormatBool(c.Default))
	}

	if len(c.Month) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "exp_month")), c.Month)
	}

	if len(c.Year) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "exp_year")), c.Year)
	}

	if len(c.Name) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "name")), c.Name)
	}

	if len(c.Address1) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_line1")), c.Address1)
	}

	if len(c.Address2) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_line2")), c.Address2)
	}

	if len(c.City) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_city")), c.City)
	}

	if len(c.State) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_state")), c.State)
	}

	if len(c.Zip) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_zip")), c.Zip)
	}

	if len(c.Country) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_country")), c.Country)
	}
}

// CardListParams is the set of parameters that can be used when listing cards.
// For more details see https://stripe.com/docs/api#list_cards.
type CardListParams struct {
	ListParams `form:"*"`
	Account    string `form:"-"`
	Customer   string `form:"-"`
	Recipient  string `form:"-"`
}

// Card is the resource representing a Stripe credit/debit card.
// For more details see https://stripe.com/docs/api#cards.
type Card struct {
	Address1      string       `json:"address_line1"`
	Address1Check Verification `json:"address_line1_check"`
	Address2      string       `json:"address_line2"`
	Brand         CardBrand    `json:"brand"`
	CVCCheck      Verification `json:"cvc_check"`
	CardCountry   string       `json:"country"`
	City          string       `json:"address_city"`
	Country       string       `json:"address_country"`
	Currency      Currency     `json:"currency"`
	Customer      *Customer    `json:"customer"`
	Default       bool         `json:"default_for_currency"`
	Deleted       bool         `json:"deleted"`

	// Description is a succinct summary of the card's information.
	//
	// Please note that this field is for internal use only and is not returned
	// as part of standard API requests.
	Description string `json:"description"`

	DynLastFour string      `json:"dynamic_last4"`
	Fingerprint string      `json:"fingerprint"`
	Funding     CardFunding `json:"funding"`
	ID          string      `json:"id"`

	// IIN is the card's "Issuer Identification Number".
	//
	// Please note that this field is for internal use only and is not returned
	// as part of standard API requests.
	IIN string `json:"iin"`

	// Issuer is a bank or financial institution that provides the card.
	//
	// Please note that this field is for internal use only and is not returned
	// as part of standard API requests.
	Issuer string `json:"issuer"`

	LastFour           string             `json:"last4"`
	Meta               map[string]string  `json:"metadata"`
	Month              uint8              `json:"exp_month"`
	Name               string             `json:"name"`
	Recipient          *Recipient         `json:"recipient"`
	State              string             `json:"address_state"`
	ThreeDSecure       *ThreeDSecure      `json:"three_d_secure"`
	TokenizationMethod TokenizationMethod `json:"tokenization_method"`
	Year               uint16             `json:"exp_year"`
	Zip                string             `json:"address_zip"`
	ZipCheck           Verification       `json:"address_zip_check"`
}

// CardList is a list object for cards.
type CardList struct {
	ListMeta
	Values []*Card `json:"data"`
}

// UnmarshalJSON handles deserialization of a Card.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (c *Card) UnmarshalJSON(data []byte) error {
	type card Card
	var cc card
	err := json.Unmarshal(data, &cc)
	if err == nil {
		*c = Card(cc)
	} else {
		// the id is surrounded by "\" characters, so strip them
		c.ID = string(data[1 : len(data)-1])
	}

	return nil
}
<commit_msg>Ensure that the token is only passed once (#479)<commit_after>package stripe

import (
	"encoding/json"
	"strconv"

	"github.com/stripe/stripe-go/form"
)

// cardSource is a string that's used to build card form parameters. It's a
// constant just to make mistakes less likely.
const cardSource = "source"

// CardBrand is the list of allowed values for the card's brand.
// Allowed values are "Unknown", "Visa", "American Express", "MasterCard", "Discover"
// "JCB", "Diners Club".
type CardBrand string

// CardFunding is the list of allowed values for the card's funding.
// Allowed values are "credit", "debit", "prepaid", "unknown".
type CardFunding string

// TokenizationMethod is the list of allowed values for the card's tokenization method.
// Allowed values are "apple_pay", "android_pay".
type TokenizationMethod string

// Verification is the list of allowed verification responses.
// Allowed values are "pass", "fail", "unchecked", "unavailable".
type Verification string

// CardParams is the set of parameters that can be used when creating or updating a card.
// For more details see https://stripe.com/docs/api#create_card and https://stripe.com/docs/api#update_card.
//
// Note that while form annotations are used for tokenization and updates,
// cards have some unusual logic on creates that necessitates manual handling
// of all parameters. See AppendToAsCardSourceOrExternalAccount.
type CardParams struct {
	Params    `form:"*"`
	Account   string `form:"-"`
	Address1  string `form:"address_line1"`
	Address2  string `form:"address_line2"`
	CVC       string `form:"cvc"`
	City      string `form:"address_city"`
	Country   string `form:"address_country"`
	Currency  string `form:"currency"`
	Customer  string `form:"-"`
	Default   bool   `form:"default_for_currency"`
	Month     string `form:"exp_month"`
	Name      string `form:"name"`
	Number    string `form:"number"`
	Recipient string `form:"-"`
	State     string `form:"address_state"`
	Token     string `form:"-"`
	Year      string `form:"exp_year"`
	Zip       string `form:"address_zip"`
}

// AppendToAsCardSourceOrExternalAccount appends the given CardParams as either a
// card or external account.
//
// It may look like an AppendTo from the form package, but it's not, and is
// only used in the special case where we use `card.New`. It's needed because
// we have some weird encoding logic here that can't be handled by the form
// package (and it's special enough that it wouldn't be desirable to have it do
// so).
//
// This is not a pattern that we want to push forward, and this largely exists
// because the cards endpoint is a little unusual. There is one other resource
// like it, which is bank account.
func (c *CardParams) AppendToAsCardSourceOrExternalAccount(body *form.Values, keyParts []string) {
	if c.Default {
		body.Add(form.FormatKey(append(keyParts, "default_for_currency")), strconv.FormatBool(c.Default))
	}

	if len(c.Token) > 0 {
		if len(c.Account) > 0 {
			body.Add(form.FormatKey(append(keyParts, "external_account")), c.Token)
		} else {
			body.Add(form.FormatKey(append(keyParts, cardSource)), c.Token)
		}
	}

	if len(c.Number) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "object")), "card")
		body.Add(form.FormatKey(append(keyParts, cardSource, "number")), c.Number)
	}

	if len(c.CVC) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "cvc")), c.CVC)
	}

	if len(c.Currency) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "currency")), c.Currency)
	}

	if c.Default {
		body.Add(form.FormatKey(append(keyParts, cardSource, "default_for_currency")), strconv.FormatBool(c.Default))
	}

	if len(c.Month) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "exp_month")), c.Month)
	}

	if len(c.Year) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "exp_year")), c.Year)
	}

	if len(c.Name) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "name")), c.Name)
	}

	if len(c.Address1) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_line1")), c.Address1)
	}

	if len(c.Address2) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_line2")), c.Address2)
	}

	if len(c.City) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_city")), c.City)
	}

	if len(c.State) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_state")), c.State)
	}

	if len(c.Zip) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_zip")), c.Zip)
	}

	if len(c.Country) > 0 {
		body.Add(form.FormatKey(append(keyParts, cardSource, "address_country")), c.Country)
	}
}

// CardListParams is the set of parameters that can be used when listing cards.
// For more details see https://stripe.com/docs/api#list_cards.
type CardListParams struct {
	ListParams `form:"*"`
	Account    string `form:"-"`
	Customer   string `form:"-"`
	Recipient  string `form:"-"`
}

// Card is the resource representing a Stripe credit/debit card.
// For more details see https://stripe.com/docs/api#cards.
type Card struct {
	Address1      string       `json:"address_line1"`
	Address1Check Verification `json:"address_line1_check"`
	Address2      string       `json:"address_line2"`
	Brand         CardBrand    `json:"brand"`
	CVCCheck      Verification `json:"cvc_check"`
	CardCountry   string       `json:"country"`
	City          string       `json:"address_city"`
	Country       string       `json:"address_country"`
	Currency      Currency     `json:"currency"`
	Customer      *Customer    `json:"customer"`
	Default       bool         `json:"default_for_currency"`
	Deleted       bool         `json:"deleted"`

	// Description is a succinct summary of the card's information.
	//
	// Please note that this field is for internal use only and is not returned
	// as part of standard API requests.
	Description string `json:"description"`

	DynLastFour string      `json:"dynamic_last4"`
	Fingerprint string      `json:"fingerprint"`
	Funding     CardFunding `json:"funding"`
	ID          string      `json:"id"`

	// IIN is the card's "Issuer Identification Number".
	//
	// Please note that this field is for internal use only and is not returned
	// as part of standard API requests.
	IIN string `json:"iin"`

	// Issuer is a bank or financial institution that provides the card.
	//
	// Please note that this field is for internal use only and is not returned
	// as part of standard API requests.
	Issuer string `json:"issuer"`

	LastFour           string             `json:"last4"`
	Meta               map[string]string  `json:"metadata"`
	Month              uint8              `json:"exp_month"`
	Name               string             `json:"name"`
	Recipient          *Recipient         `json:"recipient"`
	State              string             `json:"address_state"`
	ThreeDSecure       *ThreeDSecure      `json:"three_d_secure"`
	TokenizationMethod TokenizationMethod `json:"tokenization_method"`
	Year               uint16             `json:"exp_year"`
	Zip                string             `json:"address_zip"`
	ZipCheck           Verification       `json:"address_zip_check"`
}

// CardList is a list object for cards.
type CardList struct {
	ListMeta
	Values []*Card `json:"data"`
}

// UnmarshalJSON handles deserialization of a Card.
// This custom unmarshaling is needed because the resulting
// property may be an id or the full struct if it was expanded.
func (c *Card) UnmarshalJSON(data []byte) error {
	type card Card
	var cc card
	err := json.Unmarshal(data, &cc)
	if err == nil {
		*c = Card(cc)
	} else {
		// the id is surrounded by "\" characters, so strip them
		c.ID = string(data[1 : len(data)-1])
	}

	return nil
}
<|endoftext|>


<commit_before>package config

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

func castBool(v interface{}) (bool, error) {
	if x, ok := v.(string); ok {
		o, err := strconv.ParseBool(x)

		if err != nil {
			return false, err
		}

		return o, nil
	}

	b, ok := v.(bool)
	if !ok {
		return false, errors.New("unable to cast")
	}

	return b, nil
}

func castFloat(v interface{}) (float64, error) {
	if x, ok := v.(string); ok {
		o, err := strconv.ParseFloat(x, 64)

		if err != nil {
			return 0.0, err
		}

		return o, nil
	}

	f, ok := v.(float64)
	if !ok {
		return 0.0, fmt.Errorf("unable to cast %T", v)
	}

	return f, nil
}

func castInt(v interface{}) (int, error) {
	if x, ok := v.(string); ok {
		o, err := strconv.Atoi(x)

		if err != nil {
			return 0, err
		}

		return o, nil
	}

	if f, ok := v.(float64); ok {
		return int(f), nil
	}

	if f, ok := v.(int); ok {
		return int(f), nil
	}

	return 0, fmt.Errorf("unable to cast %T", v)
}

func castList(v interface{}) ([]string, error) {
	if x, ok := v.(string); ok {
		l := strings.Split(x, ",")

		for i, p := range l {
			l[i] = strings.TrimSpace(p)
		}

		return l, nil
	}

	switch v.(type) {
	case []interface{}:
		v := v.([]interface{})
		result := make([]string, len(v))
		for i, item := range v {
			result[i] = toString(item)
		}
		return result, nil
	case []string:
		return v.([]string), nil
	}

	return []string{}, nil
}

func castString(v interface{}) (string, error) {
	f, ok := v.(string)
	if !ok {
		return "", fmt.Errorf("unable to cast %T", v)
	}

	return f, nil
}

func castUint(v interface{}) (uint, error) {
	if x, ok := v.(string); ok {
		o, err := strconv.ParseUint(x, 10, 64)

		if err != nil {
			return 0, err
		}

		return uint(o), nil
	}

	if f, ok := v.(float64); ok {
		return uint(f), nil
	}

	if f, ok := v.(int); ok {
		return uint(f), nil
	}

	return 0, fmt.Errorf("unable to cast %T", v)
}
<commit_msg>Fix int and uint cast<commit_after>package config

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

func castBool(v interface{}) (bool, error) {
	if x, ok := v.(string); ok {
		o, err := strconv.ParseBool(x)

		if err != nil {
			return false, err
		}

		return o, nil
	}

	b, ok := v.(bool)
	if !ok {
		return false, errors.New("unable to cast")
	}

	return b, nil
}

func castFloat(v interface{}) (float64, error) {
	if x, ok := v.(string); ok {
		o, err := strconv.ParseFloat(x, 64)

		if err != nil {
			return 0.0, err
		}

		return o, nil
	}

	f, ok := v.(float64)
	if !ok {
		return 0.0, fmt.Errorf("unable to cast %T", v)
	}

	return f, nil
}

func castInt(v interface{}) (int, error) {
	if x, ok := v.(string); ok {
		o, err := strconv.Atoi(x)

		if err != nil {
			return 0, err
		}

		return o, nil
	}

	if f, ok := v.(float64); ok {
		return int(f), nil
	}

	if f, ok := v.(int64); ok {
		return int(f), nil
	}

	return 0, fmt.Errorf("unable to cast %T", v)
}

func castList(v interface{}) ([]string, error) {
	if x, ok := v.(string); ok {
		l := strings.Split(x, ",")

		for i, p := range l {
			l[i] = strings.TrimSpace(p)
		}

		return l, nil
	}

	switch v.(type) {
	case []interface{}:
		v := v.([]interface{})
		result := make([]string, len(v))
		for i, item := range v {
			result[i] = toString(item)
		}
		return result, nil
	case []string:
		return v.([]string), nil
	}

	return []string{}, nil
}

func castString(v interface{}) (string, error) {
	f, ok := v.(string)
	if !ok {
		return "", fmt.Errorf("unable to cast %T", v)
	}

	return f, nil
}

func castUint(v interface{}) (uint, error) {
	if x, ok := v.(string); ok {
		o, err := strconv.ParseUint(x, 10, 64)

		if err != nil {
			return 0, err
		}

		return uint(o), nil
	}

	if f, ok := v.(float64); ok {
		return uint(f), nil
	}

	if f, ok := v.(int64); ok {
		return uint(f), nil
	}

	return 0, fmt.Errorf("unable to cast %T", v)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package process

import (
	"errors"
	"log"
	"os/exec"
	"strconv"
	"strings"
	"testing"
	"time"

	"k8s.io/test-infra/kubetest/util"
)

var suite util.TestSuite

func TestXmlWrap(t *testing.T) {
	cases := []struct {
		name            string
		interrupted     bool
		shouldInterrupt bool
		err             string
		expectSkipped   bool
		expectError     bool
	}{
		{
			name: "xmlWrap can pass",
		},
		{
			name:        "xmlWrap can error",
			err:         "hello there",
			expectError: true,
		},
		{
			name:            "xmlWrap always errors on interrupt",
			err:             "",
			shouldInterrupt: true,
			expectError:     true,
		},
		{
			name:            "xmlWrap errors on interrupt",
			shouldInterrupt: true,
			err:             "the step failed",
			expectError:     true,
		},
		{
			name:          "xmlWrap skips errors when already interrupted",
			interrupted:   true,
			err:           "this failed because we interrupted the previous step",
			expectSkipped: true,
		},
		{
			name:        "xmlWrap can pass when interrupted",
			interrupted: true,
			err:         "",
		},
	}

	for _, tc := range cases {
		interrupt := time.NewTimer(time.Duration(0))
		terminate := time.NewTimer(time.Duration(0))
		c := NewControl(time.Duration(0), interrupt, terminate, false)
		c.interrupted = tc.interrupted
		suite.Cases = suite.Cases[:0]
		suite.Failures = 6
		suite.Tests = 9
		err := c.XmlWrap(&suite, tc.name, func() error {
			if tc.shouldInterrupt {
				c.interrupted = true
			}
			if tc.err != "" {
				return errors.New(tc.err)
			}
			return nil
		})

		if tc.shouldInterrupt && tc.expectError {
			if err == nil {
				t.Fatalf("Case %s did not error", tc.name)
			}
			if tc.err == "" {
				tc.err = err.Error()
			}
		}
		if (tc.err == "") != (err == nil) {
			t.Errorf("Case %s expected err: %s != actual: %v", tc.name, tc.err, err)
		}
		if tc.shouldInterrupt && !c.interrupted {
			t.Errorf("Case %s did not interrupt", tc.name)
		}
		if len(suite.Cases) != 1 {
			t.Fatalf("Case %s did not result in a single suite testcase: %v", tc.name, suite.Cases)
		}

		sc := suite.Cases[0]
		if sc.Name != tc.name {
			t.Errorf("Case %s resulted in wrong test case name %s", tc.name, sc.Name)
		}
		if tc.expectError {
			if sc.Failure != tc.err {
				t.Errorf("Case %s expected error %s but got %s", tc.name, tc.err, sc.Failure)
			}
			if suite.Failures != 7 {
				t.Errorf("Case %s failed and should increase suite failures from 6 to 7, found: %d", tc.name, suite.Failures)
			}
		} else if tc.expectSkipped {
			if sc.Skipped != tc.err {
				t.Errorf("Case %s expected skipped %s but got %s", tc.name, tc.err, sc.Skipped)
			}
			if suite.Failures != 7 {
				t.Errorf("Case %s interrupted and increase suite failures from 6 to 7, found: %d", tc.name, suite.Failures)
			}
		} else {
			if suite.Failures != 6 {
				t.Errorf("Case %s passed so suite failures should remain at 6, found: %d", tc.name, suite.Failures)
			}
		}

	}
}

func TestOutput(t *testing.T) {
	cases := []struct {
		name              string
		terminated        bool
		interrupted       bool
		causeTermination  bool
		causeInterruption bool
		pass              bool
		sleep             int
		output            bool
		shouldError       bool
		shouldInterrupt   bool
		shouldTerminate   bool
	}{
		{
			name: "finishRunning can pass",
			pass: true,
		},
		{
			name:   "output can pass",
			output: true,
			pass:   true,
		},
		{
			name:        "finishRuning can fail",
			pass:        false,
			shouldError: true,
		},
		{
			name:        "output can fail",
			pass:        false,
			output:      true,
			shouldError: true,
		},
		{
			name:        "finishRunning should error when terminated",
			terminated:  true,
			pass:        true,
			shouldError: true,
		},
		{
			name:        "output should error when terminated",
			terminated:  true,
			pass:        true,
			output:      true,
			shouldError: true,
		},
		{
			name:              "finishRunning should interrupt when interrupted",
			pass:              true,
			sleep:             60,
			causeInterruption: true,
			shouldError:       true,
		},
		{
			name:              "output should interrupt when interrupted",
			pass:              true,
			sleep:             60,
			output:            true,
			causeInterruption: true,
			shouldError:       true,
		},
		{
			name:             "output should terminate when terminated",
			pass:             true,
			sleep:            60,
			output:           true,
			causeTermination: true,
			shouldError:      true,
		},
		{
			name:             "finishRunning should terminate when terminated",
			pass:             true,
			sleep:            60,
			causeTermination: true,
			shouldError:      true,
		},
	}

	clearTimers := func(c *Control) {
		if !c.Terminate.Stop() {
			<-c.Terminate.C
		}
		if !c.Interrupt.Stop() {
			<-c.Interrupt.C
		}
	}

	for _, tc := range cases {
		log.Println(tc.name)
		interrupt := time.NewTimer(time.Duration(0))
		terminate := time.NewTimer(time.Duration(0))
		c := NewControl(time.Duration(0), interrupt, terminate, false)
		c.terminated = tc.terminated
		c.interrupted = tc.interrupted
		clearTimers(c)
		if tc.causeInterruption {
			interrupt.Reset(0)
		}
		if tc.causeTermination {
			terminate.Reset(0)
		}
		var cmd *exec.Cmd
		if !tc.pass {
			cmd = exec.Command("false")
		} else if tc.sleep == 0 {
			cmd = exec.Command("true")
		} else {
			cmd = exec.Command("sleep", strconv.Itoa(tc.sleep))
		}
		var err error
		if tc.output {
			_, err = c.Output(cmd)
		} else {
			err = c.FinishRunning(cmd)
		}
		if err == nil == tc.shouldError {
			t.Errorf("Step %s shouldError=%v error: %v", tc.name, tc.shouldError, err)
		}
		if tc.causeInterruption && !c.interrupted {
			t.Errorf("Step %s did not interrupt, err: %v", tc.name, err)
		} else if tc.causeInterruption && !terminate.Reset(0) {
			t.Errorf("Step %s did not reset the terminate timer: %v", tc.name, err)
		}
		if tc.causeTermination && !c.terminated {
			t.Errorf("Step %s did not terminate, err: %v", tc.name, err)
		}
	}
}

func TestFinishRunningParallel(t *testing.T) {
	cases := []struct {
		name              string
		terminated        bool
		interrupted       bool
		causeTermination  bool
		causeInterruption bool
		cmds              []*exec.Cmd
		shouldError       bool
		shouldInterrupt   bool
		shouldTerminate   bool
	}{
		{
			name: "finishRunningParallel with single command can pass",
			cmds: []*exec.Cmd{exec.Command("true")},
		},
		{
			name: "finishRunningParallel with multiple commands can pass",
			cmds: []*exec.Cmd{exec.Command("true"), exec.Command("true")},
		},
		{
			name:        "finishRunningParallel with single command can fail",
			cmds:        []*exec.Cmd{exec.Command("false")},
			shouldError: true,
		},
		{
			name:        "finishRunningParallel with multiple commands can fail",
			cmds:        []*exec.Cmd{exec.Command("true"), exec.Command("false")},
			shouldError: true,
		},
		{
			name:        "finishRunningParallel should error when terminated",
			cmds:        []*exec.Cmd{exec.Command("true"), exec.Command("true")},
			terminated:  true,
			shouldError: true,
		},
		{
			name:              "finishRunningParallel should interrupt when interrupted",
			cmds:              []*exec.Cmd{exec.Command("true"), exec.Command("sleep", "60"), exec.Command("sleep", "30")},
			causeInterruption: true,
			shouldError:       true,
		},
		{
			name:             "finishRunningParallel should terminate when terminated",
			cmds:             []*exec.Cmd{exec.Command("true"), exec.Command("sleep", "60"), exec.Command("sleep", "30")},
			causeTermination: true,
			shouldError:      true,
		},
	}

	clearTimers := func(c *Control) {
		if !c.Terminate.Stop() {
			<-c.Terminate.C
		}
		if !c.Interrupt.Stop() {
			<-c.Interrupt.C
		}
	}

	for _, tc := range cases {
		log.Println(tc.name)
		interrupt := time.NewTimer(time.Duration(0))
		terminate := time.NewTimer(time.Duration(0))
		c := NewControl(time.Duration(0), interrupt, terminate, false)
		c.terminated = tc.terminated
		c.interrupted = tc.interrupted
		clearTimers(c)
		if tc.causeInterruption {
			interrupt.Reset(1 * time.Second)
		}
		if tc.causeTermination {
			terminate.Reset(1 * time.Second)
		}

		err := c.FinishRunningParallel(tc.cmds...)
		if err == nil == tc.shouldError {
			t.Errorf("TC %q shouldError=%v error: %v", tc.name, tc.shouldError, err)
		}
		if tc.causeInterruption && !c.interrupted {
			t.Errorf("TC %q did not interrupt, err: %v", tc.name, err)
		} else if tc.causeInterruption && !terminate.Reset(0) {
			t.Errorf("TC %q did not reset the terminate timer: %v", tc.name, err)
		}
		if tc.causeTermination && !c.terminated {
			t.Errorf("TC %q did not terminate, err: %v", tc.name, err)
		}
	}
}

func TestOutputOutputs(t *testing.T) {
	interrupt := time.NewTimer(time.Duration(0))
	terminate := time.NewTimer(time.Duration(0))
	c := NewControl(time.Duration(0), interrupt, terminate, false)

	b, err := c.Output(exec.Command("echo", "hello world"))
	txt := string(b)
	if err != nil {
		t.Fatalf("failed to echo: %v", err)
	}
	if !strings.Contains(txt, "hello world") {
		t.Errorf("output() did not echo hello world: %v", txt)
	}
}
<commit_msg>Make testing race condition less likely<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package process

import (
	"errors"
	"log"
	"os/exec"
	"strconv"
	"strings"
	"testing"
	"time"

	"k8s.io/test-infra/kubetest/util"
)

var suite util.TestSuite

func TestXmlWrap(t *testing.T) {
	cases := []struct {
		name            string
		interrupted     bool
		shouldInterrupt bool
		err             string
		expectSkipped   bool
		expectError     bool
	}{
		{
			name: "xmlWrap can pass",
		},
		{
			name:        "xmlWrap can error",
			err:         "hello there",
			expectError: true,
		},
		{
			name:            "xmlWrap always errors on interrupt",
			err:             "",
			shouldInterrupt: true,
			expectError:     true,
		},
		{
			name:            "xmlWrap errors on interrupt",
			shouldInterrupt: true,
			err:             "the step failed",
			expectError:     true,
		},
		{
			name:          "xmlWrap skips errors when already interrupted",
			interrupted:   true,
			err:           "this failed because we interrupted the previous step",
			expectSkipped: true,
		},
		{
			name:        "xmlWrap can pass when interrupted",
			interrupted: true,
			err:         "",
		},
	}

	for _, tc := range cases {
		interrupt := time.NewTimer(time.Duration(0))
		terminate := time.NewTimer(time.Duration(0))
		c := NewControl(time.Duration(0), interrupt, terminate, false)
		c.interrupted = tc.interrupted
		suite.Cases = suite.Cases[:0]
		suite.Failures = 6
		suite.Tests = 9
		err := c.XmlWrap(&suite, tc.name, func() error {
			if tc.shouldInterrupt {
				c.interrupted = true
			}
			if tc.err != "" {
				return errors.New(tc.err)
			}
			return nil
		})

		if tc.shouldInterrupt && tc.expectError {
			if err == nil {
				t.Fatalf("Case %s did not error", tc.name)
			}
			if tc.err == "" {
				tc.err = err.Error()
			}
		}
		if (tc.err == "") != (err == nil) {
			t.Errorf("Case %s expected err: %s != actual: %v", tc.name, tc.err, err)
		}
		if tc.shouldInterrupt && !c.interrupted {
			t.Errorf("Case %s did not interrupt", tc.name)
		}
		if len(suite.Cases) != 1 {
			t.Fatalf("Case %s did not result in a single suite testcase: %v", tc.name, suite.Cases)
		}

		sc := suite.Cases[0]
		if sc.Name != tc.name {
			t.Errorf("Case %s resulted in wrong test case name %s", tc.name, sc.Name)
		}
		if tc.expectError {
			if sc.Failure != tc.err {
				t.Errorf("Case %s expected error %s but got %s", tc.name, tc.err, sc.Failure)
			}
			if suite.Failures != 7 {
				t.Errorf("Case %s failed and should increase suite failures from 6 to 7, found: %d", tc.name, suite.Failures)
			}
		} else if tc.expectSkipped {
			if sc.Skipped != tc.err {
				t.Errorf("Case %s expected skipped %s but got %s", tc.name, tc.err, sc.Skipped)
			}
			if suite.Failures != 7 {
				t.Errorf("Case %s interrupted and increase suite failures from 6 to 7, found: %d", tc.name, suite.Failures)
			}
		} else {
			if suite.Failures != 6 {
				t.Errorf("Case %s passed so suite failures should remain at 6, found: %d", tc.name, suite.Failures)
			}
		}

	}
}

func TestOutput(t *testing.T) {
	cases := []struct {
		name              string
		terminated        bool
		interrupted       bool
		causeTermination  bool
		causeInterruption bool
		pass              bool
		sleep             int
		output            bool
		shouldError       bool
		shouldInterrupt   bool
		shouldTerminate   bool
	}{
		{
			name: "finishRunning can pass",
			pass: true,
		},
		{
			name:   "output can pass",
			output: true,
			pass:   true,
		},
		{
			name:        "finishRuning can fail",
			pass:        false,
			shouldError: true,
		},
		{
			name:        "output can fail",
			pass:        false,
			output:      true,
			shouldError: true,
		},
		{
			name:        "finishRunning should error when terminated",
			terminated:  true,
			pass:        true,
			shouldError: true,
		},
		{
			name:        "output should error when terminated",
			terminated:  true,
			pass:        true,
			output:      true,
			shouldError: true,
		},
		{
			name:              "finishRunning should interrupt when interrupted",
			pass:              true,
			sleep:             60,
			causeInterruption: true,
			shouldError:       true,
		},
		{
			name:              "output should interrupt when interrupted",
			pass:              true,
			sleep:             60,
			output:            true,
			causeInterruption: true,
			shouldError:       true,
		},
		{
			name:             "output should terminate when terminated",
			pass:             true,
			sleep:            60,
			output:           true,
			causeTermination: true,
			shouldError:      true,
		},
		{
			name:             "finishRunning should terminate when terminated",
			pass:             true,
			sleep:            60,
			causeTermination: true,
			shouldError:      true,
		},
	}

	clearTimers := func(c *Control) {
		if !c.Terminate.Stop() {
			<-c.Terminate.C
		}
		if !c.Interrupt.Stop() {
			<-c.Interrupt.C
		}
	}

	for _, tc := range cases {
		log.Println(tc.name)
		interrupt := time.NewTimer(time.Duration(0))
		terminate := time.NewTimer(time.Duration(0))
		c := NewControl(time.Duration(0), interrupt, terminate, false)
		c.terminated = tc.terminated
		c.interrupted = tc.interrupted
		clearTimers(c)
		if tc.causeInterruption {
			interrupt.Reset(0)
		}
		if tc.causeTermination {
			terminate.Reset(0)
		}
		var cmd *exec.Cmd
		if !tc.pass {
			cmd = exec.Command("false")
		} else if tc.sleep == 0 {
			cmd = exec.Command("true")
		} else {
			cmd = exec.Command("sleep", strconv.Itoa(tc.sleep))
		}
		var err error
		if tc.output {
			_, err = c.Output(cmd)
		} else {
			err = c.FinishRunning(cmd)
		}
		if err == nil == tc.shouldError {
			t.Errorf("Step %s shouldError=%v error: %v", tc.name, tc.shouldError, err)
		}
		if tc.causeInterruption && !c.interrupted {
			t.Errorf("Step %s did not interrupt, err: %v", tc.name, err)
		} else if tc.causeInterruption && !terminate.Reset(0) {
			t.Errorf("Step %s did not reset the terminate timer: %v", tc.name, err)
		}
		if tc.causeTermination && !c.terminated {
			t.Errorf("Step %s did not terminate, err: %v", tc.name, err)
		}
	}
}

func TestFinishRunningParallel(t *testing.T) {
	cases := []struct {
		name              string
		terminated        bool
		interrupted       bool
		causeTermination  bool
		causeInterruption bool
		cmds              []*exec.Cmd
		shouldError       bool
		shouldInterrupt   bool
		shouldTerminate   bool
	}{
		{
			name: "finishRunningParallel with single command can pass",
			cmds: []*exec.Cmd{exec.Command("true")},
		},
		{
			name: "finishRunningParallel with multiple commands can pass",
			cmds: []*exec.Cmd{exec.Command("true"), exec.Command("true")},
		},
		{
			name:        "finishRunningParallel with single command can fail",
			cmds:        []*exec.Cmd{exec.Command("false")},
			shouldError: true,
		},
		{
			name:        "finishRunningParallel with multiple commands can fail",
			cmds:        []*exec.Cmd{exec.Command("true"), exec.Command("false")},
			shouldError: true,
		},
		{
			name:        "finishRunningParallel should error when terminated",
			cmds:        []*exec.Cmd{exec.Command("true"), exec.Command("true")},
			terminated:  true,
			shouldError: true,
		},
		{
			name:              "finishRunningParallel should interrupt when interrupted",
			cmds:              []*exec.Cmd{exec.Command("true"), exec.Command("sleep", "60"), exec.Command("sleep", "30")},
			causeInterruption: true,
			shouldError:       true,
		},
		{
			name:             "finishRunningParallel should terminate when terminated",
			cmds:             []*exec.Cmd{exec.Command("true"), exec.Command("sleep", "60"), exec.Command("sleep", "30")},
			causeTermination: true,
			shouldError:      true,
		},
	}

	clearTimers := func(c *Control) {
		if !c.Terminate.Stop() {
			<-c.Terminate.C
		}
		if !c.Interrupt.Stop() {
			<-c.Interrupt.C
		}
	}

	for _, tc := range cases {
		log.Println(tc.name)
		interrupt := time.NewTimer(time.Duration(0))
		terminate := time.NewTimer(time.Duration(0))
		c := NewControl(time.Duration(0), interrupt, terminate, false)
		c.terminated = tc.terminated
		c.interrupted = tc.interrupted
		clearTimers(c)
		if tc.causeInterruption {
			interrupt.Reset(1 * time.Second)
		}
		if tc.causeTermination {
			terminate.Reset(1 * time.Second)
		}

		err := c.FinishRunningParallel(tc.cmds...)
		if err == nil == tc.shouldError {
			t.Errorf("TC %q shouldError=%v error: %v", tc.name, tc.shouldError, err)
		}
		if tc.causeInterruption && !c.interrupted {
			t.Errorf("TC %q did not interrupt, err: %v", tc.name, err)
		} else if tc.causeInterruption && !terminate.Reset(0) {
			t.Errorf("TC %q did not reset the terminate timer: %v", tc.name, err)
		}
		if tc.causeTermination && !c.terminated {
			t.Errorf("TC %q did not terminate, err: %v", tc.name, err)
		}
	}
}

func TestOutputOutputs(t *testing.T) {
	interrupt := time.NewTimer(time.Duration(1) * time.Second)
	terminate := time.NewTimer(time.Duration(1) * time.Second)
	c := NewControl(time.Duration(1)*time.Second, interrupt, terminate, false)

	b, err := c.Output(exec.Command("echo", "hello world"))
	txt := string(b)
	if err != nil {
		t.Fatalf("failed to echo: %v", err)
	}
	if !strings.Contains(txt, "hello world") {
		t.Errorf("output() did not echo hello world: %v", txt)
	}
}
<|endoftext|>


<commit_before>package dokugen

import (
	"log"
	"strconv"
)

type Cell struct {
	grid *Grid
	//The number if it's explicitly set. Number() will return it if it's explicitly or implicitly set.
	number    int
	Row       int
	Col       int
	Block     int
	neighbors []*Cell
}

func NewCell(grid *Grid, row int, col int) Cell {
	//TODO: we should not set the number until neighbors are initialized.
	return Cell{grid, 0, row, col, grid.blockForCell(row, col), nil}
}

func (self *Cell) Load(data string) {
	//Format, for now, is just the number itself, or 0 if no number.
	num, _ := strconv.Atoi(data)
	self.SetNumber(num)
}

func (self *Cell) Number() int {
	//A layer of indirection since number could be set explicitly or implicitly.
	return self.number
}

func (self *Cell) SetNumber(number int) {
	//Sets the explicit number. This will affect its neighbors possibles list (in the future).
	self.number = number
}

func (self *Cell) Neighbors() []*Cell {
	if !self.grid.initalized {
		log.Println("Neighbors called before the grid had been finalized")
		return nil
	}
	if self.neighbors == nil {
		neighborsMap := make(map[*Cell]bool)
		for _, cell := range self.grid.Row(self.Row) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		for _, cell := range self.grid.Col(self.Col) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		for _, cell := range self.grid.Block(self.Block) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		self.neighbors = make([]*Cell, len(neighborsMap))
		i := 0
		for cell, _ := range neighborsMap {
			self.neighbors[i] = cell
			i++
		}
	}
	return self.neighbors

}

func (self *Cell) DataString() string {
	return strconv.Itoa(self.Number())
}

func (self *Cell) String() string {
	return "Cell[" + strconv.Itoa(self.Row) + "][" + strconv.Itoa(self.Col) + "]:" + strconv.Itoa(self.Number()) + "\n"
}
<commit_msg>Added Cell.setPossible, setImpossible, Possible. Not tested.<commit_after>package dokugen

import (
	"log"
	"strconv"
)

type Cell struct {
	grid *Grid
	//The number if it's explicitly set. Number() will return it if it's explicitly or implicitly set.
	number      int
	Row         int
	Col         int
	Block       int
	neighbors   []*Cell
	impossibles [DIM]int
}

func NewCell(grid *Grid, row int, col int) Cell {
	//TODO: we should not set the number until neighbors are initialized.
	return Cell{grid: grid, Row: row, Col: col, Block: grid.blockForCell(row, col)}
}

func (self *Cell) Load(data string) {
	//Format, for now, is just the number itself, or 0 if no number.
	num, _ := strconv.Atoi(data)
	self.SetNumber(num)
}

func (self *Cell) Number() int {
	//A layer of indirection since number could be set explicitly or implicitly.
	return self.number
}

func (self *Cell) SetNumber(number int) {
	//Sets the explicit number. This will affect its neighbors possibles list (in the future).
	self.number = number
}

func (self *Cell) setPossible(number int) {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return
	}
	if self.impossibles[number] == 0 {
		log.Println("We were told to mark something that was already possible to possible.")
		return
	}
	self.impossibles[number]--

}

func (self *Cell) setImpossible(number int) {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return
	}
	self.impossibles[number]++
}

func (self *Cell) Possible(number int) bool {
	//Number is 1 indexed, but we store it as 0-indexed
	number--
	if number < 0 || number >= DIM {
		return false
	}
	return self.impossibles[number] == 0
}

func (self *Cell) Neighbors() []*Cell {
	if !self.grid.initalized {
		log.Println("Neighbors called before the grid had been finalized")
		return nil
	}
	if self.neighbors == nil {
		neighborsMap := make(map[*Cell]bool)
		for _, cell := range self.grid.Row(self.Row) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		for _, cell := range self.grid.Col(self.Col) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		for _, cell := range self.grid.Block(self.Block) {
			if cell == self {
				continue
			}
			neighborsMap[cell] = true
		}
		self.neighbors = make([]*Cell, len(neighborsMap))
		i := 0
		for cell, _ := range neighborsMap {
			self.neighbors[i] = cell
			i++
		}
	}
	return self.neighbors

}

func (self *Cell) DataString() string {
	return strconv.Itoa(self.Number())
}

func (self *Cell) String() string {
	return "Cell[" + strconv.Itoa(self.Row) + "][" + strconv.Itoa(self.Col) + "]:" + strconv.Itoa(self.Number()) + "\n"
}
<|endoftext|>


<commit_before>package cert

import (
	"crypto/tls"
	"fmt"
	"strings"
	"time"
)

type Certs []*Cert

type Cert struct {
	DomainName string
	CommonName string
	SANs       []string
	Start      string
	End        string
}

func init() {
	loc, err := time.LoadLocation("Asia/Tokyo")
	if err != nil {
		loc = time.FixedZone("Asia/Tokyo", 9*60*60)
	}
	time.Local = loc
}

func NewCerts(s []string) (Certs, error) {
	if len(s) < 1 {
		return nil, fmt.Errorf("ドメイン名をひとつ以上指定してください。")
	}
	certs := Certs{}
	for _, d := range s[:] {
		c, err := NewCert(d)
		if err != nil {
			return nil, err
		}
		certs = append(certs, c)
	}
	return certs, nil
}

func (certs Certs) String() string {
	s := ""
	for _, c := range certs {
		s += c.String()
	}
	return s
}

func (certs Certs) Markdown() string {
	s := ""
	s += "ドメイン名 | 有効期間の開始 | 有効期間の終了 | CN | SANs\n"
	s += "--- | --- | --- | --- | ---\n"
	for _, c := range certs {
		s += c.Markdown()
	}
	return s
}

func NewCert(d string) (*Cert, error) {
	conn, err := tls.Dial("tcp", d+":443", &tls.Config{})
	if err != nil {
		return nil, err
	}
	cert := conn.ConnectionState().PeerCertificates[0]
	conn.Close()
	return &Cert{
		DomainName: d,
		CommonName: cert.Subject.CommonName,
		SANs:       cert.DNSNames,
		Start:      cert.NotBefore.In(time.Local).Format("2006/01/02 15:04:05"),
		End:        cert.NotAfter.In(time.Local).Format("2006/01/02 15:04:05"),
	}, nil
}

func (c *Cert) String() string {
	s := ""
	s += fmt.Sprintf("DomainName: %s\n", c.DomainName)
	s += fmt.Sprintf("Start: %s\n", c.Start)
	s += fmt.Sprintf("End: %s\n", c.End)
	s += fmt.Sprintf("CommonName: %s\n", c.CommonName)
	s += fmt.Sprintf("SANs: %s\n", strings.Join(c.SANs, " "))
	s += fmt.Sprintln()
	return s
}

func (c *Cert) Markdown() string {
	s := ""
	s += fmt.Sprintf("%s | %s | %s | %s | %s\n", c.DomainName, c.Start, c.End, c.CommonName, strings.Join(c.SANs, "
"))
	return s
}
<commit_msg>Will use text/template<commit_after>package cert

import (
	"crypto/tls"
	"fmt"
	"strings"
	"time"
)

type Certs []*Cert

type Cert struct {
	DomainName string
	CommonName string
	SANs       []string
	Start      string
	End        string
}

func init() {
	loc, err := time.LoadLocation("Asia/Tokyo")
	if err != nil {
		loc = time.FixedZone("Asia/Tokyo", 9*60*60)
	}
	time.Local = loc
}

func NewCerts(s []string) (Certs, error) {
	if len(s) < 1 {
		return nil, fmt.Errorf("ドメイン名をひとつ以上指定してください。")
	}
	certs := Certs{}
	for _, d := range s[:] {
		c, err := NewCert(d)
		if err != nil {
			return nil, err
		}
		certs = append(certs, c)
	}
	return certs, nil
}

func (certs Certs) String() string {
	s := ""
	for _, c := range certs {
		s += c.String()
	}
	return s
}

func (certs Certs) Markdown() string {
	s := ""
	s += "ドメイン名 | 有効期間の開始 | 有効期間の終了 | CN | SANs\n"
	s += "--- | --- | --- | --- | ---\n"
	for _, c := range certs {
		s += c.Markdown()
	}
	return s
}

func NewCert(d string) (*Cert, error) {
	conn, err := tls.Dial("tcp", d+":443", &tls.Config{})
	if err != nil {
		return nil, err
	}
	cert := conn.ConnectionState().PeerCertificates[0]
	conn.Close()
	return &Cert{
		DomainName: d,
		CommonName: cert.Subject.CommonName,
		SANs:       cert.DNSNames,
		Start:      cert.NotBefore.In(time.Local).Format("2006/01/02 15:04:05"),
		End:        cert.NotAfter.In(time.Local).Format("2006/01/02 15:04:05"),
	}, nil
}

func (c *Cert) String() string {
	s := ""
	s += fmt.Sprintf("DomainName: %s\n", c.DomainName)
	s += fmt.Sprintf("Start:      %s\n", c.Start)
	s += fmt.Sprintf("End:        %s\n", c.End)
	s += fmt.Sprintf("CommonName: %s\n", c.CommonName)
	s += fmt.Sprintf("SANs:       %s\n", strings.Join(c.SANs, " "))
	s += fmt.Sprintln()
	return s
}

func (c *Cert) Markdown() string {
	s := ""
	s += fmt.Sprintf("%s | %s | %s | %s | %s\n", c.DomainName, c.Start, c.End, c.CommonName, strings.Join(c.SANs, "
"))
	return s
}
<|endoftext|>


<commit_before>// Implementing Conway's Game Of Life
// ----------------------------------
//
// Using a map for storing the current state of the world.
//
// We are printing the successive populations in a format that can be fed
// to gnuplot and creating in this way an animated view of the population.
//
// This is just an exercise for using maps in go! Do not take this
// too serious...
//
// To see the simulation in gnuplot, call the program like this:
// ./gol.exe | gnuplot --persist

package main

import (
	"flag"
	"fmt"
	"strings"
	"strconv"
	"os"
	"math/rand"
	"runtime"
	"time"
)

// We use as many go routines as workes as there are cores/processors
// in the computer.
var cntWorkers = runtime.NumCPU()

// We are storing the cells (alive or dead) in a map. The keys are the Cartesian
// coordinates of the cells and the values are the properties of the cells,
// namely their state and number of alive neighbours.

// A cell has its state, and its number of life neighbours
type Cell struct {
	alive bool
	n int
}

// The coordinates are plain 2-d cartesian coordinates
type Coord struct {
	x int
	y int
}

// The world is a map of Coord and Cell
type World map[Coord]Cell

// Inflate inflates the world with dead cells surrounding
// the live cells
func (world World) Inflate(inflateChan, neighboursChan chan Coord) World {
	var newWorld World
	newWorld = make(World)

	// Copy the live cells first into the new world
	for coord, cell := range world {
		newWorld[coord] = cell
	}

	// Send the cells of the world to the inflate channel, so
	// the neighbouring coordinates will be produced by the
	// worker goroutines
	go func() {
		for coord := range world {
			inflateChan <- coord
		}
	}()

	// Receive the neighbours in the neighbours channel
	// We are expecting 8 neighbours for each cell,
	// i.e. 9 coordinates for each cell in the map
	for cnt := 0; cnt < 9 * len(world); cnt++ {
		neighbour := <- neighboursChan
		if _, found := newWorld[neighbour]; !found {
			newWorld[neighbour] = Cell{false, 0}
		}
	}

	return newWorld
}

// Deflate deflates the world: only the live cells remain
func (world World) Deflate() World {
	var newWorld World
	newWorld = make(World)

	for coord, cell := range world {
		if cell.alive {
			newWorld[coord] = cell
		}
	}

	return newWorld
}

// CountLiveNeighbours counts for each cell in the world its neighbouring
// alive cells and updates its counter
func (world World) CountLiveNeighbours() World {
	var newWorld World
	newWorld = make(World)

	for coord, cell := range world {
		n := 0
		for i := -1; i < 2; i++ {
			for j := -1; j < 2; j++ {
				c := Coord{coord.x + i, coord.y + j}
				if (i != 0 || j != 0) && world[c].alive {
					n = n+1
				}
			}
		}
		newWorld[coord] = Cell{cell.alive, n}
	}

	return newWorld
}

// ApplyRules applies the rules to each cell of the world. This determines
// the fate of the cell for the next tick.
func (world World) ApplyRules() World {
	var newWorld World
	newWorld = make(World)

	// apply the rules of the game to each cell
	for coord, cell := range world {
		if cell.alive {
			if 1 < cell.n && cell.n < 4 {
				newWorld[coord] = Cell{true, 0}
			}
		} else {
			if cell.n == 3 {
				newWorld[coord] = Cell{true, 0}
			}
		}
	}

	return newWorld
}

// Tick computes the next generation of live cells in the world
func (world World) Tick(inflateChan, neighboursChan chan Coord) World {
	return world.Inflate(inflateChan, neighboursChan).CountLiveNeighbours().ApplyRules().Deflate()
}

// gnuplotHeader prints the header for gnuplot
func gnuplotHeader(d int) {
	fmt.Printf("unset key; set xrange[-%[1]d:%[1]d]\n", d/2)
	fmt.Printf("set yrange[-%[1]d:%[1]d]\n", d/2)
	fmt.Println("set style line 1 lc rgb '#0060ad' pt 7")
}

// gnuplotWorld prints the coordinates of the cells in the world
func gnuplotWorld(world World) {
	fmt.Println("plot '-' with points ls 1")

	for coord := range world {
		fmt.Printf("%d, %d\n", coord.x, coord.y)
	}

	fmt.Println("e")
}

func main() {
	// Handle the command line arguments
	ticks, size, pattern := handleCommandLine()

	start := time.Now()

	// Setup the communication channels for the goroutines
	inflateChan := make(chan Coord, cntWorkers)
	neighboursChan := make(chan Coord)

	// Setup the worker goroutines that consume the inflate channel
	// and generate the neighbouring coordinates writing them to the
	// neighbours channel
	for i := 0; i < cntWorkers; i++ {
		go func() {
			for coord := range inflateChan {
				for i := -1; i < 2; i++ {
					for j := -1; j < 2; j++ {
						neighboursChan <- Coord{coord.x + i, coord.y + j}
					}
				}
			}
		}()
	}

	// The world
	var world World
	world = make(World)

	for _, coord := range pattern {
		world[coord] = Cell{true, 0}
	}

	gnuplotHeader(size)

	gnuplotWorld(world)

	for i := 0; i < ticks; i++ {
		world = world.Tick(inflateChan, neighboursChan)
		gnuplotWorld(world)
	}

	elapsed := time.Since(start)
	fmt.Printf("Elapsed: %s", elapsed)
}

func handleCommandLine() (ticks, size int, pattern []Coord) {
	// Define our own usage message, overwriting the default one
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, "Usage: cgol [flags] [pattern] | gnuplot --persist\n")
		flag.PrintDefaults()
	}

	// Define the command line flags
	flag.IntVar(&ticks, "ticks", 10, "number of iterations running the game")
	flag.IntVar(&size, "size", 50, "size of the visible world in x and y direction")
	var random *bool = flag.Bool("random", false, "generate a random pattern to start with")
	var coordinatesOpt *string = flag.String("coordinates", "1,0;0,1;1,1;1,2;2,2", "semi-colon-separated list of coordinates")
	flag.Parse()

	// Create a ranodm starting pattern or use the r-pentomino pattern
	if *random {
		// Generate a random pattern
		//pattern = make([]Coord, size*size/5, size*size)
		pattern = []Coord{}
		rand.Seed(42)
		for i := 0; i < size; i++ {
			for j := 0; j < size; j++ {
				if rand.Intn(100) < 20 {
					pattern = append(pattern, Coord{i, j})
				}
			}
		}
	} else {
		coordinates := strings.Split(*coordinatesOpt, ";")
		pattern = make([]Coord, len(coordinates))
		for idx := range coordinates {
			xy := strings.Split(coordinates[idx], ",")
			x, err := strconv.Atoi(xy[0])
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			y, err := strconv.Atoi(xy[1])
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			pattern[idx] = Coord{x, y}
		}
	}

	return ticks, size, pattern
}
<commit_msg>Returned to create workers locally in the inflate function<commit_after>// Implementing Conway's Game Of Life
// ----------------------------------
//
// Using a map for storing the current state of the world.
//
// We are printing the successive populations in a format that can be fed
// to gnuplot and creating in this way an animated view of the population.
//
// This is just an exercise for using maps in go! Do not take this
// too serious...
//
// To see the simulation in gnuplot, call the program like this:
// ./gol.exe | gnuplot --persist

package main

import (
	"flag"
	"fmt"
	"strings"
	"strconv"
	"os"
	"math/rand"
	"runtime"
	"time"
)

// We use as many go routines as workes as there are cores/processors
// in the computer.
var cntWorkers = runtime.NumCPU()

// We are storing the cells (alive or dead) in a map. The keys are the Cartesian
// coordinates of the cells and the values are the properties of the cells,
// namely their state and number of alive neighbours.

// A cell has its state, and its number of life neighbours
type Cell struct {
	alive bool
	n int
}

// The coordinates are plain 2-d cartesian coordinates
type Coord struct {
	x int
	y int
}

// The world is a map of Coord and Cell
type World map[Coord]Cell

// Inflate inflates the world with dead cells surrounding
// the live cells
func (world World) Inflate() World {
	// Setup the communication channels for the goroutines
	coordsChan := make(chan Coord, cntWorkers)
	neighboursChan := make(chan Coord, len(world)*9)
	doneChan := make(chan struct{}, cntWorkers)

	var newWorld World
	newWorld = make(World)

	// Copy the live cells first into the new world
	for coord, cell := range world {
		newWorld[coord] = cell
	}

	// Send the cells of the world to the coords channel, so
	// the neighbouring coordinates will be produced by the
	// worker goroutines
	go func() {
		for coord := range world {
			coordsChan <- coord
		}
		close(coordsChan)
	}()

	// Setup the worker goroutines that consume the coords channel
	// and generate the neighbouring coordinates
	for i := 0; i < cntWorkers; i++ {
		go func() {
			for coord := range coordsChan {
				for i := -1; i < 2; i++ {
					for j := -1; j < 2; j++ {
						neighboursChan <- Coord{coord.x + i, coord.y + j}
					}
				}
			}
			doneChan <- struct{}{}
		}()
	}

    // Wait for the completion of all worker goroutines, and
    // then close the neighbours channel
    go func() {
        for i := 0; i < cntWorkers; i++ {
            <-doneChan
        }
        close(neighboursChan)
    }()

	// Receive the neighbours in the neighbours channel
	for neighbour := range neighboursChan {
		if _, found := newWorld[neighbour]; !found {
			newWorld[neighbour] = Cell{false, 0}
		}
	}

	return newWorld
}

// Deflate deflates the world: only the live cells remain
func (world World) Deflate() World {
	var newWorld World
	newWorld = make(World)

	for coord, cell := range world {
		if cell.alive {
			newWorld[coord] = cell
		}
	}

	return newWorld
}

// CountLiveNeighbours counts for each cell in the world its neighbouring
// alive cells and updates its counter
func (world World) CountLiveNeighbours() World {
	var newWorld World
	newWorld = make(World)

	for coord, cell := range world {
		n := 0
		for i := -1; i < 2; i++ {
			for j := -1; j < 2; j++ {
				c := Coord{coord.x + i, coord.y + j}
				if (i != 0 || j != 0) && world[c].alive {
					n = n+1
				}
			}
		}
		newWorld[coord] = Cell{cell.alive, n}
	}

	return newWorld
}

// ApplyRules applies the rules to each cell of the world. This determines
// the fate of the cell for the next tick.
func (world World) ApplyRules() World {
	var newWorld World
	newWorld = make(World)

	// apply the rules of the game to each cell
	for coord, cell := range world {
		if cell.alive {
			if 1 < cell.n && cell.n < 4 {
				newWorld[coord] = Cell{true, 0}
			}
		} else {
			if cell.n == 3 {
				newWorld[coord] = Cell{true, 0}
			}
		}
	}

	return newWorld
}

// Tick computes the next generation of live cells in the world
func (world World) Tick() World {
	return world.Inflate().CountLiveNeighbours().ApplyRules().Deflate()
}

// gnuplotHeader prints the header for gnuplot
func gnuplotHeader(d int) {
	fmt.Printf("unset key; set xrange[-%[1]d:%[1]d]\n", d/2)
	fmt.Printf("set yrange[-%[1]d:%[1]d]\n", d/2)
	fmt.Println("set style line 1 lc rgb '#0060ad' pt 7")
}

// gnuplotWorld prints the coordinates of the cells in the world
func gnuplotWorld(world World) {
	fmt.Println("plot '-' with points ls 1")

	for coord := range world {
		fmt.Printf("%d, %d\n", coord.x, coord.y)
	}

	fmt.Println("e")
}

func main() {
	// Handle the command line arguments
	ticks, size, pattern := handleCommandLine()

//	start := time.Now()

	// The world
	var world World
	world = make(World)

	for _, coord := range pattern {
		world[coord] = Cell{true, 0}
	}

	gnuplotHeader(size)

	gnuplotWorld(world)

	for i := 0; i < ticks; i++ {
		world = world.Tick()
		gnuplotWorld(world)
	}

	//elapsed := time.Since(start)
	//fmt.Printf("Elapsed: %s", elapsed)
}

func handleCommandLine() (ticks, size int, pattern []Coord) {
	// Define our own usage message, overwriting the default one
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, "Usage: cgol [flags] [pattern] | gnuplot --persist\n")
		flag.PrintDefaults()
	}

	// Define the command line flags
	flag.IntVar(&ticks, "ticks", 10, "number of iterations running the game")
	flag.IntVar(&size, "size", 50, "size of the visible world in x and y direction")
	var random *bool = flag.Bool("random", false, "generate a random pattern to start with")
	var coordinatesOpt *string = flag.String("coordinates", "1,0;0,1;1,1;1,2;2,2", "semi-colon-separated list of coordinates")
	flag.Parse()

	// Create a ranodm starting pattern or use the r-pentomino pattern
	if *random {
		// Generate a random pattern
		pattern = []Coord{}
		rand.Seed(time.Now().UTC().UnixNano())
		for i := 0; i < size; i++ {
			for j := 0; j < size; j++ {
				if rand.Intn(100) < 20 {
					pattern = append(pattern, Coord{i -size/2, j - size/2})
				}
			}
		}
	} else {
		coordinates := strings.Split(*coordinatesOpt, ";")
		pattern = make([]Coord, len(coordinates))
		for idx := range coordinates {
			xy := strings.Split(coordinates[idx], ",")
			x, err := strconv.Atoi(xy[0])
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			y, err := strconv.Atoi(xy[1])
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			pattern[idx] = Coord{x, y}
		}
	}

	return ticks, size, pattern
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"os"
	"strings"
)

var (
	gCmdWords = []string{"set", "map", "cmd"}
	gOptWords = []string{
		"preview",
		"nopreview",
		"hidden",
		"nohidden",
		"tabstop",
		"scrolloff",
		"sortby",
		"showinfo",
		"opener",
		"ratios",
	}
)

func matchWord(s string, words []string) string {
	var match string

	for _, w := range words {
		if strings.HasPrefix(w, s) {
			if match != "" {
				return s
			}
			match = w
		}
	}

	if match != "" {
		return match + " "
	}

	return s
}

func matchExec(s string) string {
	var match string

	paths := strings.Split(envPath, ":")

	for _, p := range paths {
		fi, err := ioutil.ReadDir(p)
		if err != nil {
			log.Print(err)
		}

		for _, f := range fi {
			if strings.HasPrefix(f.Name(), s) {
				if !f.Mode().IsRegular() || f.Mode()&0111 == 0 {
					continue
				}
				if match != "" {
					return s
				}
				match = f.Name()
			}
		}
	}

	if match != "" {
		return match + " "
	}

	return s
}

func matchFile(s string) string {
	var match string

	wd, err := os.Getwd()
	if err != nil {
		log.Print(err)
	}

	fi, err := ioutil.ReadDir(wd)
	if err != nil {
		log.Print(err)
	}

	for _, f := range fi {
		if strings.HasPrefix(f.Name(), s) {
			if match != "" {
				return s
			}
			match = f.Name()
		}
	}

	if match != "" {
		return match + " "
	}

	return s
}

func compCmd(acc []rune) []rune {
	if len(acc) == 0 || acc[len(acc)-1] == ' ' {
		return acc
	}

	s := string(acc)
	f := strings.Fields(s)

	switch len(f) {
	case 0: // do nothing
	case 1:
		words := gCmdWords
		for c, _ := range gOpts.cmds {
			words = append(words, c)
		}
		return []rune(matchWord(s, words))
	default:
		switch f[0] {
		case "set":
			opt := matchWord(f[1], gOptWords)
			ret := []rune(f[0])
			ret = append(ret, ' ')
			ret = append(ret, []rune(opt)...)
			return ret
		case "map", "cmd": // do nothing
		default:
			ret := []rune(f[0])
			ret = append(ret, ' ')
			for i := 1; i < len(f); i++ {
				name := matchFile(f[i])
				ret = append(ret, []rune(name)...)
			}
			return ret
		}
	}

	return acc
}

func compShell(acc []rune) []rune {
	if len(acc) == 0 || acc[len(acc)-1] == ' ' {
		return acc
	}

	s := string(acc)
	f := strings.Fields(s)

	switch len(f) {
	case 0: // do nothing
	case 1:
		return []rune(matchExec(s))
	default:
		ret := []rune(f[0])
		ret = append(ret, ' ')
		for i := 1; i < len(f); i++ {
			name := matchFile(f[i])
			ret = append(ret, []rune(name)...)
		}
		return ret
	}

	return acc
}
<commit_msg>longest match completion for multiple match<commit_after>package main

import (
	"io/ioutil"
	"log"
	"os"
	"strings"
)

var (
	gCmdWords = []string{"set", "map", "cmd"}
	gOptWords = []string{
		"preview",
		"nopreview",
		"preview!",
		"hidden",
		"nohidden",
		"hidden!",
		"tabstop",
		"scrolloff",
		"sortby",
		"showinfo",
		"opener",
		"ratios",
	}
)

func matchLongest(s1, s2 string) string {
	i := 0
	for ; i < len(s1) && i < len(s2); i++ {
		if s1[i] != s2[i] {
			break
		}
	}
	return s1[:i]
}

func matchWord(s string, words []string) string {
	var match string

	for _, w := range words {
		if strings.HasPrefix(w, s) {
			if match != "" {
				match = matchLongest(match, w)
			} else {
				match = w + " "
			}
		}
	}

	if match != "" {
		return match
	}

	return s
}

func matchExec(s string) string {
	var match string

	paths := strings.Split(envPath, ":")

	for _, p := range paths {
		fi, err := ioutil.ReadDir(p)
		if err != nil {
			log.Print(err)
		}

		for _, f := range fi {
			if strings.HasPrefix(f.Name(), s) {
				if !f.Mode().IsRegular() || f.Mode()&0111 == 0 {
					continue
				}
				if match != "" {
					match = matchLongest(match, f.Name())
				} else {
					match = f.Name() + " "
				}
			}
		}
	}

	if match != "" {
		return match
	}

	return s
}

func matchFile(s string) string {
	var match string

	wd, err := os.Getwd()
	if err != nil {
		log.Print(err)
	}

	fi, err := ioutil.ReadDir(wd)
	if err != nil {
		log.Print(err)
	}

	for _, f := range fi {
		if strings.HasPrefix(f.Name(), s) {
			if match != "" {
				match = matchLongest(match, f.Name())
			} else {
				match = f.Name() + " "
			}
		}
	}

	if match != "" {
		return match
	}

	return s
}

func compCmd(acc []rune) []rune {
	if len(acc) == 0 || acc[len(acc)-1] == ' ' {
		return acc
	}

	s := string(acc)
	f := strings.Fields(s)

	switch len(f) {
	case 0: // do nothing
	case 1:
		words := gCmdWords
		for c, _ := range gOpts.cmds {
			words = append(words, c)
		}
		return []rune(matchWord(s, words))
	default:
		switch f[0] {
		case "set":
			opt := matchWord(f[1], gOptWords)
			ret := []rune(f[0])
			ret = append(ret, ' ')
			ret = append(ret, []rune(opt)...)
			return ret
		case "map", "cmd": // do nothing
		default:
			ret := []rune(f[0])
			ret = append(ret, ' ')
			for i := 1; i < len(f); i++ {
				name := matchFile(f[i])
				ret = append(ret, []rune(name)...)
			}
			return ret
		}
	}

	return acc
}

func compShell(acc []rune) []rune {
	if len(acc) == 0 || acc[len(acc)-1] == ' ' {
		return acc
	}

	s := string(acc)
	f := strings.Fields(s)

	switch len(f) {
	case 0: // do nothing
	case 1:
		return []rune(matchExec(s))
	default:
		ret := []rune(f[0])
		ret = append(ret, ' ')
		for i := 1; i < len(f); i++ {
			name := matchFile(f[i])
			ret = append(ret, []rune(name)...)
		}
		return ret
	}

	return acc
}
<|endoftext|>