<commit_before>package statemachine

import (
	"jeopardy/json"
	"jeopardy/comms"
)

import (
	"fmt"
	"math/rand"
	"strings"
	"strconv"
)
type StateId int

//const (
//	IDLE StateId = iota    // beginning of the game (expected input: admin starts game)
//	NEW_GAME             // admin started game (expected input: player1 name)
//	PLAYER              // player1 (expected input: player2 name)
////	PLAYER2              // player2 (expected input: player3 name)
//	START_GAME					 // all names know, broadcast board
//	PICK_PLAYER          // server picks player (expected input: question picked by player)
//	QUESTION_PICKED      // question is picked, display, start timer (expected input: buzzer 1,2 or 3)
//	ANSWER_QUESTION      // first buzzer pressed ansers, start timer (expected input: correct, incorrect, timer_expired)
//	ADJUST_SCORE
//	CORRECT              // adjust player score -> CHK_GAME_OVER
//	WRONG                // addjust player score -> QUESTION_PICKED / CHK_GAME_OVER
//	LAST_PLAYER          // have all players (unsuccessfully) tried to anser
//	CHK_GAME_OVER        // check if any questions are left on the board -> pick player / GAME_OVER
//	GAME_OVER
//	DETERMINE_WINNER
//)

const (
	// events can come from buzzer (high byte 00) or admin (high byte FF)
	E_START_GAME = 0xFF00
	E_PLAYER_ONE = 0xFF01
	E_PLAYER_TWO = 0xFF02
	E_PLAYER_THREE = 0xFF03
	E_QUESTION_CHOSEN = 0xFF04
	E_CORRECT = 0xFF05
	E_INCORRECT = 0xFF06

	E_BUZZER_ONE = 0x0000
	E_BUZZER_TWO = 0x0001
	E_BUZZER_THREE = 0x0002

	E_TIMEOUT_NO_ANSWER = 0xF000

)
type Event struct {
	Id int
	Data string
}

type State interface {
	Game() *Game
	EnterState(Event)
	HandleEvent(Event) State

}
//type Player struct {
//	Name string
//	Score int
//}

//type Question struct {
//	Answer string
//	Question string
//	Value int
//}

type Game struct {
	GameState State
	Players []*json.Player
	CurrentPlayer int // 0 noone ...
	LastCorrectAnswer int // 0 noone, 1 player 1, 2 = player 2...
	CurrentQuestion * json.Answer
	CurrentAttempts string  // keeps track of who has tried to answer the current Question
	QuestionsRemaining int
	Categories []*json.Category

	Admin	*comms.Admin
	UI    *comms.WebsocketHandler
	// Buzzer 1
	// Buzzer 2
	// Buzzer 3
	// UI
}

func NewGame(fn string, admin *comms.Admin)*Game {
	var err error
	game := new(Game)
	game.Admin = admin

	if game.Categories, err = json.LoadCategories(fn); err != nil {
		fmt.Printf("%s\n", err)
		panic(err.Error())
	}
	game.Players = make([]*json.Player, 3)
	game.Players[0] = &json.Player{"1", 0, "default"}
	game.Players[1] = &json.Player{"2", 0, "default"}
	game.Players[2] = &json.Player{"3", 0, "default"}

	game.GameState = new(S_Idle)

	return game
}

// sends the current gamestate to the web client
func (g * Game) SendGameState() {
	state := json.GameState{}
	state.Categories = g.Categories
	state.Players    = g.Players
	if (g.CurrentQuestion != nil) {
		state.Answer = g.CurrentQuestion.Answer
	}
	if (g.UI != nil) {
		g.UI.SendGameState(&state)
	} else {
		g.Admin.Prompt("no websocket!")
	}
}

// Input from Admin
func (g * Game) HandleEvent (e Event) {
	g.GameState = g.GameState.HandleEvent(e)
	g.GameState.EnterState(e)
}

type baseState struct {
	game *Game
}

func (s * baseState) Game()*Game {
	return s.game
}

type S_Idle struct {
	baseState
}

func (s * S_Idle) EnterState(e Event) {return}
func (s * S_Idle) HandleEvent(e Event)State {
	if (e.Id == E_START_GAME) {
		var snew S_NewGame
		snew.game = s.game
		return &snew
	}
	return s;
}

type S_NewGame struct {
	baseState
}
func (s * S_NewGame) EnterState(e Event) {
	s.game.SendGameState()
	// send (something) to buzzer
}
func (s * S_NewGame) HandleEvent(e Event)State {
	if (e.Id == E_PLAYER_ONE) {
		// s.sendBoard(e.Data)
		snew := S_Player{}
		snew.game = s.game
		return &snew
	} else {
		return s
	}
}

type S_Player struct {
	baseState
}
func (s * S_Player) EnterState(e Event) {
	switch (e.Id) {
		case E_PLAYER_ONE:
			s.game.Players[0] = &json.Player{e.Data, 0, "default"}
		case E_PLAYER_TWO:
			s.game.Players[1] = &json.Player{e.Data, 0, "default"}
		case E_PLAYER_THREE:
			s.game.Players[2] = &json.Player{e.Data, 0, "default"}
		default:
			s.game.Admin.Prompt("unexpected event")
			return
	}
	s.game.SendGameState()
}
func (s * S_Player) HandleEvent(e Event)(state State) {
	switch (e.Id) {
		case E_PLAYER_TWO:
			snew := S_Player{}
			snew.game = s.game
			return &snew
		case E_PLAYER_THREE:
			// new game will start. broadcast board.
			snew := S_StartGame{}
			snew.game = s.game
			return  &snew
		default:
			return s
	}
}

type S_StartGame struct {
	baseState
}

func (s * S_StartGame) EnterState(e Event) {
	// set up board. broadcast
	s.game.SendGameState()
	s.game.HandleEvent(e) // advance to next state automatically.
}
func (s * S_StartGame) HandleEvent(e Event)State{
	new_state := new(S_PickPlayer)
	new_state.game = s.game
	return new_state
}

type S_PickPlayer struct {
	baseState
}
func (s * S_PickPlayer) EnterState(e Event) {
	// reset some state
	s.game.CurrentAttempts = ""
	// pick player and broadcast
	if s.game.LastCorrectAnswer != 0 {
		s.game.CurrentPlayer = s.game.LastCorrectAnswer
	} else {
		s.game.CurrentPlayer = (rand.Int() % 3) + 1
	}
	s.game.Players[s.game.CurrentPlayer -1].Status = "active"
	s.game.SendGameState()
}
func (s * S_PickPlayer) HandleEvent(e Event)State {
	if (e.Id == E_QUESTION_CHOSEN) {
		nstate := new(S_QuestionChosen)
		nstate.game = s.game
		return nstate
	}
	return s
}

type S_QuestionChosen struct {
	baseState
}

func(s * S_QuestionChosen) EnterState(e Event) {
		// tell ui question
		// display question to admin
		cat_ques := strings.Split(e.Data, "_")
		var cat int64
		var ques int64
		var err error
		if cat, err = strconv.ParseInt(cat_ques[0], 10, 32); err != nil {
			mes := fmt.Sprintf("error parsing %s : %s", cat_ques[0], err.Error())
			s.game.Admin.Prompt(mes)
		}
		if ques, err = strconv.ParseInt(cat_ques[1], 10, 32); err != nil {
			mes := fmt.Sprintf("error parsing %s : %s", cat_ques[1], err.Error())
			s.game.Admin.Prompt(mes)
		}

		category := s.game.Categories[cat-1]
		answer   := category.Answers[ques-1]
		s.game.CurrentQuestion = &answer

		s.game.Admin.Prompt(answer.Answer)
		s.game.Admin.Prompt(answer.Question)

		s.game.SendGameState()

		// TODO start_timer
}
func(s * S_QuestionChosen) HandleEvent(e Event) State {
	nstate := new(S_AnswerExpected)
	nstate.game = s.game
	switch (e.Id) {
		case E_BUZZER_ONE:
			return nstate
		case E_BUZZER_TWO:
			return nstate
		case E_BUZZER_THREE:
			return nstate
		case E_TIMEOUT_NO_ANSWER:
			nstate2 := new(S_CheckGameOver)
			nstate2.game = s.game
			return nstate2
		default:
			return s
	}
}

type S_AnswerExpected struct {
	baseState
}

func(s * S_AnswerExpected) EnterState(e Event) {

		switch (e.Id) {
		case E_BUZZER_ONE:
			s.game.CurrentPlayer = 1
		case E_BUZZER_TWO:
			s.game.CurrentPlayer = 2
		case E_BUZZER_THREE:
			s.game.CurrentPlayer = 3
		}
		for i, player := range s.game.Players {
			if i+1 == s.game.CurrentPlayer {
				player.Status = "active"
			} else {
				player.Status = "default"
			}
		}
		s.game.SendGameState()
		s.game.Admin.Prompt("Was the given Answer correct?")

		// TODO start_timer
}

func(s * S_AnswerExpected) HandleEvent(e Event) State {
	var nstate State
	switch (e.Id) {
		case E_CORRECT:
			nstate := new(S_Adjust_Score)
			nstate.game = s.Game()
		case E_INCORRECT:
			nstate := new(S_Adjust_Score)
			nstate.game = s.Game()
		case E_TIMEOUT_NO_ANSWER:
			nstate := new(S_CheckGameOver)
			nstate.game = s.Game()
		default:
			return s
	}
	return nstate
}

type S_Adjust_Score struct {
	baseState
}

func(s * S_Adjust_Score) EnterState(e Event) {
		switch (e.Id) {
		case E_CORRECT:
			s.game.Players[s.game.CurrentPlayer-1].Score = s.game.CurrentQuestion.Value
			s.game.LastCorrectAnswer = s.game.CurrentPlayer
		case E_INCORRECT:
			s.game.Players[s.game.CurrentPlayer-1].Score = s.game.CurrentQuestion.Value
		}
		s.game.SendGameState()

		s.game.HandleEvent(e)

}
func(s * S_Adjust_Score) HandleEvent(e Event) State {
	switch (e.Id) {
		case E_CORRECT:
			nstate := new(S_CheckGameOver)
			nstate.game = s.game
			return nstate
		case E_INCORRECT:
			nstate := new(S_CheckLastPlayer)
			nstate.game = s.game
			if (nstate.game.CurrentPlayer == 1) {
				nstate.game.CurrentAttempts += "1"
			}else if (nstate.game.CurrentPlayer == 2) {
				nstate.game.CurrentAttempts += "2"
			} else {
				nstate.game.CurrentAttempts += "3"
			}
			return nstate
		default:
			return s
	}
}

type S_CheckGameOver struct {
	baseState
}

func(s * S_CheckGameOver) EnterState(e Event) {
	s.HandleEvent(e)
}
func(s * S_CheckGameOver) HandleEvent(e Event) State {
	if (s.game.QuestionsRemaining == 0) { // TODO!!
		nstate := new(S_DetermineWinner)
		nstate.game = s.game
		return nstate
	} else {
		nstate := new(S_PickPlayer)
		nstate.game = s.game
		return nstate
	}
}

type S_CheckLastPlayer struct {
	baseState
}

func(s * S_CheckLastPlayer) EnterState(e Event) {
	s.game.HandleEvent(e)
}
func(s * S_CheckLastPlayer) HandleEvent(e Event) State {
	if (len(s.game.CurrentAttempts) == 3) {
		nstate := new(S_CheckGameOver)
		nstate.game = s.game
		return nstate
	}
	nstate := new(S_QuestionChosen)
	nstate.game = s.game
	return nstate
}

type S_DetermineWinner struct {
	baseState
}

func(s * S_DetermineWinner) EnterState(e Event) {
	// broadcast winner.
}
func(s * S_DetermineWinner) HandleEvent(e Event) State {
	return s
}

<commit_msg>state machine interaction<commit_after>package statemachine

import (
	"jeopardy/json"
	"jeopardy/comms"
)

import (
	"fmt"
	"math/rand"
	"strings"
	"strconv"
)
type StateId int

//const (
//	IDLE StateId = iota    // beginning of the game (expected input: admin starts game)
//	NEW_GAME             // admin started game (expected input: player1 name)
//	PLAYER              // player1 (expected input: player2 name)
////	PLAYER2              // player2 (expected input: player3 name)
//	START_GAME					 // all names know, broadcast board
//	PICK_PLAYER          // server picks player (expected input: question picked by player)
//	QUESTION_PICKED      // question is picked, display, start timer (expected input: buzzer 1,2 or 3)
//	ANSWER_QUESTION      // first buzzer pressed ansers, start timer (expected input: correct, incorrect, timer_expired)
//	ADJUST_SCORE
//	CORRECT              // adjust player score -> CHK_GAME_OVER
//	WRONG                // addjust player score -> QUESTION_PICKED / CHK_GAME_OVER
//	LAST_PLAYER          // have all players (unsuccessfully) tried to anser
//	CHK_GAME_OVER        // check if any questions are left on the board -> pick player / GAME_OVER
//	GAME_OVER
//	DETERMINE_WINNER
//)

const (
	// events can come from buzzer (high byte 00) or admin (high byte FF)
	E_START_GAME = 0xFF00
	E_PLAYER_ONE = 0xFF01
	E_PLAYER_TWO = 0xFF02
	E_PLAYER_THREE = 0xFF03
	E_QUESTION_CHOSEN = 0xFF04
	E_CORRECT = 0xFF05
	E_INCORRECT = 0xFF06

	E_BUZZER_ONE = 0x0000
	E_BUZZER_TWO = 0x0001
	E_BUZZER_THREE = 0x0002

	E_TIMEOUT_NO_ANSWER = 0xF000

)
type Event struct {
	Id int
	Data string
}

type State interface {
	Game() *Game
	EnterState(Event)
	HandleEvent(Event) State

}

type Game struct {
	GameState State
	Players []*json.Player
	CurrentPlayer int // 0 noone ...
	LastCorrectAnswer int // 0 noone, 1 player 1, 2 = player 2...
	CurrentQuestion * json.Answer
	CurrentAttempts string  // keeps track of who has tried to answer the current Question
	QuestionsRemaining int
	Categories []*json.Category

	Admin	*comms.Admin
	UI    *comms.WebsocketHandler
	// Buzzer 1
	// Buzzer 2
	// Buzzer 3
	// UI
}

func NewGame(fn string, admin *comms.Admin)*Game {
	var err error
	game := new(Game)
	game.Admin = admin

	if game.Categories, err = json.LoadCategories(fn); err != nil {
		fmt.Printf("%s\n", err)
		panic(err.Error())
	}
	game.Players = make([]*json.Player, 3)
	game.Players[0] = &json.Player{"1", 0, "default"}
	game.Players[1] = &json.Player{"2", 0, "default"}
	game.Players[2] = &json.Player{"3", 0, "default"}

	game.GameState = new(S_Idle)

	return game
}

// sends the current gamestate to the web client
func (g * Game) SendGameState() {
	state := json.GameState{}
	state.Categories = g.Categories
	state.Players    = g.Players
	if (g.CurrentQuestion != nil) {
		state.Answer = g.CurrentQuestion.Answer
	}
	if (g.UI != nil) {
		g.UI.SendGameState(&state)
	} else {
		g.Admin.Prompt("no websocket!")
	}
}

// Input from Admin
func (g * Game) HandleEvent (e Event) {
	g.GameState = g.GameState.HandleEvent(e)
	g.GameState.EnterState(e)
}

type baseState struct {
	game *Game
}

func (s * baseState) Game()*Game {
	return s.game
}

type S_Idle struct {
	baseState
}

func (s * S_Idle) EnterState(e Event) {return}
func (s * S_Idle) HandleEvent(e Event)State {
	if (e.Id == E_START_GAME) {
		var snew S_NewGame
		snew.game = s.game
		return &snew
	}
	return s;
}

type S_NewGame struct {
	baseState
}
func (s * S_NewGame) EnterState(e Event) {
	s.game.SendGameState()
	// send (something) to buzzer
}
func (s * S_NewGame) HandleEvent(e Event)State {
	if (e.Id == E_PLAYER_ONE) {
		// s.sendBoard(e.Data)
		snew := S_Player{}
		snew.game = s.game
		return &snew
	} else {
		return s
	}
}

type S_Player struct {
	baseState
}
func (s * S_Player) EnterState(e Event) {
	switch (e.Id) {
		case E_PLAYER_ONE:
			s.game.Players[0] = &json.Player{e.Data, 0, "default"}
		case E_PLAYER_TWO:
			s.game.Players[1] = &json.Player{e.Data, 0, "default"}
		case E_PLAYER_THREE:
			s.game.Players[2] = &json.Player{e.Data, 0, "default"}
		default:
			s.game.Admin.Prompt("unexpected event")
			return
	}
	s.game.SendGameState()
}
func (s * S_Player) HandleEvent(e Event)(state State) {
	switch (e.Id) {
		case E_PLAYER_TWO:
			snew := S_Player{}
			snew.game = s.game
			return &snew
		case E_PLAYER_THREE:
			// new game will start. broadcast board.
			snew := S_StartGame{}
			snew.game = s.game
			return  &snew
		default:
			return s
	}
}

type S_StartGame struct {
	baseState
}

func (s * S_StartGame) EnterState(e Event) {
	// set up board. broadcast
	s.game.SendGameState()
	s.game.HandleEvent(e) // advance to next state automatically.
}
func (s * S_StartGame) HandleEvent(e Event)State{
	new_state := new(S_PickPlayer)
	new_state.game = s.game
	return new_state
}

type S_PickPlayer struct {
	baseState
}
func (s * S_PickPlayer) EnterState(e Event) {
	// reset some state
	s.game.CurrentAttempts = ""
	// pick player and broadcast
	if s.game.LastCorrectAnswer != 0 {
		s.game.CurrentPlayer = s.game.LastCorrectAnswer
	} else {
		s.game.CurrentPlayer = (rand.Int() % 3) + 1
	}
	s.game.Players[s.game.CurrentPlayer -1].Status = "active"
	s.game.SendGameState()
}
func (s * S_PickPlayer) HandleEvent(e Event)State {
	if (e.Id == E_QUESTION_CHOSEN) {
		nstate := new(S_QuestionChosen)
		nstate.game = s.game
		return nstate
	}
	return s
}

type S_QuestionChosen struct {
	baseState
}

func(s * S_QuestionChosen) EnterState(e Event) {
		// tell ui question
		// display question to admin
		cat_ques := strings.Split(e.Data, "_")
		var cat int64
		var ques int64
		var err error
		if cat, err = strconv.ParseInt(cat_ques[0], 10, 32); err != nil {
			mes := fmt.Sprintf("error parsing %s : %s", cat_ques[0], err.Error())
			s.game.Admin.Prompt(mes)
		}
		if ques, err = strconv.ParseInt(cat_ques[1], 10, 32); err != nil {
			mes := fmt.Sprintf("error parsing %s : %s", cat_ques[1], err.Error())
			s.game.Admin.Prompt(mes)
		}

		category := s.game.Categories[cat-1]
		answer   := category.Answers[ques-1]
		s.game.CurrentQuestion = &answer

		s.game.Admin.Prompt(answer.Answer)
		s.game.Admin.Prompt(answer.Question)

		s.game.SendGameState()

		// TODO start_timer
}
func(s * S_QuestionChosen) HandleEvent(e Event) State {
	nstate := new(S_AnswerExpected)
	nstate.game = s.game
	switch (e.Id) {
		case E_BUZZER_ONE:
			return nstate
		case E_BUZZER_TWO:
			return nstate
		case E_BUZZER_THREE:
			return nstate
		case E_TIMEOUT_NO_ANSWER:
			nstate2 := new(S_CheckGameOver)
			nstate2.game = s.game
			return nstate2
		default:
			return s
	}
}

type S_AnswerExpected struct {
	baseState
}

func(s * S_AnswerExpected) EnterState(e Event) {

		switch (e.Id) {
		case E_BUZZER_ONE:
			s.game.CurrentPlayer = 1
		case E_BUZZER_TWO:
			s.game.CurrentPlayer = 2
		case E_BUZZER_THREE:
			s.game.CurrentPlayer = 3
		}
		for i, player := range s.game.Players {
			if i+1 == s.game.CurrentPlayer {
				player.Status = "active"
			} else {
				player.Status = "default"
			}
		}
		s.game.SendGameState()
		s.game.Admin.Prompt("Was the given Answer correct?")

		// TODO start_timer
}

func(s * S_AnswerExpected) HandleEvent(e Event) State {
	var nstate State
	switch (e.Id) {
		case E_CORRECT:
			nstate := new(S_Adjust_Score)
			nstate.game = s.Game()
		case E_INCORRECT:
			nstate := new(S_Adjust_Score)
			nstate.game = s.Game()
		case E_TIMEOUT_NO_ANSWER:
			nstate := new(S_CheckGameOver)
			nstate.game = s.Game()
		default:
			return s
	}
	return nstate
}

type S_Adjust_Score struct {
	baseState
}

func(s * S_Adjust_Score) EnterState(e Event) {
		switch (e.Id) {
		case E_CORRECT:
			s.game.Players[s.game.CurrentPlayer-1].Score = s.game.CurrentQuestion.Value
			s.game.LastCorrectAnswer = s.game.CurrentPlayer
		case E_INCORRECT:
			s.game.Players[s.game.CurrentPlayer-1].Score = s.game.CurrentQuestion.Value
		}
		s.game.SendGameState()

		s.game.HandleEvent(e)

}
func(s * S_Adjust_Score) HandleEvent(e Event) State {
	switch (e.Id) {
		case E_CORRECT:
			nstate := new(S_CheckGameOver)
			nstate.game = s.game
			return nstate
		case E_INCORRECT:
			nstate := new(S_CheckLastPlayer)
			nstate.game = s.game
			if (nstate.game.CurrentPlayer == 1) {
				nstate.game.CurrentAttempts += "1"
			}else if (nstate.game.CurrentPlayer == 2) {
				nstate.game.CurrentAttempts += "2"
			} else {
				nstate.game.CurrentAttempts += "3"
			}
			return nstate
		default:
			return s
	}
}

type S_CheckGameOver struct {
	baseState
}

func(s * S_CheckGameOver) EnterState(e Event) {
	s.HandleEvent(e)
}
func(s * S_CheckGameOver) HandleEvent(e Event) State {
	if (s.game.QuestionsRemaining == 0) { // TODO!!
		nstate := new(S_DetermineWinner)
		nstate.game = s.game
		return nstate
	} else {
		nstate := new(S_PickPlayer)
		nstate.game = s.game
		return nstate
	}
}

type S_CheckLastPlayer struct {
	baseState
}

func(s * S_CheckLastPlayer) EnterState(e Event) {
	s.game.HandleEvent(e)
}
func(s * S_CheckLastPlayer) HandleEvent(e Event) State {
	if (len(s.game.CurrentAttempts) == 3) {
		nstate := new(S_CheckGameOver)
		nstate.game = s.game
		return nstate
	}
	nstate := new(S_QuestionChosen)
	nstate.game = s.game
	return nstate
}

type S_DetermineWinner struct {
	baseState
}

func(s * S_DetermineWinner) EnterState(e Event) {
	// broadcast winner.
}
func(s * S_DetermineWinner) HandleEvent(e Event) State {
	return s
}

<|endoftext|>


<commit_before>package common

import (
	"io"
	"path"
	"strconv"
	"strings"

	"engo.io/engo"
	"github.com/Noofbiz/tmx"
)

// createLevelFromTmx unmarshalls and unpacks tmx data into a Level
func createLevelFromTmx(r io.Reader, tmxURL string) (*Level, error) {
	tmx.TMXURL = tmxURL
	tmxLevel, err := tmx.Parse(r)
	if err != nil {
		return nil, err
	}
	level := &Level{}
	level.Orientation = orth
	level.resourceMap = make(map[uint32]Texture)
	level.pointMap = make(map[mapPoint]*Tile)

	// get a map of the gids to textures from the tilesets
	for _, ts := range tmxLevel.Tilesets {
		for _, g := range ts.Grid {
			level.Orientation = g.Orientation
		}
		for _, t := range ts.Tiles {
			for _, i := range t.Image {
				if i.Source != "" {
					tex, err := LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
					if err != nil {
						if strings.HasPrefix(err.Error(), "resource not loaded") {
							err = engo.Files.Load(path.Join(path.Dir(tmxURL), i.Source))
							if err != nil {
								return nil, err
							}
							tex, err = LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
						} else {
							return nil, err
						}
					}
					level.resourceMap[ts.FirstGID+t.ID] = *tex
				}
			}
		}
		for _, i := range ts.Image {
			if i.Source != "" {
				_, err := LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
				if err != nil {
					if strings.HasPrefix(err.Error(), "resource not loaded") {
						err = engo.Files.Load(path.Join(path.Dir(tmxURL), i.Source))
						if err != nil {
							return nil, err
						}
						_, err = LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
					} else {
						return nil, err
					}
				}
				ss := NewSpritesheetWithBorderFromFile(path.Join(path.Dir(tmxURL), i.Source), ts.TileWidth, ts.TileHeight, ts.Spacing, ts.Spacing)
				for i, tex := range ss.Cells() {
					level.resourceMap[ts.FirstGID+uint32(i)] = tex
				}
			}
		}
	}

	level.Orientation = tmxLevel.Orientation
	level.RenderOrder = tmxLevel.RenderOrder
	level.TileWidth = tmxLevel.TileWidth
	level.width = tmxLevel.Width
	level.height = tmxLevel.Height
	level.TileHeight = tmxLevel.TileHeight
	level.NextObjectID = tmxLevel.NextObjectID
	level.Properties = getProperties(tmxLevel.Properties)

	// tile layers
	for _, l := range tmxLevel.Layers {
		tl := &TileLayer{}
		tl.Name = l.Name
		tl.X = float32(l.X)
		tl.OffSetX = float32(l.OffsetX)
		tl.Y = float32(l.Y)
		tl.OffSetY = float32(l.OffsetY)
		tl.Opacity = float32(l.Opacity)
		tl.Visible = l.Visible == 1
		if l.Width != 0 {
			tl.Width = l.Width
		} else {
			tl.Width = tmxLevel.Width
		}
		if l.Height != 0 {
			tl.Height = l.Height
		} else {
			tl.Height = tmxLevel.Height
		}
		tl.Properties = getProperties(l.Properties)
		tl.Tiles = level.unpackTiles(0, 0, tl.Height, tl.Width, l.Data)
		level.TileLayers = append(level.TileLayers, tl)
	}

	//image layers
	for _, l := range tmxLevel.ImageLayers {
		il := &ImageLayer{}
		il.Name = l.Name
		il.Opacity = float32(l.Opacity)
		il.Visible = l.Visible == 1
		il.OffSetX = float32(l.OffsetX)
		il.OffSetY = float32(l.OffsetY)
		il.Properties = getProperties(l.Properties)
		il.Images, err = level.imageTiles(tmxURL, l.Images, il.OffSetX, il.OffSetY)
		if err != nil {
			return nil, err
		}
		level.ImageLayers = append(level.ImageLayers, il)
	}

	// Objects
	for _, o := range tmxLevel.ObjectGroups {
		ol := &ObjectLayer{}
		ol.Color = o.Color
		ol.Name = o.Name
		ol.DrawOrder = o.DrawOrder
		ol.OffSetX = float32(o.OffsetX)
		ol.OffSetY = float32(o.OffsetY)
		ol.Opacity = float32(o.Opacity)
		ol.Visible = o.Visible == 1
		ol.Properties = getProperties(o.Properties)
		for _, tmxobj := range o.Objects {
			object := Object{}
			object.ID = tmxobj.ID
			object.Name = tmxobj.Name
			object.Type = tmxobj.Type
			object.X = float32(tmxobj.X)
			object.Y = float32(tmxobj.Y)
			object.Width = float32(tmxobj.Width)
			object.Height = float32(tmxobj.Height)
			object.Properties = getProperties(tmxobj.Properties)
			object.Tiles = append(object.Tiles, level.tileFromGID(tmxobj.GID, engo.Point{
				X: object.X,
				Y: object.Y,
			}))
			tiles, err := level.imageTiles(tmxURL, tmxobj.Images, object.X, object.Y)
			if err != nil {
				return nil, err
			}
			object.Tiles = append(object.Tiles, tiles...)
			for _, l := range tmxobj.Polygons {
				line := TMXLine{}
				line.Lines = pointStringToLines(l.Points, tmxobj.X, tmxobj.Y)
				line.Type = "Polygon"
				object.Lines = append(object.Lines, line)
			}
			for _, l := range tmxobj.Polylines {
				line := TMXLine{}
				line.Lines = pointStringToLines(l.Points, tmxobj.X, tmxobj.Y)
				line.Type = "Polyline"
				object.Lines = append(object.Lines, line)
			}
			for range tmxobj.Ellipses {
				object.Ellipses = append(object.Ellipses, TMXCircle{
					X:      object.X,
					Y:      object.Y,
					Width:  object.Width,
					Height: object.Height,
				})
			}
			for _, t := range tmxobj.Text {
				text := TMXText{}
				text.Bold = t.Bold == 1
				text.Color = t.Color
				text.FontFamily = t.FontFamily
				text.Halign = t.Halign
				text.Italic = t.Italic == 1
				text.Kerning = t.Kerning == 1
				text.Size = float32(t.PixelSize)
				text.Strikeout = t.Strikeout == 1
				text.Underline = t.Underline == 1
				text.Valign = t.Valign
				text.WordWrap = t.Wrap == 1
				text.CharData = t.CharData
				object.Text = append(object.Text, text)
			}
		}
		level.ObjectLayers = append(level.ObjectLayers, ol)
	}

	return level, nil
}

func pointStringToLines(str string, xOff, yOff float64) []*engo.Line {
	pts := strings.Split(str, " ")
	floatPts := make([][]float64, len(pts))
	for i, x := range pts {
		pt := strings.Split(x, ",")
		floatPts[i] = make([]float64, 2)
		floatPts[i][0], _ = strconv.ParseFloat(pt[0], 64)
		floatPts[i][1], _ = strconv.ParseFloat(pt[1], 64)
	}

	lines := make([]*engo.Line, len(floatPts)-1)

	// Now to globalize line coordinates
	for i := 0; i < len(floatPts)-1; i++ {
		x1 := float32(floatPts[i][0] + xOff)
		y1 := float32(floatPts[i][1] + yOff)
		x2 := float32(floatPts[i+1][0] + xOff)
		y2 := float32(floatPts[i+1][1] + yOff)

		p1 := engo.Point{X: x1, Y: y1}
		p2 := engo.Point{X: x2, Y: y2}
		newLine := &engo.Line{P1: p1, P2: p2}

		lines[i] = newLine
	}

	return lines
}

func (l *Level) unpackTiles(x, y, w, h int, d []tmx.Data) []*Tile {
	var ret []*Tile
	const (
		rd = "right-down"
		ru = "right-up"
		ld = "left-down"
		lu = "left-up"
	)

	switch l.RenderOrder {
	case ru:
		y = h - 1
	case ld:
		x = w - 1
	case lu:
		x = w - 1
		y = h - 1
	}

	for _, data := range d {
		for _, t := range data.Tiles {
			tile := l.tileFromGID(t.GID, l.screenPoint(engo.Point{
				X: float32(x),
				Y: float32(y),
			}))
			ret = append(ret, tile)
			l.pointMap[mapPoint{X: x, Y: y}] = tile
			switch l.RenderOrder {
			case rd:
				x++
				if x >= w {
					x = 0
					y++
				}
			case ru:
				x++
				if x >= w {
					x = 0
					y--
				}
			case ld:
				x--
				if x < 0 {
					x = w
					y++
				}
			case lu:
				x--
				if x < 0 {
					x = w
					y--
				}
			}
		}
		for _, c := range data.Chunks {
			x = c.X
			y = c.Y
			switch l.RenderOrder {
			case ru:
				y += c.Height - 1
			case ld:
				x += c.Width - 1
			case lu:
				x += c.Width - 1
				y += c.Height - 1
			}
			for _, t := range c.Tiles {
				tile := l.tileFromGID(t.GID, l.screenPoint(engo.Point{
					X: float32(x),
					Y: float32(y),
				}))
				ret = append(ret, tile)
				l.pointMap[mapPoint{X: x, Y: y}] = tile
				switch l.RenderOrder {
				case rd:
					x++
					if x >= c.X+c.Width {
						x = c.X
						y++
					}
				case ru:
					x++
					if x >= c.X+c.Width {
						x = c.X
						y--
					}
				case ld:
					x--
					if x < c.X {
						x = c.X + c.Width - 1
						y++
					}
				case lu:
					x--
					if x < c.Width {
						x = c.X + c.Width - 1
						y--
					}
				}
			}
		}
	}
	return ret
}

func (l *Level) imageTiles(tmxURL string, imgs []tmx.Image, x, y float32) ([]*Tile, error) {
	ret := make([]*Tile, 0)
	for _, i := range imgs {
		if i.Source != "" {
			tex, err := LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
			if err != nil {
				if strings.HasPrefix(err.Error(), "resource not loaded") {
					err = engo.Files.Load(path.Join(path.Dir(tmxURL), i.Source))
					if err != nil {
						return nil, err
					}
					tex, err = LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
				} else {
					return nil, err
				}
			}
			tile := &Tile{
				Image: tex,
				Point: engo.Point{
					X: x,
					Y: y,
				},
			}
			ret = append(ret, tile)
		}
		// TODO: handle image data (not supported by Tiled, but some Java versions do have it)
	}
	return ret, nil
}

func (l *Level) tileFromGID(gid uint32, pt engo.Point) *Tile {
	ret := &Tile{}
	tex := l.resourceMap[gid]
	ret.Image = &tex
	ret.Point = pt
	return ret
}

func getProperties(props []tmx.Property) []Property {
	ret := make([]Property, 0)
	for _, p := range props {
		ret = append(ret, Property{
			Name:  p.Name,
			Type:  p.Type,
			Value: p.Value,
		})
	}
	return ret
}
<commit_msg>Fix two params in wrong order<commit_after>package common

import (
	"io"
	"path"
	"strconv"
	"strings"

	"engo.io/engo"
	"github.com/Noofbiz/tmx"
)

// createLevelFromTmx unmarshalls and unpacks tmx data into a Level
func createLevelFromTmx(r io.Reader, tmxURL string) (*Level, error) {
	tmx.TMXURL = tmxURL
	tmxLevel, err := tmx.Parse(r)
	if err != nil {
		return nil, err
	}
	level := &Level{}
	level.Orientation = orth
	level.resourceMap = make(map[uint32]Texture)
	level.pointMap = make(map[mapPoint]*Tile)

	// get a map of the gids to textures from the tilesets
	for _, ts := range tmxLevel.Tilesets {
		for _, g := range ts.Grid {
			level.Orientation = g.Orientation
		}
		for _, t := range ts.Tiles {
			for _, i := range t.Image {
				if i.Source != "" {
					tex, err := LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
					if err != nil {
						if strings.HasPrefix(err.Error(), "resource not loaded") {
							err = engo.Files.Load(path.Join(path.Dir(tmxURL), i.Source))
							if err != nil {
								return nil, err
							}
							tex, err = LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
						} else {
							return nil, err
						}
					}
					level.resourceMap[ts.FirstGID+t.ID] = *tex
				}
			}
		}
		for _, i := range ts.Image {
			if i.Source != "" {
				_, err := LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
				if err != nil {
					if strings.HasPrefix(err.Error(), "resource not loaded") {
						err = engo.Files.Load(path.Join(path.Dir(tmxURL), i.Source))
						if err != nil {
							return nil, err
						}
						_, err = LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
					} else {
						return nil, err
					}
				}
				ss := NewSpritesheetWithBorderFromFile(path.Join(path.Dir(tmxURL), i.Source), ts.TileWidth, ts.TileHeight, ts.Spacing, ts.Spacing)
				for i, tex := range ss.Cells() {
					level.resourceMap[ts.FirstGID+uint32(i)] = tex
				}
			}
		}
	}

	level.Orientation = tmxLevel.Orientation
	level.RenderOrder = tmxLevel.RenderOrder
	level.TileWidth = tmxLevel.TileWidth
	level.width = tmxLevel.Width
	level.height = tmxLevel.Height
	level.TileHeight = tmxLevel.TileHeight
	level.NextObjectID = tmxLevel.NextObjectID
	level.Properties = getProperties(tmxLevel.Properties)

	// tile layers
	for _, l := range tmxLevel.Layers {
		tl := &TileLayer{}
		tl.Name = l.Name
		tl.X = float32(l.X)
		tl.OffSetX = float32(l.OffsetX)
		tl.Y = float32(l.Y)
		tl.OffSetY = float32(l.OffsetY)
		tl.Opacity = float32(l.Opacity)
		tl.Visible = l.Visible == 1
		if l.Width != 0 {
			tl.Width = l.Width
		} else {
			tl.Width = tmxLevel.Width
		}
		if l.Height != 0 {
			tl.Height = l.Height
		} else {
			tl.Height = tmxLevel.Height
		}
		tl.Properties = getProperties(l.Properties)
		tl.Tiles = level.unpackTiles(0, 0, tl.Width, tl.Height, l.Data)
		level.TileLayers = append(level.TileLayers, tl)
	}

	//image layers
	for _, l := range tmxLevel.ImageLayers {
		il := &ImageLayer{}
		il.Name = l.Name
		il.Opacity = float32(l.Opacity)
		il.Visible = l.Visible == 1
		il.OffSetX = float32(l.OffsetX)
		il.OffSetY = float32(l.OffsetY)
		il.Properties = getProperties(l.Properties)
		il.Images, err = level.imageTiles(tmxURL, l.Images, il.OffSetX, il.OffSetY)
		if err != nil {
			return nil, err
		}
		level.ImageLayers = append(level.ImageLayers, il)
	}

	// Objects
	for _, o := range tmxLevel.ObjectGroups {
		ol := &ObjectLayer{}
		ol.Color = o.Color
		ol.Name = o.Name
		ol.DrawOrder = o.DrawOrder
		ol.OffSetX = float32(o.OffsetX)
		ol.OffSetY = float32(o.OffsetY)
		ol.Opacity = float32(o.Opacity)
		ol.Visible = o.Visible == 1
		ol.Properties = getProperties(o.Properties)
		for _, tmxobj := range o.Objects {
			object := Object{}
			object.ID = tmxobj.ID
			object.Name = tmxobj.Name
			object.Type = tmxobj.Type
			object.X = float32(tmxobj.X)
			object.Y = float32(tmxobj.Y)
			object.Width = float32(tmxobj.Width)
			object.Height = float32(tmxobj.Height)
			object.Properties = getProperties(tmxobj.Properties)
			object.Tiles = append(object.Tiles, level.tileFromGID(tmxobj.GID, engo.Point{
				X: object.X,
				Y: object.Y,
			}))
			tiles, err := level.imageTiles(tmxURL, tmxobj.Images, object.X, object.Y)
			if err != nil {
				return nil, err
			}
			object.Tiles = append(object.Tiles, tiles...)
			for _, l := range tmxobj.Polygons {
				line := TMXLine{}
				line.Lines = pointStringToLines(l.Points, tmxobj.X, tmxobj.Y)
				line.Type = "Polygon"
				object.Lines = append(object.Lines, line)
			}
			for _, l := range tmxobj.Polylines {
				line := TMXLine{}
				line.Lines = pointStringToLines(l.Points, tmxobj.X, tmxobj.Y)
				line.Type = "Polyline"
				object.Lines = append(object.Lines, line)
			}
			for range tmxobj.Ellipses {
				object.Ellipses = append(object.Ellipses, TMXCircle{
					X:      object.X,
					Y:      object.Y,
					Width:  object.Width,
					Height: object.Height,
				})
			}
			for _, t := range tmxobj.Text {
				text := TMXText{}
				text.Bold = t.Bold == 1
				text.Color = t.Color
				text.FontFamily = t.FontFamily
				text.Halign = t.Halign
				text.Italic = t.Italic == 1
				text.Kerning = t.Kerning == 1
				text.Size = float32(t.PixelSize)
				text.Strikeout = t.Strikeout == 1
				text.Underline = t.Underline == 1
				text.Valign = t.Valign
				text.WordWrap = t.Wrap == 1
				text.CharData = t.CharData
				object.Text = append(object.Text, text)
			}
		}
		level.ObjectLayers = append(level.ObjectLayers, ol)
	}

	return level, nil
}

func pointStringToLines(str string, xOff, yOff float64) []*engo.Line {
	pts := strings.Split(str, " ")
	floatPts := make([][]float64, len(pts))
	for i, x := range pts {
		pt := strings.Split(x, ",")
		floatPts[i] = make([]float64, 2)
		floatPts[i][0], _ = strconv.ParseFloat(pt[0], 64)
		floatPts[i][1], _ = strconv.ParseFloat(pt[1], 64)
	}

	lines := make([]*engo.Line, len(floatPts)-1)

	// Now to globalize line coordinates
	for i := 0; i < len(floatPts)-1; i++ {
		x1 := float32(floatPts[i][0] + xOff)
		y1 := float32(floatPts[i][1] + yOff)
		x2 := float32(floatPts[i+1][0] + xOff)
		y2 := float32(floatPts[i+1][1] + yOff)

		p1 := engo.Point{X: x1, Y: y1}
		p2 := engo.Point{X: x2, Y: y2}
		newLine := &engo.Line{P1: p1, P2: p2}

		lines[i] = newLine
	}

	return lines
}

func (l *Level) unpackTiles(x, y, w, h int, d []tmx.Data) []*Tile {
	var ret []*Tile
	const (
		rd = "right-down"
		ru = "right-up"
		ld = "left-down"
		lu = "left-up"
	)

	switch l.RenderOrder {
	case ru:
		y = h - 1
	case ld:
		x = w - 1
	case lu:
		x = w - 1
		y = h - 1
	}

	for _, data := range d {
		for _, t := range data.Tiles {
			tile := l.tileFromGID(t.GID, l.screenPoint(engo.Point{
				X: float32(x),
				Y: float32(y),
			}))
			ret = append(ret, tile)
			l.pointMap[mapPoint{X: x, Y: y}] = tile
			switch l.RenderOrder {
			case rd:
				x++
				if x >= w {
					x = 0
					y++
				}
			case ru:
				x++
				if x >= w {
					x = 0
					y--
				}
			case ld:
				x--
				if x < 0 {
					x = w
					y++
				}
			case lu:
				x--
				if x < 0 {
					x = w
					y--
				}
			}
		}
		for _, c := range data.Chunks {
			x = c.X
			y = c.Y
			switch l.RenderOrder {
			case ru:
				y += c.Height - 1
			case ld:
				x += c.Width - 1
			case lu:
				x += c.Width - 1
				y += c.Height - 1
			}
			for _, t := range c.Tiles {
				tile := l.tileFromGID(t.GID, l.screenPoint(engo.Point{
					X: float32(x),
					Y: float32(y),
				}))
				ret = append(ret, tile)
				l.pointMap[mapPoint{X: x, Y: y}] = tile
				switch l.RenderOrder {
				case rd:
					x++
					if x >= c.X+c.Width {
						x = c.X
						y++
					}
				case ru:
					x++
					if x >= c.X+c.Width {
						x = c.X
						y--
					}
				case ld:
					x--
					if x < c.X {
						x = c.X + c.Width - 1
						y++
					}
				case lu:
					x--
					if x < c.Width {
						x = c.X + c.Width - 1
						y--
					}
				}
			}
		}
	}
	return ret
}

func (l *Level) imageTiles(tmxURL string, imgs []tmx.Image, x, y float32) ([]*Tile, error) {
	ret := make([]*Tile, 0)
	for _, i := range imgs {
		if i.Source != "" {
			tex, err := LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
			if err != nil {
				if strings.HasPrefix(err.Error(), "resource not loaded") {
					err = engo.Files.Load(path.Join(path.Dir(tmxURL), i.Source))
					if err != nil {
						return nil, err
					}
					tex, err = LoadedSprite(path.Join(path.Dir(tmxURL), i.Source))
				} else {
					return nil, err
				}
			}
			tile := &Tile{
				Image: tex,
				Point: engo.Point{
					X: x,
					Y: y,
				},
			}
			ret = append(ret, tile)
		}
		// TODO: handle image data (not supported by Tiled, but some Java versions do have it)
	}
	return ret, nil
}

func (l *Level) tileFromGID(gid uint32, pt engo.Point) *Tile {
	ret := &Tile{}
	tex := l.resourceMap[gid]
	ret.Image = &tex
	ret.Point = pt
	return ret
}

func getProperties(props []tmx.Property) []Property {
	ret := make([]Property, 0)
	for _, p := range props {
		ret = append(ret, Property{
			Name:  p.Name,
			Type:  p.Type,
			Value: p.Value,
		})
	}
	return ret
}
<|endoftext|>


<commit_before>package gocd

import (
	"context"
	"fmt"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"testing"
)

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

	t.Run("Get", testPipelineServiceGet)
	t.Run("Create", testPipelineServiceCreate)
	t.Run("GetHistory", testPipelineServiceGetHistory)
	t.Run("GetStatus", testPipelineServiceGetStatus)
	t.Run("Pause", testPipelineServicePause)
	t.Run("Unpause", testPipelineServiceUnpause)
	t.Run("ReleaseLock", testPipelineServiceReleaseLock)
	t.Run("PaginationStub", testPipelineServicePaginationStub)
	t.Run("StageContainer", testPipelineStageContainer)
}

func testPipelineStageContainer(t *testing.T) {

	p = &Pipeline{
		Name:   "mock-name",
		Stages: []*Stage{{}, {}},
	}

	i := StageContainer(p)

	assert.Equal(t, "mock-name", i.GetName())
	assert.Len(t, i.GetStages(), 2)
}

func testPipelineServicePaginationStub(t *testing.T) {
	pgs := PipelinesService{}

	assert.Equal(t, "a/b/c/4",
		pgs.buildPaginatedStub("a/%s/c", "b", 4))

	assert.Equal(t, "a/b/c",
		pgs.buildPaginatedStub("a/%s/c", "b", 0))

}

func testPipelineServiceGetStatus(t *testing.T) {
	mux.HandleFunc("/api/pipelines/test-pipeline/status", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.Method, "GET", "Unexpected HTTP method")
		b, _ := ioutil.ReadFile("test/resources/pipeline.2.json")
		fmt.Fprint(w, string(b))
	})

	ps, _, err := client.Pipelines.GetStatus(context.Background(), "test-pipeline", 0)
	if err != nil {
		t.Error(err)
	}

	assert.NotNil(t, ps)
	assert.False(t, ps.Locked)
	assert.True(t, ps.Paused)
	assert.False(t, ps.Schedulable)
}

func testPipelineServiceCreate(t *testing.T) {
	mux.HandleFunc("/api/admin/pipelines", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.Method, "POST", "Unexpected HTTP method")
		expectedBody, _ := ioutil.ReadFile("test/request/pipeline.0.json")

		actual, _ := ioutil.ReadAll(r.Body)
		assert.Equal(t, string(expectedBody), string(actual))

		j, _ := ioutil.ReadFile("test/resources/pipeline.0.json")
		fmt.Fprint(w, string(j))
	})

	p := Pipeline{
		LabelTemplate:         "${COUNT}",
		EnablePipelineLocking: true,
		Name: "new_pipeline",
		Materials: []Material{
			{
				Type: "git", Attributes: MaterialAttributes{
					URL:          "git@github.com:sample_repo/example.git",
					Destination:  "dest",
					InvertFilter: false,
					AutoUpdate:   true,
					Branch:       "master",
					ShallowClone: true,
				},
			},
		},
		Stages: []*Stage{
			{
				Name:           "defaultStage",
				FetchMaterials: true,
				Approval: &Approval{
					Type: "success",
					Authorization: &Authorization{
						Roles: []string{},
						Users: []string{},
					},
				},
				Jobs: []*Job{
					{
						Name: "defaultJob",
						Tasks: []Task{
							{
								Type: "exec",
								Attributes: TaskAttributes{
									RunIf:   []string{"passed"},
									Command: "ls",
								},
							},
						},
					},
				},
			},
		},
	}
	pr, _, err := client.Pipelines.Create(context.Background(), &p, "first")
	if err != nil {
		t.Error(err)
	}

	assert.NotNil(t, pr)
	assert.Equal(t, "test-pipeline", pr.Name)

	assert.Len(t, pr.Stages, 1)

	stage := pr.Stages[0]
	assert.Equal(t, "stage1", stage.Name)
}

func testPipelineServiceGet(t *testing.T) {
	mux.HandleFunc("/api/admin/pipelines/test-pipeline/instance", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.Method, "GET", "Unexpected HTTP method")
		j, _ := ioutil.ReadFile("test/resources/pipeline.0.json")
		fmt.Fprint(w, string(j))
	})

	p, _, err := client.Pipelines.GetInstance(context.Background(), "test-pipeline", 0)
	if err != nil {
		t.Error(err)
	}
	assert.NotNil(t, p)
	assert.Equal(t, p.Name, "test-pipeline")

	assert.Len(t, p.Stages, 1)

	s := p.Stages[0]
	assert.Equal(t, "stage1", s.Name)
	assert.Equal(t, false, s.FetchMaterials)
	assert.Equal(t, false, s.CleanWorkingDirectory)
	assert.Equal(t, false, s.NeverCleanupArtifacts)

	assert.Len(t, s.EnvironmentVariables, 0)
	assert.Nil(t, s.Approval)
}

func testPipelineServiceGetHistory(t *testing.T) {
	mux.HandleFunc("/api/pipelines/test-pipeline/history", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.Method, "GET", "Unexpected HTTP method")
		j, _ := ioutil.ReadFile("test/resources/pipeline.1.json")
		fmt.Fprint(w, string(j))
	})
	ph, _, err := client.Pipelines.GetHistory(context.Background(), "test-pipeline", 0)
	if err != nil {
		t.Error(err)
	}

	assert.NotNil(t, ph)
	assert.Len(t, ph.Pipelines, 2)

	h1 := ph.Pipelines[0]
	assert.True(t, h1.CanRun)
	assert.Equal(t, h1.Name, "pipeline1")
	assert.Equal(t, h1.NaturalOrder, 11)
	assert.Equal(t, h1.Comment, "")
	assert.Len(t, h1.Stages, 1)

	h1s := h1.Stages[0]
	assert.Equal(t, h1s.Name, "stage1")

	h2 := ph.Pipelines[1]
	assert.True(t, h2.CanRun)
	assert.Equal(t, h2.Name, "pipeline1")
	assert.Equal(t, h2.NaturalOrder, 10)
	assert.Equal(t, h2.Comment, "")
	assert.Len(t, h2.Stages, 1)

	h2s := h2.Stages[0]
	assert.Equal(t, h2s.Name, "stage1")

}
<commit_msg>Fixed bad variable assignment<commit_after>package gocd

import (
	"context"
	"fmt"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"testing"
)

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

	t.Run("Get", testPipelineServiceGet)
	t.Run("Create", testPipelineServiceCreate)
	t.Run("GetHistory", testPipelineServiceGetHistory)
	t.Run("GetStatus", testPipelineServiceGetStatus)
	t.Run("Pause", testPipelineServicePause)
	t.Run("Unpause", testPipelineServiceUnpause)
	t.Run("ReleaseLock", testPipelineServiceReleaseLock)
	t.Run("PaginationStub", testPipelineServicePaginationStub)
	t.Run("StageContainer", testPipelineStageContainer)
}

func testPipelineStageContainer(t *testing.T) {

	p := &Pipeline{
		Name:   "mock-name",
		Stages: []*Stage{{}, {}},
	}

	i := StageContainer(p)

	assert.Equal(t, "mock-name", i.GetName())
	assert.Len(t, i.GetStages(), 2)
}

func testPipelineServicePaginationStub(t *testing.T) {
	pgs := PipelinesService{}

	assert.Equal(t, "a/b/c/4",
		pgs.buildPaginatedStub("a/%s/c", "b", 4))

	assert.Equal(t, "a/b/c",
		pgs.buildPaginatedStub("a/%s/c", "b", 0))

}

func testPipelineServiceGetStatus(t *testing.T) {
	mux.HandleFunc("/api/pipelines/test-pipeline/status", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.Method, "GET", "Unexpected HTTP method")
		b, _ := ioutil.ReadFile("test/resources/pipeline.2.json")
		fmt.Fprint(w, string(b))
	})

	ps, _, err := client.Pipelines.GetStatus(context.Background(), "test-pipeline", 0)
	if err != nil {
		t.Error(err)
	}

	assert.NotNil(t, ps)
	assert.False(t, ps.Locked)
	assert.True(t, ps.Paused)
	assert.False(t, ps.Schedulable)
}

func testPipelineServiceCreate(t *testing.T) {
	mux.HandleFunc("/api/admin/pipelines", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.Method, "POST", "Unexpected HTTP method")
		expectedBody, _ := ioutil.ReadFile("test/request/pipeline.0.json")

		actual, _ := ioutil.ReadAll(r.Body)
		assert.Equal(t, string(expectedBody), string(actual))

		j, _ := ioutil.ReadFile("test/resources/pipeline.0.json")
		fmt.Fprint(w, string(j))
	})

	p := Pipeline{
		LabelTemplate:         "${COUNT}",
		EnablePipelineLocking: true,
		Name: "new_pipeline",
		Materials: []Material{
			{
				Type: "git", Attributes: MaterialAttributes{
					URL:          "git@github.com:sample_repo/example.git",
					Destination:  "dest",
					InvertFilter: false,
					AutoUpdate:   true,
					Branch:       "master",
					ShallowClone: true,
				},
			},
		},
		Stages: []*Stage{
			{
				Name:           "defaultStage",
				FetchMaterials: true,
				Approval: &Approval{
					Type: "success",
					Authorization: &Authorization{
						Roles: []string{},
						Users: []string{},
					},
				},
				Jobs: []*Job{
					{
						Name: "defaultJob",
						Tasks: []Task{
							{
								Type: "exec",
								Attributes: TaskAttributes{
									RunIf:   []string{"passed"},
									Command: "ls",
								},
							},
						},
					},
				},
			},
		},
	}
	pr, _, err := client.Pipelines.Create(context.Background(), &p, "first")
	if err != nil {
		t.Error(err)
	}

	assert.NotNil(t, pr)
	assert.Equal(t, "test-pipeline", pr.Name)

	assert.Len(t, pr.Stages, 1)

	stage := pr.Stages[0]
	assert.Equal(t, "stage1", stage.Name)
}

func testPipelineServiceGet(t *testing.T) {
	mux.HandleFunc("/api/admin/pipelines/test-pipeline/instance", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.Method, "GET", "Unexpected HTTP method")
		j, _ := ioutil.ReadFile("test/resources/pipeline.0.json")
		fmt.Fprint(w, string(j))
	})

	p, _, err := client.Pipelines.GetInstance(context.Background(), "test-pipeline", 0)
	if err != nil {
		t.Error(err)
	}
	assert.NotNil(t, p)
	assert.Equal(t, p.Name, "test-pipeline")

	assert.Len(t, p.Stages, 1)

	s := p.Stages[0]
	assert.Equal(t, "stage1", s.Name)
	assert.Equal(t, false, s.FetchMaterials)
	assert.Equal(t, false, s.CleanWorkingDirectory)
	assert.Equal(t, false, s.NeverCleanupArtifacts)

	assert.Len(t, s.EnvironmentVariables, 0)
	assert.Nil(t, s.Approval)
}

func testPipelineServiceGetHistory(t *testing.T) {
	mux.HandleFunc("/api/pipelines/test-pipeline/history", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, r.Method, "GET", "Unexpected HTTP method")
		j, _ := ioutil.ReadFile("test/resources/pipeline.1.json")
		fmt.Fprint(w, string(j))
	})
	ph, _, err := client.Pipelines.GetHistory(context.Background(), "test-pipeline", 0)
	if err != nil {
		t.Error(err)
	}

	assert.NotNil(t, ph)
	assert.Len(t, ph.Pipelines, 2)

	h1 := ph.Pipelines[0]
	assert.True(t, h1.CanRun)
	assert.Equal(t, h1.Name, "pipeline1")
	assert.Equal(t, h1.NaturalOrder, 11)
	assert.Equal(t, h1.Comment, "")
	assert.Len(t, h1.Stages, 1)

	h1s := h1.Stages[0]
	assert.Equal(t, h1s.Name, "stage1")

	h2 := ph.Pipelines[1]
	assert.True(t, h2.CanRun)
	assert.Equal(t, h2.Name, "pipeline1")
	assert.Equal(t, h2.NaturalOrder, 10)
	assert.Equal(t, h2.Comment, "")
	assert.Len(t, h2.Stages, 1)

	h2s := h2.Stages[0]
	assert.Equal(t, h2s.Name, "stage1")

}
<|endoftext|>


<commit_before>// These functions extract (and validate) user provided form data.
package common

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

// Return the requested branch name, from get or post data.
func GetFormBranch(r *http.Request) (string, error) {
	// If no branch was given in the input, returns an empty string
	c := r.FormValue("branch")
	if c == "" {
		return "", nil
	}
	err := Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid branch name: '%v'", c))
	}
	return c, nil
}

// Return the requested database commit, from form data.
func GetFormCommit(r *http.Request) (string, error) {
	// If no commit was given in the input, returns an empty string
	c := r.FormValue("commit")
	if c == "" {
		return "", nil
	}
	err := Validate.Var(c, "hexadecimal,min=1,max=64")
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid database commit: '%v'", c))
	}
	return c, nil
}

// Extracts a database name from form data
func GetFormDatabase(r *http.Request) (string, error) {
	dbName := r.PostFormValue("dbname")
	err := ValidateDB(dbName)
	if err != nil {
		log.Printf("Validation failed for database name '%s': %s", dbName, err)
		return "", errors.New("Invalid database name")
	}
	return dbName, nil
}

// Returns the folder name (if any) present in the form data
func GetFormFolder(r *http.Request) (string, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return "", err
	}
	folder := r.PostFormValue("folder")

	// If no folder given, return
	if folder == "" {
		return "", nil
	}

	// Validate the folder name
	err = ValidateFolder(folder)
	if err != nil {
		log.Printf("Validation failed for folder: '%s': %s", folder, err)
		return "", err
	}

	return folder, nil
}

// Returns the licence name (if any) present in the form data
func GetFormLicence(r *http.Request) (licenceName string, err error) {
	// If no licence name given, return an empty string
	l := r.PostFormValue("licence")
	if l == "" {
		return "", nil
	}

	// Validate the licence name
	err = ValidateLicence(l)
	if err != nil {
		log.Printf("Validation failed for licence: '%s': %s", l, err)
		return "", err
	}
	licenceName = l

	return licenceName, nil
}

// Returns the source URL (if any) present in the form data
func GetFormSourceURL(r *http.Request) (sourceURL string, err error) {
	// Gather submitted form data (if any)
	err = r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return sourceURL, err
	}

	// Validate the source URL
	su := r.PostFormValue("sourceurl")
	if su != "" {
		err = Validate.Var(su, "url,min=5,max=255") // 255 seems like a reasonable first guess
		if err != nil {
			return sourceURL, errors.New("Validation failed for source URL field")
		}
		sourceURL = su
	}

	return sourceURL, err
}

// Return the requested release name, from get or post data.
func GetFormRelease(r *http.Request) (release string, err error) {
	// If no release was given in the input, returns an empty string
	c := r.FormValue("release")
	if c == "" {
		return "", nil
	}
	err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid release name: '%v'", c))
	}
	return c, nil
}

// Return the requested tag name, from get or post data.
func GetFormTag(r *http.Request) (tag string, err error) {
	// If no tag was given in the input, returns an empty string
	c := r.FormValue("tag")
	if c == "" {
		return "", nil
	}
	err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid tag name: '%v'", c))
	}
	return c, nil
}

// Return the username, database, and commit (if any) present in the form data.
func GetFormUDC(r *http.Request) (string, string, string, error) {
	// Extract the username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the database name
	dbName, err := GetFormDatabase(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the commit string
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", err
	}

	return userName, dbName, commitID, nil
}

// Return the username, folder, and database name (if any) present in the form data.
func GetFormUFD(r *http.Request) (string, string, string, error) {
	// Extract the username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the folder
	dbFolder, err := GetFormFolder(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the database name
	dbName, err := GetFormDatabase(r)
	if err != nil {
		return "", "", "", err
	}

	return userName, dbFolder, dbName, nil
}

// Return the username, password, and source URL from the form data.
func GetFormUPS(r *http.Request) (string, string, string, error) {
	// Get username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Get password and Source URL
	password := r.PostFormValue("pass")
	sourceURL := r.PostFormValue("sourceurl")

	// If no username/password was given, return
	if userName == "" && password == "" {
		return "", "", "", err
	}

	// Check the password isn't blank
	if len(password) < 1 {
		log.Print("Password missing")
		return "", "", "", err
	}

	// Validate the source referrer (if present)
	var bounceURL string
	if sourceURL != "" {
		ref, err := url.Parse(sourceURL)
		if err != nil {
			log.Printf("Error when parsing referrer URL for login form: %s\n", err)
		} else {
			// Only use the referrer path if no hostname is set (eg check if someone is screwing around)
			if ref.Host == "" {
				bounceURL = ref.Path
			}
		}
	}

	return userName, password, bounceURL, nil
}

// Return the username (if any) present in the form data.
func GetFormUsername(r *http.Request) (string, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return "", err
	}
	userName := r.PostFormValue("username")

	// If no username given, return
	if userName == "" {
		return "", nil
	}

	// Validate the username
	err = ValidateUser(userName)
	if err != nil {
		log.Printf("Validation failed for username: %s", err)
		return "", err
	}

	return userName, nil
}

// Returns the requested database owner and database name.
func GetOD(ignore_leading int, r *http.Request) (string, string, error) {
	// Split the request URL into path components
	pathStrings := strings.Split(r.URL.Path, "/")

	// Check that at least an owner/database combination was requested
	if len(pathStrings) < (3 + ignore_leading) {
		log.Printf("Something wrong with the requested URL: %v\n", r.URL.Path)
		return "", "", errors.New("Invalid URL")
	}
	dbOwner := pathStrings[1+ignore_leading]
	dbName := pathStrings[2+ignore_leading]

	// Validate the user supplied owner and database name
	err := ValidateUserDB(dbOwner, dbName)
	if err != nil {
		// Don't bother logging the fairly common case of a bot using an AngularJS phrase in a request
		if dbOwner == "{{ meta.Owner + '" && dbName == "' + row.Database }}" {
			return "", "", errors.New("Invalid owner or database name")
		}

		log.Printf("Validation failed for owner or database name. Owner '%s', DB name '%s': %s",
			dbOwner, dbName, err)
		return "", "", errors.New("Invalid owner or database name")
	}

	// Everything seems ok
	return dbOwner, dbName, nil
}

// Returns the requested database owner, database name, and commit revision.
func GetODC(ignore_leading int, r *http.Request) (string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the commit revision
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, commitID, nil
}

// Returns the requested database owner, database name, and table name.
func GetODT(ignore_leading int, r *http.Request) (string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", err
	}

	// If a specific table was requested, get that info too
	requestedTable, err := GetTable(r)
	if err != nil {
		return "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, requestedTable, nil
}

// Returns the requested database owner, database name, table name, and commit string.
func GetODTC(ignore_leading int, r *http.Request) (string, string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", "", err
	}

	// If a specific table was requested, get that info too
	requestedTable, err := GetTable(r)
	if err != nil {
		return "", "", "", "", err
	}

	// Extract the commit string
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, requestedTable, commitID, nil
}

// Returns the requested "public" variable, if present in the form data.
// If something goes wrong, it defaults to "false".
func GetPub(r *http.Request) (bool, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return false, err
	}
	val := r.PostFormValue("public")
	if val == "" {
		// No public/private variable found
		return false, errors.New("No public/private value present")
	}
	pub, err := strconv.ParseBool(val)
	if err != nil {
		log.Printf("Error when converting public value to boolean: %v\n", err)
		return false, err
	}

	return pub, nil
}

// Returns the requested table name (if any).
func GetTable(r *http.Request) (string, error) {
	var requestedTable string
	requestedTable = r.FormValue("table")

	// If a table name was supplied, validate it
	// FIXME: We should probably create a validation function for SQLite table names, not use our one for PG
	if requestedTable != "" {
		err := ValidatePGTable(requestedTable)
		if err != nil {
			// If the failed table name is "{{ db.Tablename }}", don't bother logging it.  It's just a
			// search bot picking up the AngularJS string then doing a request with it
			if requestedTable != "{{ db.Tablename }}" {
				log.Printf("Validation failed for table name: '%s': %s", requestedTable, err)
			}
			return "", errors.New("Invalid table name")
		}
	}

	// Everything seems ok
	return requestedTable, nil
}
<commit_msg>When validating commit ID's ensure min length is 64 characters<commit_after>// These functions extract (and validate) user provided form data.
package common

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

// Return the requested branch name, from get or post data.
func GetFormBranch(r *http.Request) (string, error) {
	// If no branch was given in the input, returns an empty string
	c := r.FormValue("branch")
	if c == "" {
		return "", nil
	}
	err := Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid branch name: '%v'", c))
	}
	return c, nil
}

// Return the requested database commit, from form data.
func GetFormCommit(r *http.Request) (string, error) {
	// If no commit was given in the input, returns an empty string
	c := r.FormValue("commit")
	if c == "" {
		return "", nil
	}
	err := Validate.Var(c, "hexadecimal,min=64,max=64")
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid database commit: '%v'", c))
	}
	return c, nil
}

// Extracts a database name from form data
func GetFormDatabase(r *http.Request) (string, error) {
	dbName := r.PostFormValue("dbname")
	err := ValidateDB(dbName)
	if err != nil {
		log.Printf("Validation failed for database name '%s': %s", dbName, err)
		return "", errors.New("Invalid database name")
	}
	return dbName, nil
}

// Returns the folder name (if any) present in the form data
func GetFormFolder(r *http.Request) (string, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return "", err
	}
	folder := r.PostFormValue("folder")

	// If no folder given, return
	if folder == "" {
		return "", nil
	}

	// Validate the folder name
	err = ValidateFolder(folder)
	if err != nil {
		log.Printf("Validation failed for folder: '%s': %s", folder, err)
		return "", err
	}

	return folder, nil
}

// Returns the licence name (if any) present in the form data
func GetFormLicence(r *http.Request) (licenceName string, err error) {
	// If no licence name given, return an empty string
	l := r.PostFormValue("licence")
	if l == "" {
		return "", nil
	}

	// Validate the licence name
	err = ValidateLicence(l)
	if err != nil {
		log.Printf("Validation failed for licence: '%s': %s", l, err)
		return "", err
	}
	licenceName = l

	return licenceName, nil
}

// Returns the source URL (if any) present in the form data
func GetFormSourceURL(r *http.Request) (sourceURL string, err error) {
	// Gather submitted form data (if any)
	err = r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return sourceURL, err
	}

	// Validate the source URL
	su := r.PostFormValue("sourceurl")
	if su != "" {
		err = Validate.Var(su, "url,min=5,max=255") // 255 seems like a reasonable first guess
		if err != nil {
			return sourceURL, errors.New("Validation failed for source URL field")
		}
		sourceURL = su
	}

	return sourceURL, err
}

// Return the requested release name, from get or post data.
func GetFormRelease(r *http.Request) (release string, err error) {
	// If no release was given in the input, returns an empty string
	c := r.FormValue("release")
	if c == "" {
		return "", nil
	}
	err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid release name: '%v'", c))
	}
	return c, nil
}

// Return the requested tag name, from get or post data.
func GetFormTag(r *http.Request) (tag string, err error) {
	// If no tag was given in the input, returns an empty string
	c := r.FormValue("tag")
	if c == "" {
		return "", nil
	}
	err = Validate.Var(c, "branchortagname,min=1,max=32") // 32 seems a reasonable first guess.
	if err != nil {
		return "", errors.New(fmt.Sprintf("Invalid tag name: '%v'", c))
	}
	return c, nil
}

// Return the username, database, and commit (if any) present in the form data.
func GetFormUDC(r *http.Request) (string, string, string, error) {
	// Extract the username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the database name
	dbName, err := GetFormDatabase(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the commit string
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", err
	}

	return userName, dbName, commitID, nil
}

// Return the username, folder, and database name (if any) present in the form data.
func GetFormUFD(r *http.Request) (string, string, string, error) {
	// Extract the username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the folder
	dbFolder, err := GetFormFolder(r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the database name
	dbName, err := GetFormDatabase(r)
	if err != nil {
		return "", "", "", err
	}

	return userName, dbFolder, dbName, nil
}

// Return the username, password, and source URL from the form data.
func GetFormUPS(r *http.Request) (string, string, string, error) {
	// Get username
	userName, err := GetFormUsername(r)
	if err != nil {
		return "", "", "", err
	}

	// Get password and Source URL
	password := r.PostFormValue("pass")
	sourceURL := r.PostFormValue("sourceurl")

	// If no username/password was given, return
	if userName == "" && password == "" {
		return "", "", "", err
	}

	// Check the password isn't blank
	if len(password) < 1 {
		log.Print("Password missing")
		return "", "", "", err
	}

	// Validate the source referrer (if present)
	var bounceURL string
	if sourceURL != "" {
		ref, err := url.Parse(sourceURL)
		if err != nil {
			log.Printf("Error when parsing referrer URL for login form: %s\n", err)
		} else {
			// Only use the referrer path if no hostname is set (eg check if someone is screwing around)
			if ref.Host == "" {
				bounceURL = ref.Path
			}
		}
	}

	return userName, password, bounceURL, nil
}

// Return the username (if any) present in the form data.
func GetFormUsername(r *http.Request) (string, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return "", err
	}
	userName := r.PostFormValue("username")

	// If no username given, return
	if userName == "" {
		return "", nil
	}

	// Validate the username
	err = ValidateUser(userName)
	if err != nil {
		log.Printf("Validation failed for username: %s", err)
		return "", err
	}

	return userName, nil
}

// Returns the requested database owner and database name.
func GetOD(ignore_leading int, r *http.Request) (string, string, error) {
	// Split the request URL into path components
	pathStrings := strings.Split(r.URL.Path, "/")

	// Check that at least an owner/database combination was requested
	if len(pathStrings) < (3 + ignore_leading) {
		log.Printf("Something wrong with the requested URL: %v\n", r.URL.Path)
		return "", "", errors.New("Invalid URL")
	}
	dbOwner := pathStrings[1+ignore_leading]
	dbName := pathStrings[2+ignore_leading]

	// Validate the user supplied owner and database name
	err := ValidateUserDB(dbOwner, dbName)
	if err != nil {
		// Don't bother logging the fairly common case of a bot using an AngularJS phrase in a request
		if dbOwner == "{{ meta.Owner + '" && dbName == "' + row.Database }}" {
			return "", "", errors.New("Invalid owner or database name")
		}

		log.Printf("Validation failed for owner or database name. Owner '%s', DB name '%s': %s",
			dbOwner, dbName, err)
		return "", "", errors.New("Invalid owner or database name")
	}

	// Everything seems ok
	return dbOwner, dbName, nil
}

// Returns the requested database owner, database name, and commit revision.
func GetODC(ignore_leading int, r *http.Request) (string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", err
	}

	// Extract the commit revision
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, commitID, nil
}

// Returns the requested database owner, database name, and table name.
func GetODT(ignore_leading int, r *http.Request) (string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", err
	}

	// If a specific table was requested, get that info too
	requestedTable, err := GetTable(r)
	if err != nil {
		return "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, requestedTable, nil
}

// Returns the requested database owner, database name, table name, and commit string.
func GetODTC(ignore_leading int, r *http.Request) (string, string, string, string, error) {
	// Grab owner and database name
	dbOwner, dbName, err := GetOD(ignore_leading, r)
	if err != nil {
		return "", "", "", "", err
	}

	// If a specific table was requested, get that info too
	requestedTable, err := GetTable(r)
	if err != nil {
		return "", "", "", "", err
	}

	// Extract the commit string
	commitID, err := GetFormCommit(r)
	if err != nil {
		return "", "", "", "", err
	}

	// Everything seems ok
	return dbOwner, dbName, requestedTable, commitID, nil
}

// Returns the requested "public" variable, if present in the form data.
// If something goes wrong, it defaults to "false".
func GetPub(r *http.Request) (bool, error) {
	// Gather submitted form data (if any)
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error when parsing form data: %s\n", err)
		return false, err
	}
	val := r.PostFormValue("public")
	if val == "" {
		// No public/private variable found
		return false, errors.New("No public/private value present")
	}
	pub, err := strconv.ParseBool(val)
	if err != nil {
		log.Printf("Error when converting public value to boolean: %v\n", err)
		return false, err
	}

	return pub, nil
}

// Returns the requested table name (if any).
func GetTable(r *http.Request) (string, error) {
	var requestedTable string
	requestedTable = r.FormValue("table")

	// If a table name was supplied, validate it
	// FIXME: We should probably create a validation function for SQLite table names, not use our one for PG
	if requestedTable != "" {
		err := ValidatePGTable(requestedTable)
		if err != nil {
			// If the failed table name is "{{ db.Tablename }}", don't bother logging it.  It's just a
			// search bot picking up the AngularJS string then doing a request with it
			if requestedTable != "{{ db.Tablename }}" {
				log.Printf("Validation failed for table name: '%s': %s", requestedTable, err)
			}
			return "", errors.New("Invalid table name")
		}
	}

	// Everything seems ok
	return requestedTable, nil
}
<|endoftext|>


<commit_before>package eval

// An Expr is an arithmetic expression.
type Expr interface {
	// Eval returns the value of this Expr in the environment env.
	Eval(env Env) float64
	// Check reports errors in this Expr and adds its Vars to the set.
	Check(vars map[Var]bool) error
}

// A Var identifies a variable, e.g., x.
type Var string

// A literal is numeric constant.
type literal float64

type unary struct {
	op rune // one of '+', '-'
	x  Expr
}

// A binary represents a binary operator expression.
type binary struct {
	op   rune
	x, y Expr
}

// A call represents a function call expression, e.g., six(x).
type call struct {
	fn   string
	args []Expr
}
<commit_msg>[7.13] Solution is added.<commit_after>package eval

import (
	"bytes"
	"fmt"
)

// An Expr is an arithmetic expression.
type Expr interface {
	// Eval returns the value of this Expr in the environment env.
	Eval(env Env) float64
	// Check reports errors in this Expr and adds its Vars to the set.
	Check(vars map[Var]bool) error
}

// A Var identifies a variable, e.g., x.
type Var string

func (e Var) String() string {
	return string(e)
}

// A literal is numeric constant.
type literal float64

func (e literal) String() string {
	return fmt.Sprintf("%g", e)
}

type unary struct {
	op rune // one of '+', '-'
	x  Expr
}

func (e unary) String() string {
	return fmt.Sprintf("(%c%s)", e.op, e.x)
}

// A binary represents a binary operator expression.
type binary struct {
	op   rune
	x, y Expr
}

func (e binary) String() string {
	return fmt.Sprintf("(%s%c%s)", e.x, e.op, e.y)
}

// A call represents a function call expression, e.g., six(x).
type call struct {
	fn   string
	args []Expr
}

func (e call) String() string {
	buf := &bytes.Buffer{}
	fmt.Fprintf(buf, "%s(", e.fn)
	for i, arg := range e.args {
		if i > 0 {
			buf.WriteString(", ")
		}
		write(buf, arg)
	}
	buf.WriteByte(')')
	return buf.String()
}
<|endoftext|>


<commit_before>package gqt_test

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"testing"
	"time"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/containerdrunner"
	"code.cloudfoundry.org/guardian/gqt/runner"
	"code.cloudfoundry.org/guardian/kawasaki/iptables"
	"code.cloudfoundry.org/guardian/pkg/locksmith"
	"github.com/burntsushi/toml"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

const (
	kb uint64 = 1024
	mb        = 1024 * kb
)

var (
	ginkgoIO = garden.ProcessIO{Stdout: GinkgoWriter, Stderr: GinkgoWriter}
	// the unprivileged user is baked into the cfgarden/garden-ci-ubuntu image
	unprivilegedUID = uint32(5000)
	unprivilegedGID = uint32(5000)

	containerdConfig  containerdrunner.Config
	containerdSession *gexec.Session
	containerdRunDir  string

	config            runner.GdnRunnerConfig
	binaries          runner.Binaries
	defaultTestRootFS string
)

func goCompile(mainPackagePath string, buildArgs ...string) string {
	if os.Getenv("RACE_DETECTION") != "" {
		buildArgs = append(buildArgs, "-race")
	}
	bin, err := gexec.Build(mainPackagePath, buildArgs...)
	Expect(err).NotTo(HaveOccurred())
	return bin
}

type runnerBinaries struct {
	Garden runner.Binaries
}

func TestGqt(t *testing.T) {
	RegisterFailHandler(Fail)
	SetDefaultEventuallyTimeout(5 * time.Second)
	RunSpecs(t, "GQT Suite")
}

var _ = SynchronizedBeforeSuite(func() []byte {
	binaries := runnerBinaries{
		Garden: getGardenBinaries(),
	}

	// chmod all the artifacts
	Expect(os.Chmod(filepath.Join(binaries.Garden.Gdn, "..", ".."), 0755)).To(Succeed())
	filepath.Walk(filepath.Join(binaries.Garden.Gdn, "..", ".."), func(path string, info os.FileInfo, err error) error {
		Expect(err).NotTo(HaveOccurred())
		Expect(os.Chmod(path, 0755)).To(Succeed())
		return nil
	})

	return jsonMarshal(binaries)
}, func(data []byte) {
	bins := new(runnerBinaries)
	jsonUnmarshal(data, bins)
	binaries = bins.Garden
	defaultTestRootFS = os.Getenv("GARDEN_TEST_ROOTFS")
})

var _ = SynchronizedAfterSuite(func() {}, func() {
	gexec.CleanupBuildArtifacts()
})

var _ = BeforeEach(func() {
	if defaultTestRootFS == "" {
		Skip("No Garden RootFS")
	}

	config = defaultConfig()
	if isContainerd() {
		containerdRunDir = tempDir("", "")
		containerdSession = startContainerd(containerdRunDir)
	}

})

var _ = AfterEach(func() {
	if isContainerd() {
		Expect(containerdSession.Terminate().Wait()).To(gexec.Exit(0))
		Expect(os.RemoveAll(containerdRunDir)).To(Succeed())
	}

	// Windows worker is not containerised and therefore the test needs to take care to delete the temporary folder
	if runtime.GOOS == "windows" {
		Expect(os.RemoveAll(config.TmpDir)).To(Succeed())
	}
})

func getGardenBinaries() runner.Binaries {
	gardenBinaries := runner.Binaries{
		Tar:           os.Getenv("GARDEN_TAR_PATH"),
		Gdn:           CompileGdn(),
		NetworkPlugin: goCompile("code.cloudfoundry.org/guardian/gqt/cmd/fake_network_plugin"),
		ImagePlugin:   goCompile("code.cloudfoundry.org/guardian/gqt/cmd/fake_image_plugin"),
		RuntimePlugin: goCompile("code.cloudfoundry.org/guardian/gqt/cmd/fake_runtime_plugin"),
		NoopPlugin:    goCompile("code.cloudfoundry.org/guardian/gqt/cmd/noop_plugin"),
	}

	gardenBinaries.PrivilegedImagePlugin = gardenBinaries.ImagePlugin + "-priv"
	Expect(copyFile(gardenBinaries.ImagePlugin, gardenBinaries.PrivilegedImagePlugin)).To(Succeed())

	if runtime.GOOS == "linux" {
		gardenBinaries.ExecRunner = goCompile("code.cloudfoundry.org/guardian/cmd/dadoo")
		gardenBinaries.Socket2me = goCompile("code.cloudfoundry.org/guardian/cmd/socket2me")

		cmd := exec.Command("make")
		runCommandInDir(cmd, "../rundmc/nstar")
		gardenBinaries.NSTar = "../rundmc/nstar/nstar"

		cmd = exec.Command("gcc", "-static", "-o", "init", "init.c", "ignore_sigchild.c")
		runCommandInDir(cmd, "../cmd/init")
		gardenBinaries.Init = "../cmd/init/init"

		gardenBinaries.Groot = goCompile("code.cloudfoundry.org/grootfs")
		gardenBinaries.Tardis = goCompile("code.cloudfoundry.org/grootfs/store/filesystems/overlayxfs/tardis")
		Expect(os.Chmod(gardenBinaries.Tardis, 04755)).To(Succeed())
	}

	return gardenBinaries
}

func CompileGdn(additionalCompileArgs ...string) string {
	defaultCompileArgs := []string{"-tags", "daemon"}
	compileArgs := append(defaultCompileArgs, additionalCompileArgs...)

	return goCompile("code.cloudfoundry.org/guardian/cmd/gdn", compileArgs...)
}

func runCommandInDir(cmd *exec.Cmd, workingDir string) string {
	cmd.Dir = workingDir
	cmdOutput, err := cmd.CombinedOutput()
	Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Running command %#v failed: %v: %s", cmd, err, string(cmdOutput)))
	return string(cmdOutput)
}

func runCommand(cmd *exec.Cmd) string {
	return runCommandInDir(cmd, "")
}

func defaultConfig() runner.GdnRunnerConfig {
	cfg := runner.DefaultGdnRunnerConfig(binaries)
	cfg.DefaultRootFS = defaultTestRootFS
	cfg.GdnBin = binaries.Gdn
	cfg.GrootBin = binaries.Groot
	cfg.Socket2meBin = binaries.Socket2me
	cfg.ExecRunnerBin = binaries.ExecRunner
	cfg.InitBin = binaries.Init
	cfg.TarBin = binaries.Tar
	cfg.NSTarBin = binaries.NSTar
	cfg.ImagePluginBin = binaries.Groot
	cfg.PrivilegedImagePluginBin = binaries.Groot

	return cfg
}

func restartGarden(client *runner.RunningGarden, config runner.GdnRunnerConfig) *runner.RunningGarden {
	Expect(client.Ping()).To(Succeed(), "tried to restart garden while it was not running")
	Expect(client.Stop()).To(Succeed())
	return runner.Start(config)
}

func runIPTables(ipTablesArgs ...string) ([]byte, error) {
	lock, err := locksmith.NewFileSystem().Lock(iptables.LockKey)
	if err != nil {
		return nil, err
	}
	defer lock.Unlock()

	outBuffer := bytes.NewBuffer([]byte{})
	errBuffer := bytes.NewBuffer([]byte{})
	cmd := exec.Command("iptables", append([]string{"-w"}, ipTablesArgs...)...)
	cmd.Stdout = outBuffer
	cmd.Stderr = errBuffer
	err = cmd.Run()

	fmt.Fprintln(GinkgoWriter, outBuffer.String())
	fmt.Fprintln(GinkgoWriter, errBuffer.String())
	return outBuffer.Bytes(), err
}

// returns the n'th ASCII character starting from 'a' through 'z'
// E.g. nodeToString(1) = a, nodeToString(2) = b, etc ...
func nodeToString(ginkgoNode int) string {
	r := 'a' + ginkgoNode - 1
	Expect(r).To(BeNumerically(">=", 'a'))
	Expect(r).To(BeNumerically("<=", 'z'))
	return string(r)
}

func intptr(i int) *int {
	return &i
}

func uint64ptr(i uint64) *uint64 {
	return &i
}

func uint32ptr(i uint32) *uint32 {
	return &i
}

func boolptr(b bool) *bool {
	return &b
}

func stringptr(s string) *string {
	return &s
}

func idToStr(id uint32) string {
	return strconv.FormatUint(uint64(id), 10)
}

func readFile(path string) []byte {
	content, err := ioutil.ReadFile(path)
	Expect(err).NotTo(HaveOccurred())
	return content
}

func readFileString(path string) string {
	return string(readFile(path))
}

func tempDir(dir, prefix string) string {
	path, err := ioutil.TempDir(dir, prefix)
	Expect(err).NotTo(HaveOccurred())
	return path
}

func tempFile(dir, prefix string) *os.File {
	f, err := ioutil.TempFile(dir, prefix)
	Expect(err).NotTo(HaveOccurred())
	return f
}

func copyFile(srcPath, dstPath string) error {
	dirPath := filepath.Dir(dstPath)
	if err := os.MkdirAll(dirPath, 0777); err != nil {
		return err
	}

	reader, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	writer, err := os.Create(dstPath)
	if err != nil {
		reader.Close()
		return err
	}

	if _, err := io.Copy(writer, reader); err != nil {
		writer.Close()
		reader.Close()
		return err
	}

	writer.Close()
	reader.Close()

	return os.Chmod(writer.Name(), 0777)
}

func removeSocket() {
	_, err := os.Stat(config.BindSocket)
	if err == nil {
		Expect(os.Remove(config.BindSocket)).To(Succeed())
	} else if !os.IsNotExist(err) {
		Expect(err).NotTo(HaveOccurred())
	}
}

func createPeaRootfs() string {
	return createRootfs(func(root string) {
		Expect(exec.Command("chown", "-R", "4294967294:4294967294", root).Run()).To(Succeed())
		Expect(ioutil.WriteFile(filepath.Join(root, "ima-pea"), []byte("pea!"), 0644)).To(Succeed())
	}, 0777)
}

func createPeaRootfsTar() string {
	return tarUpDir(createPeaRootfs())
}

func createRootfsTar(modifyRootfs func(string)) string {
	return tarUpDir(createRootfs(modifyRootfs, 0755))
}

func createRootfs(modifyRootfs func(string), perm os.FileMode) string {
	tmpDir := tempDir("", "test-rootfs")
	unpackedRootfs := filepath.Join(tmpDir, "unpacked")
	Expect(os.Mkdir(unpackedRootfs, perm)).To(Succeed())
	runCommand(exec.Command("tar", "xf", defaultTestRootFS, "-C", unpackedRootfs))

	Expect(os.Chmod(tmpDir, perm)).To(Succeed())
	modifyRootfs(unpackedRootfs)

	return unpackedRootfs
}

func tarUpDir(path string) string {
	tarPath := filepath.Join(filepath.Dir(path), filepath.Base(path)+".tar")
	repackCmd := exec.Command("sh", "-c", fmt.Sprintf("tar cf %s *", tarPath))
	runCommandInDir(repackCmd, path)

	return tarPath
}

func resetImagePluginConfig() runner.GdnRunnerConfig {
	config.ImagePluginBin = ""
	config.PrivilegedImagePluginBin = ""
	config.ImagePluginExtraArgs = []string{}
	config.PrivilegedImagePluginExtraArgs = []string{}
	return config
}

func mustGetEnv(env string) string {
	if value := os.Getenv(env); value != "" {
		return value
	}
	panic(fmt.Sprintf("%s env must be non-empty", env))
}

func jsonMarshal(v interface{}) []byte {
	buf := bytes.NewBuffer([]byte{})
	Expect(toml.NewEncoder(buf).Encode(v)).To(Succeed())
	return buf.Bytes()
}

func jsonUnmarshal(data []byte, v interface{}) {
	Expect(toml.Unmarshal(data, v)).To(Succeed())
}

func isContainerd() bool {
	return os.Getenv("CONTAINERD_ENABLED") == "true"
}

func skipIfContainerd() {
	if isContainerd() {
		Skip("irrelevant test for containerd mode")
	}
}

func skipIfNotContainerd() {
	if !isContainerd() {
		Skip("containerd not enabled")
	}
}

func skipIfDev() {
	if os.Getenv("LOCAL_DEV_RUN") == "true" {
		Skip("skipping when running locally")
	}
}

func getRuncRoot() string {
	if config.ContainerdSocket != "" {
		return "/run/containerd/runc/garden"
	}

	return "/run/runc"
}

func startContainerd(runDir string) *gexec.Session {
	containerdConfig := containerdrunner.ContainerdConfig(runDir)
	config.ContainerdSocket = containerdConfig.GRPC.Address
	return containerdrunner.NewSession(runDir, containerdConfig)
}

func restartContainerd() {
	containerdSession.Terminate().Wait()
	containerdSession = startContainerd(containerdRunDir)
}

func numGoRoutines(client *runner.RunningGarden) int {
	numGoroutines, err := client.NumGoroutines()
	ExpectWithOffset(1, err).NotTo(HaveOccurred())
	return numGoroutines
}

func pollNumGoRoutines(client *runner.RunningGarden) func() int {
	return func() int {
		return numGoRoutines(client)
	}
}
<commit_msg>Use grootfs binaries built from the GRR test script<commit_after>package gqt_test

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"testing"
	"time"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/containerdrunner"
	"code.cloudfoundry.org/guardian/gqt/runner"
	"code.cloudfoundry.org/guardian/kawasaki/iptables"
	"code.cloudfoundry.org/guardian/pkg/locksmith"
	"github.com/burntsushi/toml"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

const (
	kb uint64 = 1024
	mb        = 1024 * kb
)

var (
	ginkgoIO = garden.ProcessIO{Stdout: GinkgoWriter, Stderr: GinkgoWriter}
	// the unprivileged user is baked into the cfgarden/garden-ci-ubuntu image
	unprivilegedUID = uint32(5000)
	unprivilegedGID = uint32(5000)

	containerdConfig  containerdrunner.Config
	containerdSession *gexec.Session
	containerdRunDir  string

	config            runner.GdnRunnerConfig
	binaries          runner.Binaries
	defaultTestRootFS string

	buildNoGExecDir string
)

func goCompile(mainPackagePath string, buildArgs ...string) string {
	if os.Getenv("RACE_DETECTION") != "" {
		buildArgs = append(buildArgs, "-race")
	}
	bin, err := gexec.Build(mainPackagePath, buildArgs...)
	Expect(err).NotTo(HaveOccurred())
	return bin
}

type runnerBinaries struct {
	Garden runner.Binaries
}

func TestGqt(t *testing.T) {
	RegisterFailHandler(Fail)
	SetDefaultEventuallyTimeout(5 * time.Second)
	RunSpecs(t, "GQT Suite")
}

var _ = SynchronizedBeforeSuite(func() []byte {
	binaries := runnerBinaries{
		Garden: getGardenBinaries(),
	}

	// chmod all the artifacts
	Expect(os.Chmod(filepath.Join(binaries.Garden.Gdn, "..", ".."), 0755)).To(Succeed())
	filepath.Walk(filepath.Join(binaries.Garden.Gdn, "..", ".."), func(path string, info os.FileInfo, err error) error {
		Expect(err).NotTo(HaveOccurred())
		Expect(os.Chmod(path, 0755)).To(Succeed())
		return nil
	})

	return jsonMarshal(binaries)
}, func(data []byte) {
	bins := new(runnerBinaries)
	jsonUnmarshal(data, bins)
	binaries = bins.Garden
	defaultTestRootFS = os.Getenv("GARDEN_TEST_ROOTFS")
})

var _ = SynchronizedAfterSuite(func() {}, func() {
	gexec.CleanupBuildArtifacts()
})

var _ = BeforeEach(func() {
	if defaultTestRootFS == "" {
		Skip("No Garden RootFS")
	}

	config = defaultConfig()
	if isContainerd() {
		containerdRunDir = tempDir("", "")
		containerdSession = startContainerd(containerdRunDir)
	}

})

var _ = AfterEach(func() {
	if isContainerd() {
		Expect(containerdSession.Terminate().Wait()).To(gexec.Exit(0))
		Expect(os.RemoveAll(containerdRunDir)).To(Succeed())
	}

	// Windows worker is not containerised and therefore the test needs to take care to delete the temporary folder
	if runtime.GOOS == "windows" {
		Expect(os.RemoveAll(config.TmpDir)).To(Succeed())
	}
})

func getGardenBinaries() runner.Binaries {
	gardenBinaries := runner.Binaries{
		Tar:           os.Getenv("GARDEN_TAR_PATH"),
		Gdn:           CompileGdn(),
		NetworkPlugin: goCompile("code.cloudfoundry.org/guardian/gqt/cmd/fake_network_plugin"),
		ImagePlugin:   goCompile("code.cloudfoundry.org/guardian/gqt/cmd/fake_image_plugin"),
		RuntimePlugin: goCompile("code.cloudfoundry.org/guardian/gqt/cmd/fake_runtime_plugin"),
		NoopPlugin:    goCompile("code.cloudfoundry.org/guardian/gqt/cmd/noop_plugin"),
	}

	gardenBinaries.PrivilegedImagePlugin = gardenBinaries.ImagePlugin + "-priv"
	Expect(copyFile(gardenBinaries.ImagePlugin, gardenBinaries.PrivilegedImagePlugin)).To(Succeed())

	if runtime.GOOS == "linux" {
		gardenBinaries.ExecRunner = goCompile("code.cloudfoundry.org/guardian/cmd/dadoo")
		gardenBinaries.Socket2me = goCompile("code.cloudfoundry.org/guardian/cmd/socket2me")

		cmd := exec.Command("make")
		runCommandInDir(cmd, "../rundmc/nstar")
		gardenBinaries.NSTar = "../rundmc/nstar/nstar"

		cmd = exec.Command("gcc", "-static", "-o", "init", "init.c", "ignore_sigchild.c")
		runCommandInDir(cmd, "../cmd/init")
		gardenBinaries.Init = "../cmd/init/init"

		gardenBinaries.Groot = findInGoPathBin("grootfs")
		gardenBinaries.Tardis = findInGoPathBin("tardis")
	}

	return gardenBinaries
}

func findInGoPathBin(binary string) string {
	gopath, ok := os.LookupEnv("GOPATH")
	Expect(ok).To(BeTrue(), "GOPATH must be set")
	binPath := filepath.Join(gopath, "bin", binary)
	Expect(binPath).To(BeAnExistingFile(), fmt.Sprintf("%s does not exist", binPath))
	return binPath
}

func CompileGdn(additionalCompileArgs ...string) string {
	defaultCompileArgs := []string{"-tags", "daemon"}
	compileArgs := append(defaultCompileArgs, additionalCompileArgs...)

	return goCompile("code.cloudfoundry.org/guardian/cmd/gdn", compileArgs...)
}

func runCommandInDir(cmd *exec.Cmd, workingDir string) string {
	cmd.Dir = workingDir
	cmdOutput, err := cmd.CombinedOutput()
	Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Running command %#v failed: %v: %s", cmd, err, string(cmdOutput)))
	return string(cmdOutput)
}

func runCommand(cmd *exec.Cmd) string {
	return runCommandInDir(cmd, "")
}

func defaultConfig() runner.GdnRunnerConfig {
	cfg := runner.DefaultGdnRunnerConfig(binaries)
	cfg.DefaultRootFS = defaultTestRootFS
	cfg.GdnBin = binaries.Gdn
	cfg.GrootBin = binaries.Groot
	cfg.Socket2meBin = binaries.Socket2me
	cfg.ExecRunnerBin = binaries.ExecRunner
	cfg.InitBin = binaries.Init
	cfg.TarBin = binaries.Tar
	cfg.NSTarBin = binaries.NSTar
	cfg.ImagePluginBin = binaries.Groot
	cfg.PrivilegedImagePluginBin = binaries.Groot

	return cfg
}

func restartGarden(client *runner.RunningGarden, config runner.GdnRunnerConfig) *runner.RunningGarden {
	Expect(client.Ping()).To(Succeed(), "tried to restart garden while it was not running")
	Expect(client.Stop()).To(Succeed())
	return runner.Start(config)
}

func runIPTables(ipTablesArgs ...string) ([]byte, error) {
	lock, err := locksmith.NewFileSystem().Lock(iptables.LockKey)
	if err != nil {
		return nil, err
	}
	defer lock.Unlock()

	outBuffer := bytes.NewBuffer([]byte{})
	errBuffer := bytes.NewBuffer([]byte{})
	cmd := exec.Command("iptables", append([]string{"-w"}, ipTablesArgs...)...)
	cmd.Stdout = outBuffer
	cmd.Stderr = errBuffer
	err = cmd.Run()

	fmt.Fprintln(GinkgoWriter, outBuffer.String())
	fmt.Fprintln(GinkgoWriter, errBuffer.String())
	return outBuffer.Bytes(), err
}

// returns the n'th ASCII character starting from 'a' through 'z'
// E.g. nodeToString(1) = a, nodeToString(2) = b, etc ...
func nodeToString(ginkgoNode int) string {
	r := 'a' + ginkgoNode - 1
	Expect(r).To(BeNumerically(">=", 'a'))
	Expect(r).To(BeNumerically("<=", 'z'))
	return string(r)
}

func intptr(i int) *int {
	return &i
}

func uint64ptr(i uint64) *uint64 {
	return &i
}

func uint32ptr(i uint32) *uint32 {
	return &i
}

func boolptr(b bool) *bool {
	return &b
}

func stringptr(s string) *string {
	return &s
}

func idToStr(id uint32) string {
	return strconv.FormatUint(uint64(id), 10)
}

func readFile(path string) []byte {
	content, err := ioutil.ReadFile(path)
	Expect(err).NotTo(HaveOccurred())
	return content
}

func readFileString(path string) string {
	return string(readFile(path))
}

func tempDir(dir, prefix string) string {
	path, err := ioutil.TempDir(dir, prefix)
	Expect(err).NotTo(HaveOccurred())
	return path
}

func tempFile(dir, prefix string) *os.File {
	f, err := ioutil.TempFile(dir, prefix)
	Expect(err).NotTo(HaveOccurred())
	return f
}

func copyFile(srcPath, dstPath string) error {
	dirPath := filepath.Dir(dstPath)
	if err := os.MkdirAll(dirPath, 0777); err != nil {
		return err
	}

	reader, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	writer, err := os.Create(dstPath)
	if err != nil {
		reader.Close()
		return err
	}

	if _, err := io.Copy(writer, reader); err != nil {
		writer.Close()
		reader.Close()
		return err
	}

	writer.Close()
	reader.Close()

	return os.Chmod(writer.Name(), 0777)
}

func removeSocket() {
	_, err := os.Stat(config.BindSocket)
	if err == nil {
		Expect(os.Remove(config.BindSocket)).To(Succeed())
	} else if !os.IsNotExist(err) {
		Expect(err).NotTo(HaveOccurred())
	}
}

func createPeaRootfs() string {
	return createRootfs(func(root string) {
		Expect(exec.Command("chown", "-R", "4294967294:4294967294", root).Run()).To(Succeed())
		Expect(ioutil.WriteFile(filepath.Join(root, "ima-pea"), []byte("pea!"), 0644)).To(Succeed())
	}, 0777)
}

func createPeaRootfsTar() string {
	return tarUpDir(createPeaRootfs())
}

func createRootfsTar(modifyRootfs func(string)) string {
	return tarUpDir(createRootfs(modifyRootfs, 0755))
}

func createRootfs(modifyRootfs func(string), perm os.FileMode) string {
	tmpDir := tempDir("", "test-rootfs")
	unpackedRootfs := filepath.Join(tmpDir, "unpacked")
	Expect(os.Mkdir(unpackedRootfs, perm)).To(Succeed())
	runCommand(exec.Command("tar", "xf", defaultTestRootFS, "-C", unpackedRootfs))

	Expect(os.Chmod(tmpDir, perm)).To(Succeed())
	modifyRootfs(unpackedRootfs)

	return unpackedRootfs
}

func tarUpDir(path string) string {
	tarPath := filepath.Join(filepath.Dir(path), filepath.Base(path)+".tar")
	repackCmd := exec.Command("sh", "-c", fmt.Sprintf("tar cf %s *", tarPath))
	runCommandInDir(repackCmd, path)

	return tarPath
}

func resetImagePluginConfig() runner.GdnRunnerConfig {
	config.ImagePluginBin = ""
	config.PrivilegedImagePluginBin = ""
	config.ImagePluginExtraArgs = []string{}
	config.PrivilegedImagePluginExtraArgs = []string{}
	return config
}

func mustGetEnv(env string) string {
	if value := os.Getenv(env); value != "" {
		return value
	}
	panic(fmt.Sprintf("%s env must be non-empty", env))
}

func jsonMarshal(v interface{}) []byte {
	buf := bytes.NewBuffer([]byte{})
	Expect(toml.NewEncoder(buf).Encode(v)).To(Succeed())
	return buf.Bytes()
}

func jsonUnmarshal(data []byte, v interface{}) {
	Expect(toml.Unmarshal(data, v)).To(Succeed())
}

func isContainerd() bool {
	return os.Getenv("CONTAINERD_ENABLED") == "true"
}

func skipIfContainerd() {
	if isContainerd() {
		Skip("irrelevant test for containerd mode")
	}
}

func skipIfNotContainerd() {
	if !isContainerd() {
		Skip("containerd not enabled")
	}
}

func skipIfDev() {
	if os.Getenv("LOCAL_DEV_RUN") == "true" {
		Skip("skipping when running locally")
	}
}

func getRuncRoot() string {
	if config.ContainerdSocket != "" {
		return "/run/containerd/runc/garden"
	}

	return "/run/runc"
}

func startContainerd(runDir string) *gexec.Session {
	containerdConfig := containerdrunner.ContainerdConfig(runDir)
	config.ContainerdSocket = containerdConfig.GRPC.Address
	return containerdrunner.NewSession(runDir, containerdConfig)
}

func restartContainerd() {
	containerdSession.Terminate().Wait()
	containerdSession = startContainerd(containerdRunDir)
}

func numGoRoutines(client *runner.RunningGarden) int {
	numGoroutines, err := client.NumGoroutines()
	ExpectWithOffset(1, err).NotTo(HaveOccurred())
	return numGoroutines
}

func pollNumGoRoutines(client *runner.RunningGarden) func() int {
	return func() int {
		return numGoRoutines(client)
	}
}
<|endoftext|>


<commit_before>package metrics

import (
	"fmt"
	"net/http"
)

func init() {
	http.Handle("/metrics/counters", http.HandlerFunc(printCounters))
}

func printCounters(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	ctrs := GetAllCounters()
	for name, val := range ctrs {
		fmt.Fprintf(w, "%s %d\n", name, val)
	}
}
<commit_msg>Adding auto-registered http endpoint to get counter metrics<commit_after>package metrics

import (
	"fmt"
	"net/http"
)

const metricPrefix = "rend_"

func init() {
	http.Handle("/metrics/counters", http.HandlerFunc(printCounters))
}

func printCounters(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	ctrs := GetAllCounters()
	for name, val := range ctrs {
		fmt.Fprintf(w, "%s%s %d\n", metricPrefix, name, val)
	}
}
<|endoftext|>


<commit_before>package metrics

import "testing"

func TestAddFirstKey(t *testing.T) {
	empty := Key{}
	expected := "first"

	k := empty.Add("first")

	if k.String() != expected {
		t.Error("%v != %v", expected, k)
		t.FailNow()
	}
}

func TestAddMultipleKeys(t *testing.T) {
	empty := Key{}
	expected := "first.second.third"

	k := empty.Add("first").Add("second").Add("third")

	if k.String() != expected {
		t.Error("%v != %v", expected, k)
		t.FailNow()
	}
}
<commit_msg>replace calls to Error to Errorf which was the original intention<commit_after>package metrics

import "testing"

func TestAddFirstKey(t *testing.T) {
	empty := Key{}
	expected := "first"

	k := empty.Add("first")

	if k.String() != expected {
		t.Errorf("'%v' != '%v'", expected, k)
		t.FailNow()
	}
}

func TestAddMultipleKeys(t *testing.T) {
	empty := Key{}
	expected := "first.second.third"

	k := empty.Add("first").Add("second").Add("third")

	if k.String() != expected {
		t.Errorf("'%v' != '%v'", expected, k)
		t.FailNow()
	}
}
<|endoftext|>