<commit_before>package cmd

import (
	"fmt"
	"io"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/micro/cli"
	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/server"

	// brokers
	"github.com/micro/go-micro/broker"
	"github.com/micro/go-micro/broker/http"
	"github.com/micro/go-micro/broker/mqtt"

	// registries
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/registry/consul"

	// selectors
	"github.com/micro/go-micro/selector"
	"github.com/micro/go-micro/selector/blacklist"
	"github.com/micro/go-micro/selector/cache"
	"github.com/micro/go-micro/selector/random"
	"github.com/micro/go-micro/selector/roundrobin"

	// transports
	"github.com/micro/go-micro/transport"
	thttp "github.com/micro/go-micro/transport/http"
)

type Cmd interface {
	// The cli app within this cmd
	App() *cli.App
	// Adds options, parses flags and initialise
	// exits on error
	Init(opts ...Option) error
	// Options set within this command
	Options() Options
}

type cmd struct {
	opts Options
	app  *cli.App
}

type Option func(o *Options)

var (
	DefaultCmd = newCmd()

	DefaultFlags = []cli.Flag{
		cli.StringFlag{
			Name:   "client_request_timeout",
			EnvVar: "MICRO_CLIENT_REQUEST_TIMEOUT",
			Usage:  "Sets the client request timeout. e.g 500ms, 5s, 1m. Default: 5s",
		},
		cli.IntFlag{
			Name:   "client_retries",
			EnvVar: "MICRO_CLIENT_RETRIES",
			Usage:  "Sets the client retries. Default: 1",
		},
		cli.StringFlag{
			Name:   "server_name",
			EnvVar: "MICRO_SERVER_NAME",
			Usage:  "Name of the server. go.micro.srv.example",
		},
		cli.StringFlag{
			Name:   "server_version",
			EnvVar: "MICRO_SERVER_VERSION",
			Usage:  "Version of the server. 1.1.0",
		},
		cli.StringFlag{
			Name:   "server_id",
			EnvVar: "MICRO_SERVER_ID",
			Usage:  "Id of the server. Auto-generated if not specified",
		},
		cli.StringFlag{
			Name:   "server_address",
			EnvVar: "MICRO_SERVER_ADDRESS",
			Usage:  "Bind address for the server. 127.0.0.1:8080",
		},
		cli.StringFlag{
			Name:   "server_advertise",
			EnvVar: "MICRO_SERVER_ADVERTISE",
			Usage:  "Used instead of the server_address when registering with discovery. 127.0.0.1:8080",
		},
		cli.StringSliceFlag{
			Name:   "server_metadata",
			EnvVar: "MICRO_SERVER_METADATA",
			Value:  &cli.StringSlice{},
			Usage:  "A list of key-value pairs defining metadata. version=1.0.0",
		},
		cli.StringFlag{
			Name:   "broker",
			EnvVar: "MICRO_BROKER",
			Usage:  "Broker for pub/sub. http, nats, rabbitmq",
		},
		cli.StringFlag{
			Name:   "broker_address",
			EnvVar: "MICRO_BROKER_ADDRESS",
			Usage:  "Comma-separated list of broker addresses",
		},
		cli.StringFlag{
			Name:   "registry",
			EnvVar: "MICRO_REGISTRY",
			Usage:  "Registry for discovery. memory, consul, etcd, kubernetes",
		},
		cli.StringFlag{
			Name:   "registry_address",
			EnvVar: "MICRO_REGISTRY_ADDRESS",
			Usage:  "Comma-separated list of registry addresses",
		},
		cli.StringFlag{
			Name:   "selector",
			EnvVar: "MICRO_SELECTOR",
			Usage:  "Selector used to pick nodes for querying. random, roundrobin, blacklist",
		},
		cli.StringFlag{
			Name:   "transport",
			EnvVar: "MICRO_TRANSPORT",
			Usage:  "Transport mechanism used; http, rabbitmq, nats",
		},
		cli.StringFlag{
			Name:   "transport_address",
			EnvVar: "MICRO_TRANSPORT_ADDRESS",
			Usage:  "Comma-separated list of transport addresses",
		},
	}

	DefaultBrokers = map[string]func(...broker.Option) broker.Broker{
		"http": http.NewBroker,
		"mqtt": mqtt.NewBroker,
	}

	DefaultRegistries = map[string]func(...registry.Option) registry.Registry{
		"consul": consul.NewRegistry,
	}

	DefaultSelectors = map[string]func(...selector.Option) selector.Selector{
		"cache":      cache.NewSelector,
		"random":     random.NewSelector,
		"roundrobin": roundrobin.NewSelector,
		"blacklist":  blacklist.NewSelector,
	}

	DefaultTransports = map[string]func(...transport.Option) transport.Transport{
		"http": thttp.NewTransport,
	}

	// used for default selection as the fall back
	defaultBroker    = "http"
	defaultRegistry  = "consul"
	defaultSelector  = "random"
	defaultTransport = "http"
)

func init() {
	rand.Seed(time.Now().Unix())
	help := cli.HelpPrinter
	cli.HelpPrinter = func(writer io.Writer, templ string, data interface{}) {
		help(writer, templ, data)
		os.Exit(0)
	}
}

func newCmd(opts ...Option) Cmd {
	options := Options{
		Broker:    &broker.DefaultBroker,
		Client:    &client.DefaultClient,
		Registry:  &registry.DefaultRegistry,
		Server:    &server.DefaultServer,
		Selector:  &selector.DefaultSelector,
		Transport: &transport.DefaultTransport,

		Brokers:    DefaultBrokers,
		Registries: DefaultRegistries,
		Selectors:  DefaultSelectors,
		Transports: DefaultTransports,
	}

	for _, o := range opts {
		o(&options)
	}

	if len(options.Description) == 0 {
		options.Description = "a go-micro service"
	}

	cmd := new(cmd)
	cmd.opts = options
	cmd.app = cli.NewApp()
	cmd.app.Name = cmd.opts.Name
	cmd.app.Version = cmd.opts.Version
	cmd.app.Usage = cmd.opts.Description
	cmd.app.Before = cmd.Before
	cmd.app.Flags = DefaultFlags
	cmd.app.Action = func(c *cli.Context) {}

	if len(options.Version) == 0 {
		cmd.app.HideVersion = true
	}

	return cmd
}

func (c *cmd) App() *cli.App {
	return c.app
}

func (c *cmd) Options() Options {
	return c.opts
}

func (c *cmd) Before(ctx *cli.Context) error {
	// If flags are set then use them otherwise do nothing
	var serverOpts []server.Option
	var clientOpts []client.Option

	// Set the broker
	if name := ctx.String("broker"); len(name) > 0 || len(ctx.String("broker_address")) > 0 {
		if len(name) == 0 {
			name = defaultBroker
		}

		if b, ok := c.opts.Brokers[name]; ok {
			n := b(broker.Addrs(strings.Split(ctx.String("broker_address"), ",")...))
			*c.opts.Broker = n
		} else {
			return fmt.Errorf("Broker %s not found", name)
		}

		serverOpts = append(serverOpts, server.Broker(*c.opts.Broker))
		clientOpts = append(clientOpts, client.Broker(*c.opts.Broker))

	}

	// Set the registry
	if name := ctx.String("registry"); len(name) > 0 || len(ctx.String("registry_address")) > 0 {
		if len(name) == 0 {
			name = defaultRegistry
		}

		if r, ok := c.opts.Registries[name]; ok {
			n := r(registry.Addrs(strings.Split(ctx.String("registry_address"), ",")...))
			*c.opts.Registry = n
		} else {
			return fmt.Errorf("Registry %s not found", name)
		}

		serverOpts = append(serverOpts, server.Registry(*c.opts.Registry))
		clientOpts = append(clientOpts, client.Registry(*c.opts.Registry))

		(*c.opts.Selector).Init(selector.Registry(*c.opts.Registry))
		clientOpts = append(clientOpts, client.Selector(*c.opts.Selector))

		(*c.opts.Broker).Init(broker.Registry(*c.opts.Registry))
	}

	// Set the selector
	if name := ctx.String("selector"); len(name) > 0 {
		if s, ok := c.opts.Selectors[name]; ok {
			n := s(selector.Registry(*c.opts.Registry))
			*c.opts.Selector = n
		} else {
			return fmt.Errorf("Selector %s not found", name)
		}

		// No server option here. Should there be?
		clientOpts = append(clientOpts, client.Selector(*c.opts.Selector))
	}

	// Set the transport
	if name := ctx.String("transport"); len(name) > 0 || len(ctx.String("transport_address")) > 0 {
		if len(name) == 0 {
			name = defaultTransport
		}

		if t, ok := c.opts.Transports[name]; ok {
			n := t(transport.Addrs(strings.Split(ctx.String("transport_address"), ",")...))
			*c.opts.Transport = n
		} else {
			return fmt.Errorf("Transport %s not found", name)
		}

		serverOpts = append(serverOpts, server.Transport(*c.opts.Transport))
		clientOpts = append(clientOpts, client.Transport(*c.opts.Transport))
	}

	// Parse the server options
	metadata := make(map[string]string)
	for _, d := range ctx.StringSlice("server_metadata") {
		var key, val string
		parts := strings.Split(d, "=")
		key = parts[0]
		if len(parts) > 1 {
			val = strings.Join(parts[1:], "=")
		}
		metadata[key] = val
	}

	if len(metadata) > 0 {
		serverOpts = append(serverOpts, server.Metadata(metadata))
	}

	if len(ctx.String("server_name")) > 0 {
		serverOpts = append(serverOpts, server.Name(ctx.String("server_name")))
	}

	if len(ctx.String("server_version")) > 0 {
		serverOpts = append(serverOpts, server.Version(ctx.String("server_version")))
	}

	if len(ctx.String("server_id")) > 0 {
		serverOpts = append(serverOpts, server.Id(ctx.String("server_id")))
	}

	if len(ctx.String("server_address")) > 0 {
		serverOpts = append(serverOpts, server.Address(ctx.String("server_address")))
	}

	if len(ctx.String("server_advertise")) > 0 {
		serverOpts = append(serverOpts, server.Advertise(ctx.String("server_advertise")))
	}

	// client opts
	if r := ctx.Int("client_retries"); r > 0 {
		clientOpts = append(clientOpts, client.Retries(r))
	}

	if t := ctx.String("client_request_timeout"); len(t) > 0 {
		d, err := time.ParseDuration(t)
		if err != nil {
			return fmt.Errorf("failed to parse client_request_timeout: %v", t)
		}
		clientOpts = append(clientOpts, client.RequestTimeout(d))
	}

	// We have some command line opts for the server.
	// Lets set it up
	if len(serverOpts) > 0 {
		(*c.opts.Server).Init(serverOpts...)
	}

	// Use an init option?
	if len(clientOpts) > 0 {
		(*c.opts.Client).Init(clientOpts...)
	}

	return nil
}

func (c *cmd) Init(opts ...Option) error {
	for _, o := range opts {
		o(&c.opts)
	}
	c.app.Name = c.opts.Name
	c.app.Version = c.opts.Version
	c.app.Usage = c.opts.Description
	c.app.RunAndExitOnError()
	return nil
}

func DefaultOptions() Options {
	return DefaultCmd.Options()
}

func App() *cli.App {
	return DefaultCmd.App()
}

func Init(opts ...Option) error {
	return DefaultCmd.Init(opts...)
}

func NewCmd(opts ...Option) Cmd {
	return newCmd(opts...)
}
<commit_msg>Remove that link<commit_after>package cmd

import (
	"fmt"
	"io"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/micro/cli"
	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/server"

	// brokers
	"github.com/micro/go-micro/broker"
	"github.com/micro/go-micro/broker/http"
	"github.com/micro/go-micro/broker/mqtt"

	// registries
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/registry/consul"

	// selectors
	"github.com/micro/go-micro/selector"
	"github.com/micro/go-micro/selector/blacklist"
	"github.com/micro/go-micro/selector/random"
	"github.com/micro/go-micro/selector/roundrobin"

	// transports
	"github.com/micro/go-micro/transport"
	thttp "github.com/micro/go-micro/transport/http"
)

type Cmd interface {
	// The cli app within this cmd
	App() *cli.App
	// Adds options, parses flags and initialise
	// exits on error
	Init(opts ...Option) error
	// Options set within this command
	Options() Options
}

type cmd struct {
	opts Options
	app  *cli.App
}

type Option func(o *Options)

var (
	DefaultCmd = newCmd()

	DefaultFlags = []cli.Flag{
		cli.StringFlag{
			Name:   "client_request_timeout",
			EnvVar: "MICRO_CLIENT_REQUEST_TIMEOUT",
			Usage:  "Sets the client request timeout. e.g 500ms, 5s, 1m. Default: 5s",
		},
		cli.IntFlag{
			Name:   "client_retries",
			EnvVar: "MICRO_CLIENT_RETRIES",
			Usage:  "Sets the client retries. Default: 1",
		},
		cli.StringFlag{
			Name:   "server_name",
			EnvVar: "MICRO_SERVER_NAME",
			Usage:  "Name of the server. go.micro.srv.example",
		},
		cli.StringFlag{
			Name:   "server_version",
			EnvVar: "MICRO_SERVER_VERSION",
			Usage:  "Version of the server. 1.1.0",
		},
		cli.StringFlag{
			Name:   "server_id",
			EnvVar: "MICRO_SERVER_ID",
			Usage:  "Id of the server. Auto-generated if not specified",
		},
		cli.StringFlag{
			Name:   "server_address",
			EnvVar: "MICRO_SERVER_ADDRESS",
			Usage:  "Bind address for the server. 127.0.0.1:8080",
		},
		cli.StringFlag{
			Name:   "server_advertise",
			EnvVar: "MICRO_SERVER_ADVERTISE",
			Usage:  "Used instead of the server_address when registering with discovery. 127.0.0.1:8080",
		},
		cli.StringSliceFlag{
			Name:   "server_metadata",
			EnvVar: "MICRO_SERVER_METADATA",
			Value:  &cli.StringSlice{},
			Usage:  "A list of key-value pairs defining metadata. version=1.0.0",
		},
		cli.StringFlag{
			Name:   "broker",
			EnvVar: "MICRO_BROKER",
			Usage:  "Broker for pub/sub. http, nats, rabbitmq",
		},
		cli.StringFlag{
			Name:   "broker_address",
			EnvVar: "MICRO_BROKER_ADDRESS",
			Usage:  "Comma-separated list of broker addresses",
		},
		cli.StringFlag{
			Name:   "registry",
			EnvVar: "MICRO_REGISTRY",
			Usage:  "Registry for discovery. memory, consul, etcd, kubernetes",
		},
		cli.StringFlag{
			Name:   "registry_address",
			EnvVar: "MICRO_REGISTRY_ADDRESS",
			Usage:  "Comma-separated list of registry addresses",
		},
		cli.StringFlag{
			Name:   "selector",
			EnvVar: "MICRO_SELECTOR",
			Usage:  "Selector used to pick nodes for querying. random, roundrobin, blacklist",
		},
		cli.StringFlag{
			Name:   "transport",
			EnvVar: "MICRO_TRANSPORT",
			Usage:  "Transport mechanism used; http, rabbitmq, nats",
		},
		cli.StringFlag{
			Name:   "transport_address",
			EnvVar: "MICRO_TRANSPORT_ADDRESS",
			Usage:  "Comma-separated list of transport addresses",
		},
	}

	DefaultBrokers = map[string]func(...broker.Option) broker.Broker{
		"http": http.NewBroker,
		"mqtt": mqtt.NewBroker,
	}

	DefaultRegistries = map[string]func(...registry.Option) registry.Registry{
		"consul": consul.NewRegistry,
	}

	DefaultSelectors = map[string]func(...selector.Option) selector.Selector{
		"random":     random.NewSelector,
		"roundrobin": roundrobin.NewSelector,
		"blacklist":  blacklist.NewSelector,
	}

	DefaultTransports = map[string]func(...transport.Option) transport.Transport{
		"http": thttp.NewTransport,
	}

	// used for default selection as the fall back
	defaultBroker    = "http"
	defaultRegistry  = "consul"
	defaultSelector  = "random"
	defaultTransport = "http"
)

func init() {
	rand.Seed(time.Now().Unix())
	help := cli.HelpPrinter
	cli.HelpPrinter = func(writer io.Writer, templ string, data interface{}) {
		help(writer, templ, data)
		os.Exit(0)
	}
}

func newCmd(opts ...Option) Cmd {
	options := Options{
		Broker:    &broker.DefaultBroker,
		Client:    &client.DefaultClient,
		Registry:  &registry.DefaultRegistry,
		Server:    &server.DefaultServer,
		Selector:  &selector.DefaultSelector,
		Transport: &transport.DefaultTransport,

		Brokers:    DefaultBrokers,
		Registries: DefaultRegistries,
		Selectors:  DefaultSelectors,
		Transports: DefaultTransports,
	}

	for _, o := range opts {
		o(&options)
	}

	if len(options.Description) == 0 {
		options.Description = "a go-micro service"
	}

	cmd := new(cmd)
	cmd.opts = options
	cmd.app = cli.NewApp()
	cmd.app.Name = cmd.opts.Name
	cmd.app.Version = cmd.opts.Version
	cmd.app.Usage = cmd.opts.Description
	cmd.app.Before = cmd.Before
	cmd.app.Flags = DefaultFlags
	cmd.app.Action = func(c *cli.Context) {}

	if len(options.Version) == 0 {
		cmd.app.HideVersion = true
	}

	return cmd
}

func (c *cmd) App() *cli.App {
	return c.app
}

func (c *cmd) Options() Options {
	return c.opts
}

func (c *cmd) Before(ctx *cli.Context) error {
	// If flags are set then use them otherwise do nothing
	var serverOpts []server.Option
	var clientOpts []client.Option

	// Set the broker
	if name := ctx.String("broker"); len(name) > 0 || len(ctx.String("broker_address")) > 0 {
		if len(name) == 0 {
			name = defaultBroker
		}

		if b, ok := c.opts.Brokers[name]; ok {
			n := b(broker.Addrs(strings.Split(ctx.String("broker_address"), ",")...))
			*c.opts.Broker = n
		} else {
			return fmt.Errorf("Broker %s not found", name)
		}

		serverOpts = append(serverOpts, server.Broker(*c.opts.Broker))
		clientOpts = append(clientOpts, client.Broker(*c.opts.Broker))

	}

	// Set the registry
	if name := ctx.String("registry"); len(name) > 0 || len(ctx.String("registry_address")) > 0 {
		if len(name) == 0 {
			name = defaultRegistry
		}

		if r, ok := c.opts.Registries[name]; ok {
			n := r(registry.Addrs(strings.Split(ctx.String("registry_address"), ",")...))
			*c.opts.Registry = n
		} else {
			return fmt.Errorf("Registry %s not found", name)
		}

		serverOpts = append(serverOpts, server.Registry(*c.opts.Registry))
		clientOpts = append(clientOpts, client.Registry(*c.opts.Registry))

		(*c.opts.Selector).Init(selector.Registry(*c.opts.Registry))
		clientOpts = append(clientOpts, client.Selector(*c.opts.Selector))

		(*c.opts.Broker).Init(broker.Registry(*c.opts.Registry))
	}

	// Set the selector
	if name := ctx.String("selector"); len(name) > 0 {
		if s, ok := c.opts.Selectors[name]; ok {
			n := s(selector.Registry(*c.opts.Registry))
			*c.opts.Selector = n
		} else {
			return fmt.Errorf("Selector %s not found", name)
		}

		// No server option here. Should there be?
		clientOpts = append(clientOpts, client.Selector(*c.opts.Selector))
	}

	// Set the transport
	if name := ctx.String("transport"); len(name) > 0 || len(ctx.String("transport_address")) > 0 {
		if len(name) == 0 {
			name = defaultTransport
		}

		if t, ok := c.opts.Transports[name]; ok {
			n := t(transport.Addrs(strings.Split(ctx.String("transport_address"), ",")...))
			*c.opts.Transport = n
		} else {
			return fmt.Errorf("Transport %s not found", name)
		}

		serverOpts = append(serverOpts, server.Transport(*c.opts.Transport))
		clientOpts = append(clientOpts, client.Transport(*c.opts.Transport))
	}

	// Parse the server options
	metadata := make(map[string]string)
	for _, d := range ctx.StringSlice("server_metadata") {
		var key, val string
		parts := strings.Split(d, "=")
		key = parts[0]
		if len(parts) > 1 {
			val = strings.Join(parts[1:], "=")
		}
		metadata[key] = val
	}

	if len(metadata) > 0 {
		serverOpts = append(serverOpts, server.Metadata(metadata))
	}

	if len(ctx.String("server_name")) > 0 {
		serverOpts = append(serverOpts, server.Name(ctx.String("server_name")))
	}

	if len(ctx.String("server_version")) > 0 {
		serverOpts = append(serverOpts, server.Version(ctx.String("server_version")))
	}

	if len(ctx.String("server_id")) > 0 {
		serverOpts = append(serverOpts, server.Id(ctx.String("server_id")))
	}

	if len(ctx.String("server_address")) > 0 {
		serverOpts = append(serverOpts, server.Address(ctx.String("server_address")))
	}

	if len(ctx.String("server_advertise")) > 0 {
		serverOpts = append(serverOpts, server.Advertise(ctx.String("server_advertise")))
	}

	// client opts
	if r := ctx.Int("client_retries"); r > 0 {
		clientOpts = append(clientOpts, client.Retries(r))
	}

	if t := ctx.String("client_request_timeout"); len(t) > 0 {
		d, err := time.ParseDuration(t)
		if err != nil {
			return fmt.Errorf("failed to parse client_request_timeout: %v", t)
		}
		clientOpts = append(clientOpts, client.RequestTimeout(d))
	}

	// We have some command line opts for the server.
	// Lets set it up
	if len(serverOpts) > 0 {
		(*c.opts.Server).Init(serverOpts...)
	}

	// Use an init option?
	if len(clientOpts) > 0 {
		(*c.opts.Client).Init(clientOpts...)
	}

	return nil
}

func (c *cmd) Init(opts ...Option) error {
	for _, o := range opts {
		o(&c.opts)
	}
	c.app.Name = c.opts.Name
	c.app.Version = c.opts.Version
	c.app.Usage = c.opts.Description
	c.app.RunAndExitOnError()
	return nil
}

func DefaultOptions() Options {
	return DefaultCmd.Options()
}

func App() *cli.App {
	return DefaultCmd.App()
}

func Init(opts ...Option) error {
	return DefaultCmd.Init(opts...)
}

func NewCmd(opts ...Option) Cmd {
	return newCmd(opts...)
}
<|endoftext|>


<commit_before>package cell_test

import (
	"os"
	"path/filepath"
	"time"

	archive_helper "code.cloudfoundry.org/archiver/extractor/test_helper"
	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/inigo/fixtures"
	"code.cloudfoundry.org/inigo/helpers"
	"code.cloudfoundry.org/lager"

	repconfig "code.cloudfoundry.org/rep/cmd/rep/config"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
)

var _ = Describe("Placement Tags", func() {
	var (
		processGuid string
		runtime     ifrit.Process
	)

	BeforeEach(func() {
		processGuid = helpers.GenerateGuid()

		var fileServer ifrit.Runner
		fileServer, fileServerStaticDir := componentMaker.FileServer()
		modifyRepConfig := func(config *repconfig.RepConfig) {
			config.PlacementTags = []string{"inigo-tag"}
			config.OptionalPlacementTags = []string{"inigo-optional-tag"}
		}
		runtime = ginkgomon.Invoke(grouper.NewParallel(os.Kill, grouper.Members{
			{"file-server", fileServer},
			{"rep-with-tag", componentMaker.Rep(modifyRepConfig)},
			{"auctioneer", componentMaker.Auctioneer()},
		}))

		archive_helper.CreateZipArchive(
			filepath.Join(fileServerStaticDir, "lrp.zip"),
			fixtures.GoServerApp(),
		)
	})

	AfterEach(func() {
		helpers.StopProcesses(runtime)
	})

	It("advertises placement tags in the cell presence", func() {
		presences, err := bbsClient.Cells(logger)
		Expect(err).NotTo(HaveOccurred())

		Expect(presences).To(HaveLen(1))
		Expect(presences[0].PlacementTags).To(Equal([]string{"inigo-tag"}))
	})

	It("advertises optional placement tags in the cell presence", func() {
		presences, err := bbsClient.Cells(logger)
		Expect(err).NotTo(HaveOccurred())

		Expect(presences).To(HaveLen(1))
		Expect(presences[0].OptionalPlacementTags).To(Equal([]string{"inigo-optional-tag"}))
	})

	Describe("desired lrps", func() {
		var lrp *models.DesiredLRP

		JustBeforeEach(func() {
			err := bbsClient.DesireLRP(logger, lrp)
			Expect(err).NotTo(HaveOccurred())
		})

		Context("when the desired LRP matches the required tags", func() {
			BeforeEach(func() {
				lrp = helpers.LRPCreateRequestWithPlacementTag(processGuid, []string{"inigo-tag"})
			})

			It("succeeds and is running on correct cell", func() {
				lrpFunc := func() string {
					lrpGroups, err := bbsClient.ActualLRPGroupsByProcessGuid(logger, processGuid)
					Expect(err).NotTo(HaveOccurred())
					if len(lrpGroups) == 0 {
						return ""
					}
					lrp, _ := lrpGroups[0].Resolve()

					return lrp.CellId
				}
				Eventually(lrpFunc).Should(MatchRegexp("the-cell-id-.*-0"))
			})
		})

		Context("when the desired LRP matches the required  and optional tags", func() {
			BeforeEach(func() {
				lrp = helpers.LRPCreateRequestWithPlacementTag(processGuid, []string{"inigo-tag", "inigo-optional-tag"})
			})

			It("succeeds and is running on correct cell", func() {
				lrpFunc := func() string {
					lrpGroups, err := bbsClient.ActualLRPGroupsByProcessGuid(logger, processGuid)
					Expect(err).NotTo(HaveOccurred())
					if len(lrpGroups) == 0 {
						return ""
					}
					lrp, _ := lrpGroups[0].Resolve()

					return lrp.CellId
				}
				Eventually(lrpFunc).Should(MatchRegexp("the-cell-id-.*-0"))
			})
		})

		Context("when no cells are advertising the placement tags", func() {
			BeforeEach(func() {
				lrp = helpers.LRPCreateRequestWithPlacementTag(processGuid, []string{""})
			})

			It("fails and sets a placement error", func() {
				lrpFunc := func() string {
					lrpGroups, err := bbsClient.ActualLRPGroupsByProcessGuid(logger, processGuid)
					Expect(err).NotTo(HaveOccurred())
					if len(lrpGroups) == 0 {
						return ""
					}
					lrp, _ := lrpGroups[0].Resolve()
					logger.Info("lrp-cell-id", lager.Data{"cell-id": lrp.CellId})

					return lrp.PlacementError
				}

				Eventually(lrpFunc).Should(ContainSubstring("found no compatible cell with placement tag"))
			})
		})
	})

	Describe("tasks", func() {
		var (
			task   *models.Task
			action models.ActionInterface
		)

		BeforeEach(func() {
			action = models.Serial(
				models.Timeout(
					&models.RunAction{
						User: "vcap",
						Path: "sh",
						Args: []string{
							"-c",
							`
									kill_sleep() {
										kill -15 $child
										exit
									}

									trap kill_sleep 15 9

									sleep 1 &

									child=$!
									wait $child
									`,
						},
					},
					500*time.Millisecond,
				),
			)

		})

		JustBeforeEach(func() {
			err := bbsClient.DesireTask(logger, task.TaskGuid, task.Domain, task.TaskDefinition)
			Expect(err).NotTo(HaveOccurred())
		})

		Context("when the task matches the required tags", func() {
			BeforeEach(func() {
				task = helpers.TaskCreateRequestWithTags("task-guid", action, []string{"inigo-tag"})
			})

			It("succeeds and is running on correct cell", func() {
				taskFunc := func() string {
					t, err := bbsClient.TaskByGuid(logger, task.TaskGuid)
					Expect(err).NotTo(HaveOccurred())
					return t.CellId
				}
				Eventually(taskFunc).Should(MatchRegexp("the-cell-id-.*-0"))
			})
		})

		Context("when the task matches the required and optional tags", func() {
			BeforeEach(func() {
				task = helpers.TaskCreateRequestWithTags("task-guid", action, []string{"inigo-tag", "inigo-optional-tag"})
			})

			It("succeeds and is running on correct cell", func() {
				taskFunc := func() string {
					t, err := bbsClient.TaskByGuid(logger, task.TaskGuid)
					Expect(err).NotTo(HaveOccurred())
					return t.CellId
				}
				Eventually(taskFunc).Should(MatchRegexp("the-cell-id-.*-0"))
			})
		})

		Context("when no cells are advertising the placement tags", func() {
			BeforeEach(func() {
				task = helpers.TaskCreateRequestWithTags("task-guid", action, []string{""})
			})

			It("fails and sets a placement error", func() {
				taskFunc := func() string {
					t, err := bbsClient.TaskByGuid(logger, task.TaskGuid)
					Expect(err).NotTo(HaveOccurred())
					return t.FailureReason
				}

				Eventually(taskFunc).Should(ContainSubstring("found no compatible cell with placement tag"))
			})
		})
	})
})
<commit_msg>make the inigo tasks placement tags less flaky<commit_after>package cell_test

import (
	"os"
	"path/filepath"

	archive_helper "code.cloudfoundry.org/archiver/extractor/test_helper"
	"code.cloudfoundry.org/bbs/models"
	"code.cloudfoundry.org/inigo/fixtures"
	"code.cloudfoundry.org/inigo/helpers"
	"code.cloudfoundry.org/lager"

	repconfig "code.cloudfoundry.org/rep/cmd/rep/config"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
)

var _ = Describe("Placement Tags", func() {
	var (
		guid    string
		runtime ifrit.Process
	)

	BeforeEach(func() {
		guid = helpers.GenerateGuid()

		var fileServer ifrit.Runner
		fileServer, fileServerStaticDir := componentMaker.FileServer()
		modifyRepConfig := func(config *repconfig.RepConfig) {
			config.PlacementTags = []string{"inigo-tag"}
			config.OptionalPlacementTags = []string{"inigo-optional-tag"}
		}
		runtime = ginkgomon.Invoke(grouper.NewParallel(os.Kill, grouper.Members{
			{"file-server", fileServer},
			{"rep-with-tag", componentMaker.Rep(modifyRepConfig)},
			{"auctioneer", componentMaker.Auctioneer()},
		}))

		archive_helper.CreateZipArchive(
			filepath.Join(fileServerStaticDir, "lrp.zip"),
			fixtures.GoServerApp(),
		)
	})

	AfterEach(func() {
		helpers.StopProcesses(runtime)
	})

	It("advertises placement tags in the cell presence", func() {
		presences, err := bbsClient.Cells(logger)
		Expect(err).NotTo(HaveOccurred())

		Expect(presences).To(HaveLen(1))
		Expect(presences[0].PlacementTags).To(Equal([]string{"inigo-tag"}))
	})

	It("advertises optional placement tags in the cell presence", func() {
		presences, err := bbsClient.Cells(logger)
		Expect(err).NotTo(HaveOccurred())

		Expect(presences).To(HaveLen(1))
		Expect(presences[0].OptionalPlacementTags).To(Equal([]string{"inigo-optional-tag"}))
	})

	Describe("desired lrps", func() {
		var lrp *models.DesiredLRP

		JustBeforeEach(func() {
			err := bbsClient.DesireLRP(logger, lrp)
			Expect(err).NotTo(HaveOccurred())
		})

		Context("when the desired LRP matches the required tags", func() {
			BeforeEach(func() {
				lrp = helpers.LRPCreateRequestWithPlacementTag(guid, []string{"inigo-tag"})
			})

			It("succeeds and is running on correct cell", func() {
				lrpFunc := func() string {
					lrpGroups, err := bbsClient.ActualLRPGroupsByProcessGuid(logger, guid)
					Expect(err).NotTo(HaveOccurred())
					if len(lrpGroups) == 0 {
						return ""
					}
					lrp, _ := lrpGroups[0].Resolve()

					return lrp.CellId
				}
				Eventually(lrpFunc).Should(MatchRegexp("the-cell-id-.*-0"))
			})
		})

		Context("when the desired LRP matches the required  and optional tags", func() {
			BeforeEach(func() {
				lrp = helpers.LRPCreateRequestWithPlacementTag(guid, []string{"inigo-tag", "inigo-optional-tag"})
			})

			It("succeeds and is running on correct cell", func() {
				lrpFunc := func() string {
					lrpGroups, err := bbsClient.ActualLRPGroupsByProcessGuid(logger, guid)
					Expect(err).NotTo(HaveOccurred())
					if len(lrpGroups) == 0 {
						return ""
					}
					lrp, _ := lrpGroups[0].Resolve()

					return lrp.CellId
				}
				Eventually(lrpFunc).Should(MatchRegexp("the-cell-id-.*-0"))
			})
		})

		Context("when no cells are advertising the placement tags", func() {
			BeforeEach(func() {
				lrp = helpers.LRPCreateRequestWithPlacementTag(guid, []string{""})
			})

			It("fails and sets a placement error", func() {
				lrpFunc := func() string {
					lrpGroups, err := bbsClient.ActualLRPGroupsByProcessGuid(logger, guid)
					Expect(err).NotTo(HaveOccurred())
					if len(lrpGroups) == 0 {
						return ""
					}
					lrp, _ := lrpGroups[0].Resolve()
					logger.Info("lrp-cell-id", lager.Data{"cell-id": lrp.CellId})

					return lrp.PlacementError
				}

				Eventually(lrpFunc).Should(ContainSubstring("found no compatible cell with placement tag"))
			})
		})
	})

	Describe("tasks", func() {
		var (
			task   *models.Task
			action models.ActionInterface
		)

		BeforeEach(func() {
			action = models.Serial(
				&models.RunAction{
					User: "vcap",
					Path: "sh",
					Args: []string{
						"-c",
						`
									kill_sleep() {
										kill -15 $child
										exit
									}

									trap kill_sleep 15 9

									sleep 1 &

									child=$!
									wait $child
									`,
					},
				},
			)

		})

		JustBeforeEach(func() {
			err := bbsClient.DesireTask(logger, task.TaskGuid, task.Domain, task.TaskDefinition)
			Expect(err).NotTo(HaveOccurred())
		})

		taskShouldRunSuccessfully := func() {
			It("succeeds", func() {
				var completedTask *models.Task
				Eventually(func() interface{} {
					var err error

					completedTask, err = bbsClient.TaskByGuid(logger, guid)
					Expect(err).NotTo(HaveOccurred())

					return completedTask.State
				}).Should(Equal(models.Task_Completed))

				Expect(completedTask.Failed).To(BeFalse())
			})
		}

		Context("when the task matches the required tags", func() {
			BeforeEach(func() {
				task = helpers.TaskCreateRequestWithTags(guid, action, []string{"inigo-tag"})
			})

			taskShouldRunSuccessfully()
		})

		Context("when the task matches the required and optional tags", func() {
			BeforeEach(func() {
				task = helpers.TaskCreateRequestWithTags(guid, action, []string{"inigo-tag", "inigo-optional-tag"})
			})

			taskShouldRunSuccessfully()
		})

		Context("when no cells are advertising the placement tags", func() {
			BeforeEach(func() {
				task = helpers.TaskCreateRequestWithTags(guid, action, []string{""})
			})

			It("fails and sets a placement error", func() {
				taskFunc := func() string {
					t, err := bbsClient.TaskByGuid(logger, task.TaskGuid)
					Expect(err).NotTo(HaveOccurred())
					return t.FailureReason
				}

				Eventually(taskFunc).Should(ContainSubstring("found no compatible cell with placement tag"))
			})
		})
	})
})
<|endoftext|>


<commit_before>package actors

import (
	"errors"
	"fmt"

	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/models"
)

type ServicePlanActor interface {
	UpdateSinglePlanForService(string, string) (bool, error)
}

type ServicePlanHandler struct {
	serviceRepo               api.ServiceRepository
	servicePlanRepo           api.ServicePlanRepository
	servicePlanVisibilityRepo api.ServicePlanVisibilityRepository
	orgRepo                   api.OrganizationRepository
}

func NewServicePlanHandler(service api.ServiceRepository, plan api.ServicePlanRepository, vis api.ServicePlanVisibilityRepository, org api.OrganizationRepository) ServicePlanHandler {
	return ServicePlanHandler{
		serviceRepo:               service,
		servicePlanRepo:           plan,
		servicePlanVisibilityRepo: vis,
		orgRepo:                   org,
	}
}

func (actor ServicePlanHandler) UpdateSinglePlanForService(serviceName string, planName string) (bool, error) {
	var servicePlan models.ServicePlanFields

	serviceOffering, err := actor.serviceRepo.FindServiceOfferingByLabel(serviceName)
	if err != nil {
		return false, err
	}

	//get all service plans for the one specific service
	//if there are no plans for the service it returns an empty set
	servicePlans, err := actor.servicePlanRepo.Search(map[string]string{"service_guid": serviceOffering.Guid})
	if err != nil {
		return false, err
	}

	//find the service plan and set it as the only service plan for update
	serviceOffering.Plans = nil //set it to nil initialy
	for _, servicePlan := range servicePlans {
		if servicePlan.Name == planName {
			serviceOffering.Plans = []models.ServicePlanFields{servicePlan} //he has the orgs inside him!!!
			break
		}
	}

	if serviceOffering.Plans == nil {
		return false, errors.New(fmt.Sprintf("The plan %s could not be found for service %s", planName, serviceName))
	} else {
		servicePlan = serviceOffering.Plans[0]
	}

	err = actor.updateServicePlanAvailability(serviceOffering.Guid, servicePlan, true)
	if err != nil {
		return false, err
	}

	return servicePlan.Public, nil
}

func (actor ServicePlanHandler) updateServicePlanAvailability(serviceGuid string, servicePlan models.ServicePlanFields, public bool) error {
	//delete service_plan_visibility guids[] and public: true
	err := actor.removeServicePlanVisibilities(servicePlan.Guid)
	if err != nil {
		return err
	}

	return actor.servicePlanRepo.Update(servicePlan, serviceGuid, public)
}

func (actor ServicePlanHandler) removeServicePlanVisibilities(servicePlanGuid string) error {
	planVisibilities, err := actor.servicePlanVisibilityRepo.List()
	if err != nil {
		return err
	}

	for _, planVisibility := range planVisibilities {
		if planVisibility.ServicePlanGuid == servicePlanGuid {
			err := actor.servicePlanVisibilityRepo.Delete(planVisibility.Guid)
			if err != nil {
				return err
			}
		}
		//else we simply skip it
	}

	return nil
}

/*
func (actor ServicePlanHandler) GetSingleServicePlan(serviceName string, planName string) (models.ServicePlanFields, error) {
	//find service guid
	serviceOffering, err := actor.serviceRepo.FindServiceOfferingByLabel(serviceName)
	if err != nil {
		return models.ServicePlanFields{}, err
	}

	//get all service plans for the service
	servicePlans, err := actor.servicePlanRepo.Search(map[string]string{"service_guid": serviceOffering.Guid})
	if err != nil {
		return models.ServicePlanFields{}, err
	}

	//find the service plan
	var plan models.ServicePlanFields //he has the orgs inside him!!!!
	for _, servicePlan := range servicePlans {
		if servicePlan.Name == planName {

			serviceOffering.Plan = plan

			//plan = servicePlan
		}
	}

	return serviceOffering, nil
	//return plan, nil
}
*/
<commit_msg>Remove extra api call when plan is already public.<commit_after>package actors

import (
	"errors"
	"fmt"

	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/models"
)

type ServicePlanActor interface {
	UpdateSinglePlanForService(string, string) (bool, error)
}

type ServicePlanHandler struct {
	serviceRepo               api.ServiceRepository
	servicePlanRepo           api.ServicePlanRepository
	servicePlanVisibilityRepo api.ServicePlanVisibilityRepository
	orgRepo                   api.OrganizationRepository
}

func NewServicePlanHandler(service api.ServiceRepository, plan api.ServicePlanRepository, vis api.ServicePlanVisibilityRepository, org api.OrganizationRepository) ServicePlanHandler {
	return ServicePlanHandler{
		serviceRepo:               service,
		servicePlanRepo:           plan,
		servicePlanVisibilityRepo: vis,
		orgRepo:                   org,
	}
}

func (actor ServicePlanHandler) UpdateSinglePlanForService(serviceName string, planName string) (bool, error) {
	var servicePlan models.ServicePlanFields

	serviceOffering, err := actor.serviceRepo.FindServiceOfferingByLabel(serviceName)
	if err != nil {
		return false, err
	}

	//get all service plans for the one specific service
	//if there are no plans for the service it returns an empty set
	servicePlans, err := actor.servicePlanRepo.Search(map[string]string{"service_guid": serviceOffering.Guid})
	if err != nil {
		return false, err
	}

	//find the service plan and set it as the only service plan for update
	serviceOffering.Plans = nil //set it to nil initialy
	for _, servicePlan := range servicePlans {
		if servicePlan.Name == planName {
			serviceOffering.Plans = []models.ServicePlanFields{servicePlan} //he has the orgs inside him!!!
			break
		}
	}

	if serviceOffering.Plans == nil {
		return false, errors.New(fmt.Sprintf("The plan %s could not be found for service %s", planName, serviceName))
	} else {
		servicePlan = serviceOffering.Plans[0]
	}

	err = actor.updateServicePlanAvailability(serviceOffering.Guid, servicePlan, true)
	if err != nil {
		return false, err
	}

	return servicePlan.Public, nil
}

func (actor ServicePlanHandler) updateServicePlanAvailability(serviceGuid string, servicePlan models.ServicePlanFields, public bool) error {
	//delete service_plan_visibility guids[] and public: true
	err := actor.removeServicePlanVisibilities(servicePlan.Guid)
	if err != nil {
		return err
	}

	if servicePlan.Public {
		return nil
	}

	return actor.servicePlanRepo.Update(servicePlan, serviceGuid, public)
}

func (actor ServicePlanHandler) removeServicePlanVisibilities(servicePlanGuid string) error {
	planVisibilities, err := actor.servicePlanVisibilityRepo.List()
	if err != nil {
		return err
	}

	for _, planVisibility := range planVisibilities {
		if planVisibility.ServicePlanGuid == servicePlanGuid {
			err := actor.servicePlanVisibilityRepo.Delete(planVisibility.Guid)
			if err != nil {
				return err
			}
		}
		//else we simply skip it
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2020 Red Hat, Inc.
 *
 */

package libvmi

import (
	k8sv1 "k8s.io/api/core/v1"

	v1 "kubevirt.io/api/core/v1"
)

// WithContainerImage specifies the name of the container image to be used.
func WithContainerImage(name string) Option {
	return func(vmi *v1.VirtualMachineInstance) {
		diskName := "disk0"
		addDisk(vmi, newDisk(diskName, v1.DiskBusVirtio))
		addVolume(vmi, newContainerVolume(diskName, name))
	}
}

// WithPersistentVolumeClaim specifies the name of the PersistentVolumeClaim to be used.
func WithPersistentVolumeClaim(diskName, pvcName string) Option {
	return func(vmi *v1.VirtualMachineInstance) {
		addDisk(vmi, newDisk(diskName, v1.DiskBusVirtio))
		addVolume(vmi, newPersistentVolumeClaimVolume(diskName, pvcName))
	}
}

// WithDataVolume specifies the name of the DataVolume to be used.
func WithDataVolume(diskName, pvcName string) Option {
	return func(vmi *v1.VirtualMachineInstance) {
		addDisk(vmi, newDisk(diskName, v1.DiskBusVirtio))
		addVolume(vmi, newDataVolume(diskName, pvcName))
	}
}

func addDisk(vmi *v1.VirtualMachineInstance, disk v1.Disk) {
	if !diskExists(vmi, disk) {
		vmi.Spec.Domain.Devices.Disks = append(vmi.Spec.Domain.Devices.Disks, disk)
	}
}

func addVolume(vmi *v1.VirtualMachineInstance, volume v1.Volume) {
	if !volumeExists(vmi, volume) {
		vmi.Spec.Volumes = append(vmi.Spec.Volumes, volume)
	}
}

func getVolume(vmi *v1.VirtualMachineInstance, name string) *v1.Volume {
	for i := range vmi.Spec.Volumes {
		if vmi.Spec.Volumes[i].Name == name {
			return &vmi.Spec.Volumes[i]
		}
	}
	return nil
}

func diskExists(vmi *v1.VirtualMachineInstance, disk v1.Disk) bool {
	for _, d := range vmi.Spec.Domain.Devices.Disks {
		if d.Name == disk.Name {
			return true
		}
	}
	return false
}

func volumeExists(vmi *v1.VirtualMachineInstance, volume v1.Volume) bool {
	for _, v := range vmi.Spec.Volumes {
		if v.Name == volume.Name {
			return true
		}
	}
	return false
}

func newDisk(name string, bus v1.DiskBus) v1.Disk {
	return v1.Disk{
		Name: name,
		DiskDevice: v1.DiskDevice{
			Disk: &v1.DiskTarget{
				Bus: bus,
			},
		},
	}
}

func newVolume(name string) v1.Volume {
	return v1.Volume{Name: name}
}

func newContainerVolume(name, image string) v1.Volume {
	return v1.Volume{
		Name: name,
		VolumeSource: v1.VolumeSource{
			ContainerDisk: &v1.ContainerDiskSource{
				Image: image,
			},
		},
	}
}

func newPersistentVolumeClaimVolume(name, claimName string) v1.Volume {
	return v1.Volume{
		Name: name,
		VolumeSource: v1.VolumeSource{
			PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
				PersistentVolumeClaimVolumeSource: k8sv1.PersistentVolumeClaimVolumeSource{
					ClaimName: claimName,
				}},
		},
	}
}

func newDataVolume(name, dataVolumeName string) v1.Volume {
	return v1.Volume{
		Name: name,
		VolumeSource: v1.VolumeSource{
			DataVolume: &v1.DataVolumeSource{
				Name: dataVolumeName,
			},
		},
	}
}
<commit_msg>libvmi: add `WithEmptyDisk` Option<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2020 Red Hat, Inc.
 *
 */

package libvmi

import (
	k8sv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"

	v1 "kubevirt.io/api/core/v1"
)

// WithContainerImage specifies the name of the container image to be used.
func WithContainerImage(name string) Option {
	return func(vmi *v1.VirtualMachineInstance) {
		diskName := "disk0"
		addDisk(vmi, newDisk(diskName, v1.DiskBusVirtio))
		addVolume(vmi, newContainerVolume(diskName, name))
	}
}

// WithPersistentVolumeClaim specifies the name of the PersistentVolumeClaim to be used.
func WithPersistentVolumeClaim(diskName, pvcName string) Option {
	return func(vmi *v1.VirtualMachineInstance) {
		addDisk(vmi, newDisk(diskName, v1.DiskBusVirtio))
		addVolume(vmi, newPersistentVolumeClaimVolume(diskName, pvcName))
	}
}

// WithDataVolume specifies the name of the DataVolume to be used.
func WithDataVolume(diskName, pvcName string) Option {
	return func(vmi *v1.VirtualMachineInstance) {
		addDisk(vmi, newDisk(diskName, v1.DiskBusVirtio))
		addVolume(vmi, newDataVolume(diskName, pvcName))
	}
}

// WithEmptyDisk specifies the name of the EmptyDisk to be used.
func WithEmptyDisk(diskName string, bus v1.DiskBus, capacity resource.Quantity) Option {
	return func(vmi *v1.VirtualMachineInstance) {
		addDisk(vmi, newDisk(diskName, bus))
		addVolume(vmi, newEmptyDisk(diskName, capacity))
	}
}

func addDisk(vmi *v1.VirtualMachineInstance, disk v1.Disk) {
	if !diskExists(vmi, disk) {
		vmi.Spec.Domain.Devices.Disks = append(vmi.Spec.Domain.Devices.Disks, disk)
	}
}

func addVolume(vmi *v1.VirtualMachineInstance, volume v1.Volume) {
	if !volumeExists(vmi, volume) {
		vmi.Spec.Volumes = append(vmi.Spec.Volumes, volume)
	}
}

func getVolume(vmi *v1.VirtualMachineInstance, name string) *v1.Volume {
	for i := range vmi.Spec.Volumes {
		if vmi.Spec.Volumes[i].Name == name {
			return &vmi.Spec.Volumes[i]
		}
	}
	return nil
}

func diskExists(vmi *v1.VirtualMachineInstance, disk v1.Disk) bool {
	for _, d := range vmi.Spec.Domain.Devices.Disks {
		if d.Name == disk.Name {
			return true
		}
	}
	return false
}

func volumeExists(vmi *v1.VirtualMachineInstance, volume v1.Volume) bool {
	for _, v := range vmi.Spec.Volumes {
		if v.Name == volume.Name {
			return true
		}
	}
	return false
}

func newDisk(name string, bus v1.DiskBus) v1.Disk {
	return v1.Disk{
		Name: name,
		DiskDevice: v1.DiskDevice{
			Disk: &v1.DiskTarget{
				Bus: bus,
			},
		},
	}
}

func newVolume(name string) v1.Volume {
	return v1.Volume{Name: name}
}

func newContainerVolume(name, image string) v1.Volume {
	return v1.Volume{
		Name: name,
		VolumeSource: v1.VolumeSource{
			ContainerDisk: &v1.ContainerDiskSource{
				Image: image,
			},
		},
	}
}

func newPersistentVolumeClaimVolume(name, claimName string) v1.Volume {
	return v1.Volume{
		Name: name,
		VolumeSource: v1.VolumeSource{
			PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
				PersistentVolumeClaimVolumeSource: k8sv1.PersistentVolumeClaimVolumeSource{
					ClaimName: claimName,
				}},
		},
	}
}

func newDataVolume(name, dataVolumeName string) v1.Volume {
	return v1.Volume{
		Name: name,
		VolumeSource: v1.VolumeSource{
			DataVolume: &v1.DataVolumeSource{
				Name: dataVolumeName,
			},
		},
	}
}

func newEmptyDisk(name string, capacity resource.Quantity) v1.Volume {
	return v1.Volume{
		Name: name,
		VolumeSource: v1.VolumeSource{
			EmptyDisk: &v1.EmptyDiskSource{
				Capacity: capacity,
			},
		},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"reflect"
	"testing"
)

const (
	TEST_MCROUTER = "localhost:5000"
)

// Expect incoming message: stats all
// Return Example stats
func handleRequest(conn net.Conn) {
	buf := make([]byte, 1024)
	_, err := conn.Read(buf)
	if err != nil {
		fmt.Println("Error reading:", err.Error())
	}
	ret := []byte("STAT pid 1\r\nSTAT parent_pid 0\r\nSTAT fibers_allocated 1\r\nEND\r\n")
	conn.Write(ret)
	conn.Close()
}

// Test parsing a sample stats result
func TestStatsParsing(t *testing.T) {
	// Create a dummy server to return stats info
	go func() {
		l, err := net.Listen("tcp", "localhost:9213")
		if err != nil {
			t.Fatal("Failed to create TCP Server:", err.Error())
		}
		defer l.Close()
		for {
			conn, err := l.Accept()
			if err != nil {
				t.Fatal("Error accepting:", err.Error())
			}
			go handleRequest(conn)
		}
	}()

	client, _ := net.Dial("tcp", "localhost:9213")
	stats, _ := getStats(client)
	expected := make(map[string]string)
	expected["pid"] = "1"
	expected["parent_pid"] = "0"
	expected["fibers_allocated"] = "1"
	if !reflect.DeepEqual(stats, expected) {
		t.Errorf("Failed to parse stats into string map:\nGot:%s\nExpected:%s", stats, expected)
	}

}
<commit_msg>goconvey tests<commit_after>package main

import (
	"fmt"
	"net"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

const (
	TEST_MCROUTER = "localhost:5000"
)

// Expect incoming message: stats all
// Return Example stats
func handleRequest(conn net.Conn) {
	buf := make([]byte, 1024)
	_, err := conn.Read(buf)
	if err != nil {
		fmt.Println("Error reading:", err.Error())
	}
	ret := []byte("STAT pid 1\r\nSTAT parent_pid 0\r\nSTAT fibers_allocated 1\r\nEND\r\n")
	conn.Write(ret)
	conn.Close()
}

func TestStatsParsing(t *testing.T) {
	Convey("Given a remote mcrouter stats endpoint", t, func() {
		go func() {
			l, err := net.Listen("tcp", "localhost:9213")
			if err != nil {
				t.Fatal("Failed to create TCP Server:", err.Error())
			}
			defer l.Close()
			for {
				conn, err := l.Accept()
				if err != nil {
					t.Fatal("Error accepting:", err.Error())
				}
				go handleRequest(conn)
			}
		}()
		Convey("When scraped by our client", func() {
			client, _ := net.Dial("tcp", "localhost:9213")
			stats, _ := getStats(client)
			Convey("It should parse the stats into a string map", func() {
				expected := make(map[string]string)
				expected["pid"] = "1"
				expected["parent_pid"] = "0"
				expected["fibers_allocated"] = "1"
				So(stats, ShouldResemble, expected)
			})
		})
	})
}
<|endoftext|>


<commit_before>package main

import (
	"testing"

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

	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
)

var (
	server *RequestRecordingServer
	port   int
)

func TestMain(m *testing.M) {
	port = 8000
	server = CreateRequestRecordingServer(port)
	server.Start()
	os.Exit(m.Run())
	server.Stop()
}

var _ = Describe("Main", func() {

	BeforeEach(func() {
		server.Clear()
	})

	It("Makes a http POST request", func() {
		list := `http://127.0.0.1:8000/A -X POST`

		file, err := ioutil.TempFile(os.TempDir(), "prefix")
		if err != nil {
			panic(err)
		}
		file.WriteString(list)
		defer os.Remove(file.Name())

		exePath, err := filepath.Abs("./code-named-something")
		if err != nil {
			panic(err)
		}
		cmd := exec.Command(exePath, "-f", file.Name())
		output, err := cmd.CombinedOutput()

		fmt.Println(string(output))

		Expect(err).To(BeNil())
		Expect(server.Contains(RequestWithPath("/A"), RequestWithMethod("POST"))).To(Equal(true))
	})

	It("Makes a http get request to each url in a file", func() {
		list := `http://127.0.0.1:8000/A
			http://127.0.0.1:8000/B
			http://127.0.0.1:8000/C`
		file, err := ioutil.TempFile(os.TempDir(), "prefix")
		if err != nil {
			panic(err)
		}
		file.WriteString(list)
		defer os.Remove(file.Name())

		exePath, err := filepath.Abs("./code-named-something")
		if err != nil {
			panic(err)
		}
		cmd := exec.Command(exePath, "-f", file.Name())
		_, _ = cmd.CombinedOutput()

		Expect(err).To(BeNil())
		Expect(server.Contains(RequestWithPath("/A"))).To(Equal(true))
		Expect(server.Contains(RequestWithPath("/B"))).To(Equal(true))
		Expect(server.Contains(RequestWithPath("/C"))).To(Equal(true))
	})
})
<commit_msg>Supports the HTTP verbs POST, PUT, GET and DELETE<commit_after>package main

import (
	"testing"

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

	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
)

var (
	server *RequestRecordingServer
	port   int
)

func TestMain(m *testing.M) {
	port = 8000
	server = CreateRequestRecordingServer(port)
	server.Start()
	os.Exit(m.Run())
	server.Stop()
}

func CreateList(lines string) *os.File {
	file, err := ioutil.TempFile(os.TempDir(), "prefix")
	if err != nil {
		panic(err)
	}
	file.WriteString(lines)
	return file
}

var _ = Describe("Main", func() {

	var (
		exePath string
		err     error
	)

	BeforeEach(func() {
		exePath, err = filepath.Abs("./code-named-something")
		if err != nil {
			panic(err)
		}
		server.Clear()
	})

	supportedMethods := []string{"GET", "POST", "PUT", "DELETE"}
	for _, method := range supportedMethods {
		It(fmt.Sprintf("Makes a http %s request", method), func() {
			list := fmt.Sprintf(`http://127.0.0.1:8000/A -X %s`, method)
			file := CreateList(list)
			defer os.Remove(file.Name())
			cmd := exec.Command(exePath, "-f", file.Name())
			output, err := cmd.CombinedOutput()
			fmt.Println(string(output))
			Expect(err).To(BeNil())
			Expect(server.Contains(RequestWithPath("/A"), RequestWithMethod(method))).To(Equal(true))
		})

	}

	It("Makes a http get request to each url in a file", func() {
		list := `http://127.0.0.1:8000/A
			http://127.0.0.1:8000/B
			http://127.0.0.1:8000/C`
		file := CreateList(list)
		defer os.Remove(file.Name())

		cmd := exec.Command(exePath, "-f", file.Name())
		output, err := cmd.CombinedOutput()
		fmt.Println(string(output))

		Expect(err).To(BeNil())
		Expect(server.Contains(RequestWithPath("/A"))).To(Equal(true))
		Expect(server.Contains(RequestWithPath("/B"))).To(Equal(true))
		Expect(server.Contains(RequestWithPath("/C"))).To(Equal(true))
	})
})
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

type Response map[string]interface{}

func TestInvalidHeaderLogin(t *testing.T) {
	var expected, response Response

	expected = Response{"error": "Must send content as text/json"}

	r, _ := http.NewRequest("POST", "/login", strings.NewReader("TeST"))
	w := httptest.NewRecorder()

	LoginHandler(w, r)

	if w.Code != http.StatusBadRequest {
		t.Errorf("Expected status %d got %v", http.StatusBadRequest, w.Code)
	}

	b, err := ioutil.ReadAll(w.Body)
	if err != nil {
		t.Error("Can't read the response body")
	}

	err = json.Unmarshal(b, &response)
	if err != nil {
		t.Error("Can't read the response json")
	}

	for key, v := range expected {
		if _, ok := response[key]; !ok {
			t.Errorf("Expected %s:%v but key is missing in %v", key, v, len(response))
		} else if response[key] != v {
			t.Errorf("Expected %s:%v got %v", key, v, response[key])
		}
	}

}
<commit_msg>Added another test<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

type Response map[string]interface{}

func TestInvalidHeaderLogin(t *testing.T) {
	var expected, response Response

	expected = Response{"error": "Must send content as text/json"}

	r, _ := http.NewRequest("POST", "/login", strings.NewReader("TeST"))
	w := httptest.NewRecorder()

	LoginHandler(w, r)

	if w.Code != http.StatusBadRequest {
		t.Errorf("Expected status %d got %v", http.StatusBadRequest, w.Code)
	}

	b, err := ioutil.ReadAll(w.Body)
	if err != nil {
		t.Error("Can't read the response body")
	}

	err = json.Unmarshal(b, &response)
	if err != nil {
		t.Error("Can't read the response json")
	}

	for key, v := range expected {
		if _, ok := response[key]; !ok {
			t.Errorf("Expected %s:%v but key is missing in %v", key, v, len(response))
		} else if response[key] != v {
			t.Errorf("Expected %s:%v got %v", key, v, response[key])
		}
	}

}

func TestMalformedJSONLogin(t *testing.T) {
	var expected, response Response

	expected = Response{"error": "Bad Request"}

	r, _ := http.NewRequest("POST", "/login", strings.NewReader("TeST"))
	r.Header.Set("Content-Type", "text/json")
	w := httptest.NewRecorder()

	LoginHandler(w, r)

	if w.Code != http.StatusBadRequest {
		t.Errorf("Expected status %d got %v", http.StatusBadRequest, w.Code)
	}

	b, err := ioutil.ReadAll(w.Body)
	if err != nil {
		t.Error("Can't read the response body")
	}

	err = json.Unmarshal(b, &response)
	if err != nil {
		t.Error("Can't read the response json")
	}

	for key, v := range expected {
		if _, ok := response[key]; !ok {
			t.Errorf("Expected %s:%v but key is missing in %v", key, v, len(response))
		} else if response[key] != v {
			t.Errorf("Expected %s:%v got %v", key, v, response[key])
		}
	}

}
<|endoftext|>


<commit_before>package main

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

var (
	// mux is the HTTP request multiplexer used with the test server.
	mux *http.ServeMux

	// server is a test HTTP server used to provide mock API responses.
	server *httptest.Server
)

// setup sets up a test HTTP server along with a github.Client that is
// configured to talk to that test server. Tests should register handlers on
// mux which provide mock responses for the API method being tested.
func setup() {
	// test server
	mux = http.NewServeMux()

	// We want to ensure that tests catch mistakes where the endpoint URL is
	// specified as absolute rather than relative. It only makes a difference
	// when there's a non-empty base URL path. So, use that. See issue #752.
	apiHandler := http.NewServeMux()

	server = httptest.NewServer(apiHandler)
}

// teardown closes the test HTTP server.
func teardown() {
	server.Close()
}

func TestGetJIRAClient_IssueNotExists(t *testing.T) {
	setup()
	defer teardown()

	c, err := getJIRAClient(server.URL, "", "")
	if err != nil {
		t.Errorf("Failed to create a JIRA client: %s", err)
	}

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
	})

	err = checkIfIssue("WEB-1234", c)
	if err == nil {
		t.Error("No error occuered. Expected a 404")
	}
}

func TestGetIssuesOutOfMessage(t *testing.T) {
	dataProvider := []struct {
		Message  string
		Projects []string
		Result   []string
	}{
		{"WEB-22861 remove authentication prod build for now", []string{"WEB"}, []string{"WEB-22861"}},
		{"[WEB-22861] remove authentication prod build for now", []string{"WEB"}, []string{"WEB-22861"}},
		{"WEB-4711 SYS-1234 PRD-5678 remove authentication prod build for now", []string{"WEB", "SYS", "PRD"}, []string{"WEB-4711", "SYS-1234", "PRD-5678"}},
		{"[SCC-27] Replace deprecated autoloader strategy PSR-0 with PSR-4", []string{"SCC"}, []string{"SCC-27"}},
		{"WeB-4711 sys-1234 PRD-5678 remove authentication prod build for now", []string{"WEB", "SYS", "PRD"}, []string{"WeB-4711", "sys-1234", "PRD-5678"}},
		{"TASKLESS: Removes duplicated comment code.", []string{"WEB"}, nil},
		{"This is a commit message and we applied the PHP standard PSR-0 to the codebase", []string{"WEB"}, nil},
	}

	for _, data := range dataProvider {
		res := getIssuesOutOfMessage(data.Projects, data.Message)
		if reflect.DeepEqual(data.Result, res) == false {
			t.Errorf("Test failed, expected: '%+v' (%d), got: '%+v' (%d)", data.Result, len(data.Result), res, len(res))
		}
	}
}

func TestGetTextToAnalyze(t *testing.T) {
	dataProvider := []struct {
		Message string
		Stdin   bool
		Result  string
	}{
		{"", false, ""},
		{"From arguments without stdin", false, "From arguments without stdin"},
		{"From arguments with stdin", true, "From arguments with stdin"},
		// TODO: Test stdin
	}

	for _, data := range dataProvider {
		text := getTextToAnalyze(data.Message, data.Stdin)
		if text != data.Result {
			t.Errorf("Test failed, expected: '%+v', got: '%+v'", data.Result, text)
		}
	}
}
<commit_msg>Added a more detailled unit test message<commit_after>package main

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

var (
	// mux is the HTTP request multiplexer used with the test server.
	mux *http.ServeMux

	// server is a test HTTP server used to provide mock API responses.
	server *httptest.Server
)

// setup sets up a test HTTP server along with a github.Client that is
// configured to talk to that test server. Tests should register handlers on
// mux which provide mock responses for the API method being tested.
func setup() {
	// test server
	mux = http.NewServeMux()

	// We want to ensure that tests catch mistakes where the endpoint URL is
	// specified as absolute rather than relative. It only makes a difference
	// when there's a non-empty base URL path. So, use that. See issue #752.
	apiHandler := http.NewServeMux()

	server = httptest.NewServer(apiHandler)
}

// teardown closes the test HTTP server.
func teardown() {
	server.Close()
}

func TestGetJIRAClient_IssueNotExists(t *testing.T) {
	setup()
	defer teardown()

	c, err := getJIRAClient(server.URL, "", "")
	if err != nil {
		t.Errorf("Failed to create a JIRA client: %s", err)
	}

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
	})

	err = checkIfIssue("WEB-1234", c)
	if err == nil {
		t.Error("No error occuered. Expected a 404")
	}
}

func TestGetIssuesOutOfMessage(t *testing.T) {
	dataProvider := []struct {
		Message  string
		Projects []string
		Result   []string
	}{
		{"WEB-22861 remove authentication prod build for now", []string{"WEB"}, []string{"WEB-22861"}},
		{"[WEB-22861] remove authentication prod build for now", []string{"WEB"}, []string{"WEB-22861"}},
		{"WEB-4711 SYS-1234 PRD-5678 remove authentication prod build for now", []string{"WEB", "SYS", "PRD"}, []string{"WEB-4711", "SYS-1234", "PRD-5678"}},
		{"[SCC-27] Replace deprecated autoloader strategy PSR-0 with PSR-4", []string{"SCC"}, []string{"SCC-27"}},
		{"WeB-4711 sys-1234 PRD-5678 remove authentication prod build for now", []string{"WEB", "SYS", "PRD"}, []string{"WeB-4711", "sys-1234", "PRD-5678"}},
		{"TASKLESS: Removes duplicated comment code.", []string{"WEB"}, nil},
		{"This is a commit message and we applied the PHP standard PSR-0 to the codebase", []string{"WEB"}, nil},
		{"Merge remote-tracking branch 'origin/master' into bugfix/web-12345-fix-hotel-award-2017-on-android-7", []string{"WEB"}, []string{"web-12345"}},
	}

	for _, data := range dataProvider {
		res := getIssuesOutOfMessage(data.Projects, data.Message)
		if reflect.DeepEqual(data.Result, res) == false {
			t.Errorf("Test failed, expected: '%+v' (%d), got: '%+v' (%d)", data.Result, len(data.Result), res, len(res))
		}
	}
}

func TestGetTextToAnalyze(t *testing.T) {
	dataProvider := []struct {
		Message string
		Stdin   bool
		Result  string
	}{
		{"", false, ""},
		{"From arguments without stdin", false, "From arguments without stdin"},
		{"From arguments with stdin", true, "From arguments with stdin"},
		// TODO: Test stdin
	}

	for _, data := range dataProvider {
		text := getTextToAnalyze(data.Message, data.Stdin)
		if text != data.Result {
			t.Errorf("Test failed, expected: '%+v', got: '%+v'", data.Result, text)
		}
	}
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

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

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Printf("Init called, initializing chaincode")

	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	// Initialize the chaincode
	A = args[0]
	Aval, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	B = args[2]
	Bval, err = strconv.Atoi(args[3])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Transaction makes payment of X units from A to B but 5 times the value
func (t *SimpleChaincode) invoke5(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	fmt.Printf("Running invoke5")

	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var X int          // Transaction value
	var err error

	if len(args) != 3 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A = args[0]
	B = args[1]

	// Get the state from the ledger
	// TODO: will be nice to have a GetAllState call to ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Avalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Aval, _ = strconv.Atoi(string(Avalbytes))

	Bvalbytes, err := stub.GetState(B)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Bvalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Bval, _ = strconv.Atoi(string(Bvalbytes))

	// Perform the execution
	X, err = strconv.Atoi(args[2])
	Aval = Aval - X - X - X - X - X
	Bval = Bval + X + X + X + X + X
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state back to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	fmt.Printf("Running invoke")

	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var X int          // Transaction value
	var err error

	if len(args) != 3 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A = args[0]
	B = args[1]

	// Get the state from the ledger
	// TODO: will be nice to have a GetAllState call to ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Avalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Aval, _ = strconv.Atoi(string(Avalbytes))

	Bvalbytes, err := stub.GetState(B)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Bvalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Bval, _ = strconv.Atoi(string(Bvalbytes))

	// Perform the execution
	X, err = strconv.Atoi(args[2])
	Aval = Aval - X
	Bval = Bval + X
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state back to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	fmt.Printf("Running delete")

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(A)
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	return nil, nil
}

// Invoke callback representing the invocation of a chaincode
// This chaincode will manage two accounts A and B and will transfer X units from A to B upon invoke
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Printf("Invoke called, determining function")

	// Handle different functions
	if function == "invoke" {
		// Transaction makes payment of X units from A to B
		fmt.Printf("Function is invoke")
		return t.invoke(stub, args)
	} else if function == "init" {
		fmt.Printf("Function is init")
		return t.Init(stub, function, args)
	} else if function == "invoke5" {
		fmt.Printf("Function is invoke5")
		return t.invoke5(stub, args)
	} else if function == "delete" {
		// Deletes an entity from its state
		fmt.Printf("Function is delete")
		return t.delete(stub, args)
	}

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

func (t* SimpleChaincode) Run(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Printf("Run called, passing through to Invoke (same function)")

	// Handle different functions
	if function == "invoke" {
		// Transaction makes payment of X units from A to B
		fmt.Printf("Function is invoke")
		return t.invoke(stub, args)
	} else if function == "invoke5" {
		fmt.Printf("Function is invoke5")
		return t.invoke5(stub, args)
	} else if function == "init" {
		fmt.Printf("Function is init")
		return t.Init(stub, function, args)
	} else if function == "delete" {
		// Deletes an entity from its state
		fmt.Printf("Function is delete")
		return t.delete(stub, args)
	}

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

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Printf("Query called, determining function")

	if function != "query" {
		fmt.Printf("Function is query")
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var A string // Entities
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	A = args[0]

	// Get the state from the ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	if Avalbytes == nil {
		jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return Avalbytes, nil
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}
<commit_msg>11apr<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

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

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Printf("Init called, initializing chaincode")

	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var err error

	if len(args) != 4 {
		return nil, errors.New("Incorrect number of arguments. Expecting 4")
	}

	// Initialize the chaincode
	A = args[0]
	Aval, err = strconv.Atoi(args[1])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	B = args[2]
	Bval, err = strconv.Atoi(args[3])
	if err != nil {
		return nil, errors.New("Expecting integer value for asset holding")
	}
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Transaction makes payment of X units from A to B but 2 times the value
func (t *SimpleChaincode) invoke2(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	fmt.Printf("Running invoke2")

	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var X int          // Transaction value
	var err error

	if len(args) != 3 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A = args[0]
	B = args[1]

	// Get the state from the ledger
	// TODO: will be nice to have a GetAllState call to ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Avalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Aval, _ = strconv.Atoi(string(Avalbytes))

	Bvalbytes, err := stub.GetState(B)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Bvalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Bval, _ = strconv.Atoi(string(Bvalbytes))

	// Perform the execution
	X, err = strconv.Atoi(args[2])
	Aval = Aval - X - X
	Bval = Bval + X + X
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state back to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	fmt.Printf("Running invoke")

	var A, B string    // Entities
	var Aval, Bval int // Asset holdings
	var X int          // Transaction value
	var err error

	if len(args) != 3 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A = args[0]
	B = args[1]

	// Get the state from the ledger
	// TODO: will be nice to have a GetAllState call to ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Avalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Aval, _ = strconv.Atoi(string(Avalbytes))

	Bvalbytes, err := stub.GetState(B)
	if err != nil {
		return nil, errors.New("Failed to get state")
	}
	if Bvalbytes == nil {
		return nil, errors.New("Entity not found")
	}
	Bval, _ = strconv.Atoi(string(Bvalbytes))

	// Perform the execution
	X, err = strconv.Atoi(args[2])
	Aval = Aval - X
	Bval = Bval + X
	fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

	// Write the state back to the ledger
	err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
	if err != nil {
		return nil, err
	}

	err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
	if err != nil {
		return nil, err
	}

	return nil, nil
}

// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	fmt.Printf("Running delete")

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 3")
	}

	A := args[0]

	// Delete the key from the state in ledger
	err := stub.DelState(A)
	if err != nil {
		return nil, errors.New("Failed to delete state")
	}

	return nil, nil
}

// Invoke callback representing the invocation of a chaincode
// This chaincode will manage two accounts A and B and will transfer X units from A to B upon invoke
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Printf("Invoke called, determining function")

	// Handle different functions
	if function == "invoke" {
		// Transaction makes payment of X units from A to B
		fmt.Printf("Function is invoke")
		return t.invoke(stub, args)
	} else if function == "init" {
		fmt.Printf("Function is init")
		return t.Init(stub, function, args)
	} else if function == "invoke2" {
		fmt.Printf("Function is invoke2")
		return t.invoke2(stub, args)
	} else if function == "delete" {
		// Deletes an entity from its state
		fmt.Printf("Function is delete")
		return t.delete(stub, args)
	}

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

func (t* SimpleChaincode) Run(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Printf("Run called, passing through to Invoke (same function)")

	// Handle different functions
	if function == "invoke" {
		// Transaction makes payment of X units from A to B
		fmt.Printf("Function is invoke")
		return t.invoke(stub, args)
	} else if function == "invoke2" {
		fmt.Printf("Function is invoke2")
		return t.invoke2(stub, args)
	} else if function == "init" {
		fmt.Printf("Function is init")
		return t.Init(stub, function, args)
	} else if function == "delete" {
		// Deletes an entity from its state
		fmt.Printf("Function is delete")
		return t.delete(stub, args)
	}

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

// Query callback representing the query of a chaincode
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Printf("Query called, determining function")

	if function != "query" {
		fmt.Printf("Function is query")
		return nil, errors.New("Invalid query function name. Expecting \"query\"")
	}
	var A string // Entities
	var err error

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query")
	}

	A = args[0]

	// Get the state from the ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	if Avalbytes == nil {
		jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
		return nil, errors.New(jsonResp)
	}

	jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
	fmt.Printf("Query Response:%s\n", jsonResp)
	return Avalbytes, nil
}

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


<commit_before>package webpoll

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/matryer/go-oauth/oauth"
)

type tweet struct {
	Text string `json:"text"`
}

type TwitterBallot struct {
	authClient *oauth.Client
	creds      *oauth.Credentials
	conn       net.Conn
	reader     io.ReadCloser
	out        chan string
}

func NewTwitterBallot(consumerKey, consumerSecret, accessToken, accessSecret string) *TwitterBallot {
	return &TwitterBallot{
		creds: &oauth.Credentials{
			Token:  accessToken,
			Secret: accessSecret,
		},
		authClient: &oauth.Client{
			Credentials: oauth.Credentials{
				Token:  consumerKey,
				Secret: consumerSecret,
			},
		},
	}
}

func (t *TwitterBallot) Start(options []string) (<-chan string, error) {

	for i, _ := range options {
		options[i] = "#" + strings.ToLower(options[i])
	}

	form := url.Values{"track": {strings.Join(options, ",")}}
	formEnc := form.Encode()
	u, _ := url.Parse("https://stream.twitter.com/1.1/statuses/filter.json")
	req, err := http.NewRequest("POST", u.String(), strings.NewReader(formEnc))
	if err != nil {
		return nil, fmt.Errorf("Creating filter request failed: %s", err)
	}

	req.Header.Set("Authorization", t.authClient.AuthorizationHeader(t.creds, "POST", u, form))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Content-Length", strconv.Itoa(len(formEnc)))

	client := &http.Client{
		Transport: &http.Transport{
			Dial: func(netw, addr string) (net.Conn, error) {
				netc, err := net.DialTimeout(netw, addr, 1*time.Minute)
				if err != nil {
					return nil, err
				}
				t.conn = netc
				return netc, nil
			},
		},
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		body, _ := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		return nil, fmt.Errorf("Twitter filter failed (%d): %s", resp.StatusCode, body)
	}

	t.reader = resp.Body
	decoder := json.NewDecoder(t.reader)

	t.out = make(chan string)

	go func() {
		for {
			var tweet *tweet
			if err := decoder.Decode(&tweet); err != nil {
				return
			} else {
				for _, option := range options {
					if strings.Contains(strings.ToLower(tweet.Text), option) {
						t.out <- option
					}
				}
			}
		}
	}()

	return t.out, nil
}

func (t *TwitterBallot) Stop() {
	if t.reader != nil {
		t.reader.Close()
	}
	t.conn.Close()
	close(t.out)
}
<commit_msg>improved connection closing<commit_after>package webpoll

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"github.com/matryer/go-oauth/oauth"
)

type tweet struct {
	Text string `json:"text"`
}

type TwitterBallot struct {
	authClient *oauth.Client
	creds      *oauth.Credentials
	conn       net.Conn
	reader     io.ReadCloser
	out        chan string
}

func NewTwitterBallot(consumerKey, consumerSecret, accessToken, accessSecret string) *TwitterBallot {
	return &TwitterBallot{
		creds: &oauth.Credentials{
			Token:  accessToken,
			Secret: accessSecret,
		},
		authClient: &oauth.Client{
			Credentials: oauth.Credentials{
				Token:  consumerKey,
				Secret: consumerSecret,
			},
		},
	}
}

func (t *TwitterBallot) Start(options []string) (<-chan string, error) {

	for i, _ := range options {
		options[i] = "#" + strings.ToLower(options[i])
	}

	form := url.Values{"track": {strings.Join(options, ",")}}
	formEnc := form.Encode()
	u, _ := url.Parse("https://stream.twitter.com/1.1/statuses/filter.json")
	req, err := http.NewRequest("POST", u.String(), strings.NewReader(formEnc))
	if err != nil {
		return nil, fmt.Errorf("Creating filter request failed: %s", err)
	}

	req.Header.Set("Authorization", t.authClient.AuthorizationHeader(t.creds, "POST", u, form))
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Content-Length", strconv.Itoa(len(formEnc)))

	client := &http.Client{
		Transport: &http.Transport{
			Dial: func(netw, addr string) (net.Conn, error) {
				netc, err := net.DialTimeout(netw, addr, 1*time.Minute)
				if err != nil {
					return nil, err
				}
				t.conn = netc
				return netc, nil
			},
		},
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		body, _ := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		return nil, fmt.Errorf("Twitter filter failed (%d): %s", resp.StatusCode, body)
	}

	t.reader = resp.Body
	decoder := json.NewDecoder(t.reader)

	t.out = make(chan string)

	go func() {
		for {
			var tweet *tweet
			if err := decoder.Decode(&tweet); err != nil {
				return
			} else {
				for _, option := range options {
					if strings.Contains(strings.ToLower(tweet.Text), option) {
						t.out <- option
					}
				}
			}
		}
	}()

	return t.out, nil
}

func (t *TwitterBallot) Stop() {
	if err := t.conn.Close(); err != nil {
		log.Println("ERROR: Failed to close conn:", err)
	}
	if t.reader != nil {
		if err := t.reader.Close(); err != nil {
			log.Println("ERROR: Failed to close connection reader:", err)
		}
	}
	close(t.out)
}
<|endoftext|>


<commit_before>package slackapi

// ResponseBot defines the JSON-encoded output for Bot.
type ResponseBot struct {
	Response
	Bot BotEntity `json:"bot"`
}

// BotEntity defines the expected data from the JSON-encoded API response.
type BotEntity struct {
	ID      string            `json:"id"`
	Deleted bool              `json:"deleted"`
	Name    string            `json:"name"`
	Icons   map[string]string `json:"icons"`
}

// BotsInfo gets information about a bot user.
func (s *SlackAPI) BotsInfo(bot string) ResponseBot {
	var response ResponseBot
	s.GetRequest(&response, "bots.info", "token", "bot="+s.UsersID(bot))
	return response
}
<commit_msg>Modify name of the data type that holds the bot entity<commit_after>package slackapi

// ResponseBot defines the JSON-encoded output for Bot.
type ResponseBot struct {
	Response
	Bot Bot `json:"bot"`
}

// Bot defines the expected data from the JSON-encoded API response.
type Bot struct {
	ID      string            `json:"id"`
	Deleted bool              `json:"deleted"`
	Name    string            `json:"name"`
	Icons   map[string]string `json:"icons"`
}

// BotsInfo gets information about a bot user.
func (s *SlackAPI) BotsInfo(bot string) ResponseBot {
	var response ResponseBot
	s.GetRequest(&response, "bots.info", "token", "bot="+s.UsersID(bot))
	return response
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package bootstrap_test

import (
	"github.com/juju/errors"
	jc "github.com/juju/testing/checkers"
	gc "launchpad.net/gocheck"

	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/bootstrap"
	"github.com/juju/juju/juju/arch"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/tools"
	"github.com/juju/juju/version"
)

type toolsSuite struct {
	coretesting.BaseSuite
}

var _ = gc.Suite(&toolsSuite{})

func (s *toolsSuite) TestValidateUploadAllowedIncompatibleHostArch(c *gc.C) {
	// Host runs amd64, want ppc64 tools.
	s.PatchValue(&arch.HostArch, func() string {
		return "amd64"
	})
	// Force a dev version by having a non zero build number.
	// This is because we have not uploaded any tools and auto
	// upload is only enabled for dev versions.
	devVersion := version.Current
	devVersion.Build = 1234
	s.PatchValue(&version.Current, devVersion)
	env := newEnviron("foo", useDefaultKeys, nil)
	arch := "ppc64el"
	err := bootstrap.ValidateUploadAllowed(env, &arch)
	c.Assert(err, gc.ErrorMatches, `cannot build tools for "ppc64el" using a machine running on "amd64"`)
}

func (s *toolsSuite) TestValidateUploadAllowedIncompatibleTargetArch(c *gc.C) {
	// Host runs ppc64el, environment only supports amd64, arm64.
	s.PatchValue(&arch.HostArch, func() string {
		return "ppc64el"
	})
	// Force a dev version by having a non zero build number.
	// This is because we have not uploaded any tools and auto
	// upload is only enabled for dev versions.
	devVersion := version.Current
	devVersion.Build = 1234
	s.PatchValue(&version.Current, devVersion)
	env := newEnviron("foo", useDefaultKeys, nil)
	err := bootstrap.ValidateUploadAllowed(env, nil)
	c.Assert(err, gc.ErrorMatches, `environment "foo" of type dummy does not support instances running on "ppc64el"`)
}

func (s *toolsSuite) TestValidateUploadAllowed(c *gc.C) {
	env := newEnviron("foo", useDefaultKeys, nil)
	// Host runs arm64, environment supports arm64.
	arm64 := "arm64"
	s.PatchValue(&arch.HostArch, func() string {
		return arm64
	})
	err := bootstrap.ValidateUploadAllowed(env, &arm64)
	c.Assert(err, gc.IsNil)
}

func (s *toolsSuite) TestFindBootstrapTools(c *gc.C) {
	var called int
	var filter tools.Filter
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		called++
		c.Check(major, gc.Equals, version.Current.Major)
		c.Check(minor, gc.Equals, version.Current.Minor)
		c.Check(retry, jc.IsFalse)
		filter = f
		return nil, nil
	})

	vers := version.MustParse("1.2.1")
	arm64 := "arm64"

	type test struct {
		version *version.Number
		arch    *string
		dev     bool
		filter  tools.Filter
	}
	tests := []test{{
		version: nil,
		arch:    nil,
		dev:     false,
		filter:  tools.Filter{Released: true},
	}, {
		version: nil,
		arch:    nil,
		dev:     true,
		filter:  tools.Filter{},
	}, {
		version: &vers,
		arch:    nil,
		dev:     false,
		filter:  tools.Filter{Number: vers},
	}, {
		version: nil,
		arch:    &arm64,
		dev:     false,
		filter:  tools.Filter{Arch: arm64, Released: true},
	}, {
		version: &vers,
		arch:    &arm64,
		dev:     true,
		filter:  tools.Filter{Arch: arm64, Number: vers},
	}}

	for i, test := range tests {
		c.Logf("test %d: %#v", i, test)
		bootstrap.FindBootstrapTools(nil, test.version, test.arch, test.dev)
		c.Assert(called, gc.Equals, i+1)
		c.Assert(filter, gc.Equals, test.filter)
	}
}

func (s *toolsSuite) TestFindAvailableToolsError(c *gc.C) {
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		return nil, errors.New("splat")
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	_, err := bootstrap.FindAvailableTools(env, nil, false)
	c.Assert(err, gc.ErrorMatches, "splat")
}

func (s *toolsSuite) TestFindAvailableToolsNoUpload(c *gc.C) {
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		return nil, errors.NotFoundf("tools")
	})
	env := newEnviron("foo", useDefaultKeys, map[string]interface{}{
		"agent-version": "1.17.1",
	})
	_, err := bootstrap.FindAvailableTools(env, nil, false)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)
}

func (s *toolsSuite) TestFindAvailableToolsForceUpload(c *gc.C) {
	s.PatchValue(&arch.HostArch, func() string {
		return "amd64"
	})
	var findToolsCalled int
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		findToolsCalled++
		return nil, errors.NotFoundf("tools")
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	uploadedTools, err := bootstrap.FindAvailableTools(env, nil, true)
	c.Assert(err, gc.IsNil)
	c.Assert(uploadedTools, gc.Not(gc.HasLen), 0)
	c.Assert(findToolsCalled, gc.Equals, 0)
	for _, tools := range uploadedTools {
		c.Assert(tools.Version.Number, gc.Equals, version.Current.Number)
		c.Assert(tools.URL, gc.Equals, "")
	}
}

func (s *toolsSuite) TestFindAvailableToolsAutoUpload(c *gc.C) {
	s.PatchValue(&arch.HostArch, func() string {
		return "amd64"
	})
	s.PatchValue(&version.Current.Arch, "amd64")
	trustyTools := &tools.Tools{
		Version: version.MustParseBinary("1.2.3-trusty-amd64"),
		URL:     "http://testing.invalid/tools.tar.gz",
	}
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		return tools.List{trustyTools}, nil
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	availableTools, err := bootstrap.FindAvailableTools(env, nil, false)
	c.Assert(err, gc.IsNil)
	c.Assert(len(availableTools), jc.GreaterThan, 1)
	c.Assert(env.supportedArchitecturesCount, gc.Equals, 1)
	var trustyToolsFound int
	for _, tools := range availableTools {
		if tools == trustyTools {
			trustyToolsFound++
		} else {
			c.Assert(tools.Version.Number, gc.Equals, version.Current.Number)
			c.Assert(tools.Version.Series, gc.Not(gc.Equals), "trusty")
			c.Assert(tools.URL, gc.Equals, "")
		}
	}
	c.Assert(trustyToolsFound, gc.Equals, 1)
}

func (s *toolsSuite) TestFindAvailableToolsCompleteNoValidate(c *gc.C) {
	s.PatchValue(&arch.HostArch, func() string {
		return "amd64"
	})
	s.PatchValue(&version.Current.Arch, "amd64")

	var allTools tools.List
	for _, series := range version.SupportedSeries() {
		binary := version.Current
		binary.Series = series
		allTools = append(allTools, &tools.Tools{
			Version: binary,
			URL:     "http://testing.invalid/tools.tar.gz",
		})
	}

	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		return allTools, nil
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	availableTools, err := bootstrap.FindAvailableTools(env, nil, false)
	c.Assert(err, gc.IsNil)
	c.Assert(availableTools, gc.HasLen, len(allTools))
	c.Assert(env.supportedArchitecturesCount, gc.Equals, 0)
}
<commit_msg>environs/bootstrap: more coverage in findAvailableTools<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package bootstrap_test

import (
	"github.com/juju/errors"
	jc "github.com/juju/testing/checkers"
	gc "launchpad.net/gocheck"

	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/bootstrap"
	"github.com/juju/juju/juju/arch"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/tools"
	"github.com/juju/juju/version"
)

type toolsSuite struct {
	coretesting.BaseSuite
}

var _ = gc.Suite(&toolsSuite{})

func (s *toolsSuite) TestValidateUploadAllowedIncompatibleHostArch(c *gc.C) {
	// Host runs amd64, want ppc64 tools.
	s.PatchValue(&arch.HostArch, func() string {
		return "amd64"
	})
	// Force a dev version by having a non zero build number.
	// This is because we have not uploaded any tools and auto
	// upload is only enabled for dev versions.
	devVersion := version.Current
	devVersion.Build = 1234
	s.PatchValue(&version.Current, devVersion)
	env := newEnviron("foo", useDefaultKeys, nil)
	arch := "ppc64el"
	err := bootstrap.ValidateUploadAllowed(env, &arch)
	c.Assert(err, gc.ErrorMatches, `cannot build tools for "ppc64el" using a machine running on "amd64"`)
}

func (s *toolsSuite) TestValidateUploadAllowedIncompatibleTargetArch(c *gc.C) {
	// Host runs ppc64el, environment only supports amd64, arm64.
	s.PatchValue(&arch.HostArch, func() string {
		return "ppc64el"
	})
	// Force a dev version by having a non zero build number.
	// This is because we have not uploaded any tools and auto
	// upload is only enabled for dev versions.
	devVersion := version.Current
	devVersion.Build = 1234
	s.PatchValue(&version.Current, devVersion)
	env := newEnviron("foo", useDefaultKeys, nil)
	err := bootstrap.ValidateUploadAllowed(env, nil)
	c.Assert(err, gc.ErrorMatches, `environment "foo" of type dummy does not support instances running on "ppc64el"`)
}

func (s *toolsSuite) TestValidateUploadAllowed(c *gc.C) {
	env := newEnviron("foo", useDefaultKeys, nil)
	// Host runs arm64, environment supports arm64.
	arm64 := "arm64"
	s.PatchValue(&arch.HostArch, func() string {
		return arm64
	})
	err := bootstrap.ValidateUploadAllowed(env, &arm64)
	c.Assert(err, gc.IsNil)
}

func (s *toolsSuite) TestFindBootstrapTools(c *gc.C) {
	var called int
	var filter tools.Filter
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		called++
		c.Check(major, gc.Equals, version.Current.Major)
		c.Check(minor, gc.Equals, version.Current.Minor)
		c.Check(retry, jc.IsFalse)
		filter = f
		return nil, nil
	})

	vers := version.MustParse("1.2.1")
	arm64 := "arm64"

	type test struct {
		version *version.Number
		arch    *string
		dev     bool
		filter  tools.Filter
	}
	tests := []test{{
		version: nil,
		arch:    nil,
		dev:     false,
		filter:  tools.Filter{Released: true},
	}, {
		version: nil,
		arch:    nil,
		dev:     true,
		filter:  tools.Filter{},
	}, {
		version: &vers,
		arch:    nil,
		dev:     false,
		filter:  tools.Filter{Number: vers},
	}, {
		version: nil,
		arch:    &arm64,
		dev:     false,
		filter:  tools.Filter{Arch: arm64, Released: true},
	}, {
		version: &vers,
		arch:    &arm64,
		dev:     true,
		filter:  tools.Filter{Arch: arm64, Number: vers},
	}}

	for i, test := range tests {
		c.Logf("test %d: %#v", i, test)
		bootstrap.FindBootstrapTools(nil, test.version, test.arch, test.dev)
		c.Assert(called, gc.Equals, i+1)
		c.Assert(filter, gc.Equals, test.filter)
	}
}

func (s *toolsSuite) TestFindAvailableToolsError(c *gc.C) {
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		return nil, errors.New("splat")
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	_, err := bootstrap.FindAvailableTools(env, nil, false)
	c.Assert(err, gc.ErrorMatches, "splat")
}

func (s *toolsSuite) TestFindAvailableToolsNoUpload(c *gc.C) {
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		return nil, errors.NotFoundf("tools")
	})
	env := newEnviron("foo", useDefaultKeys, map[string]interface{}{
		"agent-version": "1.17.1",
	})
	_, err := bootstrap.FindAvailableTools(env, nil, false)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)
}

func (s *toolsSuite) TestFindAvailableToolsForceUpload(c *gc.C) {
	s.PatchValue(&arch.HostArch, func() string {
		return "amd64"
	})
	var findToolsCalled int
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		findToolsCalled++
		return nil, errors.NotFoundf("tools")
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	uploadedTools, err := bootstrap.FindAvailableTools(env, nil, true)
	c.Assert(err, gc.IsNil)
	c.Assert(uploadedTools, gc.Not(gc.HasLen), 0)
	c.Assert(findToolsCalled, gc.Equals, 0)
	for _, tools := range uploadedTools {
		c.Assert(tools.Version.Number, gc.Equals, version.Current.Number)
		c.Assert(tools.URL, gc.Equals, "")
	}
}

func (s *toolsSuite) TestFindAvailableToolsForceUploadInvalidArch(c *gc.C) {
	s.PatchValue(&arch.HostArch, func() string {
		return arch.I386
	})
	var findToolsCalled int
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		findToolsCalled++
		return nil, errors.NotFoundf("tools")
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	_, err := bootstrap.FindAvailableTools(env, nil, true)
	c.Assert(err, gc.ErrorMatches, `environment "foo" of type dummy does not support instances running on "i386"`)
	c.Assert(findToolsCalled, gc.Equals, 0)
}

func (s *toolsSuite) TestFindAvailableToolsAutoUpload(c *gc.C) {
	s.PatchValue(&arch.HostArch, func() string {
		return "amd64"
	})
	s.PatchValue(&version.Current.Arch, "amd64")
	trustyTools := &tools.Tools{
		Version: version.MustParseBinary("1.2.3-trusty-amd64"),
		URL:     "http://testing.invalid/tools.tar.gz",
	}
	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		return tools.List{trustyTools}, nil
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	availableTools, err := bootstrap.FindAvailableTools(env, nil, false)
	c.Assert(err, gc.IsNil)
	c.Assert(len(availableTools), jc.GreaterThan, 1)
	c.Assert(env.supportedArchitecturesCount, gc.Equals, 1)
	var trustyToolsFound int
	for _, tools := range availableTools {
		if tools == trustyTools {
			trustyToolsFound++
		} else {
			c.Assert(tools.Version.Number, gc.Equals, version.Current.Number)
			c.Assert(tools.Version.Series, gc.Not(gc.Equals), "trusty")
			c.Assert(tools.URL, gc.Equals, "")
		}
	}
	c.Assert(trustyToolsFound, gc.Equals, 1)
}

func (s *toolsSuite) TestFindAvailableToolsCompleteNoValidate(c *gc.C) {
	s.PatchValue(&arch.HostArch, func() string {
		return "amd64"
	})
	s.PatchValue(&version.Current.Arch, "amd64")

	var allTools tools.List
	for _, series := range version.SupportedSeries() {
		binary := version.Current
		binary.Series = series
		allTools = append(allTools, &tools.Tools{
			Version: binary,
			URL:     "http://testing.invalid/tools.tar.gz",
		})
	}

	s.PatchValue(bootstrap.FindTools, func(_ environs.ConfigGetter, major, minor int, f tools.Filter, retry bool) (tools.List, error) {
		return allTools, nil
	})
	env := newEnviron("foo", useDefaultKeys, nil)
	availableTools, err := bootstrap.FindAvailableTools(env, nil, false)
	c.Assert(err, gc.IsNil)
	c.Assert(availableTools, gc.HasLen, len(allTools))
	c.Assert(env.supportedArchitecturesCount, gc.Equals, 0)
}
<|endoftext|>