<commit_before>package kite

import (
	"encoding/json"
	"fmt"
	"github.com/streadway/amqp"
	"io"
	"koding/config"
	"koding/tools/dnode"
	"koding/tools/log"
	"koding/tools/utils"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"strconv"
	"syscall"
)

type Kite struct {
	Name     string
	Handlers map[string]Handler
}

type Handler struct {
	Concurrent bool
	Callback   func(args *dnode.Partial, session *Session) (interface{}, error)
}

func New(name string) *Kite {
	return &Kite{
		Name:     name,
		Handlers: make(map[string]Handler),
	}
}

func (k *Kite) Handle(method string, concurrent bool, callback func(args *dnode.Partial, session *Session) (interface{}, error)) {
	k.Handlers[method] = Handler{concurrent, callback}
}

func (k *Kite) Run() {
	utils.RunStatusLogger()

	sigtermChannel := make(chan os.Signal)
	signal.Notify(sigtermChannel, syscall.SIGTERM)

	utils.AmqpAutoReconnect(k.Name+"-kite", func(consumeConn, publishConn *amqp.Connection) {
		routeMap := make(map[string](chan<- []byte))
		defer func() {
			for _, channel := range routeMap {
				close(channel)
			}
		}()

		publishChannel := utils.CreateAmqpChannel(publishConn)
		defer publishChannel.Close()

		consumeChannel := utils.CreateAmqpChannel(consumeConn)
		utils.DeclareAmqpPresenceExchange(consumeChannel, "services-presence", "kite", "kite-"+k.Name, "kite-"+k.Name)
		stream := utils.DeclareBindConsumeAmqpQueue(consumeChannel, "fanout", "kite-"+k.Name, "")

		for {
			select {
			case message, ok := <-stream:
				if !ok {
					return
				}

				switch message.RoutingKey {
				case "auth.join":
					arguments := make(map[string]interface{})
					json.Unmarshal(message.Body, &arguments)
					username := arguments["username"].(string)
					routingKey := arguments["routingKey"].(string)

					if _, found := routeMap[routingKey]; found {
						continue // duplicate key
					}
					channel := make(chan []byte, 1024)
					routeMap[routingKey] = channel

					go func() {
						defer log.RecoverAndLog()

						utils.ChangeNumClients <- 1
						log.Debug("Client connected: " + username)
						defer func() {
							utils.ChangeNumClients <- -1
							log.Debug("Client disconnected: " + username)
						}()

						session := NewSession(username)
						defer session.Close()

						d := dnode.New()
						defer d.Close()
						d.OnRootMethod = func(method string, args *dnode.Partial) {
							defer log.RecoverAndLog()

							if method == "ping" {
								d.Send("pong")
								return
							}

							var partials []*dnode.Partial
							err := args.Unmarshal(&partials)
							if err != nil {
								panic(err)
							}

							var options map[string]*dnode.Partial
							err = partials[0].Unmarshal(&options)
							if err != nil {
								panic(err)
							}
							var resultCallback dnode.Callback
							err = partials[1].Unmarshal(&resultCallback)
							if err != nil {
								panic(err)
							}

							handler, found := k.Handlers[method]
							if !found {
								resultCallback(fmt.Sprintf("Method '%v' not known.", method), nil)
								return
							}

							execHandler := func() {
								result, err := handler.Callback(options["withArgs"], session)
								if err != nil {
									resultCallback(err.Error(), result)
								} else if result != nil {
									resultCallback(nil, result)
								}
							}
							if handler.Concurrent {
								go func() {
									defer log.RecoverAndLog()
									execHandler()
								}()
							} else {
								execHandler()
							}
						}

						go func() {
							defer log.RecoverAndLog()
							for data := range d.SendChan {
								log.Debug("Write", routingKey, data)
								err := publishChannel.Publish("broker", routingKey, false, false, amqp.Publishing{Body: data})
								if err != nil {
									panic(err)
								}
							}
						}()

						d.Send("ready", "kite-"+k.Name)

						for message := range channel {
							log.Debug("Read", routingKey, message)
							d.ProcessMessage(message)
						}
					}()

				case "auth.leave":
					arguments := make(map[string]interface{})
					json.Unmarshal(message.Body, &arguments)
					routingKey := arguments["routingKey"].(string)
					channel, found := routeMap[routingKey]
					if found {
						close(channel)
						delete(routeMap, routingKey)
					}

				default:
					channel, found := routeMap[message.RoutingKey]
					if found {
						select {
						case channel <- message.Body:
							// successful
						default:
							close(channel)
							delete(routeMap, message.RoutingKey)
							log.Warn("Dropped client because of message buffer overflow.")
						}
					}
				}

			case <-sigtermChannel:
				log.Info("Received TERM signal. Beginning shutdown...")
				utils.BeginShutdown()
				consumeChannel.Close()
			}
		}
	})
}

type Session struct {
	User, Home string
	Uid, Gid   int
	closers    []io.Closer
}

func NewSession(username string) *Session {
	userData, err := user.Lookup(username)
	if err != nil {
		panic(err)
	}
	uid, err := strconv.Atoi(userData.Uid)
	if err != nil {
		panic(err)
	}
	gid, err := strconv.Atoi(userData.Gid)
	if err != nil {
		panic(err)
	}
	if uid == 0 || gid == 0 {
		panic("SECURITY BREACH: User lookup returned root.")
	}
	return &Session{
		User: username,
		Home: config.Current.HomePrefix + username,
		Uid:  uid,
		Gid:  gid,
	}
}

func (session *Session) CloseOnDisconnect(closer io.Closer) {
	session.closers = append(session.closers, closer)
}

func (session *Session) Close() {
	for _, closer := range session.closers {
		closer.Close()
	}
	session.closers = nil
}

func (session *Session) CreateCommand(command ...string) *exec.Cmd {
	var cmd *exec.Cmd
	if config.Current.UseLVE {
		cmd = exec.Command("/bin/lve_exec", command...)
	} else {
		cmd = exec.Command(command[0], command[1:]...)
	}
	cmd.Dir = session.Home
	cmd.Env = []string{
		"USER=" + session.User,
		"LOGNAME=" + session.User,
		"HOME=" + session.Home,
		"SHELL=/bin/bash",
		"TERM=xterm",
		"LANG=en_US.UTF-8",
		"PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:" + session.Home + "/bin",
	}
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Credential: &syscall.Credential{
			Uid: uint32(session.Uid),
			Gid: uint32(session.Gid),
		},
	}

	return cmd
}
<commit_msg>go: Avoid not fully reading channel on error, thus blocking.<commit_after>package kite

import (
	"encoding/json"
	"fmt"
	"github.com/streadway/amqp"
	"io"
	"koding/config"
	"koding/tools/dnode"
	"koding/tools/log"
	"koding/tools/utils"
	"os"
	"os/exec"
	"os/signal"
	"os/user"
	"strconv"
	"syscall"
)

type Kite struct {
	Name     string
	Handlers map[string]Handler
}

type Handler struct {
	Concurrent bool
	Callback   func(args *dnode.Partial, session *Session) (interface{}, error)
}

func New(name string) *Kite {
	return &Kite{
		Name:     name,
		Handlers: make(map[string]Handler),
	}
}

func (k *Kite) Handle(method string, concurrent bool, callback func(args *dnode.Partial, session *Session) (interface{}, error)) {
	k.Handlers[method] = Handler{concurrent, callback}
}

func (k *Kite) Run() {
	utils.RunStatusLogger()

	sigtermChannel := make(chan os.Signal)
	signal.Notify(sigtermChannel, syscall.SIGTERM)

	utils.AmqpAutoReconnect(k.Name+"-kite", func(consumeConn, publishConn *amqp.Connection) {
		routeMap := make(map[string](chan<- []byte))
		defer func() {
			for _, channel := range routeMap {
				close(channel)
			}
		}()

		publishChannel := utils.CreateAmqpChannel(publishConn)
		defer publishChannel.Close()

		consumeChannel := utils.CreateAmqpChannel(consumeConn)
		utils.DeclareAmqpPresenceExchange(consumeChannel, "services-presence", "kite", "kite-"+k.Name, "kite-"+k.Name)
		stream := utils.DeclareBindConsumeAmqpQueue(consumeChannel, "fanout", "kite-"+k.Name, "")

		for {
			select {
			case message, ok := <-stream:
				if !ok {
					return
				}

				switch message.RoutingKey {
				case "auth.join":
					arguments := make(map[string]interface{})
					json.Unmarshal(message.Body, &arguments)
					username := arguments["username"].(string)
					routingKey := arguments["routingKey"].(string)

					if _, found := routeMap[routingKey]; found {
						continue // duplicate key
					}
					channel := make(chan []byte, 1024)
					routeMap[routingKey] = channel

					go func() {
						defer log.RecoverAndLog()

						utils.ChangeNumClients <- 1
						log.Debug("Client connected: " + username)
						defer func() {
							utils.ChangeNumClients <- -1
							log.Debug("Client disconnected: " + username)
						}()

						session := NewSession(username)
						defer session.Close()

						d := dnode.New()
						defer d.Close()
						d.OnRootMethod = func(method string, args *dnode.Partial) {
							defer log.RecoverAndLog()

							if method == "ping" {
								d.Send("pong")
								return
							}

							var partials []*dnode.Partial
							err := args.Unmarshal(&partials)
							if err != nil {
								panic(err)
							}

							var options map[string]*dnode.Partial
							err = partials[0].Unmarshal(&options)
							if err != nil {
								panic(err)
							}
							var resultCallback dnode.Callback
							err = partials[1].Unmarshal(&resultCallback)
							if err != nil {
								panic(err)
							}

							handler, found := k.Handlers[method]
							if !found {
								resultCallback(fmt.Sprintf("Method '%v' not known.", method), nil)
								return
							}

							execHandler := func() {
								result, err := handler.Callback(options["withArgs"], session)
								if err != nil {
									resultCallback(err.Error(), result)
								} else if result != nil {
									resultCallback(nil, result)
								}
							}
							if handler.Concurrent {
								go func() {
									defer log.RecoverAndLog()
									execHandler()
								}()
							} else {
								execHandler()
							}
						}

						go func() {
							defer log.RecoverAndLog()
							for data := range d.SendChan {
								log.Debug("Write", routingKey, data)
								err := publishChannel.Publish("broker", routingKey, false, false, amqp.Publishing{Body: data})
								if err != nil {
									log.LogError(err, 0)
								}
							}
						}()

						d.Send("ready", "kite-"+k.Name)

						for message := range channel {
							log.Debug("Read", routingKey, message)
							d.ProcessMessage(message)
						}
					}()

				case "auth.leave":
					arguments := make(map[string]interface{})
					json.Unmarshal(message.Body, &arguments)
					routingKey := arguments["routingKey"].(string)
					channel, found := routeMap[routingKey]
					if found {
						close(channel)
						delete(routeMap, routingKey)
					}

				default:
					channel, found := routeMap[message.RoutingKey]
					if found {
						select {
						case channel <- message.Body:
							// successful
						default:
							close(channel)
							delete(routeMap, message.RoutingKey)
							log.Warn("Dropped client because of message buffer overflow.")
						}
					}
				}

			case <-sigtermChannel:
				log.Info("Received TERM signal. Beginning shutdown...")
				utils.BeginShutdown()
				consumeChannel.Close()
			}
		}
	})
}

type Session struct {
	User, Home string
	Uid, Gid   int
	closers    []io.Closer
}

func NewSession(username string) *Session {
	userData, err := user.Lookup(username)
	if err != nil {
		panic(err)
	}
	uid, err := strconv.Atoi(userData.Uid)
	if err != nil {
		panic(err)
	}
	gid, err := strconv.Atoi(userData.Gid)
	if err != nil {
		panic(err)
	}
	if uid == 0 || gid == 0 {
		panic("SECURITY BREACH: User lookup returned root.")
	}
	return &Session{
		User: username,
		Home: config.Current.HomePrefix + username,
		Uid:  uid,
		Gid:  gid,
	}
}

func (session *Session) CloseOnDisconnect(closer io.Closer) {
	session.closers = append(session.closers, closer)
}

func (session *Session) Close() {
	for _, closer := range session.closers {
		closer.Close()
	}
	session.closers = nil
}

func (session *Session) CreateCommand(command ...string) *exec.Cmd {
	var cmd *exec.Cmd
	if config.Current.UseLVE {
		cmd = exec.Command("/bin/lve_exec", command...)
	} else {
		cmd = exec.Command(command[0], command[1:]...)
	}
	cmd.Dir = session.Home
	cmd.Env = []string{
		"USER=" + session.User,
		"LOGNAME=" + session.User,
		"HOME=" + session.Home,
		"SHELL=/bin/bash",
		"TERM=xterm",
		"LANG=en_US.UTF-8",
		"PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:" + session.Home + "/bin",
	}
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Credential: &syscall.Credential{
			Uid: uint32(session.Uid),
			Gid: uint32(session.Gid),
		},
	}

	return cmd
}
<|endoftext|>


<commit_before>package rest

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"socialapi/models"
	"socialapi/request"
	"strconv"
	"time"

	"github.com/google/go-querystring/query"
)

func GetHistory(channelId int64, q *request.Query, token string) (*models.HistoryResponse, error) {
	v, err := query.Values(q)
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf("/channel/%d/history?%s", channelId, v.Encode())
	res, err := sendRequestWithAuth("GET", url, nil, token)
	if err != nil {
		return nil, err
	}

	var history models.HistoryResponse
	err = json.Unmarshal(res, &history)
	if err != nil {
		return nil, err
	}

	return &history, nil
}

func CountHistory(channelId int64) (*models.CountResponse, error) {
	c := models.NewChannelMessageList()
	c.ChannelId = channelId

	url := fmt.Sprintf("/channel/%d/history/count", channelId)
	res, err := marshallAndSendRequest("GET", url, c)
	if err != nil {
		return nil, err
	}

	var count models.CountResponse
	err = json.Unmarshal(res, &count)
	if err != nil {
		return nil, err
	}

	return &count, nil
}

func FetchChannels(accountId int64) ([]*models.Channel, error) {
	return FetchChannelsByGroupName(accountId, "koding")
}

func FetchChannelsByGroupName(accountId int64, groupName string) ([]*models.Channel, error) {
	url := fmt.Sprintf("/account/%d/channels?groupName=%s", accountId, groupName)
	res, err := sendRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	var ccs []*models.ChannelContainer
	err = json.Unmarshal(res, &ccs)
	if err != nil {
		return nil, err
	}

	channels := make([]*models.Channel, len(ccs))
	for i, cc := range ccs {
		channels[i] = cc.Channel
	}

	return channels, nil
}

func DeleteChannel(creatorId, channelId int64) error {
	c := models.NewChannel()
	c.CreatorId = creatorId
	c.Id = channelId

	url := fmt.Sprintf("/channel/%d/delete", channelId)
	_, err := sendModel("POST", url, c)
	if err != nil {
		return err
	}
	return nil
}

func CreateChannel(creatorId int64) (*models.Channel, error) {
	return CreateChannelWithType(creatorId, models.Channel_TYPE_DEFAULT)
}

func CreateChannelWithType(creatorId int64, typeConstant string) (*models.Channel, error) {
	c := buildChannelWithRandomGroup(creatorId)
	c.TypeConstant = typeConstant

	return CreateChannelByGroupNameAndType(creatorId, c.GroupName, typeConstant)
}

func CreatePublicChannel(creatorId int64, groupName string) (*models.Channel, error) {
	c := models.NewChannel()
	c.GroupName = groupName
	c.CreatorId = creatorId
	c.TypeConstant = models.Channel_TYPE_GROUP
	c.PrivacyConstant = models.Channel_PRIVACY_PUBLIC
	c.Name = "public"
	cm, err := sendModel("POST", "/channel", c)
	if err != nil {
		return nil, err
	}

	return cm.(*models.Channel), nil
}

// buildChannelWithRandomGroup creates a channel with group name "koding[randonnumber]"
func buildChannelWithRandomGroup(creatorId int64) *models.Channel {
	c := models.NewChannel()
	rand.Seed(time.Now().UnixNano())
	c.GroupName = c.GroupName + strconv.Itoa(rand.Intn(100000000))

	return c
}

func CreateChannelByGroupNameAndType(creatorId int64, groupName, typeConstant string) (*models.Channel, error) {
	c := models.NewChannel()
	c.GroupName = groupName
	c.CreatorId = creatorId
	c.TypeConstant = typeConstant
	c.PrivacyConstant = models.Channel_PRIVACY_PUBLIC
	c.Name = c.Name + strconv.Itoa(rand.Intn(100000000))
	cm, err := sendModel("POST", "/channel", c)
	if err != nil {
		return nil, err
	}
	return cm.(*models.Channel), nil
}

func UpdateChannel(cm *models.Channel) (*models.Channel, error) {
	url := fmt.Sprintf("/channel/%d", cm.Id)
	cmI, err := sendModel("POST", url, cm)
	if err != nil {
		return nil, err
	}

	return cmI.(*models.Channel), nil
}

func GetChannel(id int64) (*models.Channel, error) {

	url := fmt.Sprintf("/channel/%d", id)
	cc := models.NewChannelContainer()
	cmI, err := sendModel("GET", url, cc)
	if err != nil {
		return nil, err
	}
	cc = cmI.(*models.ChannelContainer)

	return cc.Channel, nil
}

func SearchChannels(q *request.Query) ([]*models.Channel, error) {
	v, err := query.Values(q)
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf("/channel/search?%s", v.Encode())
	res, err := sendRequestWithAuth("GET", url, nil, "")
	if err != nil {
		return nil, err
	}

	channels := make([]*models.Channel{}, 0)
	err = json.Unmarshal(res, &channels)
	if err != nil {
		return nil, err
	}

	return &channels, nil
}

func CreateGroupActivityChannel(creatorId int64, groupName string) (*models.Channel, error) {
	c := models.NewChannel()
	c.GroupName = groupName
	c.CreatorId = creatorId
	c.TypeConstant = models.Channel_TYPE_GROUP
	c.Name = groupName

	cm, err := sendModel("POST", "/channel", c)
	if err != nil {
		return nil, err
	}

	return cm.(*models.Channel), nil
}
<commit_msg>socialapi: fix literal definition error<commit_after>package rest

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"socialapi/models"
	"socialapi/request"
	"strconv"
	"time"

	"github.com/google/go-querystring/query"
)

func GetHistory(channelId int64, q *request.Query, token string) (*models.HistoryResponse, error) {
	v, err := query.Values(q)
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf("/channel/%d/history?%s", channelId, v.Encode())
	res, err := sendRequestWithAuth("GET", url, nil, token)
	if err != nil {
		return nil, err
	}

	var history models.HistoryResponse
	err = json.Unmarshal(res, &history)
	if err != nil {
		return nil, err
	}

	return &history, nil
}

func CountHistory(channelId int64) (*models.CountResponse, error) {
	c := models.NewChannelMessageList()
	c.ChannelId = channelId

	url := fmt.Sprintf("/channel/%d/history/count", channelId)
	res, err := marshallAndSendRequest("GET", url, c)
	if err != nil {
		return nil, err
	}

	var count models.CountResponse
	err = json.Unmarshal(res, &count)
	if err != nil {
		return nil, err
	}

	return &count, nil
}

func FetchChannels(accountId int64) ([]*models.Channel, error) {
	return FetchChannelsByGroupName(accountId, "koding")
}

func FetchChannelsByGroupName(accountId int64, groupName string) ([]*models.Channel, error) {
	url := fmt.Sprintf("/account/%d/channels?groupName=%s", accountId, groupName)
	res, err := sendRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	var ccs []*models.ChannelContainer
	err = json.Unmarshal(res, &ccs)
	if err != nil {
		return nil, err
	}

	channels := make([]*models.Channel, len(ccs))
	for i, cc := range ccs {
		channels[i] = cc.Channel
	}

	return channels, nil
}

func DeleteChannel(creatorId, channelId int64) error {
	c := models.NewChannel()
	c.CreatorId = creatorId
	c.Id = channelId

	url := fmt.Sprintf("/channel/%d/delete", channelId)
	_, err := sendModel("POST", url, c)
	if err != nil {
		return err
	}
	return nil
}

func CreateChannel(creatorId int64) (*models.Channel, error) {
	return CreateChannelWithType(creatorId, models.Channel_TYPE_DEFAULT)
}

func CreateChannelWithType(creatorId int64, typeConstant string) (*models.Channel, error) {
	c := buildChannelWithRandomGroup(creatorId)
	c.TypeConstant = typeConstant

	return CreateChannelByGroupNameAndType(creatorId, c.GroupName, typeConstant)
}

func CreatePublicChannel(creatorId int64, groupName string) (*models.Channel, error) {
	c := models.NewChannel()
	c.GroupName = groupName
	c.CreatorId = creatorId
	c.TypeConstant = models.Channel_TYPE_GROUP
	c.PrivacyConstant = models.Channel_PRIVACY_PUBLIC
	c.Name = "public"
	cm, err := sendModel("POST", "/channel", c)
	if err != nil {
		return nil, err
	}

	return cm.(*models.Channel), nil
}

// buildChannelWithRandomGroup creates a channel with group name "koding[randonnumber]"
func buildChannelWithRandomGroup(creatorId int64) *models.Channel {
	c := models.NewChannel()
	rand.Seed(time.Now().UnixNano())
	c.GroupName = c.GroupName + strconv.Itoa(rand.Intn(100000000))

	return c
}

func CreateChannelByGroupNameAndType(creatorId int64, groupName, typeConstant string) (*models.Channel, error) {
	c := models.NewChannel()
	c.GroupName = groupName
	c.CreatorId = creatorId
	c.TypeConstant = typeConstant
	c.PrivacyConstant = models.Channel_PRIVACY_PUBLIC
	c.Name = c.Name + strconv.Itoa(rand.Intn(100000000))
	cm, err := sendModel("POST", "/channel", c)
	if err != nil {
		return nil, err
	}
	return cm.(*models.Channel), nil
}

func UpdateChannel(cm *models.Channel) (*models.Channel, error) {
	url := fmt.Sprintf("/channel/%d", cm.Id)
	cmI, err := sendModel("POST", url, cm)
	if err != nil {
		return nil, err
	}

	return cmI.(*models.Channel), nil
}

func GetChannel(id int64) (*models.Channel, error) {

	url := fmt.Sprintf("/channel/%d", id)
	cc := models.NewChannelContainer()
	cmI, err := sendModel("GET", url, cc)
	if err != nil {
		return nil, err
	}
	cc = cmI.(*models.ChannelContainer)

	return cc.Channel, nil
}

func SearchChannels(q *request.Query) ([]*models.Channel, error) {
	v, err := query.Values(q)
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf("/channel/search?%s", v.Encode())
	res, err := sendRequestWithAuth("GET", url, nil, "")
	if err != nil {
		return nil, err
	}

	channels := make([]*models.Channel, 0)
	err = json.Unmarshal(res, &channels)
	if err != nil {
		return nil, err
	}

	return &channels, nil
}

func CreateGroupActivityChannel(creatorId int64, groupName string) (*models.Channel, error) {
	c := models.NewChannel()
	c.GroupName = groupName
	c.CreatorId = creatorId
	c.TypeConstant = models.Channel_TYPE_GROUP
	c.Name = groupName

	cm, err := sendModel("POST", "/channel", c)
	if err != nil {
		return nil, err
	}

	return cm.(*models.Channel), nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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

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

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

package v1alpha1_test

import (
	"testing"

	"github.com/knative/build-pipeline/pkg/apis/pipeline/v1alpha1"
	tb "github.com/knative/build-pipeline/test/builder"
)

func TestPipelineSpec_Validate_Error(t *testing.T) {
	tests := []struct {
		name string
		p    *v1alpha1.Pipeline
	}{
		{
			name: "duplicate tasks",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineTask("foo", "foo-task"),
				tb.PipelineTask("foo", "foo-task"),
			)),
		},
		{
			name: "providedby task doesnt exist",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "great-resource", tb.ProvidedBy("bar"))),
			)),
		},
		{
			name: "providedby task is afterward",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "great-resource", tb.ProvidedBy("bar"))),
				tb.PipelineTask("bar", "bar-task",
					tb.PipelineTaskOutputResource("the-resource", "great-resource")),
			)),
		},
		{
			name: "unused resources declared",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineDeclaredResource("extra-resource", v1alpha1.PipelineResourceTypeImage),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "great-resource")),
			)),
		},
		{
			name: "output resources missing from declaration",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "great-resource"),
					tb.PipelineTaskOutputResource("the-magic-resource", "missing-resource")),
			)),
		},
		{
			name: "input resources missing from declaration",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "missing-resource"),
					tb.PipelineTaskOutputResource("the-magic-resource", "great-resource")),
			)),
		},
		{
			name: "providedBy resource isn't output by task",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineDeclaredResource("wonderful-resource", v1alpha1.PipelineResourceTypeImage),
				tb.PipelineTask("bar", "bar-task",
					tb.PipelineTaskInputResource("some-workspace", "great-resource")),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("wow-image", "wonderful-resource", tb.ProvidedBy("bar"))),
			)),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.p.Spec.Validate(); err == nil {
				t.Error("PipelineSpec.Validate() did not return error, wanted error")
			}
		})
	}
}

func TestPipelineSpec_Validate_Valid(t *testing.T) {
	tests := []struct {
		name string
		p    *v1alpha1.Pipeline
	}{
		{
			name: "no duplicate tasks",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineTask("foo", "foo-task"),
				tb.PipelineTask("bar", "bar-task"),
			)),
		},
		{
			name: "valid resource declarations and usage",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineDeclaredResource("wonderful-resource", v1alpha1.PipelineResourceTypeImage),
				tb.PipelineTask("bar", "bar-task",
					tb.PipelineTaskInputResource("some-workspace", "great-resource"),
					tb.PipelineTaskOutputResource("some-image", "wonderful-resource")),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("wow-image", "wonderful-resource", tb.ProvidedBy("bar"))),
			)),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.p.Spec.Validate(); err != nil {
				t.Errorf("PipelineSpec.Validate() returned error: %v", err)
			}
		})
	}
}
<commit_msg>Add case to make sure nil pointer is handled<commit_after>/*
Copyright 2018 The Knative Authors

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

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

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

package v1alpha1_test

import (
	"testing"

	"github.com/knative/build-pipeline/pkg/apis/pipeline/v1alpha1"
	tb "github.com/knative/build-pipeline/test/builder"
)

func TestPipelineSpec_Validate_Error(t *testing.T) {
	tests := []struct {
		name string
		p    *v1alpha1.Pipeline
	}{
		{
			name: "duplicate tasks",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineTask("foo", "foo-task"),
				tb.PipelineTask("foo", "foo-task"),
			)),
		},
		{
			name: "providedby task doesnt exist",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "great-resource", tb.ProvidedBy("bar"))),
			)),
		},
		{
			name: "providedby task is afterward",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "great-resource", tb.ProvidedBy("bar"))),
				tb.PipelineTask("bar", "bar-task",
					tb.PipelineTaskOutputResource("the-resource", "great-resource")),
			)),
		},
		{
			name: "unused resources declared",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineDeclaredResource("extra-resource", v1alpha1.PipelineResourceTypeImage),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "great-resource")),
			)),
		},
		{
			name: "output resources missing from declaration",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "great-resource"),
					tb.PipelineTaskOutputResource("the-magic-resource", "missing-resource")),
			)),
		},
		{
			name: "input resources missing from declaration",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("the-resource", "missing-resource"),
					tb.PipelineTaskOutputResource("the-magic-resource", "great-resource")),
			)),
		},
		{
			name: "providedBy resource isn't output by task",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineDeclaredResource("wonderful-resource", v1alpha1.PipelineResourceTypeImage),
				tb.PipelineTask("bar", "bar-task",
					tb.PipelineTaskInputResource("some-workspace", "great-resource")),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("wow-image", "wonderful-resource", tb.ProvidedBy("bar"))),
			)),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.p.Spec.Validate(); err == nil {
				t.Error("PipelineSpec.Validate() did not return error, wanted error")
			}
		})
	}
}

func TestPipelineSpec_Validate_Valid(t *testing.T) {
	tests := []struct {
		name string
		p    *v1alpha1.Pipeline
	}{
		{
			name: "no duplicate tasks",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineTask("foo", "foo-task"),
				tb.PipelineTask("bar", "bar-task"),
			)),
		},
		{
			// Adding this case because `task.Resources` is a pointer, explicitly making sure this is handled
			name: "task without resources",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("wonderful-resource", v1alpha1.PipelineResourceTypeImage),
				tb.PipelineTask("bar", "bar-task"),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("wow-image", "wonderful-resource")),
			)),
		},
		{
			name: "valid resource declarations and usage",
			p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec(
				tb.PipelineDeclaredResource("great-resource", v1alpha1.PipelineResourceTypeGit),
				tb.PipelineDeclaredResource("wonderful-resource", v1alpha1.PipelineResourceTypeImage),
				tb.PipelineTask("bar", "bar-task",
					tb.PipelineTaskInputResource("some-workspace", "great-resource"),
					tb.PipelineTaskOutputResource("some-image", "wonderful-resource")),
				tb.PipelineTask("foo", "foo-task",
					tb.PipelineTaskInputResource("wow-image", "wonderful-resource", tb.ProvidedBy("bar"))),
			)),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if err := tt.p.Spec.Validate(); err != nil {
				t.Errorf("PipelineSpec.Validate() returned error: %v", err)
			}
		})
	}
}
<|endoftext|>


<commit_before>package dependency

import (
	"fmt"
	"testing"

	"github.com/hashicorp/consul/api"
	"github.com/stretchr/testify/assert"
)

func TestNewHealthServiceQuery(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		i    string
		exp  *HealthServiceQuery
		err  bool
	}{
		{
			"empty",
			"",
			nil,
			true,
		},
		{
			"dc_only",
			"@dc1",
			nil,
			true,
		},
		{
			"near_only",
			"~near",
			nil,
			true,
		},
		{
			"tag_only",
			"tag.",
			nil,
			true,
		},
		{
			"name",
			"name",
			&HealthServiceQuery{
				filters: []string{"passing"},
				name:    "name",
			},
			false,
		},
		{
			"name_dc",
			"name@dc1",
			&HealthServiceQuery{
				dc:      "dc1",
				filters: []string{"passing"},
				name:    "name",
			},
			false,
		},
		{
			"name_dc_near",
			"name@dc1~near",
			&HealthServiceQuery{
				dc:      "dc1",
				filters: []string{"passing"},
				name:    "name",
				near:    "near",
			},
			false,
		},
		{
			"name_near",
			"name~near",
			&HealthServiceQuery{
				filters: []string{"passing"},
				name:    "name",
				near:    "near",
			},
			false,
		},
		{
			"tag_name",
			"tag.name",
			&HealthServiceQuery{
				filters: []string{"passing"},
				name:    "name",
				tag:     "tag",
			},
			false,
		},
		{
			"tag_name_dc",
			"tag.name@dc",
			&HealthServiceQuery{
				dc:      "dc",
				filters: []string{"passing"},
				name:    "name",
				tag:     "tag",
			},
			false,
		},
		{
			"tag_name_near",
			"tag.name~near",
			&HealthServiceQuery{
				filters: []string{"passing"},
				name:    "name",
				near:    "near",
				tag:     "tag",
			},
			false,
		},
		{
			"tag_name_dc_near",
			"tag.name@dc~near",
			&HealthServiceQuery{
				dc:      "dc",
				filters: []string{"passing"},
				name:    "name",
				near:    "near",
				tag:     "tag",
			},
			false,
		},
	}

	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
			act, err := NewHealthServiceQuery(tc.i)
			if (err != nil) != tc.err {
				t.Fatal(err)
			}

			if act != nil {
				act.stopCh = nil
			}

			assert.Equal(t, tc.exp, act)
		})
	}
	// Connect
	// all tests above also test connect, just need to check enabling it
	t.Run("connect_query", func(t *testing.T) {
		act, err := NewHealthConnectQuery("name")
		if err != nil {
			t.Fatal(err)
		}
		if act != nil {
			act.stopCh = nil
		}
		exp := &HealthServiceQuery{
			filters: []string{"passing"},
			name:    "name",
			connect: true,
		}

		assert.Equal(t, exp, act)
	})
}

func TestHealthConnectServiceQuery_Fetch(t *testing.T) {
	t.Parallel()
	cases := []struct {
		name string
		in   string
		exp  []*HealthService
	}{
		{
			"connect-service",
			"foo",
			[]*HealthService{
				&HealthService{
					Name:        "foo-sidecar-proxy",
					ID:          "foo",
					Port:        21999,
					Status:      "passing",
					Address:     "127.0.0.1",
					NodeAddress: "127.0.0.1",
					Tags:        ServiceTags([]string{}),
					NodeMeta: map[string]string{
						"consul-network-segment": ""},
				},
			},
		},
	}
	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
			d, err := NewHealthConnectQuery(tc.in)
			if err != nil {
				t.Fatal(err)
			}
			defer func() {
				d.Stop()
			}()
			res, _, err := d.Fetch(testClients, nil)
			if err != nil {
				t.Fatal(err)
			}
			var act []*HealthService
			if act = res.([]*HealthService); len(act) != 1 {
				t.Fatal("Expected 1 result, got ", len(act))
			}
			// blank out fields we don't want to test
			inst := act[0]
			inst.Node, inst.NodeID = "", ""
			inst.Checks = nil
			inst.NodeTaggedAddresses = nil

			assert.Equal(t, tc.exp, act)
		})
	}
}

func TestHealthServiceQuery_Fetch(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		i    string
		exp  []*HealthService
	}{
		{
			"consul",
			"consul",
			[]*HealthService{
				&HealthService{
					Node:        testConsul.Config.NodeName,
					NodeAddress: testConsul.Config.Bind,
					NodeTaggedAddresses: map[string]string{
						"lan": "127.0.0.1",
						"wan": "127.0.0.1",
					},
					NodeMeta: map[string]string{
						"consul-network-segment": "",
					},
					ServiceMeta: map[string]string{},
					Address:     testConsul.Config.Bind,
					ID:          "consul",
					Name:        "consul",
					Tags:        []string{},
					Status:      "passing",
					Port:        testConsul.Config.Ports.Server,
					Weights: api.AgentWeights{
						Passing: 1,
						Warning: 1,
					},
				},
			},
		},
		{
			"filters",
			"consul|warning",
			[]*HealthService{},
		},
		{
			"multifilter",
			"consul|warning,passing",
			[]*HealthService{
				&HealthService{
					Node:        testConsul.Config.NodeName,
					NodeAddress: testConsul.Config.Bind,
					NodeTaggedAddresses: map[string]string{
						"lan": "127.0.0.1",
						"wan": "127.0.0.1",
					},
					NodeMeta: map[string]string{
						"consul-network-segment": "",
					},
					ServiceMeta: map[string]string{},
					Address:     testConsul.Config.Bind,
					ID:          "consul",
					Name:        "consul",
					Tags:        []string{},
					Status:      "passing",
					Port:        testConsul.Config.Ports.Server,
					Weights: api.AgentWeights{
						Passing: 1,
						Warning: 1,
					},
				},
			},
		},
		{
			"service-meta",
			"service-meta",
			[]*HealthService{
				&HealthService{
					Node:        testConsul.Config.NodeName,
					NodeAddress: testConsul.Config.Bind,
					NodeTaggedAddresses: map[string]string{
						"lan": "127.0.0.1",
						"wan": "127.0.0.1",
					},
					NodeMeta: map[string]string{
						"consul-network-segment": "",
					},
					ServiceMeta: map[string]string{
						"meta1": "value1",
					},
					Address: testConsul.Config.Bind,
					ID:      "service-meta",
					Name:    "service-meta",
					Tags:    []string{"tag1"},
					Status:  "passing",
					Weights: api.AgentWeights{
						Passing: 1,
						Warning: 1,
					},
				},
			},
		},
	}

	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
			d, err := NewHealthServiceQuery(tc.i)
			if err != nil {
				t.Fatal(err)
			}

			act, _, err := d.Fetch(testClients, nil)
			if err != nil {
				t.Fatal(err)
			}

			if act != nil {
				for _, v := range act.([]*HealthService) {
					v.NodeID = ""
					v.Checks = nil
					// delete any version data from ServiceMeta
					v.ServiceMeta = filterVersionMeta(v.ServiceMeta)
				}
			}

			assert.Equal(t, tc.exp, act)
		})
	}
}

func TestHealthServiceQuery_String(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		i    string
		exp  string
	}{
		{
			"name",
			"name",
			"health.service(name|passing)",
		},
		{
			"name_dc",
			"name@dc",
			"health.service(name@dc|passing)",
		},
		{
			"name_filter",
			"name|any",
			"health.service(name|any)",
		},
		{
			"name_multifilter",
			"name|warning,passing",
			"health.service(name|passing,warning)",
		},
		{
			"name_near",
			"name~near",
			"health.service(name~near|passing)",
		},
		{
			"name_near_filter",
			"name~near|any",
			"health.service(name~near|any)",
		},
		{
			"name_dc_near",
			"name@dc~near",
			"health.service(name@dc~near|passing)",
		},
		{
			"name_dc_near_filter",
			"name@dc~near|any",
			"health.service(name@dc~near|any)",
		},
		{
			"tag_name",
			"tag.name",
			"health.service(tag.name|passing)",
		},
		{
			"tag_name_dc",
			"tag.name@dc",
			"health.service(tag.name@dc|passing)",
		},
		{
			"tag_name_near",
			"tag.name~near",
			"health.service(tag.name~near|passing)",
		},
		{
			"tag_name_dc_near",
			"tag.name@dc~near",
			"health.service(tag.name@dc~near|passing)",
		},
	}

	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
			d, err := NewHealthServiceQuery(tc.i)
			if err != nil {
				t.Fatal(err)
			}
			assert.Equal(t, tc.exp, d.String())
		})
	}
}
<commit_msg>add weights where needed in a test<commit_after>package dependency

import (
	"fmt"
	"testing"

	"github.com/hashicorp/consul/api"
	"github.com/stretchr/testify/assert"
)

func TestNewHealthServiceQuery(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		i    string
		exp  *HealthServiceQuery
		err  bool
	}{
		{
			"empty",
			"",
			nil,
			true,
		},
		{
			"dc_only",
			"@dc1",
			nil,
			true,
		},
		{
			"near_only",
			"~near",
			nil,
			true,
		},
		{
			"tag_only",
			"tag.",
			nil,
			true,
		},
		{
			"name",
			"name",
			&HealthServiceQuery{
				filters: []string{"passing"},
				name:    "name",
			},
			false,
		},
		{
			"name_dc",
			"name@dc1",
			&HealthServiceQuery{
				dc:      "dc1",
				filters: []string{"passing"},
				name:    "name",
			},
			false,
		},
		{
			"name_dc_near",
			"name@dc1~near",
			&HealthServiceQuery{
				dc:      "dc1",
				filters: []string{"passing"},
				name:    "name",
				near:    "near",
			},
			false,
		},
		{
			"name_near",
			"name~near",
			&HealthServiceQuery{
				filters: []string{"passing"},
				name:    "name",
				near:    "near",
			},
			false,
		},
		{
			"tag_name",
			"tag.name",
			&HealthServiceQuery{
				filters: []string{"passing"},
				name:    "name",
				tag:     "tag",
			},
			false,
		},
		{
			"tag_name_dc",
			"tag.name@dc",
			&HealthServiceQuery{
				dc:      "dc",
				filters: []string{"passing"},
				name:    "name",
				tag:     "tag",
			},
			false,
		},
		{
			"tag_name_near",
			"tag.name~near",
			&HealthServiceQuery{
				filters: []string{"passing"},
				name:    "name",
				near:    "near",
				tag:     "tag",
			},
			false,
		},
		{
			"tag_name_dc_near",
			"tag.name@dc~near",
			&HealthServiceQuery{
				dc:      "dc",
				filters: []string{"passing"},
				name:    "name",
				near:    "near",
				tag:     "tag",
			},
			false,
		},
	}

	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
			act, err := NewHealthServiceQuery(tc.i)
			if (err != nil) != tc.err {
				t.Fatal(err)
			}

			if act != nil {
				act.stopCh = nil
			}

			assert.Equal(t, tc.exp, act)
		})
	}
	// Connect
	// all tests above also test connect, just need to check enabling it
	t.Run("connect_query", func(t *testing.T) {
		act, err := NewHealthConnectQuery("name")
		if err != nil {
			t.Fatal(err)
		}
		if act != nil {
			act.stopCh = nil
		}
		exp := &HealthServiceQuery{
			filters: []string{"passing"},
			name:    "name",
			connect: true,
		}

		assert.Equal(t, exp, act)
	})
}

func TestHealthConnectServiceQuery_Fetch(t *testing.T) {
	t.Parallel()
	cases := []struct {
		name string
		in   string
		exp  []*HealthService
	}{
		{
			"connect-service",
			"foo",
			[]*HealthService{
				&HealthService{
					Name:        "foo-sidecar-proxy",
					ID:          "foo",
					Port:        21999,
					Status:      "passing",
					Address:     "127.0.0.1",
					NodeAddress: "127.0.0.1",
					Tags:        ServiceTags([]string{}),
					NodeMeta: map[string]string{
						"consul-network-segment": ""},
					Weights: api.AgentWeights{
						Passing: 1,
						Warning: 1,
					},
				},
			},
		},
	}
	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
			d, err := NewHealthConnectQuery(tc.in)
			if err != nil {
				t.Fatal(err)
			}
			defer func() {
				d.Stop()
			}()
			res, _, err := d.Fetch(testClients, nil)
			if err != nil {
				t.Fatal(err)
			}
			var act []*HealthService
			if act = res.([]*HealthService); len(act) != 1 {
				t.Fatal("Expected 1 result, got ", len(act))
			}
			// blank out fields we don't want to test
			inst := act[0]
			inst.Node, inst.NodeID = "", ""
			inst.Checks = nil
			inst.NodeTaggedAddresses = nil

			assert.Equal(t, tc.exp, act)
		})
	}
}

func TestHealthServiceQuery_Fetch(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		i    string
		exp  []*HealthService
	}{
		{
			"consul",
			"consul",
			[]*HealthService{
				&HealthService{
					Node:        testConsul.Config.NodeName,
					NodeAddress: testConsul.Config.Bind,
					NodeTaggedAddresses: map[string]string{
						"lan": "127.0.0.1",
						"wan": "127.0.0.1",
					},
					NodeMeta: map[string]string{
						"consul-network-segment": "",
					},
					ServiceMeta: map[string]string{},
					Address:     testConsul.Config.Bind,
					ID:          "consul",
					Name:        "consul",
					Tags:        []string{},
					Status:      "passing",
					Port:        testConsul.Config.Ports.Server,
					Weights: api.AgentWeights{
						Passing: 1,
						Warning: 1,
					},
				},
			},
		},
		{
			"filters",
			"consul|warning",
			[]*HealthService{},
		},
		{
			"multifilter",
			"consul|warning,passing",
			[]*HealthService{
				&HealthService{
					Node:        testConsul.Config.NodeName,
					NodeAddress: testConsul.Config.Bind,
					NodeTaggedAddresses: map[string]string{
						"lan": "127.0.0.1",
						"wan": "127.0.0.1",
					},
					NodeMeta: map[string]string{
						"consul-network-segment": "",
					},
					ServiceMeta: map[string]string{},
					Address:     testConsul.Config.Bind,
					ID:          "consul",
					Name:        "consul",
					Tags:        []string{},
					Status:      "passing",
					Port:        testConsul.Config.Ports.Server,
					Weights: api.AgentWeights{
						Passing: 1,
						Warning: 1,
					},
				},
			},
		},
		{
			"service-meta",
			"service-meta",
			[]*HealthService{
				&HealthService{
					Node:        testConsul.Config.NodeName,
					NodeAddress: testConsul.Config.Bind,
					NodeTaggedAddresses: map[string]string{
						"lan": "127.0.0.1",
						"wan": "127.0.0.1",
					},
					NodeMeta: map[string]string{
						"consul-network-segment": "",
					},
					ServiceMeta: map[string]string{
						"meta1": "value1",
					},
					Address: testConsul.Config.Bind,
					ID:      "service-meta",
					Name:    "service-meta",
					Tags:    []string{"tag1"},
					Status:  "passing",
					Weights: api.AgentWeights{
						Passing: 1,
						Warning: 1,
					},
				},
			},
		},
	}

	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
			d, err := NewHealthServiceQuery(tc.i)
			if err != nil {
				t.Fatal(err)
			}

			act, _, err := d.Fetch(testClients, nil)
			if err != nil {
				t.Fatal(err)
			}

			if act != nil {
				for _, v := range act.([]*HealthService) {
					v.NodeID = ""
					v.Checks = nil
					// delete any version data from ServiceMeta
					v.ServiceMeta = filterVersionMeta(v.ServiceMeta)
				}
			}

			assert.Equal(t, tc.exp, act)
		})
	}
}

func TestHealthServiceQuery_String(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name string
		i    string
		exp  string
	}{
		{
			"name",
			"name",
			"health.service(name|passing)",
		},
		{
			"name_dc",
			"name@dc",
			"health.service(name@dc|passing)",
		},
		{
			"name_filter",
			"name|any",
			"health.service(name|any)",
		},
		{
			"name_multifilter",
			"name|warning,passing",
			"health.service(name|passing,warning)",
		},
		{
			"name_near",
			"name~near",
			"health.service(name~near|passing)",
		},
		{
			"name_near_filter",
			"name~near|any",
			"health.service(name~near|any)",
		},
		{
			"name_dc_near",
			"name@dc~near",
			"health.service(name@dc~near|passing)",
		},
		{
			"name_dc_near_filter",
			"name@dc~near|any",
			"health.service(name@dc~near|any)",
		},
		{
			"tag_name",
			"tag.name",
			"health.service(tag.name|passing)",
		},
		{
			"tag_name_dc",
			"tag.name@dc",
			"health.service(tag.name@dc|passing)",
		},
		{
			"tag_name_near",
			"tag.name~near",
			"health.service(tag.name~near|passing)",
		},
		{
			"tag_name_dc_near",
			"tag.name@dc~near",
			"health.service(tag.name@dc~near|passing)",
		},
	}

	for i, tc := range cases {
		t.Run(fmt.Sprintf("%d_%s", i, tc.name), func(t *testing.T) {
			d, err := NewHealthServiceQuery(tc.i)
			if err != nil {
				t.Fatal(err)
			}
			assert.Equal(t, tc.exp, d.String())
		})
	}
}
<|endoftext|>


<commit_before>// Command line app to process fiddles in bulk.
//
// Example:
//  fiddlecli --input demo/testbulk.json --output /tmp/output.json
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"sync"

	"golang.org/x/sync/errgroup"

	"go.skia.org/infra/fiddle/go/types"
	"go.skia.org/infra/go/httputils"
)

// flags
var (
	domain = flag.String("domain", "https://fiddle.skia.org", "Where to send the JSON request.")
	input  = flag.String("input", "", "The name of the file to read the JSON from.")
	output = flag.String("output", "", "The name of the file to write the JSON results to.")
	procs  = flag.Int("procs", 4, "The number of parallel requests to make to the fiddle server.")
	quiet  = flag.Bool("quiet", false, "Run without a progress bar.")
	force  = flag.Bool("force", false, "Force a compile and run for each fiddle, don't take the fast path.")
)

// chanRequest is sent to each worker in the pool.
type chanRequest struct {
	id  string
	req *types.FiddleContext
}

func main() {
	// Check flags.
	flag.Parse()
	if *input == "" {
		flag.Usage()
		log.Fatalf("--input is a required flag.")
	}
	if *output == "" {
		flag.Usage()
		log.Fatalf("--output is a required flag.")
	}

	// Read the source JSON file.
	b, err := ioutil.ReadFile(*input)
	if err != nil {
		log.Fatalf("Failed to read %s: %s", *input, err)
	}
	requests := types.BulkRequest{}
	if err := json.Unmarshal(b, &requests); err != nil {
		log.Fatalf("%s does not contain valid JSON: %s", *input, err)
	}
	lastWritten := types.BulkResponse{}
	b, err = ioutil.ReadFile(*output)
	if err == nil {
		if err := json.Unmarshal(b, &lastWritten); err != nil {
			lastWritten = nil
		}
	}
	g := errgroup.Group{}
	requestsCh := make(chan chanRequest, len(requests))

	// mutex protects response.
	mutex := sync.Mutex{}
	response := types.BulkResponse{}

	c := httputils.NewTimeoutClient()
	resp, err := c.Get("https://fiddle.skia.org/reset_gpu/")
	if resp.StatusCode != 200 {
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("Failed to read response when resetting GPU: %s", err)
		} else {
			log.Fatalf("Failed to reset GPU: %s", string(b))
		}
	}

	// Spin up workers.
	for i := 0; i < *procs; i++ {
		g.Go(func() error {
			c := httputils.NewTimeoutClient()
			for req := range requestsCh {
				if !*quiet {
					fmt.Print(".")
				}
				if *force {
					req.req.Fast = false
				} else if lastWritten != nil {
					fiddleHash, err := req.req.Options.ComputeHash(req.req.Code)
					if err == nil {
						if lastWritten[req.id] != nil {
							if lastWritten[req.id].FiddleHash == fiddleHash {
								mutex.Lock()
								response[req.id] = lastWritten[req.id]
								mutex.Unlock()
								continue
							}
						}
					}
				}
				// POST to fiddle.
				b, err = json.Marshal(req.req)
				if err != nil {
					return fmt.Errorf("Failed to encode an individual request: %s", err)
				}
				resp, err := c.Post(*domain+"/_/run", "application/json", bytes.NewReader(b))
				if err != nil || resp.StatusCode != 200 {
					return fmt.Errorf("Failed to make request: %s", err)
				}

				// Decode response and add to all responses.
				runResults := types.RunResults{}
				if err := json.NewDecoder(resp.Body).Decode(&runResults); err != nil {
					return fmt.Errorf("Failed to read response: %s", err)
				}
				if resp.StatusCode != 200 {
					return fmt.Errorf("Request failed with %d: %s", resp.StatusCode, string(b))
				}
				mutex.Lock()
				response[req.id] = &runResults
				mutex.Unlock()
			}
			return nil
		})
	}

	// Loop over each entry and queue them up for the workers.
	for id, req := range requests {
		requestsCh <- chanRequest{
			id:  id,
			req: req,
		}
	}
	close(requestsCh)

	// Wait for the workers to finish.
	if err := g.Wait(); err != nil {
		log.Fatalf("Failed to complete all requests: %s", err)
	}

	if !*quiet {
		fmt.Print("\n")
	}
	b, err = json.MarshalIndent(response, "", "  ")
	if err != nil {
		log.Fatalf("Failed to encode response file: %s", err)
	}
	if err := ioutil.WriteFile(*output, b, 0600); err != nil {
		log.Fatalf("Failed to write response file: %s", err)
	}
}
<commit_msg>[fiddlecli] Make more robust and report better errors.<commit_after>// Command line app to process fiddles in bulk.
//
// Example:
//  fiddlecli --input demo/testbulk.json --output /tmp/output.json
package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"sync"

	"golang.org/x/sync/errgroup"

	"go.skia.org/infra/fiddle/go/types"
	"go.skia.org/infra/go/common"
	"go.skia.org/infra/go/httputils"
	"go.skia.org/infra/go/sklog"
)

// flags
var (
	domain = flag.String("domain", "https://fiddle.skia.org", "Where to send the JSON request.")
	input  = flag.String("input", "", "The name of the file to read the JSON from.")
	output = flag.String("output", "", "The name of the file to write the JSON results to.")
	procs  = flag.Int("procs", 4, "The number of parallel requests to make to the fiddle server.")
	quiet  = flag.Bool("quiet", false, "Run without a progress bar.")
	force  = flag.Bool("force", false, "Force a compile and run for each fiddle, don't take the fast path.")
)

// chanRequest is sent to each worker in the pool.
type chanRequest struct {
	id  string
	req *types.FiddleContext
}

func main() {
	// Check flags.
	common.Init()
	if *input == "" {
		flag.Usage()
		log.Fatalf("--input is a required flag.")
	}
	if *output == "" {
		flag.Usage()
		log.Fatalf("--output is a required flag.")
	}

	// Read the source JSON file.
	b, err := ioutil.ReadFile(*input)
	if err != nil {
		log.Fatalf("Failed to read %s: %s", *input, err)
	}
	requests := types.BulkRequest{}
	if err := json.Unmarshal(b, &requests); err != nil {
		log.Fatalf("%s does not contain valid JSON: %s", *input, err)
	}
	lastWritten := types.BulkResponse{}
	b, err = ioutil.ReadFile(*output)
	if err == nil {
		if err := json.Unmarshal(b, &lastWritten); err != nil {
			lastWritten = nil
		}
	}
	g := errgroup.Group{}
	requestsCh := make(chan chanRequest, len(requests))

	// mutex protects response.
	mutex := sync.Mutex{}
	response := types.BulkResponse{}

	// Spin up workers.
	for i := 0; i < *procs; i++ {
		g.Go(func() error {
			c := httputils.NewTimeoutClient()
			for req := range requestsCh {
				if !*quiet {
					fmt.Print(".")
				}
				if *force {
					req.req.Fast = false
				} else if lastWritten != nil {
					fiddleHash, err := req.req.Options.ComputeHash(req.req.Code)
					if err == nil {
						if lastWritten[req.id] != nil {
							if lastWritten[req.id].FiddleHash == fiddleHash {
								mutex.Lock()
								response[req.id] = lastWritten[req.id]
								mutex.Unlock()
								continue
							}
						}
					}
				}
				// POST to fiddle.
				b, err = json.Marshal(req.req)
				if err != nil {
					return fmt.Errorf("Failed to encode an individual request: %s", err)
				}
				resp, err := c.Post(*domain+"/_/run", "application/json", bytes.NewReader(b))
				if err != nil || resp.StatusCode != 200 {
					sklog.Warningf("Failed to make request: %s %s", err, resp.Status)
					continue
				}

				// Decode response and add to all responses.
				runResults := types.RunResults{}
				if err := json.NewDecoder(resp.Body).Decode(&runResults); err != nil {
					return fmt.Errorf("Failed to read response: %s", err)
				}
				mutex.Lock()
				response[req.id] = &runResults
				mutex.Unlock()
			}
			return nil
		})
	}

	// Loop over each entry and queue them up for the workers.
	for id, req := range requests {
		requestsCh <- chanRequest{
			id:  id,
			req: req,
		}
	}
	close(requestsCh)

	// Wait for the workers to finish.
	if err := g.Wait(); err != nil {
		log.Fatalf("Failed to complete all requests: %s", err)
	}

	if !*quiet {
		fmt.Print("\n")
	}
	b, err = json.MarshalIndent(response, "", "  ")
	if err != nil {
		log.Fatalf("Failed to encode response file: %s", err)
	}
	if err := ioutil.WriteFile(*output, b, 0600); err != nil {
		log.Fatalf("Failed to write response file: %s", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

import (
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	federationapi "k8s.io/kubernetes/federation/apis/federation"
	"k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/test/e2e/framework"
)

// Create/delete cluster api objects
var _ = framework.KubeDescribe("Federation apiserver [Feature:Federation]", func() {
	f := framework.NewDefaultFederatedFramework("federation-cluster")
	It("should allow creation of cluster api objects", func() {
		framework.SkipUnlessFederated(f.Client)

		contexts := f.GetUnderlyingFederatedContexts()

		for _, context := range contexts {
			framework.Logf("Creating cluster object: %s (%s, secret: %s)", context.Name, context.Cluster.Cluster.Server, context.Name)
			cluster := federationapi.Cluster{
				ObjectMeta: api.ObjectMeta{
					Name: context.Name,
				},
				Spec: federationapi.ClusterSpec{
					ServerAddressByClientCIDRs: []federationapi.ServerAddressByClientCIDR{
						{
							ClientCIDR:    "0.0.0.0/0",
							ServerAddress: context.Cluster.Cluster.Server,
						},
					},
					SecretRef: &api.LocalObjectReference{
						// Note: Name must correlate with federation build script secret name,
						//       which currently matches the cluster name.
						//       See federation/cluster/common.sh:132
						Name: context.Name,
					},
				},
			}
			_, err := f.FederationClientset.Federation().Clusters().Create(&cluster)
			framework.ExpectNoError(err, fmt.Sprintf("creating cluster: %+v", err))
		}

		for _, context := range contexts {
			c, err := f.FederationClientset.Federation().Clusters().Get(context.Name)
			framework.ExpectNoError(err, fmt.Sprintf("get cluster: %+v", err))
			if c.ObjectMeta.Name != context.Name {
				framework.Failf("cluster name does not match input context: actual=%+v, expected=%+v", c, context)
			}
			err = isReady(context.Name, f.FederationClientset)
			framework.ExpectNoError(err, fmt.Sprintf("unexpected error in verifying if cluster %s is ready: %+v", context.Name, err))
		}
	})
})

// Verify that the cluster is marked ready.
func isReady(clusterName string, clientset *federation_internalclientset.Clientset) error {
	return wait.PollImmediate(time.Second, wait.ForeverTestTimeout, func() (bool, error) {
		c, err := clientset.Federation().Clusters().Get(clusterName)
		if err != nil {
			return false, err
		}
		for _, condition := range c.Status.Conditions {
			if condition.Type == federationapi.ClusterReady && condition.Status == api.ConditionTrue {
				return true, nil
			}
		}
		return false, nil
	})
}
<commit_msg>Cleaning up clusters after federation apiserver test is run<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

import (
	"fmt"
	"time"

	. "github.com/onsi/ginkgo"
	federationapi "k8s.io/kubernetes/federation/apis/federation"
	"k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/test/e2e/framework"

	. "github.com/onsi/gomega"
)

// Create/delete cluster api objects
var _ = framework.KubeDescribe("Federation apiserver [Feature:Federation]", func() {
	f := framework.NewDefaultFederatedFramework("federation-cluster")

	AfterEach(func() {
		framework.SkipUnlessFederated(f.Client)

		// Delete registered clusters.
		// This is if a test failed, it should not affect other tests.
		clusterList, err := f.FederationClientset.Federation().Clusters().List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		for _, cluster := range clusterList.Items {
			err := f.FederationClientset.Federation().Clusters().Delete(cluster.Name, &api.DeleteOptions{})
			Expect(err).NotTo(HaveOccurred())
		}
	})

	It("should allow creation and deletion of cluster api objects", func() {
		framework.SkipUnlessFederated(f.Client)

		contexts := f.GetUnderlyingFederatedContexts()

		for _, context := range contexts {
			framework.Logf("Creating cluster object: %s (%s, secret: %s)", context.Name, context.Cluster.Cluster.Server, context.Name)
			cluster := federationapi.Cluster{
				ObjectMeta: api.ObjectMeta{
					Name: context.Name,
				},
				Spec: federationapi.ClusterSpec{
					ServerAddressByClientCIDRs: []federationapi.ServerAddressByClientCIDR{
						{
							ClientCIDR:    "0.0.0.0/0",
							ServerAddress: context.Cluster.Cluster.Server,
						},
					},
					SecretRef: &api.LocalObjectReference{
						// Note: Name must correlate with federation build script secret name,
						//       which currently matches the cluster name.
						//       See federation/cluster/common.sh:132
						Name: context.Name,
					},
				},
			}
			_, err := f.FederationClientset.Federation().Clusters().Create(&cluster)
			framework.ExpectNoError(err, fmt.Sprintf("creating cluster: %+v", err))
		}

		for _, context := range contexts {
			c, err := f.FederationClientset.Federation().Clusters().Get(context.Name)
			framework.ExpectNoError(err, fmt.Sprintf("get cluster: %+v", err))
			if c.ObjectMeta.Name != context.Name {
				framework.Failf("cluster name does not match input context: actual=%+v, expected=%+v", c, context)
			}
			err = isReady(context.Name, f.FederationClientset)
			framework.ExpectNoError(err, fmt.Sprintf("unexpected error in verifying if cluster %s is ready: %+v", context.Name, err))
		}

		// Verify that deletion works.
		for _, context := range contexts {
			framework.Logf("Deleting cluster object: %s (%s, secret: %s)", context.Name, context.Cluster.Cluster.Server, context.Name)
			err := f.FederationClientset.Federation().Clusters().Delete(context.Name, &api.DeleteOptions{})
			framework.ExpectNoError(err, fmt.Sprintf("unexpected error in deleting cluster %s: %+v", context.Name, err))
		}

		// There should not be any remaining cluster.
		clusterList, err := f.FederationClientset.Federation().Clusters().List(api.ListOptions{})
		Expect(err).NotTo(HaveOccurred())
		if len(clusterList.Items) != 0 {
			framework.Failf("there should not have been any remaining clusters. Found: %+v", clusterList)
		}
	})
})

// Verify that the cluster is marked ready.
func isReady(clusterName string, clientset *federation_internalclientset.Clientset) error {
	return wait.PollImmediate(time.Second, wait.ForeverTestTimeout, func() (bool, error) {
		c, err := clientset.Federation().Clusters().Get(clusterName)
		if err != nil {
			return false, err
		}
		for _, condition := range c.Status.Conditions {
			if condition.Type == federationapi.ClusterReady && condition.Status == api.ConditionTrue {
				return true, nil
			}
		}
		return false, nil
	})
}
<|endoftext|>


<commit_before>package hlt

import (
	"fmt"
	"math"
	"strconv"
)

// DockingStatus represents possible ship.DockingStatus values
type DockingStatus int

const (
	// UNDOCKED ship.DockingStatus value
	UNDOCKED DockingStatus = iota
	// DOCKING ship.DockingStatus value
	DOCKING
	// DOCKED ship.DockingStatus value
	DOCKED
	// UNDOCKING ship.DockingStatus value
	UNDOCKING
)

// Entity captures spacial and ownership state for Planets and Ships
type Entity struct {
	X      float64
	Y      float64
	Radius float64
	Health float64
	Owner  int
	ID     int
}

// Position in 2D space
type Position struct {
	X, Y float64
}

// Planet object from which Halite is mined
type Planet struct {
	Entity
	NumDockingSpots    float64
	NumDockedShips     float64
	CurrentProduction  float64
	RemainingResources float64
	DockedShipIDs      []int
	DockedShips        []Ship
	Owned              float64
	Distance           float64
}

// Ship is a player controlled Entity made for the purpose of doing combat and mining Halite
type Ship struct {
	Entity
	VelX float64
	VelY float64

	PlanetID        int
	Planet          Planet
	DockingStatus   DockingStatus
	DockingProgress float64
	WeaponCooldown  float64
}

// CalculateDistanceTo returns a euclidean distance to the target
func (entity Entity) CalculateDistanceTo(target Entity) float64 {
	dx := target.X - entity.X
	dy := target.Y - entity.Y

	return math.Sqrt(dx*dx + dy*dy)
}

// CalculateAngleTo returns an angle in degrees to the target
func (entity Entity) CalculateAngleTo(target Entity) float64 {
	return RadToDeg(entity.CalculateRadAngleTo(target))
}

// CalculateRadAngleTo returns an angle in radians to the target
func (entity Entity) CalculateRadAngleTo(target Entity) float64 {
	dx := target.X - entity.X
	dy := target.Y - entity.Y

	return math.Atan2(dy, dx)
}

// ClosestPointTo returns the closest point that is at least minDistance from the target
func (entity Entity) ClosestPointTo(target Entity, minDistance float64) Entity {
	dist := entity.CalculateDistanceTo(target) - target.Radius - minDistance
	angle := entity.CalculateRadAngleTo(target)
	x := entity.X + dist*math.Cos(angle)
	y := entity.Y + dist*math.Sin(angle)
	return Entity{
		X:      x,
		Y:      y,
		Radius: 0,
		Health: 0,
		Owner:  -1,
		ID:     -1,
	}
}

// ParseShip from a slice of game state tokens
func ParseShip(playerID int, tokens []string) (Ship, []string) {
	shipID, _ := strconv.Atoi(tokens[0])
	shipX, _ := strconv.ParseFloat(tokens[1], 64)
	shipY, _ := strconv.ParseFloat(tokens[2], 64)
	shipHealth, _ := strconv.ParseFloat(tokens[3], 64)
	shipVelX, _ := strconv.ParseFloat(tokens[4], 64)
	shipVelY, _ := strconv.ParseFloat(tokens[5], 64)
	shipDockingStatus, _ := strconv.Atoi(tokens[6])
	shipPlanetID, _ := strconv.Atoi(tokens[7])
	shipDockingProgress, _ := strconv.ParseFloat(tokens[8], 64)
	shipWeaponCooldown, _ := strconv.ParseFloat(tokens[9], 64)

	shipEntity := Entity{
		X:      shipX,
		Y:      shipY,
		Radius: .5,
		Health: shipHealth,
		Owner:  playerID,
		ID:     shipID,
	}

	ship := Ship{
		PlanetID:        shipPlanetID,
		DockingStatus:   IntToDockingStatus(shipDockingStatus),
		DockingProgress: shipDockingProgress,
		WeaponCooldown:  shipWeaponCooldown,
		VelX:            shipVelX,
		VelY:            shipVelY,
		Entity:          shipEntity,
	}

	return ship, tokens[10:]
}

// ParsePlanet from a slice of game state tokens
func ParsePlanet(tokens []string) (Planet, []string) {
	planetID, _ := strconv.Atoi(tokens[0])
	planetX, _ := strconv.ParseFloat(tokens[1], 64)
	planetY, _ := strconv.ParseFloat(tokens[2], 64)
	planetHealth, _ := strconv.ParseFloat(tokens[3], 64)
	planetRadius, _ := strconv.ParseFloat(tokens[4], 64)
	planetNumDockingSpots, _ := strconv.ParseFloat(tokens[5], 64)
	planetCurrentProduction, _ := strconv.ParseFloat(tokens[6], 64)
	planetRemainingResources, _ := strconv.ParseFloat(tokens[7], 64)
	planetOwned, _ := strconv.ParseFloat(tokens[8], 64)
	planetOwner, _ := strconv.Atoi(tokens[9])
	planetNumDockedShips, _ := strconv.ParseFloat(tokens[10], 64)

	planetEntity := Entity{
		X:      planetX,
		Y:      planetY,
		Radius: planetRadius,
		Health: planetHealth,
		Owner:  planetOwner,
		ID:     planetID,
	}

	planet := Planet{
		NumDockingSpots:    planetNumDockingSpots,
		NumDockedShips:     planetNumDockedShips,
		CurrentProduction:  planetCurrentProduction,
		RemainingResources: planetRemainingResources,
		DockedShipIDs:      nil,
		DockedShips:        nil,
		Owned:              planetOwned,
		Entity:             planetEntity,
	}

	for i := 0; i < int(planetNumDockedShips); i++ {
		dockedShipID, _ := strconv.Atoi(tokens[11+i])
		planet.DockedShipIDs = append(planet.DockedShipIDs, dockedShipID)
	}
	return planet, tokens[11+int(planetNumDockedShips):]
}

// IntToDockingStatus converts an int to a DockingStatus
func IntToDockingStatus(i int) DockingStatus {
	statuses := [4]DockingStatus{UNDOCKED, DOCKING, DOCKED, UNDOCKING}
	return statuses[i]
}

// Thrust generates a string describing the ship's intension to move during the current turn
func (ship Ship) Thrust(magnitude float64, angle float64) string {
	return fmt.Sprintf("t %s %s %s", strconv.Itoa(ship.ID), strconv.Itoa(int(magnitude)), strconv.Itoa(int(angle)))
}

// Dock generates a string describing the ship's intension to dock during the current turn
func (ship Ship) Dock(planet Planet) string {
	return fmt.Sprintf("d %s %s", strconv.Itoa(ship.ID), strconv.Itoa(planet.ID))
}

// Undock generates a string describing the ship's intension to undock during the current turn
func (ship Ship) Undock() string {
	return fmt.Sprintf("u %s", strconv.Itoa(ship.ID))
}

// NavigateBasic demonstrates how the player might move ships through space
func (ship Ship) NavigateBasic(target Entity, gameMap Map) string {
	distance := ship.CalculateDistanceTo(target)

	angle := ship.CalculateAngleTo(target)
	speed := 7.0
	if distance < 10 {
		speed = 3.0
	}

	speed = math.Min(speed, distance)
	return ship.Thrust(speed, angle)
}

// CanDock indicates that a ship is close enough to a given planet to dock
func (ship Ship) CanDock(planet Planet) bool {
	dist := ship.CalculateDistanceTo(planet.Entity)

	return dist <= (planet.Radius + 6)
}

// Navigate demonstrates how the player might negotiate obsticles between
// a ship and its target
func (ship Ship) Navigate(target Entity, gameMap Map) string {
	ob := gameMap.ObstaclesBetween(ship.Entity, target)

	if !ob {
		return ship.NavigateBasic(target, gameMap)
	}

	x0 := math.Min(ship.X, target.X)
	x2 := math.Max(ship.X, target.X)
	y0 := math.Min(ship.Y, target.Y)
	y2 := math.Max(ship.Y, target.Y)

	dx := (x2 - x0) / 5
	dy := (y2 - y0) / 5
	bestdist := 1000.0
	bestTarget := target

	for x1 := x0; x1 <= x2; x1 += dx {
		for y1 := y0; y1 <= y2; y1 += dy {
			intermediateTarget := Entity{
				X:      x1,
				Y:      y1,
				Radius: 0,
				Health: 0,
				Owner:  0,
				ID:     -1,
			}
			ob1 := gameMap.ObstaclesBetween(ship.Entity, intermediateTarget)
			if !ob1 {
				ob2 := gameMap.ObstaclesBetween(intermediateTarget, target)
				if !ob2 {
					totdist := math.Sqrt(math.Pow(x1-x0, 2)+math.Pow(y1-y0, 2)) + math.Sqrt(math.Pow(x1-x2, 2)+math.Pow(y1-y2, 2))
					if totdist < bestdist {
						bestdist = totdist
						bestTarget = intermediateTarget

					}
				}
			}
		}
	}

	return ship.NavigateBasic(bestTarget, gameMap)
}
<commit_msg>A few fixes to the starter go bot<commit_after>package hlt

import (
	"fmt"
	"math"
	"strconv"
)

// DockingStatus represents possible ship.DockingStatus values
type DockingStatus int

const (
	// UNDOCKED ship.DockingStatus value
	UNDOCKED DockingStatus = iota
	// DOCKING ship.DockingStatus value
	DOCKING
	// DOCKED ship.DockingStatus value
	DOCKED
	// UNDOCKING ship.DockingStatus value
	UNDOCKING
)

// Entity captures spacial and ownership state for Planets and Ships
type Entity struct {
	X      float64
	Y      float64
	Radius float64
	Health float64
	Owner  int
	ID     int
}

// Position in 2D space
type Position struct {
	X, Y float64
}

// Planet object from which Halite is mined
type Planet struct {
	Entity
	NumDockingSpots    float64
	NumDockedShips     float64
	CurrentProduction  float64
	RemainingResources float64
	DockedShipIDs      []int
	DockedShips        []Ship
	Owned              float64
	Distance           float64
}

// Ship is a player controlled Entity made for the purpose of doing combat and mining Halite
type Ship struct {
	Entity
	VelX float64
	VelY float64

	PlanetID        int
	Planet          Planet
	DockingStatus   DockingStatus
	DockingProgress float64
	WeaponCooldown  float64
}

// CalculateDistanceTo returns a euclidean distance to the target
func (entity Entity) CalculateDistanceTo(target Entity) float64 {
	dx := target.X - entity.X
	dy := target.Y - entity.Y

	return math.Sqrt(dx*dx + dy*dy)
}

// CalculateAngleTo returns an angle in degrees to the target
func (entity Entity) CalculateAngleTo(target Entity) float64 {
	return RadToDeg(entity.CalculateRadAngleTo(target))
}

// CalculateRadAngleTo returns an angle in radians to the target
func (entity Entity) CalculateRadAngleTo(target Entity) float64 {
	dx := target.X - entity.X
	dy := target.Y - entity.Y

	return math.Atan2(dy, dx)
}

// ClosestPointTo returns the closest point that is at least minDistance from the target
func (entity Entity) ClosestPointTo(target Entity, minDistance float64) Entity {
	dist := entity.CalculateDistanceTo(target) - target.Radius - minDistance
	angle := target.CalculateRadAngleTo(entity)
	x := target.X + dist*math.Cos(angle)
	y := target.Y + dist*math.Sin(angle)
	return Entity{
		X:      x,
		Y:      y,
		Radius: 0,
		Health: 0,
		Owner:  -1,
		ID:     -1,
	}
}

// ParseShip from a slice of game state tokens
func ParseShip(playerID int, tokens []string) (Ship, []string) {
	shipID, _ := strconv.Atoi(tokens[0])
	shipX, _ := strconv.ParseFloat(tokens[1], 64)
	shipY, _ := strconv.ParseFloat(tokens[2], 64)
	shipHealth, _ := strconv.ParseFloat(tokens[3], 64)
	shipVelX, _ := strconv.ParseFloat(tokens[4], 64)
	shipVelY, _ := strconv.ParseFloat(tokens[5], 64)
	shipDockingStatus, _ := strconv.Atoi(tokens[6])
	shipPlanetID, _ := strconv.Atoi(tokens[7])
	shipDockingProgress, _ := strconv.ParseFloat(tokens[8], 64)
	shipWeaponCooldown, _ := strconv.ParseFloat(tokens[9], 64)

	shipEntity := Entity{
		X:      shipX,
		Y:      shipY,
		Radius: .5,
		Health: shipHealth,
		Owner:  playerID,
		ID:     shipID,
	}

	ship := Ship{
		PlanetID:        shipPlanetID,
		DockingStatus:   IntToDockingStatus(shipDockingStatus),
		DockingProgress: shipDockingProgress,
		WeaponCooldown:  shipWeaponCooldown,
		VelX:            shipVelX,
		VelY:            shipVelY,
		Entity:          shipEntity,
	}

	return ship, tokens[10:]
}

// ParsePlanet from a slice of game state tokens
func ParsePlanet(tokens []string) (Planet, []string) {
	planetID, _ := strconv.Atoi(tokens[0])
	planetX, _ := strconv.ParseFloat(tokens[1], 64)
	planetY, _ := strconv.ParseFloat(tokens[2], 64)
	planetHealth, _ := strconv.ParseFloat(tokens[3], 64)
	planetRadius, _ := strconv.ParseFloat(tokens[4], 64)
	planetNumDockingSpots, _ := strconv.ParseFloat(tokens[5], 64)
	planetCurrentProduction, _ := strconv.ParseFloat(tokens[6], 64)
	planetRemainingResources, _ := strconv.ParseFloat(tokens[7], 64)
	planetOwned, _ := strconv.ParseFloat(tokens[8], 64)
	planetOwner, _ := strconv.Atoi(tokens[9])
	planetNumDockedShips, _ := strconv.ParseFloat(tokens[10], 64)

	planetEntity := Entity{
		X:      planetX,
		Y:      planetY,
		Radius: planetRadius,
		Health: planetHealth,
		Owner:  planetOwner,
		ID:     planetID,
	}

	planet := Planet{
		NumDockingSpots:    planetNumDockingSpots,
		NumDockedShips:     planetNumDockedShips,
		CurrentProduction:  planetCurrentProduction,
		RemainingResources: planetRemainingResources,
		DockedShipIDs:      nil,
		DockedShips:        nil,
		Owned:              planetOwned,
		Entity:             planetEntity,
	}

	for i := 0; i < int(planetNumDockedShips); i++ {
		dockedShipID, _ := strconv.Atoi(tokens[11+i])
		planet.DockedShipIDs = append(planet.DockedShipIDs, dockedShipID)
	}
	return planet, tokens[11+int(planetNumDockedShips):]
}

// IntToDockingStatus converts an int to a DockingStatus
func IntToDockingStatus(i int) DockingStatus {
	statuses := [4]DockingStatus{UNDOCKED, DOCKING, DOCKED, UNDOCKING}
	return statuses[i]
}

// Thrust generates a string describing the ship's intension to move during the current turn
func (ship Ship) Thrust(magnitude float64, angle float64) string {
	boundedAngle := int(angle)
	if boundedAngle < 0 {
		boundedAngle += 360
	} else if boundedAngle >= 360 {
		boundedAngle -= 360
	}
	return fmt.Sprintf("t %s %s %s", strconv.Itoa(ship.ID), strconv.Itoa(int(magnitude)), strconv.Itoa(boundedAngle))
}

// Dock generates a string describing the ship's intension to dock during the current turn
func (ship Ship) Dock(planet Planet) string {
	return fmt.Sprintf("d %s %s", strconv.Itoa(ship.ID), strconv.Itoa(planet.ID))
}

// Undock generates a string describing the ship's intension to undock during the current turn
func (ship Ship) Undock() string {
	return fmt.Sprintf("u %s", strconv.Itoa(ship.ID))
}

// NavigateBasic demonstrates how the player might move ships through space
func (ship Ship) NavigateBasic(target Entity, gameMap Map) string {
	distance := ship.CalculateDistanceTo(target)
	safeDistance := distance - ship.Entity.Radius - target.Entity.Radius - .1

	angle := ship.CalculateAngleTo(target)
	speed := 7.0
	if distance < 10 {
		speed = 3.0
	}

	speed = math.Min(speed, safeDistance)
	return ship.Thrust(speed, angle)
}

// CanDock indicates that a ship is close enough to a given planet to dock
func (ship Ship) CanDock(planet Planet) bool {
	dist := ship.CalculateDistanceTo(planet.Entity)

	return dist <= (planet.Radius + 4)
}

// Navigate demonstrates how the player might negotiate obsticles between
// a ship and its target
func (ship Ship) Navigate(target Entity, gameMap Map) string {
	ob := gameMap.ObstaclesBetween(ship.Entity, target)

	if !ob {
		return ship.NavigateBasic(target, gameMap)
	}

	x0 := math.Min(ship.X, target.X)
	x2 := math.Max(ship.X, target.X)
	y0 := math.Min(ship.Y, target.Y)
	y2 := math.Max(ship.Y, target.Y)

	dx := (x2 - x0) / 5
	dy := (y2 - y0) / 5
	bestdist := 1000.0
	bestTarget := target

	for x1 := x0; x1 <= x2; x1 += dx {
		for y1 := y0; y1 <= y2; y1 += dy {
			intermediateTarget := Entity{
				X:      x1,
				Y:      y1,
				Radius: 0,
				Health: 0,
				Owner:  0,
				ID:     -1,
			}
			ob1 := gameMap.ObstaclesBetween(ship.Entity, intermediateTarget)
			if !ob1 {
				ob2 := gameMap.ObstaclesBetween(intermediateTarget, target)
				if !ob2 {
					totdist := math.Sqrt(math.Pow(x1-x0, 2)+math.Pow(y1-y0, 2)) + math.Sqrt(math.Pow(x1-x2, 2)+math.Pow(y1-y2, 2))
					if totdist < bestdist {
						bestdist = totdist
						bestTarget = intermediateTarget

					}
				}
			}
		}
	}

	return ship.NavigateBasic(bestTarget, gameMap)
}
<|endoftext|>


<commit_before>package install

import (
	"github.com/go-xorm/builder"
	"github.com/google/uuid"
	"github.com/itchio/butler/butlerd"
	"github.com/itchio/butler/database/models"
	"github.com/itchio/butler/endpoints/fetch"
	"github.com/itchio/hades"
	"github.com/pkg/errors"
)

func InstallLocationsGetByID(rc *butlerd.RequestContext, params butlerd.InstallLocationsGetByIDParams) (*butlerd.InstallLocationsGetByIDResult, error) {
	if params.ID == "" {
		return nil, errors.Errorf("id must be set")
	}

	conn := rc.GetConn()
	defer rc.PutConn(conn)

	il := models.InstallLocationByID(conn, params.ID)
	if il == nil {
		return nil, errors.Errorf("install location (%s) not found", params.ID)
	}

	res := &butlerd.InstallLocationsGetByIDResult{
		InstallLocation: fetch.FormatInstallLocation(conn, rc.Consumer, il),
	}
	return res, nil
}

func InstallLocationsList(rc *butlerd.RequestContext, params butlerd.InstallLocationsListParams) (*butlerd.InstallLocationsListResult, error) {
	conn := rc.GetConn()
	defer rc.PutConn(conn)

	var locations []*models.InstallLocation
	models.MustSelect(conn, &locations, builder.NewCond(), hades.Search{})

	var flocs []*butlerd.InstallLocationSummary
	for _, il := range locations {
		flocs = append(flocs, fetch.FormatInstallLocation(conn, rc.Consumer, il))
	}

	res := &butlerd.InstallLocationsListResult{
		InstallLocations: flocs,
	}
	return res, nil
}

func InstallLocationsAdd(rc *butlerd.RequestContext, params butlerd.InstallLocationsAddParams) (*butlerd.InstallLocationsAddResult, error) {
	conn := rc.GetConn()
	defer rc.PutConn(conn)
	consumer := rc.Consumer

	hadID := false
	if params.ID == "" {
		hadID = true
		params.ID = uuid.New().String()
	}
	if params.Path == "" {
		return nil, errors.New("path must be set")
	}

	if hadID {
		existing := models.InstallLocationByID(conn, params.ID)
		if existing != nil {
			if existing.Path == params.Path {
				consumer.Statf("(%s) exists, and has same path (%s), doing nothing", params.ID, params.Path)
				res := &butlerd.InstallLocationsAddResult{}
				return res, nil
			}
			return nil, errors.Errorf("(%s) exists but has path (%s) - we were passed (%s)", params.ID, existing.Path, params.Path)
		}
	}

	il := &models.InstallLocation{
		ID:   params.ID,
		Path: params.Path,
	}
	models.MustSave(conn, il)

	res := &butlerd.InstallLocationsAddResult{}
	return res, nil
}

func InstallLocationsRemove(rc *butlerd.RequestContext, params butlerd.InstallLocationsRemoveParams) (*butlerd.InstallLocationsRemoveResult, error) {
	conn := rc.GetConn()
	defer rc.PutConn(conn)
	consumer := rc.Consumer

	if params.ID == "" {
		return nil, errors.Errorf("id must be set")
	}

	il := models.InstallLocationByID(conn, params.ID)
	if il == nil {
		consumer.Statf("Install location (%s) does not exist, doing nothing")
		res := &butlerd.InstallLocationsRemoveResult{}
		return res, nil
	}

	caveCount := models.MustCount(conn, &models.Cave{}, builder.Eq{"install_location_id": il.ID})
	if caveCount > 0 {
		// TODO: suggest moving to another install location
		return nil, errors.Errorf("Refusing to remove install location (%s) because it is not empty", params.ID)
	}

	locationCount := models.MustCount(conn, &models.InstallLocation{}, builder.NewCond())
	if locationCount <= 1 {
		return nil, errors.Errorf("Refusing to remove last install location")
	}

	models.MustDelete(conn, &models.InstallLocation{}, builder.Eq{"id": il.ID})
	res := &butlerd.InstallLocationsRemoveResult{}
	return res, nil
}
<commit_msg>Additional checks when adding install locations<commit_after>package install

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/go-xorm/builder"
	"github.com/google/uuid"
	"github.com/itchio/butler/butlerd"
	"github.com/itchio/butler/database/models"
	"github.com/itchio/butler/endpoints/fetch"
	"github.com/itchio/hades"
	"github.com/pkg/errors"
)

func InstallLocationsGetByID(rc *butlerd.RequestContext, params butlerd.InstallLocationsGetByIDParams) (*butlerd.InstallLocationsGetByIDResult, error) {
	if params.ID == "" {
		return nil, errors.Errorf("id must be set")
	}

	conn := rc.GetConn()
	defer rc.PutConn(conn)

	il := models.InstallLocationByID(conn, params.ID)
	if il == nil {
		return nil, errors.Errorf("install location (%s) not found", params.ID)
	}

	res := &butlerd.InstallLocationsGetByIDResult{
		InstallLocation: fetch.FormatInstallLocation(conn, rc.Consumer, il),
	}
	return res, nil
}

func InstallLocationsList(rc *butlerd.RequestContext, params butlerd.InstallLocationsListParams) (*butlerd.InstallLocationsListResult, error) {
	conn := rc.GetConn()
	defer rc.PutConn(conn)

	var locations []*models.InstallLocation
	models.MustSelect(conn, &locations, builder.NewCond(), hades.Search{})

	var flocs []*butlerd.InstallLocationSummary
	for _, il := range locations {
		flocs = append(flocs, fetch.FormatInstallLocation(conn, rc.Consumer, il))
	}

	res := &butlerd.InstallLocationsListResult{
		InstallLocations: flocs,
	}
	return res, nil
}

func InstallLocationsAdd(rc *butlerd.RequestContext, params butlerd.InstallLocationsAddParams) (*butlerd.InstallLocationsAddResult, error) {
	conn := rc.GetConn()
	defer rc.PutConn(conn)
	consumer := rc.Consumer

	hadID := false
	if params.ID == "" {
		hadID = true
		params.ID = uuid.New().String()
	}
	if params.Path == "" {
		return nil, errors.New("path must be set")
	}

	if hadID {
		existing := models.InstallLocationByID(conn, params.ID)
		if existing != nil {
			if existing.Path == params.Path {
				consumer.Statf("(%s) exists, and has same path (%s), doing nothing", params.ID, params.Path)
				res := &butlerd.InstallLocationsAddResult{}
				return res, nil
			}
			return nil, errors.Errorf("(%s) exists but has path (%s) - we were passed (%s)", params.ID, existing.Path, params.Path)
		}
	}

	stats, err := os.Stat(params.Path)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	if !stats.IsDir() {
		return nil, errors.Errorf("(%s) is not a directory", params.Path)
	}

	// try writing a file
	testFileName := fmt.Sprintf(".butler-test-file-%d", os.Getpid())
	testFilePath := filepath.Join(params.Path, testFileName)
	defer os.Remove(testFilePath)
	err = ioutil.WriteFile(testFilePath, []byte{}, os.FileMode(0644))
	if err != nil {
		return nil, errors.Errorf("Can't write to (%s) not adding as an install location: %s", params.Path, err.Error())
	}

	il := &models.InstallLocation{
		ID:   params.ID,
		Path: params.Path,
	}
	models.MustSave(conn, il)

	res := &butlerd.InstallLocationsAddResult{}
	return res, nil
}

func InstallLocationsRemove(rc *butlerd.RequestContext, params butlerd.InstallLocationsRemoveParams) (*butlerd.InstallLocationsRemoveResult, error) {
	conn := rc.GetConn()
	defer rc.PutConn(conn)
	consumer := rc.Consumer

	if params.ID == "" {
		return nil, errors.Errorf("id must be set")
	}

	il := models.InstallLocationByID(conn, params.ID)
	if il == nil {
		consumer.Statf("Install location (%s) does not exist, doing nothing")
		res := &butlerd.InstallLocationsRemoveResult{}
		return res, nil
	}

	caveCount := models.MustCount(conn, &models.Cave{}, builder.Eq{"install_location_id": il.ID})
	if caveCount > 0 {
		// TODO: suggest moving to another install location
		return nil, errors.Errorf("Refusing to remove install location (%s) because it is not empty", params.ID)
	}

	locationCount := models.MustCount(conn, &models.InstallLocation{}, builder.NewCond())
	if locationCount <= 1 {
		return nil, errors.Errorf("Refusing to remove last install location")
	}

	models.MustDelete(conn, &models.InstallLocation{}, builder.Eq{"id": il.ID})
	res := &butlerd.InstallLocationsRemoveResult{}
	return res, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Skaffold Authors

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

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

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

package integration

import (
	"testing"

	"github.com/GoogleContainerTools/skaffold/integration/skaffold"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubectl"
	kubectx "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/context"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/portforward"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
	runcontext "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext/v2"
)

func TestPortForward(t *testing.T) {
	// TODO: This test shall pass once render v2 is completed.
	t.SkipNow()

	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		ns, _ := SetupNamespace(t)

		skaffold.Run().InDir(test.dir).InNs(ns.Name).RunOrFail(t)

		cfg, err := kubectx.CurrentConfig()
		failNowIfError(t, err)

		kubectlCLI := kubectl.NewCLI(&runcontext.RunContext{
			KubeContext: cfg.CurrentContext,
			Opts: config.SkaffoldOptions{
				Namespace: ns.Name,
			},
		}, "")

		portforward.SimulateDevCycle(t, kubectlCLI, ns.Name, log.TraceLevel)
	}
}

func TestRunPortForward(t *testing.T) {
	// TODO: This test shall pass once render v2 is completed.
	t.SkipNow()

	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		ns, _ := SetupNamespace(t)

		rpcAddr := randomPort()
		skaffold.Run("--port-forward", "--rpc-port", rpcAddr).InDir(test.dir).InNs(ns.Name).RunBackground(t)

		_, entries := apiEvents(t, rpcAddr)

		address, localPort := getLocalPortFromPortForwardEvent(t, entries, "leeroy-app", "service", ns.Name)
		assertResponseFromPort(t, address, localPort, constants.LeeroyAppResponse)
	}
}

func TestRunUserPortForwardResource(t *testing.T) {
	// TODO: This test shall pass once render v2 is completed.
	t.SkipNow()

	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		ns, _ := SetupNamespace(t)

		rpcAddr := randomPort()
		skaffold.Run("--port-forward", "--rpc-port", rpcAddr).InDir(test.dir).InNs(ns.Name).RunBackground(t)

		_, entries := apiEvents(t, rpcAddr)

		address, localPort := getLocalPortFromPortForwardEvent(t, entries, "leeroy-web", "deployment", ns.Name)
		assertResponseFromPort(t, address, localPort, constants.LeeroyAppResponse)
	}
}

func TestRunPortForwardByPortName(t *testing.T) {
	// TODO: This test shall pass once render v2 is completed.
	t.SkipNow()

	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		ns, _ := SetupNamespace(t)

		rpcAddr := randomPort()
		skaffold.Run("--port-forward", "--rpc-port", rpcAddr).InDir(test.dir).InNs(ns.Name).RunBackground(t)

		_, entries := apiEvents(t, rpcAddr)

		address1, localPort1 := getLocalPortFromPortForwardEvent(t, entries, "leeroy-app", "deployment", ns.Name)
		assertResponseFromPort(t, address1, localPort1, constants.LeeroyAppResponse)
	}
}

// TestDevPortForwardDeletePod tests that port forwarding works
// as expected. Then, the test force deletes a pod,
// and tests that the pod eventually comes up at the same port again.
func TestDevPortForwardDeletePod(t *testing.T) {
	// TODO: This test shall pass once render v2 is completed.
	t.SkipNow()

	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		// pre-build images to avoid tripping the 1-minute timeout in getLocalPortFromPortForwardEvent()
		skaffold.Build().InDir(test.dir).RunOrFail(t)

		ns, _ := SetupNamespace(t)

		rpcAddr := randomPort()
		skaffold.Dev("--port-forward", "--rpc-port", rpcAddr).InDir(test.dir).InNs(ns.Name).RunBackground(t)

		_, entries := apiEvents(t, rpcAddr)

		address, localPort := getLocalPortFromPortForwardEvent(t, entries, "leeroy-app", "service", ns.Name)
		assertResponseFromPort(t, address, localPort, constants.LeeroyAppResponse)

		// now, delete all pods in this namespace.
		Run(t, ".", "kubectl", "delete", "pods", "--all", "-n", ns.Name)

		assertResponseFromPort(t, address, localPort, constants.LeeroyAppResponse)
	}
}
<commit_msg>chore: re-enable tests in port_forward_test.go (#7523)<commit_after>/*
Copyright 2019 The Skaffold Authors

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

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

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

package integration

import (
	"testing"

	"github.com/GoogleContainerTools/skaffold/integration/skaffold"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubectl"
	kubectx "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/context"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/portforward"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
	runcontext "github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext/v2"
)

func TestPortForward(t *testing.T) {
	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		ns, _ := SetupNamespace(t)

		skaffold.Run().InDir(test.dir).InNs(ns.Name).RunOrFail(t)

		cfg, err := kubectx.CurrentConfig()
		failNowIfError(t, err)

		kubectlCLI := kubectl.NewCLI(&runcontext.RunContext{
			KubeContext: cfg.CurrentContext,
			Opts: config.SkaffoldOptions{
				Namespace: ns.Name,
			},
		}, "")

		portforward.SimulateDevCycle(t, kubectlCLI, ns.Name, log.TraceLevel)
	}
}

func TestRunPortForward(t *testing.T) {
	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		ns, _ := SetupNamespace(t)

		rpcAddr := randomPort()
		skaffold.Run("--port-forward", "--rpc-port", rpcAddr).InDir(test.dir).InNs(ns.Name).RunBackground(t)

		_, entries := apiEvents(t, rpcAddr)

		address, localPort := getLocalPortFromPortForwardEvent(t, entries, "leeroy-app", "service", ns.Name)
		assertResponseFromPort(t, address, localPort, constants.LeeroyAppResponse)
	}
}

func TestRunUserPortForwardResource(t *testing.T) {
	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		ns, _ := SetupNamespace(t)

		rpcAddr := randomPort()
		skaffold.Run("--port-forward", "--rpc-port", rpcAddr).InDir(test.dir).InNs(ns.Name).RunBackground(t)

		_, entries := apiEvents(t, rpcAddr)

		address, localPort := getLocalPortFromPortForwardEvent(t, entries, "leeroy-web", "deployment", ns.Name)
		assertResponseFromPort(t, address, localPort, constants.LeeroyAppResponse)
	}
}

func TestRunPortForwardByPortName(t *testing.T) {
	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		ns, _ := SetupNamespace(t)

		rpcAddr := randomPort()
		skaffold.Run("--port-forward", "--rpc-port", rpcAddr).InDir(test.dir).InNs(ns.Name).RunBackground(t)

		_, entries := apiEvents(t, rpcAddr)

		address1, localPort1 := getLocalPortFromPortForwardEvent(t, entries, "leeroy-app", "deployment", ns.Name)
		assertResponseFromPort(t, address1, localPort1, constants.LeeroyAppResponse)
	}
}

// TestDevPortForwardDeletePod tests that port forwarding works
// as expected. Then, the test force deletes a pod,
// and tests that the pod eventually comes up at the same port again.
func TestDevPortForwardDeletePod(t *testing.T) {
	MarkIntegrationTest(t, CanRunWithoutGcp)
	tests := []struct {
		dir string
	}{
		{dir: "examples/microservices"},
		{dir: "examples/multi-config-microservices"},
	}
	for _, test := range tests {
		// pre-build images to avoid tripping the 1-minute timeout in getLocalPortFromPortForwardEvent()
		skaffold.Build().InDir(test.dir).RunOrFail(t)

		ns, _ := SetupNamespace(t)

		rpcAddr := randomPort()
		skaffold.Dev("--port-forward", "--rpc-port", rpcAddr).InDir(test.dir).InNs(ns.Name).RunBackground(t)

		_, entries := apiEvents(t, rpcAddr)

		address, localPort := getLocalPortFromPortForwardEvent(t, entries, "leeroy-app", "service", ns.Name)
		assertResponseFromPort(t, address, localPort, constants.LeeroyAppResponse)

		// now, delete all pods in this namespace.
		Run(t, ".", "kubectl", "delete", "pods", "--all", "-n", ns.Name)

		assertResponseFromPort(t, address, localPort, constants.LeeroyAppResponse)
	}
}
<|endoftext|>