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

package text

import (
	"code.google.com/p/freetype-go/freetype"
	"code.google.com/p/freetype-go/freetype/truetype"
	"fmt"
	"image"
	"io"
	"io/ioutil"
)

// LoadTruetype loads a truetype font from the given stream and
// applies the given font scale in points.
//
// The low and high values determine the lower and upper rune limits
// we should load for this font. For standard ASCII this would be: 32, 127.
//
// The dir value determines the orientation of the text we render
// with this font. This should be any of the predefined Direction constants.
func LoadTruetype(r io.Reader, scale int32, low, high rune, dir Direction) (*Font, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	// Read the truetype font.
	ttf, err := truetype.Parse(data)
	if err != nil {
		return nil, err
	}

	// Create our FontConfig type.
	var fc FontConfig
	fc.Dir = dir
	fc.Low = low
	fc.High = high
	fc.Glyphs = make(Charset, high-low+1)

	// Create an image, large enough to store all requested glyphs.
	//
	// We limit the image to 16 glyphs per row. Then add as many rows as
	// needed to encompass all glyphs, while making sure the resulting image
	// has power-of-two dimensions.
	gc := int32(len(fc.Glyphs))
	gpr := int32(16)
	gpc := (gc / gpr) + 1

	if gpc == 0 {
		gpc = 1
	}

	gb := ttf.Bounds(scale)
	gw := gb.XMax - gb.XMin
	gh := gb.YMax - gb.YMin
	iw := pow2(uint32(gw * gpr))
	ih := pow2(uint32(gh * gpc))

	rect := image.Rect(0, 0, int(iw), int(ih))
	img := image.NewRGBA(rect)

	// Use a freetype context to do the drawing.
	c := freetype.NewContext()
	c.SetDPI(72)
	c.SetFont(ttf)
	c.SetFontSize(float64(scale))
	c.SetClip(img.Bounds())
	c.SetDst(img)
	c.SetSrc(image.White)

	// Iterate over all relevant glyphs in the truetype font and
	// draw them all to the image buffer.
	//
	// For each glyph, we also create a corresponding Glyph structure
	// for our Charset. It contains the appropriate glyph coordinate offsets.
	var gi int
	var px, py int32
	buf := truetype.NewGlyphBuf()

	for ch := low; ch <= high; ch++ {
		index := ttf.Index(ch)
		err := buf.Load(ttf, scale, index, nil)

		if err != nil {
			return nil, fmt.Errorf("Failed to load glyph data for rune %c: %v", ch, err)
		}

		metric := ttf.HMetric(scale, index)
		fc.Glyphs[gi].Advance = int(metric.AdvanceWidth)
		fc.Glyphs[gi].X = int(px)
		fc.Glyphs[gi].Y = int(py)
		fc.Glyphs[gi].Width = int(gw)
		fc.Glyphs[gi].Height = int(gh)

		pt := freetype.Pt(int(px), int(py)+int(c.PointToFix32(float64(scale))>>8))
		c.DrawString(string(ch), pt)

		if gi%16 == 0 {
			px = 0
			py += gh
		} else {
			px += gw
		}

		gi++
	}

	return loadFont(img, &fc)
}

/*
// makeList makes a display list for the given glyph.
func (f *TruetypeFont) makeList(ttf *truetype.Font, gb *truetype.GlyphBuf, r rune) (err error) {
	glyph := ttf.Index(r)

	err = gb.Load(ttf, f.scale, glyph, nil)
	if err != nil {
		return
	}

	// Glyph dimensions.
	metric := ttf.HMetric(f.scale, glyph)
	glyphWidth := float32(metric.AdvanceWidth)
	glyphHeight := float32(f.scale)

	// Create power-of-two texture dimensions.
	texWidth := pow2(int(glyphWidth))
	texHeight := pow2(int(glyphHeight))

	// Create a temporary image to render to.
	rect := image.Rect(0, 0, texWidth, texHeight)
	img := image.NewGray16(rect)

	// Use a freetype context to do the drawing.
	c := freetype.NewContext()
	c.SetDPI(72)
	c.SetFont(ttf)
	c.SetFontSize(float64(f.scale))
	c.SetClip(img.Bounds())
	c.SetDst(img)
	c.SetSrc(image.White)

	// Draw the glyph.
	pt := freetype.Pt(0, int(glyphHeight)+int(gb.B.YMin))
	c.DrawString(string(r), pt)

	// Index for our display list and texture. This is the same as the rune
	// value, minus the character set's lower bound.
	tex := r - f.charset.Low

	// Initialize glyph texture and render the image to it.
	f.textures[tex].Bind(gl.TEXTURE_2D)

	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texWidth, texHeight,
		0, gl.LUMINANCE_ALPHA, gl.UNSIGNED_BYTE, img.Pix)

	// Build the display list which renders the texture to an
	// adequately positioned and scaled quad.
	gl.NewList(f.listbase+uint(tex), gl.COMPILE)
	f.textures[tex].Bind(gl.TEXTURE_2D)

	gl.Translatef(float32(gb.B.XMin), 0, 0)
	gl.PushMatrix()
	//gl.Translatef(0, float32(gb.B.YMin), 0)

	x := float64(glyphWidth) / float64(texWidth)
	y := float64(glyphHeight) / float64(texHeight)

	// Draw the quad.
	gl.Begin(gl.QUADS)
	gl.TexCoord2d(0, 0)
	gl.Vertex2f(0, glyphHeight)
	gl.TexCoord2d(0, y)
	gl.Vertex2f(0, 0)
	gl.TexCoord2d(x, y)
	gl.Vertex2f(glyphWidth, 0)
	gl.TexCoord2d(x, 0)
	gl.Vertex2f(glyphWidth, glyphHeight)
	gl.End()

	gl.PopMatrix()

	// Advance the current transformation to the next glyph location.
	gl.Translatef(float32(metric.AdvanceWidth), 0, 0)

	gl.EndList()
	return
}

*/
<commit_msg>Removes unnecessary bounds check.<commit_after>// Copyright 2012 The go-gl Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package text

import (
	"code.google.com/p/freetype-go/freetype"
	"code.google.com/p/freetype-go/freetype/truetype"
	"fmt"
	"image"
	"io"
	"io/ioutil"
)

// LoadTruetype loads a truetype font from the given stream and
// applies the given font scale in points.
//
// The low and high values determine the lower and upper rune limits
// we should load for this font. For standard ASCII this would be: 32, 127.
//
// The dir value determines the orientation of the text we render
// with this font. This should be any of the predefined Direction constants.
func LoadTruetype(r io.Reader, scale int32, low, high rune, dir Direction) (*Font, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	// Read the truetype font.
	ttf, err := truetype.Parse(data)
	if err != nil {
		return nil, err
	}

	// Create our FontConfig type.
	var fc FontConfig
	fc.Dir = dir
	fc.Low = low
	fc.High = high
	fc.Glyphs = make(Charset, high-low+1)

	// Create an image, large enough to store all requested glyphs.
	//
	// We limit the image to 16 glyphs per row. Then add as many rows as
	// needed to encompass all glyphs, while making sure the resulting image
	// has power-of-two dimensions.
	gc := int32(len(fc.Glyphs))
	gpr := int32(16)
	gpc := (gc / gpr) + 1

	gb := ttf.Bounds(scale)
	gw := gb.XMax - gb.XMin
	gh := gb.YMax - gb.YMin
	iw := pow2(uint32(gw * gpr))
	ih := pow2(uint32(gh * gpc))

	rect := image.Rect(0, 0, int(iw), int(ih))
	img := image.NewRGBA(rect)

	// Use a freetype context to do the drawing.
	c := freetype.NewContext()
	c.SetDPI(72)
	c.SetFont(ttf)
	c.SetFontSize(float64(scale))
	c.SetClip(img.Bounds())
	c.SetDst(img)
	c.SetSrc(image.White)

	// Iterate over all relevant glyphs in the truetype font and
	// draw them all to the image buffer.
	//
	// For each glyph, we also create a corresponding Glyph structure
	// for our Charset. It contains the appropriate glyph coordinate offsets.
	var gi int
	var px, py int32
	buf := truetype.NewGlyphBuf()

	for ch := low; ch <= high; ch++ {
		index := ttf.Index(ch)
		err := buf.Load(ttf, scale, index, nil)

		if err != nil {
			return nil, fmt.Errorf("Failed to load glyph data for rune %c: %v", ch, err)
		}

		metric := ttf.HMetric(scale, index)
		fc.Glyphs[gi].Advance = int(metric.AdvanceWidth)
		fc.Glyphs[gi].X = int(px)
		fc.Glyphs[gi].Y = int(py)
		fc.Glyphs[gi].Width = int(gw)
		fc.Glyphs[gi].Height = int(gh)

		pt := freetype.Pt(int(px), int(py)+int(c.PointToFix32(float64(scale))>>8))
		c.DrawString(string(ch), pt)

		if gi%16 == 0 {
			px = 0
			py += gh
		} else {
			px += gw
		}

		gi++
	}

	return loadFont(img, &fc)
}

/*
// makeList makes a display list for the given glyph.
func (f *TruetypeFont) makeList(ttf *truetype.Font, gb *truetype.GlyphBuf, r rune) (err error) {
	glyph := ttf.Index(r)

	err = gb.Load(ttf, f.scale, glyph, nil)
	if err != nil {
		return
	}

	// Glyph dimensions.
	metric := ttf.HMetric(f.scale, glyph)
	glyphWidth := float32(metric.AdvanceWidth)
	glyphHeight := float32(f.scale)

	// Create power-of-two texture dimensions.
	texWidth := pow2(int(glyphWidth))
	texHeight := pow2(int(glyphHeight))

	// Create a temporary image to render to.
	rect := image.Rect(0, 0, texWidth, texHeight)
	img := image.NewGray16(rect)

	// Use a freetype context to do the drawing.
	c := freetype.NewContext()
	c.SetDPI(72)
	c.SetFont(ttf)
	c.SetFontSize(float64(f.scale))
	c.SetClip(img.Bounds())
	c.SetDst(img)
	c.SetSrc(image.White)

	// Draw the glyph.
	pt := freetype.Pt(0, int(glyphHeight)+int(gb.B.YMin))
	c.DrawString(string(r), pt)

	// Index for our display list and texture. This is the same as the rune
	// value, minus the character set's lower bound.
	tex := r - f.charset.Low

	// Initialize glyph texture and render the image to it.
	f.textures[tex].Bind(gl.TEXTURE_2D)

	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, texWidth, texHeight,
		0, gl.LUMINANCE_ALPHA, gl.UNSIGNED_BYTE, img.Pix)

	// Build the display list which renders the texture to an
	// adequately positioned and scaled quad.
	gl.NewList(f.listbase+uint(tex), gl.COMPILE)
	f.textures[tex].Bind(gl.TEXTURE_2D)

	gl.Translatef(float32(gb.B.XMin), 0, 0)
	gl.PushMatrix()
	//gl.Translatef(0, float32(gb.B.YMin), 0)

	x := float64(glyphWidth) / float64(texWidth)
	y := float64(glyphHeight) / float64(texHeight)

	// Draw the quad.
	gl.Begin(gl.QUADS)
	gl.TexCoord2d(0, 0)
	gl.Vertex2f(0, glyphHeight)
	gl.TexCoord2d(0, y)
	gl.Vertex2f(0, 0)
	gl.TexCoord2d(x, y)
	gl.Vertex2f(glyphWidth, 0)
	gl.TexCoord2d(x, 0)
	gl.Vertex2f(glyphWidth, glyphHeight)
	gl.End()

	gl.PopMatrix()

	// Advance the current transformation to the next glyph location.
	gl.Translatef(float32(metric.AdvanceWidth), 0, 0)

	gl.EndList()
	return
}

*/
<|endoftext|>


<commit_before>package testdb

import (
	"crypto/sha1"
	"database/sql"
	"database/sql/driver"
	"encoding/csv"
	"io"
	"regexp"
	"strings"
	"time"
)

var d *testDriver

func init() {
	d = newDriver()
	sql.Register("testdb", d)
}

type testDriver struct {
	openFunc          func(dsn string) (driver.Conn, error)
	conn              *conn
	enableTimeParsing bool
	timeParsingFormat string
}

type query struct {
	rows   driver.Rows
	result *Result
	err    error
}

func newDriver() *testDriver {
	return &testDriver{
		conn:              newConn(),
		timeParsingFormat: time.RFC3339,
	}
}

func EnableTimeParsing(flag bool) {
	d.enableTimeParsing = flag
}

func EnableTimeParsingWithFormat(format string) {
	d.enableTimeParsing = true
	d.timeParsingFormat = format
}

func (d *testDriver) Open(dsn string) (driver.Conn, error) {
	if d.openFunc != nil {
		conn, err := d.openFunc(dsn)
		return conn, err
	}

	if d.conn == nil {
		d.conn = newConn()
	}

	return d.conn, nil
}

var whitespaceRegexp = regexp.MustCompile("\\s")

func getQueryHash(query string) string {
	// Remove whitespace and lowercase to make stubbing less brittle
	query = strings.ToLower(whitespaceRegexp.ReplaceAllString(query, ""))

	h := sha1.New()
	io.WriteString(h, query)

	return string(h.Sum(nil))
}

// Set your own function to be executed when db.Query() is called. As with StubQuery() you can use the RowsFromCSVString() method to easily generate the driver.Rows, or you can return your own.
func SetQueryFunc(f func(query string) (result driver.Rows, err error)) {
	SetQueryWithArgsFunc(func(query string, args []driver.Value) (result driver.Rows, err error) {
		return f(query)
	})
}

// Set your own function to be executed when db.Query() is called. As with StubQuery() you can use the RowsFromCSVString() method to easily generate the driver.Rows, or you can return your own.
func SetQueryWithArgsFunc(f func(query string, args []driver.Value) (result driver.Rows, err error)) {
	d.conn.queryFunc = f
}

// Stubs the global driver.Conn to return the supplied driver.Rows when db.Query() is called, query stubbing is case insensitive, and whitespace is also ignored.
func StubQuery(q string, rows driver.Rows) {
	d.conn.queries[getQueryHash(q)] = query{
		rows: rows,
	}
}

// Stubs the global driver.Conn to return the supplied error when db.Query() is called, query stubbing is case insensitive, and whitespace is also ignored.
func StubQueryError(q string, err error) {
	d.conn.queries[getQueryHash(q)] = query{
		err: err,
	}
}

// Set your own function to be executed when db.Open() is called. You can either hand back a valid connection, or an error. Conn() can be used to grab the global Conn object containing stubbed queries.
func SetOpenFunc(f func(dsn string) (driver.Conn, error)) {
	d.openFunc = f
}

// Set your own function to be executed when db.Exec is called. You can return an error or a Result object with the LastInsertId and RowsAffected
func SetExecFunc(f func(query string) (driver.Result, error)) {
	SetExecWithArgsFunc(func(query string, args []driver.Value) (driver.Result, error) {
		return f(query)
	})
}

// Set your own function to be executed when db.Exec is called. You can return an error or a Result object with the LastInsertId and RowsAffected
func SetExecWithArgsFunc(f func(query string, args []driver.Value) (driver.Result, error)) {
	d.conn.execFunc = f
}

// Stubs the global driver.Conn to return the supplied Result when db.Exec is called, query stubbing is case insensitive, and whitespace is also ignored.
func StubExec(q string, r *Result) {
	d.conn.queries[getQueryHash(q)] = query{
		result: r,
	}
}

// Stubs the global driver.Conn to return the supplied error when db.Exec() is called, query stubbing is case insensitive, and whitespace is also ignored.
func StubExecError(q string, err error) {
	StubQueryError(q, err)
}

// Clears all stubbed queries, and replaced functions.
func Reset() {
	d.conn = newConn()
	d.openFunc = nil
}

// Returns a pointer to the global conn object associated with this driver.
func Conn() driver.Conn {
	return d.conn
}

func RowsFromCSVString(columns []string, s string) driver.Rows {
	r := strings.NewReader(strings.TrimSpace(s))
	csvReader := csv.NewReader(r)

	rows := [][]driver.Value{}
	for {
		r, err := csvReader.Read()

		if err != nil || r == nil {
			break
		}

		row := make([]driver.Value, len(columns))

		for i, v := range r {
			v := strings.TrimSpace(v)

			// If enableTimeParsing is on, check to see if this is a
			// time in defined format (RFC33339 by default)
			if d.enableTimeParsing {
				if time, err := time.Parse(d.timeParsingFormat, v); err == nil {
					row[i] = time
				} else {
					row[i] = v
				}
			} else {
				row[i] = v
			}
		}

		rows = append(rows, row)
	}

	return RowsFromSlice(columns, rows)
}

func RowsFromSlice(columns []string, data [][]driver.Value) driver.Rows {
	return &rows{
		closed:  false,
		columns: columns,
		rows:    data,
		pos:     0,
	}
}
<commit_msg>Fix RFC number<commit_after>package testdb

import (
	"crypto/sha1"
	"database/sql"
	"database/sql/driver"
	"encoding/csv"
	"io"
	"regexp"
	"strings"
	"time"
)

var d *testDriver

func init() {
	d = newDriver()
	sql.Register("testdb", d)
}

type testDriver struct {
	openFunc          func(dsn string) (driver.Conn, error)
	conn              *conn
	enableTimeParsing bool
	timeParsingFormat string
}

type query struct {
	rows   driver.Rows
	result *Result
	err    error
}

func newDriver() *testDriver {
	return &testDriver{
		conn:              newConn(),
		timeParsingFormat: time.RFC3339,
	}
}

func EnableTimeParsing(flag bool) {
	d.enableTimeParsing = flag
}

func EnableTimeParsingWithFormat(format string) {
	d.enableTimeParsing = true
	d.timeParsingFormat = format
}

func (d *testDriver) Open(dsn string) (driver.Conn, error) {
	if d.openFunc != nil {
		conn, err := d.openFunc(dsn)
		return conn, err
	}

	if d.conn == nil {
		d.conn = newConn()
	}

	return d.conn, nil
}

var whitespaceRegexp = regexp.MustCompile("\\s")

func getQueryHash(query string) string {
	// Remove whitespace and lowercase to make stubbing less brittle
	query = strings.ToLower(whitespaceRegexp.ReplaceAllString(query, ""))

	h := sha1.New()
	io.WriteString(h, query)

	return string(h.Sum(nil))
}

// Set your own function to be executed when db.Query() is called. As with StubQuery() you can use the RowsFromCSVString() method to easily generate the driver.Rows, or you can return your own.
func SetQueryFunc(f func(query string) (result driver.Rows, err error)) {
	SetQueryWithArgsFunc(func(query string, args []driver.Value) (result driver.Rows, err error) {
		return f(query)
	})
}

// Set your own function to be executed when db.Query() is called. As with StubQuery() you can use the RowsFromCSVString() method to easily generate the driver.Rows, or you can return your own.
func SetQueryWithArgsFunc(f func(query string, args []driver.Value) (result driver.Rows, err error)) {
	d.conn.queryFunc = f
}

// Stubs the global driver.Conn to return the supplied driver.Rows when db.Query() is called, query stubbing is case insensitive, and whitespace is also ignored.
func StubQuery(q string, rows driver.Rows) {
	d.conn.queries[getQueryHash(q)] = query{
		rows: rows,
	}
}

// Stubs the global driver.Conn to return the supplied error when db.Query() is called, query stubbing is case insensitive, and whitespace is also ignored.
func StubQueryError(q string, err error) {
	d.conn.queries[getQueryHash(q)] = query{
		err: err,
	}
}

// Set your own function to be executed when db.Open() is called. You can either hand back a valid connection, or an error. Conn() can be used to grab the global Conn object containing stubbed queries.
func SetOpenFunc(f func(dsn string) (driver.Conn, error)) {
	d.openFunc = f
}

// Set your own function to be executed when db.Exec is called. You can return an error or a Result object with the LastInsertId and RowsAffected
func SetExecFunc(f func(query string) (driver.Result, error)) {
	SetExecWithArgsFunc(func(query string, args []driver.Value) (driver.Result, error) {
		return f(query)
	})
}

// Set your own function to be executed when db.Exec is called. You can return an error or a Result object with the LastInsertId and RowsAffected
func SetExecWithArgsFunc(f func(query string, args []driver.Value) (driver.Result, error)) {
	d.conn.execFunc = f
}

// Stubs the global driver.Conn to return the supplied Result when db.Exec is called, query stubbing is case insensitive, and whitespace is also ignored.
func StubExec(q string, r *Result) {
	d.conn.queries[getQueryHash(q)] = query{
		result: r,
	}
}

// Stubs the global driver.Conn to return the supplied error when db.Exec() is called, query stubbing is case insensitive, and whitespace is also ignored.
func StubExecError(q string, err error) {
	StubQueryError(q, err)
}

// Clears all stubbed queries, and replaced functions.
func Reset() {
	d.conn = newConn()
	d.openFunc = nil
}

// Returns a pointer to the global conn object associated with this driver.
func Conn() driver.Conn {
	return d.conn
}

func RowsFromCSVString(columns []string, s string) driver.Rows {
	r := strings.NewReader(strings.TrimSpace(s))
	csvReader := csv.NewReader(r)

	rows := [][]driver.Value{}
	for {
		r, err := csvReader.Read()

		if err != nil || r == nil {
			break
		}

		row := make([]driver.Value, len(columns))

		for i, v := range r {
			v := strings.TrimSpace(v)

			// If enableTimeParsing is on, check to see if this is a
			// time in defined format (RFC3339 by default)
			if d.enableTimeParsing {
				if time, err := time.Parse(d.timeParsingFormat, v); err == nil {
					row[i] = time
				} else {
					row[i] = v
				}
			} else {
				row[i] = v
			}
		}

		rows = append(rows, row)
	}

	return RowsFromSlice(columns, rows)
}

func RowsFromSlice(columns []string, data [][]driver.Value) driver.Rows {
	return &rows{
		closed:  false,
		columns: columns,
		rows:    data,
		pos:     0,
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Alex Browne.  All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

// File setup.go contains helper functions SetUp() and TearDown()

// Package test_support contains various types and functions that
// are used to simplify test and benchmark execution. Not intended
// for external use.
package test_support

import (
	"github.com/stephenalexbrowne/zoom"
	"github.com/stephenalexbrowne/zoom/redis"
	"math/rand"
	"time"
)

func SetUp() {

	conn := connect()
	defer conn.Close()

	// make sure database #9 is empty
	n, err := redis.Int(conn.Do("DBSIZE"))
	if err != nil {
		panic(err.Error())
	}
	if n != 0 {
		panic("Database #9 is not empty, test can not continue")
	}

	// register the types in types.go
	if err := zoom.Register(&Person{}, "person"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&ModelWithList{}, "modelWithList"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&ModelWithSet{}, "modelWithSet"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&Artist{}, "artist"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&Color{}, "color"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&PetOwner{}, "petOwner"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&Pet{}, "pet"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&Friend{}, "friend"); err != nil {
		panic(err.Error())
	}

	// generate a new seed for rand
	rand.Seed(time.Now().UTC().UnixNano())
}

func connect() redis.Conn {

	// initialize zoom
	dialUNIX()

	// if dialUNIX failed, try using a tcp connection
	conn := zoom.GetConn()
	if err := testConn(conn); err != nil {
		dialTCP()
		conn = zoom.GetConn()
		if err := testConn(conn); err != nil {
			// if dialTCP failed, panic.
			panic(err)
		}
	}

	// get a connection
	return conn
}

func dialUNIX() {
	zoom.Init(&zoom.Configuration{
		Address:  "/tmp/redis.sock",
		Network:  "unix",
		Database: 9,
	})
}

func dialTCP() {
	zoom.Init(&zoom.Configuration{
		Address:  "localhost:6379",
		Network:  "tcp",
		Database: 9,
	})
}

func testConn(conn redis.Conn) error {
	if _, err := conn.Do("PING"); err != nil {
		return err
	}
	return nil
}

func TearDown() {

	// unregister types in types.go
	zoom.UnregisterName("person")
	zoom.UnregisterName("modelWithList")
	zoom.UnregisterName("modelWithSet")
	zoom.UnregisterName("artist")
	zoom.UnregisterName("color")
	zoom.UnregisterName("petOwner")
	zoom.UnregisterName("pet")
	zoom.UnregisterName("friend")

	// flush and close the database
	conn := zoom.GetConn()
	_, err := conn.Do("flushdb")
	if err != nil {
		panic(err)
	}
	conn.Close()
	zoom.Close()
}
<commit_msg>add support for address, network, and database flags for tests and benchmarks<commit_after>// Copyright 2013 Alex Browne.  All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

// File setup.go contains helper functions SetUp() and TearDown()

// Package test_support contains various types and functions that
// are used to simplify test and benchmark execution. Not intended
// for external use.
package test_support

import (
	"flag"
	"fmt"
	"github.com/stephenalexbrowne/zoom"
	"github.com/stephenalexbrowne/zoom/redis"
	"math/rand"
	"time"
)

var address *string = flag.String("address", "localhost:6379", "the address of a redis server to connect to")
var network *string = flag.String("network", "tcp", "the network to use for the database connection (e.g. 'tcp' or 'unix')")
var database *int = flag.Int("database", 9, "the redis database number to use for testing")

func SetUp() {
	conn := connect()
	defer conn.Close()

	// make sure database is empty
	n, err := redis.Int(conn.Do("DBSIZE"))
	if err != nil {
		panic(err.Error())
	}
	if n != 0 {
		msg := fmt.Sprintf("Database #%d is not empty, test can not continue", *database)
		panic(msg)
	}

	// register the types in types.go
	if err := zoom.Register(&Person{}, "person"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&ModelWithList{}, "modelWithList"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&ModelWithSet{}, "modelWithSet"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&Artist{}, "artist"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&Color{}, "color"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&PetOwner{}, "petOwner"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&Pet{}, "pet"); err != nil {
		panic(err.Error())
	}
	if err := zoom.Register(&Friend{}, "friend"); err != nil {
		panic(err.Error())
	}

	// generate a new seed for rand
	rand.Seed(time.Now().UTC().UnixNano())
}

// initialize zoom and test the connection
func connect() redis.Conn {
	dial()
	conn := zoom.GetConn()
	if err := testConn(conn); err != nil {
		panic(err)
	}
	return conn
}

func dial() {
	zoom.Init(&zoom.Configuration{
		Address:  *address,
		Network:  *network,
		Database: *database,
	})
}

func testConn(conn redis.Conn) error {
	if _, err := conn.Do("PING"); err != nil {
		return err
	}
	return nil
}

func TearDown() {

	// unregister types in types.go
	zoom.UnregisterName("person")
	zoom.UnregisterName("modelWithList")
	zoom.UnregisterName("modelWithSet")
	zoom.UnregisterName("artist")
	zoom.UnregisterName("color")
	zoom.UnregisterName("petOwner")
	zoom.UnregisterName("pet")
	zoom.UnregisterName("friend")

	// flush and close the database
	conn := zoom.GetConn()
	_, err := conn.Do("flushdb")
	if err != nil {
		panic(err)
	}
	conn.Close()
	zoom.Close()
}
<|endoftext|>


<commit_before>package vm

import "reflect"

type Object interface{}

type Callable interface {
	Call(...*Thunk) *Thunk
}

type Equalable interface {
	Equal(Equalable) bool
}

func Equal(ts ...*Thunk) *Thunk {
	for _, t := range ts {
		go t.Eval()
	}

	e0, ok := ts[0].Eval().(Equalable)

	if !ok {
		return notEqualableError(e0)
	}

	for _, t := range ts[1:] {
		if e, ok := t.Eval().(Equalable); !ok {
			return notEqualableError(e)
		} else if reflect.TypeOf(e0) != reflect.TypeOf(e) || !e0.Equal(e) {
			return False
		}
	}

	return True
}

func notEqualableError(o Object) *Thunk {
	return TypeError(o, "Equalable")
}
<commit_msg>Add add<commit_after>package vm

import "reflect"

type Object interface{}

type Callable interface {
	Call(...*Thunk) *Thunk
}

type Equalable interface {
	Equal(Equalable) bool
}

func Equal(ts ...*Thunk) *Thunk {
	for _, t := range ts {
		go t.Eval()
	}

	o := ts[0].Eval()
	e0, ok := o.(Equalable)

	if !ok {
		return notEqualableError(o)
	}

	for _, t := range ts[1:] {
		if e, ok := t.Eval().(Equalable); !ok {
			return notEqualableError(e)
		} else if reflect.TypeOf(e0) != reflect.TypeOf(e) || !e0.Equal(e) {
			return False
		}
	}

	return True
}

func notEqualableError(o Object) *Thunk {
	return TypeError(o, "Equalable")
}

type Addable interface {
	Add(Addable) Addable
}

func Add(ts ...*Thunk) *Thunk {
	for _, t := range ts {
		go t.Eval()
	}

	o := ts[0].Eval()
	a0, ok := o.(Addable)

	if !ok {
		return TypeError(o, "Addable")
	}

	for _, t := range ts[1:] {
		o := t.Eval()

		if typ := reflect.TypeOf(a0); typ != reflect.TypeOf(o) {
			return TypeError(o, typ.Name())
		}

		a0 = a0.Add(o.(Addable))
	}

	return Normal(a0)
}
<|endoftext|>


<commit_before>package fire

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/256dpi/fire/coal"

	"github.com/256dpi/jsonapi"
	"gopkg.in/mgo.v2/bson"
)

// A Tester provides facilities to the test a fire API.
type Tester struct {
	// The store to use for cleaning the database.
	Store *coal.Store

	// The registered models.
	Models []coal.Model

	// The handler to be tested.
	Handler http.Handler

	// A path prefix e.g. 'api'.
	Prefix string

	// The header to be set on all requests and contexts.
	Header map[string]string

	// Context to be set on fake requests.
	Context context.Context
}

// NewTester returns a new tester.
func NewTester(store *coal.Store, models ...coal.Model) *Tester {
	return &Tester{
		Store:   store,
		Models:  models,
		Header:  make(map[string]string),
		Context: context.Background(),
	}
}

// Register will register the specified model with the tester.
func (t *Tester) Register(model coal.Model) {
	t.Models = append(t.Models, model)
}

// Clean will remove the collections of models that have been registered and
// reset the header map.
func (t *Tester) Clean() {
	store := t.Store.Copy()
	defer store.Close()

	for _, model := range t.Models {
		// remove all is faster than dropping the collection
		_, err := store.C(model).RemoveAll(nil)
		if err != nil {
			panic(err)
		}
	}

	// reset header
	t.Header = make(map[string]string)

	// reset context
	t.Context = context.Background()
}

// Save will save the specified model.
func (t *Tester) Save(model coal.Model) coal.Model {
	store := t.Store.Copy()
	defer store.Close()

	// initialize model
	model = coal.Init(model)

	// insert to collection
	err := store.C(model).Insert(model)
	if err != nil {
		panic(err)
	}

	return model
}

// SaveAll will save the specified models.
func (t *Tester) SaveAll(models ...coal.Model) {
	store := t.Store.Copy()
	defer store.Close()

	// loop through all models
	for _, model := range models {
		// initialize model
		model = coal.Init(model)

		// insert to collection
		err := store.C(model).Insert(model)
		if err != nil {
			panic(err)
		}
	}
}

// FindLast will return the last saved model.
func (t *Tester) FindLast(model coal.Model) coal.Model {
	store := t.Store.Copy()
	defer store.Close()

	err := store.C(model).Find(nil).Sort("-_id").One(model)
	if err != nil {
		panic(err)
	}

	return coal.Init(model)
}

// Path returns a root prefixed path for the supplied path.
func (t *Tester) Path(path string) string {
	// add root slash
	path = "/" + strings.Trim(path, "/")

	// add prefix if available
	if t.Prefix != "" {
		path = "/" + t.Prefix + path
	}

	return path
}

// RunAuthorizer is a helper to test validators. The caller should assert the
// returned error of the validator, the state of the supplied model and maybe
// other objects in the database.
//
// Note: Only the Action, Query, Model and Store are set since these are the
// only attributes an authorizer should rely on.
//
// Note: A fake http request is set to allow access to request headers.
func (t *Tester) RunAuthorizer(action Action, query bson.M, model coal.Model, validator Callback) error {
	// get store
	store := t.Store.Copy()
	defer store.Close()

	// init model if present
	if model != nil {
		coal.Init(model)
	}

	// create request
	req, err := http.NewRequest("GET", "", nil)
	if err != nil {
		panic(err)
	}

	// set headers
	for key, value := range t.Header {
		req.Header.Set(key, value)
	}

	// set context
	req = req.WithContext(t.Context)

	// create context
	ctx := &Context{
		Action:      action,
		Query:       query,
		Model:       model,
		Store:       store,
		HTTPRequest: req,
	}

	// call validator
	return validator(ctx)
}

// RunValidator is a helper to test validators. The caller should assert the
// returned error of the validator, the state of the supplied model and maybe
// other objects in the database.
//
// Note: Only the Action, Model and Store attribute of the context are set since
// these are the only attributes a validator should rely on.
//
// Note: A fake http request is set to allow access to request headers.
func (t *Tester) RunValidator(action Action, model coal.Model, validator Callback) error {
	// check action
	if action.Read() {
		panic("validator are only run on create, update and delete")
	}

	// get store
	store := t.Store.Copy()
	defer store.Close()

	// init model if present
	if model != nil {
		coal.Init(model)
	}

	// create request
	req, err := http.NewRequest("GET", "", nil)
	if err != nil {
		panic(err)
	}

	// set headers
	for key, value := range t.Header {
		req.Header.Set(key, value)
	}

	// set context
	req = req.WithContext(t.Context)

	// create context
	ctx := &Context{
		Action:      action,
		Model:       model,
		Store:       store,
		HTTPRequest: req,
	}

	// call validator
	return validator(ctx)
}

// TODO: Add RunNotifier helper.

// Request will run the specified request against the registered handler. This
// function can be used to create custom testing facilities.
func (t *Tester) Request(method, path string, payload string, callback func(*httptest.ResponseRecorder, *http.Request)) {
	// create request
	request, err := http.NewRequest(method, t.Path(path), strings.NewReader(payload))
	if err != nil {
		panic(err)
	}

	// prepare recorder
	recorder := httptest.NewRecorder()

	// preset jsonapi accept header
	request.Header.Set("Accept", jsonapi.MediaType)

	// add content type if required
	if method == "POST" || method == "PATCH" || method == "DELETE" {
		request.Header.Set("Content-Type", jsonapi.MediaType)
	}

	// set custom headers
	for k, v := range t.Header {
		request.Header.Set(k, v)
	}

	// server request
	t.Handler.ServeHTTP(recorder, request)

	// run callback
	callback(recorder, request)
}

// DebugRequest returns a string of information to debug requests.
func (t *Tester) DebugRequest(r *http.Request, rr *httptest.ResponseRecorder) string {
	return fmt.Sprintf(`
	URL:    %s
	Header: %s
	Status: %d
	Header: %v
	Body:   %v`, r.URL.String(), r.Header, rr.Code, rr.HeaderMap, rr.Body.String())
}
<commit_msg>removed unneeded functions<commit_after>package fire

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/256dpi/fire/coal"

	"github.com/256dpi/jsonapi"
	"gopkg.in/mgo.v2/bson"
)

// A Tester provides facilities to the test a fire API.
type Tester struct {
	// The store to use for cleaning the database.
	Store *coal.Store

	// The registered models.
	Models []coal.Model

	// The handler to be tested.
	Handler http.Handler

	// A path prefix e.g. 'api'.
	Prefix string

	// The header to be set on all requests and contexts.
	Header map[string]string

	// Context to be set on fake requests.
	Context context.Context
}

// NewTester returns a new tester.
func NewTester(store *coal.Store, models ...coal.Model) *Tester {
	return &Tester{
		Store:   store,
		Models:  models,
		Header:  make(map[string]string),
		Context: context.Background(),
	}
}

// Clean will remove the collections of models that have been registered and
// reset the header map.
func (t *Tester) Clean() {
	store := t.Store.Copy()
	defer store.Close()

	for _, model := range t.Models {
		// remove all is faster than dropping the collection
		_, err := store.C(model).RemoveAll(nil)
		if err != nil {
			panic(err)
		}
	}

	// reset header
	t.Header = make(map[string]string)

	// reset context
	t.Context = context.Background()
}

// Save will save the specified model.
func (t *Tester) Save(model coal.Model) coal.Model {
	store := t.Store.Copy()
	defer store.Close()

	// initialize model
	model = coal.Init(model)

	// insert to collection
	err := store.C(model).Insert(model)
	if err != nil {
		panic(err)
	}

	return model
}

// FindLast will return the last saved model.
func (t *Tester) FindLast(model coal.Model) coal.Model {
	store := t.Store.Copy()
	defer store.Close()

	err := store.C(model).Find(nil).Sort("-_id").One(model)
	if err != nil {
		panic(err)
	}

	return coal.Init(model)
}

// Path returns a root prefixed path for the supplied path.
func (t *Tester) Path(path string) string {
	// add root slash
	path = "/" + strings.Trim(path, "/")

	// add prefix if available
	if t.Prefix != "" {
		path = "/" + t.Prefix + path
	}

	return path
}

// RunAuthorizer is a helper to test validators. The caller should assert the
// returned error of the validator, the state of the supplied model and maybe
// other objects in the database.
//
// Note: Only the Action, Query, Model and Store are set since these are the
// only attributes an authorizer should rely on.
//
// Note: A fake http request is set to allow access to request headers.
func (t *Tester) RunAuthorizer(action Action, query bson.M, model coal.Model, validator Callback) error {
	// get store
	store := t.Store.Copy()
	defer store.Close()

	// init model if present
	if model != nil {
		coal.Init(model)
	}

	// create request
	req, err := http.NewRequest("GET", "", nil)
	if err != nil {
		panic(err)
	}

	// set headers
	for key, value := range t.Header {
		req.Header.Set(key, value)
	}

	// set context
	req = req.WithContext(t.Context)

	// create context
	ctx := &Context{
		Action:      action,
		Query:       query,
		Model:       model,
		Store:       store,
		HTTPRequest: req,
	}

	// call validator
	return validator(ctx)
}

// RunValidator is a helper to test validators. The caller should assert the
// returned error of the validator, the state of the supplied model and maybe
// other objects in the database.
//
// Note: Only the Action, Model and Store attribute of the context are set since
// these are the only attributes a validator should rely on.
//
// Note: A fake http request is set to allow access to request headers.
func (t *Tester) RunValidator(action Action, model coal.Model, validator Callback) error {
	// check action
	if action.Read() {
		panic("validator are only run on create, update and delete")
	}

	// get store
	store := t.Store.Copy()
	defer store.Close()

	// init model if present
	if model != nil {
		coal.Init(model)
	}

	// create request
	req, err := http.NewRequest("GET", "", nil)
	if err != nil {
		panic(err)
	}

	// set headers
	for key, value := range t.Header {
		req.Header.Set(key, value)
	}

	// set context
	req = req.WithContext(t.Context)

	// create context
	ctx := &Context{
		Action:      action,
		Model:       model,
		Store:       store,
		HTTPRequest: req,
	}

	// call validator
	return validator(ctx)
}

// TODO: Add RunNotifier helper.

// Request will run the specified request against the registered handler. This
// function can be used to create custom testing facilities.
func (t *Tester) Request(method, path string, payload string, callback func(*httptest.ResponseRecorder, *http.Request)) {
	// create request
	request, err := http.NewRequest(method, t.Path(path), strings.NewReader(payload))
	if err != nil {
		panic(err)
	}

	// prepare recorder
	recorder := httptest.NewRecorder()

	// preset jsonapi accept header
	request.Header.Set("Accept", jsonapi.MediaType)

	// add content type if required
	if method == "POST" || method == "PATCH" || method == "DELETE" {
		request.Header.Set("Content-Type", jsonapi.MediaType)
	}

	// set custom headers
	for k, v := range t.Header {
		request.Header.Set(k, v)
	}

	// server request
	t.Handler.ServeHTTP(recorder, request)

	// run callback
	callback(recorder, request)
}

// DebugRequest returns a string of information to debug requests.
func (t *Tester) DebugRequest(r *http.Request, rr *httptest.ResponseRecorder) string {
	return fmt.Sprintf(`
	URL:    %s
	Header: %s
	Status: %d
	Header: %v
	Body:   %v`, r.URL.String(), r.Header, rr.Code, rr.HeaderMap, rr.Body.String())
}
<|endoftext|>


<commit_before>package boomer

import (
	"sync/atomic"
	"testing"
	"time"
)

func TestSafeRun(t *testing.T) {
	runner := &runner{}
	runner.safeRun(func() {
		panic("Runner will catch this panic")
	})
}

func TestSpawnGoRoutines(t *testing.T) {
	taskA := &Task{
		Weight: 10,
		Fn: func() {
			time.Sleep(time.Second)
		},
		Name: "TaskA",
	}
	taskB := &Task{
		Weight: 20,
		Fn: func() {
			time.Sleep(2 * time.Second)
		},
		Name: "TaskB",
	}
	tasks := []*Task{taskA, taskB}
	rateLimiter := newStableRateLimiter(100, time.Second)
	runner := newRunner(tasks, rateLimiter, "asap")
	defer runner.close()

	runner.client = newClient("localhost", 5557)
	runner.hatchRate = 10

	runner.spawnGoRoutines(10, runner.stopChannel)
	if runner.numClients != 10 {
		t.Error("Number of goroutines mismatches, expected: 10, current count", runner.numClients)
	}
}

func TestSpawnGoRoutinesSmoothly(t *testing.T) {
	taskA := &Task{
		Weight: 10,
		Fn: func() {
			time.Sleep(time.Second)
		},
		Name: "TaskA",
	}
	tasks := []*Task{taskA}

	runner := newRunner(tasks, nil, "smooth")
	defer runner.close()

	runner.client = newClient("localhost", 5557)
	runner.hatchRate = 10

	go runner.spawnGoRoutines(10, runner.stopChannel)
	time.Sleep(2 * time.Millisecond)

	currentClients := atomic.LoadInt32(&runner.numClients)
	if currentClients > 3 {
		t.Error("Spawning goroutines too fast, current count", currentClients)
	}
}

func TestHatchAndStop(t *testing.T) {
	taskA := &Task{
		Fn: func() {
			time.Sleep(time.Second)
		},
	}
	taskB := &Task{
		Fn: func() {
			time.Sleep(2 * time.Second)
		},
	}
	tasks := []*Task{taskA, taskB}
	runner := newRunner(tasks, nil, "asap")
	defer runner.close()
	runner.client = newClient("localhost", 5557)

	go func() {
		var ticker = time.NewTicker(time.Second)
		for {
			select {
			case <-ticker.C:
				t.Error("Timeout waiting for message sent by startHatching()")
				return
			case <-defaultStats.clearStatsChannel:
				// just quit
				return
			}
		}
	}()

	runner.startHatching(10, 10)
	// wait for spawning goroutines
	time.Sleep(100 * time.Millisecond)
	if runner.numClients != 10 {
		t.Error("Number of goroutines mismatches, expected: 10, current count", runner.numClients)
	}

	msg := <-runner.client.sendChannel()
	if msg.Type != "hatch_complete" {
		t.Error("Runner should send hatch_complete message when hatching completed, got", msg.Type)
	}
	runner.stop()

	runner.onQuiting()
	msg = <-runner.client.sendChannel()
	if msg.Type != "quit" {
		t.Error("Runner should send quit message on quitting, got", msg.Type)
	}
}

func TestStop(t *testing.T) {
	taskA := &Task{
		Fn: func() {
			time.Sleep(time.Second)
		},
	}
	tasks := []*Task{taskA}
	runner := newRunner(tasks, nil, "asap")
	runner.stopChannel = make(chan bool)

	stopped := false
	handler := func() {
		stopped = true
	}
	Events.Subscribe("boomer:stop", handler)
	defer Events.Unsubscribe("boomer:stop", handler)

	runner.stop()

	if stopped != true {
		t.Error("Expected stopped to be true, was", stopped)
	}
}

func TestOnMessage(t *testing.T) {
	taskA := &Task{
		Fn: func() {
			time.Sleep(time.Second)
		},
	}
	taskB := &Task{
		Fn: func() {
			time.Sleep(2 * time.Second)
		},
	}
	tasks := []*Task{taskA, taskB}

	runner := newRunner(tasks, nil, "asap")
	defer runner.close()
	runner.client = newClient("localhost", 5557)
	runner.state = stateInit

	go func() {
		// consumes clearStatsChannel
		count := 0
		for {
			select {
			case <-defaultStats.clearStatsChannel:
				// receive two hatch message from master
				if count >= 2 {
					return
				}
				count++
			}
		}
	}()

	// start hatching
	runner.onMessage(newMessage("hatch", map[string]interface{}{
		"hatch_rate":  float64(10),
		"num_clients": int64(10),
	}, runner.nodeID))

	msg := <-runner.client.sendChannel()
	if msg.Type != "hatching" {
		t.Error("Runner should send hatching message when starting hatch, got", msg.Type)
	}

	// hatch complete and running
	time.Sleep(100 * time.Millisecond)
	if runner.state != stateRunning {
		t.Error("State of runner is not running after hatch, got", runner.state)
	}
	if runner.numClients != 10 {
		t.Error("Number of goroutines mismatches, expected: 10, current count:", runner.numClients)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "hatch_complete" {
		t.Error("Runner should send hatch_complete message when hatch completed, got", msg.Type)
	}

	// increase num_clients while running
	runner.onMessage(newMessage("hatch", map[string]interface{}{
		"hatch_rate":  float64(20),
		"num_clients": int64(20),
	}, runner.nodeID))

	msg = <-runner.client.sendChannel()
	if msg.Type != "hatching" {
		t.Error("Runner should send hatching message when starting hatch, got", msg.Type)
	}

	time.Sleep(100 * time.Millisecond)
	if runner.state != stateRunning {
		t.Error("State of runner is not running after hatch, got", runner.state)
	}
	if runner.numClients != 20 {
		t.Error("Number of goroutines mismatches, expected: 20, current count:", runner.numClients)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "hatch_complete" {
		t.Error("Runner should send hatch_complete message when hatch completed, got", msg.Type)
	}

	// stop all the workers
	runner.onMessage(newMessage("stop", nil, runner.nodeID))
	if runner.state != stateStopped {
		t.Error("State of runner is not stopped, got", runner.state)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "client_stopped" {
		t.Error("Runner should send client_stopped message, got", msg.Type)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "client_ready" {
		t.Error("Runner should send client_ready message, got", msg.Type)
	}

	// hatch again
	runner.onMessage(newMessage("hatch", map[string]interface{}{
		"hatch_rate":  float64(10),
		"num_clients": uint64(10),
	}, runner.nodeID))

	msg = <-runner.client.sendChannel()
	if msg.Type != "hatching" {
		t.Error("Runner should send hatching message when starting hatch, got", msg.Type)
	}

	// hatch complete and running
	time.Sleep(100 * time.Millisecond)
	if runner.state != stateRunning {
		t.Error("State of runner is not running after hatch, got", runner.state)
	}
	if runner.numClients != 10 {
		t.Error("Number of goroutines mismatches, expected: 10, current count:", runner.numClients)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "hatch_complete" {
		t.Error("Runner should send hatch_complete message when hatch completed, got", msg.Type)
	}

	// stop all the workers
	runner.onMessage(newMessage("stop", nil, runner.nodeID))
	if runner.state != stateStopped {
		t.Error("State of runner is not stopped, got", runner.state)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "client_stopped" {
		t.Error("Runner should send client_stopped message, got", msg.Type)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "client_ready" {
		t.Error("Runner should send client_ready message, got", msg.Type)
	}
}

func TestGetReady(t *testing.T) {
	masterHost := "127.0.0.1"
	masterPort := 6557

	server := newTestServer(masterHost, masterPort+1, masterPort)
	defer server.close()
	server.start()

	rateLimiter := newStableRateLimiter(100, time.Second)
	r := newRunner(nil, rateLimiter, "asap")
	r.masterHost = masterHost
	r.masterPort = masterPort
	defer r.close()
	defer Events.Unsubscribe("boomer:quit", r.onQuiting)

	r.getReady()

	msg := <-server.fromClient
	if msg.Type != "client_ready" {
		t.Error("Runner should send client_ready message to server.")
	}

	r.numClients = 10
	data := make(map[string]interface{})
	defaultStats.messageToRunner <- data

	msg = <-server.fromClient
	if msg.Type != "stats" {
		t.Error("Runner should send stats message to server.")
	}

	userCount := msg.Data["user_count"].(int64)
	if userCount != int64(10) {
		t.Error("User count mismatch, expect: 10, got:", userCount)
	}
}
<commit_msg>FIX: test is blocked<commit_after>package boomer

import (
	"sync/atomic"
	"testing"
	"time"
)

func TestSafeRun(t *testing.T) {
	runner := &runner{}
	runner.safeRun(func() {
		panic("Runner will catch this panic")
	})
}

func TestSpawnGoRoutines(t *testing.T) {
	taskA := &Task{
		Weight: 10,
		Fn: func() {
			time.Sleep(time.Second)
		},
		Name: "TaskA",
	}
	taskB := &Task{
		Weight: 20,
		Fn: func() {
			time.Sleep(2 * time.Second)
		},
		Name: "TaskB",
	}
	tasks := []*Task{taskA, taskB}
	rateLimiter := newStableRateLimiter(100, time.Second)
	runner := newRunner(tasks, rateLimiter, "asap")
	defer runner.close()

	runner.client = newClient("localhost", 5557)
	runner.hatchRate = 10

	runner.spawnGoRoutines(10, runner.stopChannel)
	if runner.numClients != 10 {
		t.Error("Number of goroutines mismatches, expected: 10, current count", runner.numClients)
	}
}

func TestSpawnGoRoutinesSmoothly(t *testing.T) {
	taskA := &Task{
		Weight: 10,
		Fn: func() {
			time.Sleep(time.Second)
		},
		Name: "TaskA",
	}
	tasks := []*Task{taskA}

	runner := newRunner(tasks, nil, "smooth")
	defer runner.close()

	runner.client = newClient("localhost", 5557)
	runner.hatchRate = 10

	go runner.spawnGoRoutines(10, runner.stopChannel)
	time.Sleep(2 * time.Millisecond)

	currentClients := atomic.LoadInt32(&runner.numClients)
	if currentClients > 3 {
		t.Error("Spawning goroutines too fast, current count", currentClients)
	}
}

func TestHatchAndStop(t *testing.T) {
	taskA := &Task{
		Fn: func() {
			time.Sleep(time.Second)
		},
	}
	taskB := &Task{
		Fn: func() {
			time.Sleep(2 * time.Second)
		},
	}
	tasks := []*Task{taskA, taskB}
	runner := newRunner(tasks, nil, "asap")
	defer runner.close()
	runner.client = newClient("localhost", 5557)

	go func() {
		var ticker = time.NewTicker(time.Second)
		for {
			select {
			case <-ticker.C:
				t.Error("Timeout waiting for message sent by startHatching()")
				return
			case <-defaultStats.clearStatsChannel:
				// just quit
				return
			}
		}
	}()

	runner.startHatching(10, 10)
	// wait for spawning goroutines
	time.Sleep(100 * time.Millisecond)
	if runner.numClients != 10 {
		t.Error("Number of goroutines mismatches, expected: 10, current count", runner.numClients)
	}

	msg := <-runner.client.sendChannel()
	if msg.Type != "hatch_complete" {
		t.Error("Runner should send hatch_complete message when hatching completed, got", msg.Type)
	}
	runner.stop()

	runner.onQuiting()
	msg = <-runner.client.sendChannel()
	if msg.Type != "quit" {
		t.Error("Runner should send quit message on quitting, got", msg.Type)
	}
}

func TestStop(t *testing.T) {
	taskA := &Task{
		Fn: func() {
			time.Sleep(time.Second)
		},
	}
	tasks := []*Task{taskA}
	runner := newRunner(tasks, nil, "asap")
	runner.stopChannel = make(chan bool)

	stopped := false
	handler := func() {
		stopped = true
	}
	Events.Subscribe("boomer:stop", handler)
	defer Events.Unsubscribe("boomer:stop", handler)

	runner.stop()

	if stopped != true {
		t.Error("Expected stopped to be true, was", stopped)
	}
}

func TestOnMessage(t *testing.T) {
	taskA := &Task{
		Fn: func() {
			time.Sleep(time.Second)
		},
	}
	taskB := &Task{
		Fn: func() {
			time.Sleep(2 * time.Second)
		},
	}
	tasks := []*Task{taskA, taskB}

	runner := newRunner(tasks, nil, "asap")
	defer runner.close()
	runner.client = newClient("localhost", 5557)
	runner.state = stateInit

	go func() {
		// consumes clearStatsChannel
		count := 0
		for {
			select {
			case <-defaultStats.clearStatsChannel:
				// receive two hatch message from master
				if count >= 2 {
					return
				}
				count++
			}
		}
	}()

	// start hatching
	runner.onMessage(newMessage("hatch", map[string]interface{}{
		"hatch_rate":  float64(10),
		"num_clients": int64(10),
	}, runner.nodeID))

	msg := <-runner.client.sendChannel()
	if msg.Type != "hatching" {
		t.Error("Runner should send hatching message when starting hatch, got", msg.Type)
	}

	// hatch complete and running
	time.Sleep(100 * time.Millisecond)
	if runner.state != stateRunning {
		t.Error("State of runner is not running after hatch, got", runner.state)
	}
	if runner.numClients != 10 {
		t.Error("Number of goroutines mismatches, expected: 10, current count:", runner.numClients)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "hatch_complete" {
		t.Error("Runner should send hatch_complete message when hatch completed, got", msg.Type)
	}

	// increase num_clients while running
	runner.onMessage(newMessage("hatch", map[string]interface{}{
		"hatch_rate":  float64(20),
		"num_clients": int64(20),
	}, runner.nodeID))

	msg = <-runner.client.sendChannel()
	if msg.Type != "hatching" {
		t.Error("Runner should send hatching message when starting hatch, got", msg.Type)
	}

	time.Sleep(100 * time.Millisecond)
	if runner.state != stateRunning {
		t.Error("State of runner is not running after hatch, got", runner.state)
	}
	if runner.numClients != 20 {
		t.Error("Number of goroutines mismatches, expected: 20, current count:", runner.numClients)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "hatch_complete" {
		t.Error("Runner should send hatch_complete message when hatch completed, got", msg.Type)
	}

	// stop all the workers
	runner.onMessage(newMessage("stop", nil, runner.nodeID))
	if runner.state != stateStopped {
		t.Error("State of runner is not stopped, got", runner.state)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "client_stopped" {
		t.Error("Runner should send client_stopped message, got", msg.Type)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "client_ready" {
		t.Error("Runner should send client_ready message, got", msg.Type)
	}

	// hatch again
	runner.onMessage(newMessage("hatch", map[string]interface{}{
		"hatch_rate":  float64(10),
		"num_clients": uint64(10),
	}, runner.nodeID))

	msg = <-runner.client.sendChannel()
	if msg.Type != "hatching" {
		t.Error("Runner should send hatching message when starting hatch, got", msg.Type)
	}

	// hatch complete and running
	time.Sleep(100 * time.Millisecond)
	if runner.state != stateRunning {
		t.Error("State of runner is not running after hatch, got", runner.state)
	}
	if runner.numClients != 10 {
		t.Error("Number of goroutines mismatches, expected: 10, current count:", runner.numClients)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "hatch_complete" {
		t.Error("Runner should send hatch_complete message when hatch completed, got", msg.Type)
	}

	// stop all the workers
	runner.onMessage(newMessage("stop", nil, runner.nodeID))
	if runner.state != stateStopped {
		t.Error("State of runner is not stopped, got", runner.state)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "client_stopped" {
		t.Error("Runner should send client_stopped message, got", msg.Type)
	}
	msg = <-runner.client.sendChannel()
	if msg.Type != "client_ready" {
		t.Error("Runner should send client_ready message, got", msg.Type)
	}
}

func TestGetReady(t *testing.T) {
	masterHost := "127.0.0.1"
	masterPort := 6557

	server := newTestServer(masterHost, masterPort+1, masterPort)
	defer server.close()
	server.start()

	rateLimiter := newStableRateLimiter(100, time.Second)
	r := newRunner(nil, rateLimiter, "asap")
	r.masterHost = masterHost
	r.masterPort = masterPort
	defer r.close()
	defer Events.Unsubscribe("boomer:quit", r.onQuiting)

	r.getReady()

	msg := <-server.fromClient
	if msg.Type != "client_ready" {
		t.Error("Runner should send client_ready message to server.")
	}

	r.numClients = 10
	// it's not really running
	r.state = stateRunning
	data := make(map[string]interface{})
	defaultStats.messageToRunner <- data

	msg = <-server.fromClient
	if msg.Type != "stats" {
		t.Error("Runner should send stats message to server.")
	}

	userCount := msg.Data["user_count"].(int64)
	if userCount != int64(10) {
		t.Error("User count mismatch, expect: 10, got:", userCount)
	}
}
<|endoftext|>


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

package test

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"testing"

	"github.com/pkg/errors"
)

const (
	ProjectRoot string = "src/github.com/golang/notexist"
)

type RunFunc func(prog string, newargs []string, outW, errW io.Writer, dir string, env []string) error

// IntegrationTestProject manages the "virtual" test project directory structure
// and content
type IntegrationTestProject struct {
	t          *testing.T
	h          *Helper
	preImports []string
	tempdir    string
	env        []string
	origWd     string
	stdout     bytes.Buffer
	stderr     bytes.Buffer
	run        RunFunc
}

func NewTestProject(t *testing.T, initPath, wd string, externalProc bool, run RunFunc) *IntegrationTestProject {
	new := &IntegrationTestProject{
		t:      t,
		origWd: wd,
		env:    os.Environ(),
		run:    run,
	}
	new.makeRootTempDir()
	new.TempDir(ProjectRoot, "vendor")
	new.CopyTree(initPath)

	// Note that the Travis darwin platform, directories with certain roots such
	// as /var are actually links to a dirtree under /private.  Without the patch
	// below the wd, and therefore the GOPATH, is recorded as "/var/..." but the
	// actual process runs in "/private/var/..." and dies due to not being in the
	// GOPATH because the roots don't line up.
	if externalProc && runtime.GOOS == "darwin" && needsPrivateLeader(new.tempdir) {
		new.Setenv("GOPATH", filepath.Join("/private", new.tempdir))
	} else {
		new.Setenv("GOPATH", new.tempdir)
	}

	return new
}

func (p *IntegrationTestProject) Cleanup() {
	os.RemoveAll(p.tempdir)
}

func (p *IntegrationTestProject) Path(args ...string) string {
	return filepath.Join(p.tempdir, filepath.Join(args...))
}

func (p *IntegrationTestProject) ProjPath(args ...string) string {
	localPath := append([]string{ProjectRoot}, args...)
	return p.Path(localPath...)
}

func (p *IntegrationTestProject) TempDir(args ...string) {
	fullPath := p.Path(args...)
	if err := os.MkdirAll(fullPath, 0755); err != nil && !os.IsExist(err) {
		p.t.Fatalf("%+v", errors.Errorf("Unable to create temp directory: %s", fullPath))
	}
}

func (p *IntegrationTestProject) TempProjDir(args ...string) {
	localPath := append([]string{ProjectRoot}, args...)
	p.TempDir(localPath...)
}

func (p *IntegrationTestProject) VendorPath(args ...string) string {
	localPath := append([]string{ProjectRoot, "vendor"}, args...)
	p.TempDir(localPath...)
	return p.Path(localPath...)
}

func (p *IntegrationTestProject) RunGo(args ...string) {
	cmd := exec.Command("go", args...)
	p.stdout.Reset()
	p.stderr.Reset()
	cmd.Stdout = &p.stdout
	cmd.Stderr = &p.stderr
	cmd.Dir = p.tempdir
	cmd.Env = p.env
	status := cmd.Run()
	if p.stdout.Len() > 0 {
		p.t.Log("go standard output:")
		p.t.Log(p.stdout.String())
	}
	if p.stderr.Len() > 0 {
		p.t.Log("go standard error:")
		p.t.Log(p.stderr.String())
	}
	if status != nil {
		p.t.Logf("go %v failed unexpectedly: %v", args, status)
		p.t.FailNow()
	}
}

func (p *IntegrationTestProject) RunGit(dir string, args ...string) {
	cmd := exec.Command("git", args...)
	p.stdout.Reset()
	p.stderr.Reset()
	cmd.Stdout = &p.stdout
	cmd.Stderr = &p.stderr
	cmd.Dir = dir
	cmd.Env = p.env
	status := cmd.Run()
	if *PrintLogs {
		if p.stdout.Len() > 0 {
			p.t.Logf("git %v standard output:", args)
			p.t.Log(p.stdout.String())
		}
		if p.stderr.Len() > 0 {
			p.t.Logf("git %v standard error:", args)
			p.t.Log(p.stderr.String())
		}
	}
	if status != nil {
		p.t.Logf("git %v failed unexpectedly: %v", args, status)
		p.t.FailNow()
	}
}

// GetStdout gets the Stdout output from test run
func (p *IntegrationTestProject) GetStdout() string {
	return p.stdout.String()
}

// GetStderr gets the Stderr output from test run
func (p *IntegrationTestProject) GetStderr() string {
	return p.stderr.String()
}

func (p *IntegrationTestProject) GetVendorGit(ip string) {
	parse := strings.Split(ip, "/")
	gitDir := strings.Join(parse[:len(parse)-1], string(filepath.Separator))
	p.TempProjDir("vendor", gitDir)
	p.RunGit(p.ProjPath("vendor", gitDir), "clone", "http://"+ip)
}

func (p *IntegrationTestProject) DoRun(args []string) error {
	if *PrintLogs {
		p.t.Logf("running testdep %v", args)
	}
	prog := filepath.Join(p.origWd, "testdep"+ExeSuffix)
	newargs := append([]string{args[0], "-v"}, args[1:]...)

	p.stdout.Reset()
	p.stderr.Reset()

	status := p.run(prog, newargs, &p.stdout, &p.stderr, p.ProjPath(""), p.env)

	if *PrintLogs {
		if p.stdout.Len() > 0 {
			p.t.Log("standard output:")
			p.t.Log(p.stdout.String())
		}
		if p.stderr.Len() > 0 {
			p.t.Log("standard error:")
			p.t.Log(p.stderr.String())
		}
	}
	return status
}

func (p *IntegrationTestProject) CopyTree(src string) {
	filepath.Walk(src,
		func(path string, info os.FileInfo, err error) error {
			if path != src {
				localpath := path[len(src)+1:]
				if info.IsDir() {
					p.TempDir(ProjectRoot, localpath)
				} else {
					destpath := filepath.Join(p.ProjPath(), localpath)
					copyFile(destpath, path)
				}
			}
			return nil
		})
}

func copyFile(dest, src string) {
	in, err := os.Open(src)
	if err != nil {
		panic(err)
	}
	defer in.Close()

	out, err := os.Create(dest)
	if err != nil {
		panic(err)
	}
	defer out.Close()

	io.Copy(out, in)
}

// Collect final vendor paths at a depth of three levels
func (p *IntegrationTestProject) GetVendorPaths() []string {
	vendorPath := p.ProjPath("vendor")
	result := make([]string, 0)
	filepath.Walk(
		vendorPath,
		func(path string, info os.FileInfo, err error) error {
			if len(path) > len(vendorPath) && info.IsDir() {
				parse := strings.Split(path[len(vendorPath)+1:], string(filepath.Separator))
				if len(parse) == 3 {
					result = append(result, strings.Join(parse, "/"))
					return filepath.SkipDir
				}
			}
			return nil
		},
	)
	sort.Strings(result)
	return result
}

// Collect final vendor paths at a depth of three levels
func (p *IntegrationTestProject) GetImportPaths() []string {
	importPath := p.Path("src")
	result := make([]string, 0)
	filepath.Walk(
		importPath,
		func(path string, info os.FileInfo, err error) error {
			if len(path) > len(importPath) && info.IsDir() {
				parse := strings.Split(path[len(importPath)+1:], string(filepath.Separator))
				if len(parse) == 3 {
					result = append(result, strings.Join(parse, "/"))
					return filepath.SkipDir
				}
			}
			return nil
		},
	)
	sort.Strings(result)
	return result
}

// Take a snapshot of the import paths before test is run
func (p *IntegrationTestProject) RecordImportPaths() {
	p.preImports = p.GetImportPaths()
}

// Compare import paths before and after commands
func (p *IntegrationTestProject) CompareImportPaths() {
	wantImportPaths := p.preImports
	gotImportPaths := p.GetImportPaths()
	if len(gotImportPaths) != len(wantImportPaths) {
		p.t.Fatalf("Import path count changed during command: pre %d post %d", len(wantImportPaths), len(gotImportPaths))
	}
	for ind := range gotImportPaths {
		if gotImportPaths[ind] != wantImportPaths[ind] {
			p.t.Errorf("Change in import paths during: pre %s post %s", gotImportPaths, wantImportPaths)
		}
	}
}

// makeRootTempdir makes a temporary directory for a run of testgo. If
// the temporary directory was already created, this does nothing.
func (p *IntegrationTestProject) makeRootTempDir() {
	if p.tempdir == "" {
		var err error
		p.tempdir, err = ioutil.TempDir("", "gotest")
		p.Must(err)
	}
}

// Setenv sets an environment variable to use when running the test go
// command.
func (p *IntegrationTestProject) Setenv(name, val string) {
	p.env = append(p.env, name+"="+val)
}

// Must gives a fatal error if err is not nil.
func (p *IntegrationTestProject) Must(err error) {
	if err != nil {
		p.t.Fatalf("%+v", err)
	}
}

// Checks for filepath beginnings that result in the "/private" leader
// on Mac platforms
func needsPrivateLeader(path string) bool {
	var roots = []string{"/var", "/tmp", "/etc"}
	for _, root := range roots {
		if strings.HasPrefix(path, root) {
			return true
		}
	}
	return false
}
<commit_msg>Print integration test output on a newline<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package test

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"testing"

	"github.com/pkg/errors"
)

const (
	ProjectRoot string = "src/github.com/golang/notexist"
)

type RunFunc func(prog string, newargs []string, outW, errW io.Writer, dir string, env []string) error

// IntegrationTestProject manages the "virtual" test project directory structure
// and content
type IntegrationTestProject struct {
	t          *testing.T
	h          *Helper
	preImports []string
	tempdir    string
	env        []string
	origWd     string
	stdout     bytes.Buffer
	stderr     bytes.Buffer
	run        RunFunc
}

func NewTestProject(t *testing.T, initPath, wd string, externalProc bool, run RunFunc) *IntegrationTestProject {
	new := &IntegrationTestProject{
		t:      t,
		origWd: wd,
		env:    os.Environ(),
		run:    run,
	}
	new.makeRootTempDir()
	new.TempDir(ProjectRoot, "vendor")
	new.CopyTree(initPath)

	// Note that the Travis darwin platform, directories with certain roots such
	// as /var are actually links to a dirtree under /private.  Without the patch
	// below the wd, and therefore the GOPATH, is recorded as "/var/..." but the
	// actual process runs in "/private/var/..." and dies due to not being in the
	// GOPATH because the roots don't line up.
	if externalProc && runtime.GOOS == "darwin" && needsPrivateLeader(new.tempdir) {
		new.Setenv("GOPATH", filepath.Join("/private", new.tempdir))
	} else {
		new.Setenv("GOPATH", new.tempdir)
	}

	return new
}

func (p *IntegrationTestProject) Cleanup() {
	os.RemoveAll(p.tempdir)
}

func (p *IntegrationTestProject) Path(args ...string) string {
	return filepath.Join(p.tempdir, filepath.Join(args...))
}

func (p *IntegrationTestProject) ProjPath(args ...string) string {
	localPath := append([]string{ProjectRoot}, args...)
	return p.Path(localPath...)
}

func (p *IntegrationTestProject) TempDir(args ...string) {
	fullPath := p.Path(args...)
	if err := os.MkdirAll(fullPath, 0755); err != nil && !os.IsExist(err) {
		p.t.Fatalf("%+v", errors.Errorf("Unable to create temp directory: %s", fullPath))
	}
}

func (p *IntegrationTestProject) TempProjDir(args ...string) {
	localPath := append([]string{ProjectRoot}, args...)
	p.TempDir(localPath...)
}

func (p *IntegrationTestProject) VendorPath(args ...string) string {
	localPath := append([]string{ProjectRoot, "vendor"}, args...)
	p.TempDir(localPath...)
	return p.Path(localPath...)
}

func (p *IntegrationTestProject) RunGo(args ...string) {
	cmd := exec.Command("go", args...)
	p.stdout.Reset()
	p.stderr.Reset()
	cmd.Stdout = &p.stdout
	cmd.Stderr = &p.stderr
	cmd.Dir = p.tempdir
	cmd.Env = p.env
	status := cmd.Run()
	if p.stdout.Len() > 0 {
		p.t.Log("go standard output:")
		p.t.Log(p.stdout.String())
	}
	if p.stderr.Len() > 0 {
		p.t.Log("go standard error:")
		p.t.Log(p.stderr.String())
	}
	if status != nil {
		p.t.Logf("go %v failed unexpectedly: %v", args, status)
		p.t.FailNow()
	}
}

func (p *IntegrationTestProject) RunGit(dir string, args ...string) {
	cmd := exec.Command("git", args...)
	p.stdout.Reset()
	p.stderr.Reset()
	cmd.Stdout = &p.stdout
	cmd.Stderr = &p.stderr
	cmd.Dir = dir
	cmd.Env = p.env
	status := cmd.Run()
	if *PrintLogs {
		if p.stdout.Len() > 0 {
			p.t.Logf("git %v standard output:", args)
			p.t.Log(p.stdout.String())
		}
		if p.stderr.Len() > 0 {
			p.t.Logf("git %v standard error:", args)
			p.t.Log(p.stderr.String())
		}
	}
	if status != nil {
		p.t.Logf("git %v failed unexpectedly: %v", args, status)
		p.t.FailNow()
	}
}

// GetStdout gets the Stdout output from test run
func (p *IntegrationTestProject) GetStdout() string {
	return p.stdout.String()
}

// GetStderr gets the Stderr output from test run
func (p *IntegrationTestProject) GetStderr() string {
	return p.stderr.String()
}

func (p *IntegrationTestProject) GetVendorGit(ip string) {
	parse := strings.Split(ip, "/")
	gitDir := strings.Join(parse[:len(parse)-1], string(filepath.Separator))
	p.TempProjDir("vendor", gitDir)
	p.RunGit(p.ProjPath("vendor", gitDir), "clone", "http://"+ip)
}

func (p *IntegrationTestProject) DoRun(args []string) error {
	if *PrintLogs {
		p.t.Logf("running testdep %v", args)
	}
	prog := filepath.Join(p.origWd, "testdep"+ExeSuffix)
	newargs := append([]string{args[0], "-v"}, args[1:]...)

	p.stdout.Reset()
	p.stderr.Reset()

	status := p.run(prog, newargs, &p.stdout, &p.stderr, p.ProjPath(""), p.env)

	if *PrintLogs {
		if p.stdout.Len() > 0 {
			p.t.Logf("\nstandard output:%s", p.stdout.String())
		}
		if p.stderr.Len() > 0 {
			p.t.Logf("standard error:\n%s", p.stderr.String())
		}
	}
	return status
}

func (p *IntegrationTestProject) CopyTree(src string) {
	filepath.Walk(src,
		func(path string, info os.FileInfo, err error) error {
			if path != src {
				localpath := path[len(src)+1:]
				if info.IsDir() {
					p.TempDir(ProjectRoot, localpath)
				} else {
					destpath := filepath.Join(p.ProjPath(), localpath)
					copyFile(destpath, path)
				}
			}
			return nil
		})
}

func copyFile(dest, src string) {
	in, err := os.Open(src)
	if err != nil {
		panic(err)
	}
	defer in.Close()

	out, err := os.Create(dest)
	if err != nil {
		panic(err)
	}
	defer out.Close()

	io.Copy(out, in)
}

// Collect final vendor paths at a depth of three levels
func (p *IntegrationTestProject) GetVendorPaths() []string {
	vendorPath := p.ProjPath("vendor")
	result := make([]string, 0)
	filepath.Walk(
		vendorPath,
		func(path string, info os.FileInfo, err error) error {
			if len(path) > len(vendorPath) && info.IsDir() {
				parse := strings.Split(path[len(vendorPath)+1:], string(filepath.Separator))
				if len(parse) == 3 {
					result = append(result, strings.Join(parse, "/"))
					return filepath.SkipDir
				}
			}
			return nil
		},
	)
	sort.Strings(result)
	return result
}

// Collect final vendor paths at a depth of three levels
func (p *IntegrationTestProject) GetImportPaths() []string {
	importPath := p.Path("src")
	result := make([]string, 0)
	filepath.Walk(
		importPath,
		func(path string, info os.FileInfo, err error) error {
			if len(path) > len(importPath) && info.IsDir() {
				parse := strings.Split(path[len(importPath)+1:], string(filepath.Separator))
				if len(parse) == 3 {
					result = append(result, strings.Join(parse, "/"))
					return filepath.SkipDir
				}
			}
			return nil
		},
	)
	sort.Strings(result)
	return result
}

// Take a snapshot of the import paths before test is run
func (p *IntegrationTestProject) RecordImportPaths() {
	p.preImports = p.GetImportPaths()
}

// Compare import paths before and after commands
func (p *IntegrationTestProject) CompareImportPaths() {
	wantImportPaths := p.preImports
	gotImportPaths := p.GetImportPaths()
	if len(gotImportPaths) != len(wantImportPaths) {
		p.t.Fatalf("Import path count changed during command: pre %d post %d", len(wantImportPaths), len(gotImportPaths))
	}
	for ind := range gotImportPaths {
		if gotImportPaths[ind] != wantImportPaths[ind] {
			p.t.Errorf("Change in import paths during: pre %s post %s", gotImportPaths, wantImportPaths)
		}
	}
}

// makeRootTempdir makes a temporary directory for a run of testgo. If
// the temporary directory was already created, this does nothing.
func (p *IntegrationTestProject) makeRootTempDir() {
	if p.tempdir == "" {
		var err error
		p.tempdir, err = ioutil.TempDir("", "gotest")
		p.Must(err)
	}
}

// Setenv sets an environment variable to use when running the test go
// command.
func (p *IntegrationTestProject) Setenv(name, val string) {
	p.env = append(p.env, name+"="+val)
}

// Must gives a fatal error if err is not nil.
func (p *IntegrationTestProject) Must(err error) {
	if err != nil {
		p.t.Fatalf("%+v", err)
	}
}

// Checks for filepath beginnings that result in the "/private" leader
// on Mac platforms
func needsPrivateLeader(path string) bool {
	var roots = []string{"/var", "/tmp", "/etc"}
	for _, root := range roots {
		if strings.HasPrefix(path, root) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

func newTestPostServer(check func([]byte)) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			panic(err)
		}
		check(body)
		w.WriteHeader(200)
		w.Write([]byte("Success"))
	}))
}

func TestRunByTags(t *testing.T) {
	checkBody := func(body []byte) {
		if string(body) != `{"tags":["foo","bar"]}` {
			t.Errorf(`expected {"tags":["foo","bar"]}, got %v`, string(body))
		}
	}
	ts := newTestPostServer(checkBody)
	defer ts.Close()
	baseURL = ts.URL
	smartFolderID = 0
	siteID = 0
	tags = "foo,bar"
	createRun()
}

func TestRunBySmartFolder(t *testing.T) {
	checkBody := func(body []byte) {
		if string(body) != `{"tags":[""],"smart_folder_id":700}` {
			t.Errorf(`expected {"tags":[""],"smart_folder_id":700}, got %v`, string(body))
		}
	}
	ts := newTestPostServer(checkBody)
	defer ts.Close()
	baseURL = ts.URL
	smartFolderID = 700
	siteID = 0
	tags = ""
	createRun()
}

func TestRunBySiteId(t *testing.T) {
	checkBody := func(body []byte) {
		if string(body) != `{"tags":[""],"site_id":800}` {
			t.Errorf(`expected {"tags":[""],"site_id":800}, got %v`, string(body))
		}
	}
	ts := newTestPostServer(checkBody)
	defer ts.Close()
	baseURL = ts.URL
	smartFolderID = 0
	siteID = 800
	tags = ""
	createRun()
}

func TestRunByTestID(t *testing.T) {
	checkBody := func(body []byte) {
		if string(body) != `{"tests":["1","3","4","7"]}` {
			t.Errorf(`expected {"tests":["1","3","4","7"]}, got %v`, string(body))
		}
	}
	ts := newTestPostServer(checkBody)
	defer ts.Close()
	baseURL = ts.URL
	smartFolderID = 0
	siteID = 0
	testIDs = "1,3,4,7"
	createRun()
}
<commit_msg>changed string comparison in reunner_test. fixed build<commit_after>package main

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

func newTestPostServer(check func([]byte)) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			panic(err)
		}
		check(body)
		w.WriteHeader(200)
		w.Write([]byte("Success"))
	}))
}

func TestRunByTags(t *testing.T) {
	checkBody := func(body []byte) {
		if string(body) != `{"tags":["foo","bar"]}` {
			t.Errorf(`expected {"tags":["foo","bar"]}, got %v`, string(body))
		}
	}
	ts := newTestPostServer(checkBody)
	defer ts.Close()
	baseURL = ts.URL
	smartFolderID = 0
	siteID = 0
	tags = "foo,bar"
	createRun()
}

func TestRunBySmartFolder(t *testing.T) {
	checkBody := func(body []byte) {
		if string(body) != `{"tags":[""],"smart_folder_id":700}` {
			t.Errorf(`expected {"tags":[""],"smart_folder_id":700}, got %v`, string(body))
		}
	}
	ts := newTestPostServer(checkBody)
	defer ts.Close()
	baseURL = ts.URL
	smartFolderID = 700
	siteID = 0
	tags = ""
	createRun()
}

func TestRunBySiteId(t *testing.T) {
	checkBody := func(body []byte) {
		if string(body) != `{"tags":[""],"site_id":800}` {
			t.Errorf(`expected {"tags":[""],"site_id":800}, got %v`, string(body))
		}
	}
	ts := newTestPostServer(checkBody)
	defer ts.Close()
	baseURL = ts.URL
	smartFolderID = 0
	siteID = 800
	tags = ""
	createRun()
}

func TestRunByTestID(t *testing.T) {
	checkBody := func(body []byte) {
		if string(body) != `{"tests":"1,3,4,7"}` {
			t.Errorf(`expected {"tests":"1,3,4,7"}, got %v`, string(body))
		}
	}
	ts := newTestPostServer(checkBody)
	defer ts.Close()
	baseURL = ts.URL
	smartFolderID = 0
	siteID = 0
	testIDs = "1,3,4,7"
	createRun()
}
<|endoftext|>


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

package main

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strings"
	"testing"

	"github.com/ghodss/yaml"

	"istio.io/istio/istioctl/pkg/kubernetes"
	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pkg/version"
)

var meshInfo = version.MeshInfo{
	{"Pilot", version.BuildInfo{"1.0.0", "gitSHA123", "user1", "host1", "go1.10", "hub.docker.com", "Clean", "Tag"}},
	{"Injector", version.BuildInfo{"1.0.1", "gitSHAabc", "user2", "host2", "go1.10.1", "hub.docker.com", "Modified", "OtherTag"}},
	{"Citadel", version.BuildInfo{"1.2", "gitSHA321", "user3", "host3", "go1.11.0", "hub.docker.com", "Clean", "Tag"}},
}

type outputKind int

const (
	rawOutputMock outputKind = iota
	shortOutputMock
	jsonOutputMock
	yamlOutputMock
)

func printMeshVersion(kind outputKind) string {
	switch kind {
	case yamlOutputMock:
		ver := &version.Version{MeshVersion: &meshInfo}
		res, _ := yaml.Marshal(ver)
		return string(res)
	case jsonOutputMock:
		res, _ := json.MarshalIndent(&meshInfo, "", "  ")
		return string(res)
	}

	res := ""
	for _, info := range meshInfo {
		switch kind {
		case rawOutputMock:
			res += fmt.Sprintf("%s version: %#v\n", info.Component, info.Info)
		case shortOutputMock:
			res += fmt.Sprintf("%s version: %s\n", info.Component, info.Info.Version)
		}
	}
	return res
}

func TestVersion(t *testing.T) {
	clientExecFactory = mockExecClientVersionTest

	cases := []testCase{
		{ // case 0 client-side only, normal output
			configs: []model.Config{},
			args:    strings.Split("version --remote=false", " "),
			expectedRegexp: regexp.MustCompile("version.BuildInfo{Version:\"unknown\", GitRevision:\"unknown\", " +
				"User:\"unknown\", Host:\"unknown\", GolangVersion:\"go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\", DockerHub:\"unknown\", BuildStatus:\"unknown\", GitTag:\"unknown\"}"),
		},
		{ // case 1 client-side only, short output
			configs:        []model.Config{},
			args:           strings.Split("version -s --remote=false", " "),
			expectedOutput: "unknown\n",
		},
		{ // case 2 client-side only, yaml output
			configs: []model.Config{},
			args:    strings.Split("version --remote=false -o yaml", " "),
			expectedRegexp: regexp.MustCompile("clientVersion:\n" +
				"  golang_version: go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\n" +
				"  host: unknown\n" +
				"  hub: unknown\n" +
				"  revision: unknown\n" +
				"  status: unknown\n" +
				"  tag: unknown\n" +
				"  user: unknown\n" +
				"  version: unknown\n\n"),
		},
		{ // case 3 client-side only, json output
			configs: []model.Config{},
			args:    strings.Split("version --remote=false -o json", " "),
			expectedRegexp: regexp.MustCompile("{\n" +
				"  \"clientVersion\": {\n" +
				"    \"version\": \"unknown\",\n" +
				"    \"revision\": \"unknown\",\n" +
				"    \"user\": \"unknown\",\n" +
				"    \"host\": \"unknown\",\n" +
				"    \"golang_version\": \"go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\",\n" +
				"    \"hub\": \"unknown\",\n" +
				"    \"status\": \"unknown\",\n" +
				"    \"tag\": \"unknown\"\n" +
				"  }\n" +
				"}\n"),
		},

		{ // case 4 remote, normal output
			configs: []model.Config{},
			args:    strings.Split("version --remote=true --short=false --output=", " "),
			expectedRegexp: regexp.MustCompile("client version: version.BuildInfo{Version:\"unknown\", GitRevision:\"unknown\", " +
				"User:\"unknown\", Host:\"unknown\", GolangVersion:\"go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\", DockerHub:\"unknown\", BuildStatus:\"unknown\", GitTag:\"unknown\"}\n" +
				printMeshVersion(rawOutputMock)),
		},
		{ // case 5 remote, short output
			configs:        []model.Config{},
			args:           strings.Split("version --short=true --remote=true --output=", " "),
			expectedOutput: "client version: unknown\n" + printMeshVersion(shortOutputMock),
		},
		{ // case 6 remote, yaml output
			configs: []model.Config{},
			args:    strings.Split("version --remote=true -o yaml", " "),
			expectedRegexp: regexp.MustCompile("clientVersion:\n" +
				"  golang_version: go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\n" +
				"  host: unknown\n" +
				"  hub: unknown\n" +
				"  revision: unknown\n" +
				"  status: unknown\n" +
				"  tag: unknown\n" +
				"  user: unknown\n" +
				"  version: unknown\n" + printMeshVersion(yamlOutputMock)),
		},
		{ // case 7 remote, json output
			configs: []model.Config{},
			args:    strings.Split("version --remote=true -o json", " "),
			expectedRegexp: regexp.MustCompile("{\n" +
				"  \"clientVersion\": {\n" +
				"    \"version\": \"unknown\",\n" +
				"    \"revision\": \"unknown\",\n" +
				"    \"user\": \"unknown\",\n" +
				"    \"host\": \"unknown\",\n" +
				"    \"golang_version\": \"go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\",\n" +
				"    \"hub\": \"unknown\",\n" +
				"    \"status\": \"unknown\",\n" +
				"    \"tag\": \"unknown\"\n" +
				"  },\n" +
				printMeshVersion(jsonOutputMock)),
		},

		{ // case 8 bogus arg
			configs:        []model.Config{},
			args:           strings.Split("version --typo", " "),
			expectedOutput: "Error: unknown flag: --typo\n",
			wantException:  true,
		},

		{ // case 9 bogus output arg
			configs:        []model.Config{},
			args:           strings.Split("version --output xyz", " "),
			expectedOutput: "Error: --output must be 'yaml' or 'json'\n",
			wantException:  true,
		},
	}

	for i, c := range cases {
		t.Run(fmt.Sprintf("case %d %s", i, strings.Join(c.args, " ")), func(t *testing.T) {
			verifyOutput(t, c)
		})
	}
}

type mockExecVersionConfig struct {
}

func (client mockExecVersionConfig) AllPilotsDiscoveryDo(pilotNamespace, method, path string, body []byte) (map[string][]byte, error) {
	return nil, nil
}

func (client mockExecVersionConfig) EnvoyDo(podName, podNamespace, method, path string, body []byte) ([]byte, error) {
	return nil, nil
}

func (client mockExecVersionConfig) PilotDiscoveryDo(pilotNamespace, method, path string, body []byte) ([]byte, error) {
	return nil, nil
}

// nolint: unparam
func (client mockExecVersionConfig) GetIstioVersions(namespace string) (*version.MeshInfo, error) {
	return &meshInfo, nil
}

func mockExecClientVersionTest(kubeconfig, configContext string) (kubernetes.ExecClient, error) {
	return &mockExecVersionConfig{}, nil
}
<commit_msg>Fix line length lint issue<commit_after>// Copyright 2018 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"fmt"
	"regexp"
	"strings"
	"testing"

	"github.com/ghodss/yaml"

	"istio.io/istio/istioctl/pkg/kubernetes"
	"istio.io/istio/pilot/pkg/model"
	"istio.io/istio/pkg/version"
)

var meshInfo = version.MeshInfo{
	{"Pilot", version.BuildInfo{"1.0.0", "gitSHA123", "user1", "host1", "go1.10", "hub.docker.com", "Clean", "Tag"}},
	{"Injector", version.BuildInfo{"1.0.1", "gitSHAabc", "user2", "host2", "go1.10.1", "hub.docker.com", "Modified", "OtherTag"}},
	{"Citadel", version.BuildInfo{"1.2", "gitSHA321", "user3", "host3", "go1.11.0", "hub.docker.com", "Clean", "Tag"}},
}

type outputKind int

const (
	rawOutputMock outputKind = iota
	shortOutputMock
	jsonOutputMock
	yamlOutputMock
)

func printMeshVersion(kind outputKind) string {
	switch kind {
	case yamlOutputMock:
		ver := &version.Version{MeshVersion: &meshInfo}
		res, _ := yaml.Marshal(ver)
		return string(res)
	case jsonOutputMock:
		res, _ := json.MarshalIndent(&meshInfo, "", "  ")
		return string(res)
	}

	res := ""
	for _, info := range meshInfo {
		switch kind {
		case rawOutputMock:
			res += fmt.Sprintf("%s version: %#v\n", info.Component, info.Info)
		case shortOutputMock:
			res += fmt.Sprintf("%s version: %s\n", info.Component, info.Info.Version)
		}
	}
	return res
}

func TestVersion(t *testing.T) {
	clientExecFactory = mockExecClientVersionTest

	cases := []testCase{
		{ // case 0 client-side only, normal output
			configs: []model.Config{},
			args:    strings.Split("version --remote=false", " "),
			expectedRegexp: regexp.MustCompile("version.BuildInfo{Version:\"unknown\", GitRevision:\"unknown\", " +
				"User:\"unknown\", Host:\"unknown\", GolangVersion:\"go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\", " +
				"DockerHub:\"unknown\", BuildStatus:\"unknown\", GitTag:\"unknown\"}"),
		},
		{ // case 1 client-side only, short output
			configs:        []model.Config{},
			args:           strings.Split("version -s --remote=false", " "),
			expectedOutput: "unknown\n",
		},
		{ // case 2 client-side only, yaml output
			configs: []model.Config{},
			args:    strings.Split("version --remote=false -o yaml", " "),
			expectedRegexp: regexp.MustCompile("clientVersion:\n" +
				"  golang_version: go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\n" +
				"  host: unknown\n" +
				"  hub: unknown\n" +
				"  revision: unknown\n" +
				"  status: unknown\n" +
				"  tag: unknown\n" +
				"  user: unknown\n" +
				"  version: unknown\n\n"),
		},
		{ // case 3 client-side only, json output
			configs: []model.Config{},
			args:    strings.Split("version --remote=false -o json", " "),
			expectedRegexp: regexp.MustCompile("{\n" +
				"  \"clientVersion\": {\n" +
				"    \"version\": \"unknown\",\n" +
				"    \"revision\": \"unknown\",\n" +
				"    \"user\": \"unknown\",\n" +
				"    \"host\": \"unknown\",\n" +
				"    \"golang_version\": \"go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\",\n" +
				"    \"hub\": \"unknown\",\n" +
				"    \"status\": \"unknown\",\n" +
				"    \"tag\": \"unknown\"\n" +
				"  }\n" +
				"}\n"),
		},

		{ // case 4 remote, normal output
			configs: []model.Config{},
			args:    strings.Split("version --remote=true --short=false --output=", " "),
			expectedRegexp: regexp.MustCompile("client version: version.BuildInfo{Version:\"unknown\", GitRevision:\"unknown\", " +
				"User:\"unknown\", Host:\"unknown\", GolangVersion:\"go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\", " +
				"DockerHub:\"unknown\", BuildStatus:\"unknown\", GitTag:\"unknown\"}\n" +
				printMeshVersion(rawOutputMock)),
		},
		{ // case 5 remote, short output
			configs:        []model.Config{},
			args:           strings.Split("version --short=true --remote=true --output=", " "),
			expectedOutput: "client version: unknown\n" + printMeshVersion(shortOutputMock),
		},
		{ // case 6 remote, yaml output
			configs: []model.Config{},
			args:    strings.Split("version --remote=true -o yaml", " "),
			expectedRegexp: regexp.MustCompile("clientVersion:\n" +
				"  golang_version: go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\n" +
				"  host: unknown\n" +
				"  hub: unknown\n" +
				"  revision: unknown\n" +
				"  status: unknown\n" +
				"  tag: unknown\n" +
				"  user: unknown\n" +
				"  version: unknown\n" + printMeshVersion(yamlOutputMock)),
		},
		{ // case 7 remote, json output
			configs: []model.Config{},
			args:    strings.Split("version --remote=true -o json", " "),
			expectedRegexp: regexp.MustCompile("{\n" +
				"  \"clientVersion\": {\n" +
				"    \"version\": \"unknown\",\n" +
				"    \"revision\": \"unknown\",\n" +
				"    \"user\": \"unknown\",\n" +
				"    \"host\": \"unknown\",\n" +
				"    \"golang_version\": \"go1.([0-9+?(\\.)?]+)(rc[0-9]?)?\",\n" +
				"    \"hub\": \"unknown\",\n" +
				"    \"status\": \"unknown\",\n" +
				"    \"tag\": \"unknown\"\n" +
				"  },\n" +
				printMeshVersion(jsonOutputMock)),
		},

		{ // case 8 bogus arg
			configs:        []model.Config{},
			args:           strings.Split("version --typo", " "),
			expectedOutput: "Error: unknown flag: --typo\n",
			wantException:  true,
		},

		{ // case 9 bogus output arg
			configs:        []model.Config{},
			args:           strings.Split("version --output xyz", " "),
			expectedOutput: "Error: --output must be 'yaml' or 'json'\n",
			wantException:  true,
		},
	}

	for i, c := range cases {
		t.Run(fmt.Sprintf("case %d %s", i, strings.Join(c.args, " ")), func(t *testing.T) {
			verifyOutput(t, c)
		})
	}
}

type mockExecVersionConfig struct {
}

func (client mockExecVersionConfig) AllPilotsDiscoveryDo(pilotNamespace, method, path string, body []byte) (map[string][]byte, error) {
	return nil, nil
}

func (client mockExecVersionConfig) EnvoyDo(podName, podNamespace, method, path string, body []byte) ([]byte, error) {
	return nil, nil
}

func (client mockExecVersionConfig) PilotDiscoveryDo(pilotNamespace, method, path string, body []byte) ([]byte, error) {
	return nil, nil
}

// nolint: unparam
func (client mockExecVersionConfig) GetIstioVersions(namespace string) (*version.MeshInfo, error) {
	return &meshInfo, nil
}

func mockExecClientVersionTest(kubeconfig, configContext string) (kubernetes.ExecClient, error) {
	return &mockExecVersionConfig{}, nil
}
<|endoftext|>


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

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

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

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

package integration

import (
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"runtime"
	"testing"

	"github.com/docker/machine/libmachine/state"
	"github.com/pkg/errors"
	"k8s.io/minikube/test/integration/util"
)

func TestVersionUpgrade(t *testing.T) {
	currentRunner := NewMinikubeRunner(t)
	currentRunner.RunCommand("delete", true)
	currentRunner.CheckStatus(state.None.String())

	isoName := "minikube-linux-amd64"
	if runtime.GOOS == "darwin" {
		isoName = "minikube-darwin-amd64"
	} else if runtime.GOOS == "windows" {
		isoName = "minikube-windows-amd64.exe"
	}
	// Grab latest release binary
	url := "https://storage.googleapis.com/minikube/releases/latest/" + isoName
	resp, err := http.Get(url)
	if err != nil {
		t.Fatal(errors.Wrap(err, "Failed to get latest release binary"))
	}
	defer resp.Body.Close()

	iso, err := ioutil.TempFile("", isoName)
	if err != nil {
		t.Fatal(errors.Wrap(err, "Failed to create binary file"))
	}
	defer os.Remove(iso.Name())

	_, err = io.Copy(iso, resp.Body)
	if err != nil {
		t.Fatal(errors.Wrap(err, "Failed to populate iso file"))
	}
	if err := iso.Close(); err != nil {
		t.Fatal(errors.Wrap(err, "Failed to close iso"))
	}

	if runtime.GOOS != "windows" {
		if err := exec.Command("chmod", "+x", iso.Name()).Run(); err != nil {
			t.Fatal(errors.Wrap(err, "Failed to make binary executable."))
		}
	}

	latestRunner := util.MinikubeRunner{
		Args:       currentRunner.Args,
		BinaryPath: iso.Name(),
		StartArgs:  currentRunner.StartArgs,
		MountArgs:  currentRunner.MountArgs,
		T:          t,
	}
	latestRunner.Start()
	latestRunner.CheckStatus(state.Running.String())
	latestRunner.RunCommand("stop", true)
	latestRunner.CheckStatus(state.Stopped.String())

	currentRunner.Start()
	currentRunner.CheckStatus(state.Running.String())
	currentRunner.RunCommand("delete", true)
	currentRunner.CheckStatus(state.None.String())
}
<commit_msg>addressing comments<commit_after>/*
Copyright 2019 The Kubernetes Authors All rights reserved.

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

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

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

package integration

import (
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"runtime"
	"testing"

	"github.com/docker/machine/libmachine/state"
	"github.com/pkg/errors"
	pkgutil "k8s.io/minikube/pkg/util"
	"k8s.io/minikube/test/integration/util"
)

func TestVersionUpgrade(t *testing.T) {
	currentRunner := NewMinikubeRunner(t)
	currentRunner.RunCommand("delete", true)
	currentRunner.CheckStatus(state.None.String())

	// Grab latest release binary
	url := pkgutil.GetBinaryDownloadURL("latest", runtime.GOOS)
	resp, err := http.Get(url)
	if err != nil {
		t.Fatal(errors.Wrap(err, "Failed to get latest release binary"))
	}
	defer resp.Body.Close()

	tf, err := ioutil.TempFile("", "minikube")
	if err != nil {
		t.Fatal(errors.Wrap(err, "Failed to create binary file"))
	}
	defer os.Remove(tf.Name())

	_, err = io.Copy(tf, resp.Body)
	if err != nil {
		t.Fatal(errors.Wrap(err, "Failed to populate temp file"))
	}
	if err := tf.Close(); err != nil {
		t.Fatal(errors.Wrap(err, "Failed to close temp file"))
	}

	if runtime.GOOS != "windows" {
		if err := os.Chmod(tf.Name(), 0700); err != nil {
			t.Fatal(errors.Wrap(err, "Failed to make binary executable."))
		}
	}

	releaseRunner := util.MinikubeRunner{
		Args:       currentRunner.Args,
		BinaryPath: tf.Name(),
		StartArgs:  currentRunner.StartArgs,
		MountArgs:  currentRunner.MountArgs,
		T:          t,
	}
	releaseRunner.Start()
	releaseRunner.CheckStatus(state.Running.String())
	releaseRunner.RunCommand("stop", true)
	releaseRunner.CheckStatus(state.Stopped.String())

	currentRunner.Start()
	currentRunner.CheckStatus(state.Running.String())
	currentRunner.RunCommand("delete", true)
	currentRunner.CheckStatus(state.None.String())
}
<|endoftext|>