<commit_before>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package store

import (
	l4g "github.com/alecthomas/log4go"
	"github.com/mattermost/platform/model"
	"github.com/mattermost/platform/utils"
)

type SqlSessionStore struct {
	*SqlStore
}

func NewSqlSessionStore(sqlStore *SqlStore) SessionStore {
	us := &SqlSessionStore{sqlStore}

	for _, db := range sqlStore.GetAllConns() {
		table := db.AddTableWithName(model.Session{}, "Sessions").SetKeys(false, "Id")
		table.ColMap("Id").SetMaxSize(26)
		table.ColMap("Token").SetMaxSize(26)
		table.ColMap("UserId").SetMaxSize(26)
		table.ColMap("TeamId").SetMaxSize(26)
		table.ColMap("DeviceId").SetMaxSize(512)
		table.ColMap("Roles").SetMaxSize(64)
		table.ColMap("Props").SetMaxSize(1000)
	}

	return us
}

func (me SqlSessionStore) UpgradeSchemaIfNeeded() {
	// ADDED for 2.1 REMOVE for 2.5
	deviceIdLength := me.GetMaxLengthOfColumnIfExists("Sessions", "DeviceId")
	if len(deviceIdLength) > 0 && deviceIdLength != "512" {
		me.AlterColumnTypeIfExists("Sessions", "DeviceId", "VARCHAR(512)", "VARCHAR(512)")
	}
}

func (me SqlSessionStore) CreateIndexesIfNotExists() {
	me.CreateIndexIfNotExists("idx_sessions_user_id", "Sessions", "UserId")
	me.CreateIndexIfNotExists("idx_sessions_token", "Sessions", "Token")
}

func (me SqlSessionStore) Save(session *model.Session) StoreChannel {

	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		if len(session.Id) > 0 {
			result.Err = model.NewLocAppError("SqlSessionStore.Save", "store.sql_session.save.existing.app_error", nil, "id="+session.Id)
			storeChannel <- result
			close(storeChannel)
			return
		}

		session.PreSave()

		if cur := <-me.CleanUpExpiredSessions(session.UserId); cur.Err != nil {
			l4g.Error(utils.T("store.sql_session.save.cleanup.error"), cur.Err)
		}

		if err := me.GetMaster().Insert(session); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+err.Error())
		} else {
			result.Data = session
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) Get(sessionIdOrToken string) StoreChannel {

	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		var sessions []*model.Session

		if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE Token = :Token OR Id = :Id LIMIT 1", map[string]interface{}{"Token": sessionIdOrToken, "Id": sessionIdOrToken}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken+", "+err.Error())
		} else if sessions == nil || len(sessions) == 0 {
			result.Err = model.NewLocAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken)
		} else {
			result.Data = sessions[0]
		}

		storeChannel <- result
		close(storeChannel)

	}()

	return storeChannel
}

func (me SqlSessionStore) GetSessions(userId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {

		if cur := <-me.CleanUpExpiredSessions(userId); cur.Err != nil {
			l4g.Error(utils.T("store.sql_session.get_sessions.error"), cur.Err)
		}

		result := StoreResult{}

		var sessions []*model.Session

		if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE UserId = :UserId ORDER BY LastActivityAt DESC", map[string]interface{}{"UserId": userId}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, err.Error())
		} else {

			result.Data = sessions
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) Remove(sessionIdOrToken string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE Id = :Id Or Token = :Token", map[string]interface{}{"Id": sessionIdOrToken, "Token": sessionIdOrToken})
		if err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.RemoveSession", "store.sql_session.remove.app_error", nil, "id="+sessionIdOrToken+", err="+err.Error())
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) RemoveAllSessionsForTeam(teamId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId})
		if err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.RemoveAllSessionsForTeam", "store.sql_session.remove_all_sessions_for_team.app_error", nil, "id="+teamId+", err="+err.Error())
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) PermanentDeleteSessionsByUser(userId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
		if err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.RemoveAllSessionsForUser", "store.sql_session.permanent_delete_sessions_by_user.app_error", nil, "id="+userId+", err="+err.Error())
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) CleanUpExpiredSessions(userId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		if _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId AND ExpiresAt != 0 AND :ExpiresAt > ExpiresAt", map[string]interface{}{"UserId": userId, "ExpiresAt": model.GetMillis()}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.CleanUpExpiredSessions", "store.sql_session.cleanup_expired_sessions.app_error", nil, err.Error())
		} else {
			result.Data = userId
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) UpdateLastActivityAt(sessionId string, time int64) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		if _, err := me.GetMaster().Exec("UPDATE Sessions SET LastActivityAt = :LastActivityAt WHERE Id = :Id", map[string]interface{}{"LastActivityAt": time, "Id": sessionId}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.UpdateLastActivityAt", "store.sql_session.update_last_activity.app_error", nil, "sessionId="+sessionId)
		} else {
			result.Data = sessionId
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) UpdateRoles(userId, roles string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}
		if _, err := me.GetMaster().Exec("UPDATE Sessions SET Roles = :Roles WHERE UserId = :UserId", map[string]interface{}{"Roles": roles, "UserId": userId}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.UpdateRoles", "store.sql_session.update_roles.app_error", nil, "userId="+userId)
		} else {
			result.Data = userId
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) UpdateDeviceId(id, deviceId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}
		if _, err := me.GetMaster().Exec("UPDATE Sessions SET DeviceId = :DeviceId WHERE Id = :Id", map[string]interface{}{"DeviceId": deviceId, "Id": id}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, err.Error())
		} else {
			result.Data = deviceId
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) AnalyticsSessionCount(teamId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		query :=
			`SELECT
                COUNT(*)
            FROM
                Sessions`

		if len(teamId) > 0 {
			query += " WHERE TeamId = :TeamId"
		}

		if c, err := me.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.AnalyticsSessionCount", "store.sql_session.analytics_session_count.app_error", nil, err.Error())
		} else {
			result.Data = c
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}
<commit_msg>Don't count expired sessions<commit_after>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package store

import (
	l4g "github.com/alecthomas/log4go"
	"github.com/mattermost/platform/model"
	"github.com/mattermost/platform/utils"
)

type SqlSessionStore struct {
	*SqlStore
}

func NewSqlSessionStore(sqlStore *SqlStore) SessionStore {
	us := &SqlSessionStore{sqlStore}

	for _, db := range sqlStore.GetAllConns() {
		table := db.AddTableWithName(model.Session{}, "Sessions").SetKeys(false, "Id")
		table.ColMap("Id").SetMaxSize(26)
		table.ColMap("Token").SetMaxSize(26)
		table.ColMap("UserId").SetMaxSize(26)
		table.ColMap("TeamId").SetMaxSize(26)
		table.ColMap("DeviceId").SetMaxSize(512)
		table.ColMap("Roles").SetMaxSize(64)
		table.ColMap("Props").SetMaxSize(1000)
	}

	return us
}

func (me SqlSessionStore) UpgradeSchemaIfNeeded() {
	// ADDED for 2.1 REMOVE for 2.5
	deviceIdLength := me.GetMaxLengthOfColumnIfExists("Sessions", "DeviceId")
	if len(deviceIdLength) > 0 && deviceIdLength != "512" {
		me.AlterColumnTypeIfExists("Sessions", "DeviceId", "VARCHAR(512)", "VARCHAR(512)")
	}
}

func (me SqlSessionStore) CreateIndexesIfNotExists() {
	me.CreateIndexIfNotExists("idx_sessions_user_id", "Sessions", "UserId")
	me.CreateIndexIfNotExists("idx_sessions_token", "Sessions", "Token")
}

func (me SqlSessionStore) Save(session *model.Session) StoreChannel {

	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		if len(session.Id) > 0 {
			result.Err = model.NewLocAppError("SqlSessionStore.Save", "store.sql_session.save.existing.app_error", nil, "id="+session.Id)
			storeChannel <- result
			close(storeChannel)
			return
		}

		session.PreSave()

		if cur := <-me.CleanUpExpiredSessions(session.UserId); cur.Err != nil {
			l4g.Error(utils.T("store.sql_session.save.cleanup.error"), cur.Err)
		}

		if err := me.GetMaster().Insert(session); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+err.Error())
		} else {
			result.Data = session
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) Get(sessionIdOrToken string) StoreChannel {

	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		var sessions []*model.Session

		if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE Token = :Token OR Id = :Id LIMIT 1", map[string]interface{}{"Token": sessionIdOrToken, "Id": sessionIdOrToken}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken+", "+err.Error())
		} else if sessions == nil || len(sessions) == 0 {
			result.Err = model.NewLocAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken)
		} else {
			result.Data = sessions[0]
		}

		storeChannel <- result
		close(storeChannel)

	}()

	return storeChannel
}

func (me SqlSessionStore) GetSessions(userId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {

		if cur := <-me.CleanUpExpiredSessions(userId); cur.Err != nil {
			l4g.Error(utils.T("store.sql_session.get_sessions.error"), cur.Err)
		}

		result := StoreResult{}

		var sessions []*model.Session

		if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE UserId = :UserId ORDER BY LastActivityAt DESC", map[string]interface{}{"UserId": userId}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, err.Error())
		} else {

			result.Data = sessions
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) Remove(sessionIdOrToken string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE Id = :Id Or Token = :Token", map[string]interface{}{"Id": sessionIdOrToken, "Token": sessionIdOrToken})
		if err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.RemoveSession", "store.sql_session.remove.app_error", nil, "id="+sessionIdOrToken+", err="+err.Error())
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) RemoveAllSessionsForTeam(teamId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId})
		if err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.RemoveAllSessionsForTeam", "store.sql_session.remove_all_sessions_for_team.app_error", nil, "id="+teamId+", err="+err.Error())
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) PermanentDeleteSessionsByUser(userId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		_, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
		if err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.RemoveAllSessionsForUser", "store.sql_session.permanent_delete_sessions_by_user.app_error", nil, "id="+userId+", err="+err.Error())
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) CleanUpExpiredSessions(userId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		if _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId AND ExpiresAt != 0 AND :ExpiresAt > ExpiresAt", map[string]interface{}{"UserId": userId, "ExpiresAt": model.GetMillis()}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.CleanUpExpiredSessions", "store.sql_session.cleanup_expired_sessions.app_error", nil, err.Error())
		} else {
			result.Data = userId
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) UpdateLastActivityAt(sessionId string, time int64) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		if _, err := me.GetMaster().Exec("UPDATE Sessions SET LastActivityAt = :LastActivityAt WHERE Id = :Id", map[string]interface{}{"LastActivityAt": time, "Id": sessionId}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.UpdateLastActivityAt", "store.sql_session.update_last_activity.app_error", nil, "sessionId="+sessionId)
		} else {
			result.Data = sessionId
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) UpdateRoles(userId, roles string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}
		if _, err := me.GetMaster().Exec("UPDATE Sessions SET Roles = :Roles WHERE UserId = :UserId", map[string]interface{}{"Roles": roles, "UserId": userId}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.UpdateRoles", "store.sql_session.update_roles.app_error", nil, "userId="+userId)
		} else {
			result.Data = userId
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) UpdateDeviceId(id, deviceId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}
		if _, err := me.GetMaster().Exec("UPDATE Sessions SET DeviceId = :DeviceId WHERE Id = :Id", map[string]interface{}{"DeviceId": deviceId, "Id": id}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, err.Error())
		} else {
			result.Data = deviceId
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}

func (me SqlSessionStore) AnalyticsSessionCount(teamId string) StoreChannel {
	storeChannel := make(StoreChannel)

	go func() {
		result := StoreResult{}

		query :=
			`SELECT
                COUNT(*)
            FROM
                Sessions
            WHERE ExpiresAt > :Time`

		if len(teamId) > 0 {
			query += " AND TeamId = :TeamId"
		}

		if c, err := me.GetReplica().SelectInt(query, map[string]interface{}{"Time": model.GetMillis(), "TeamId": teamId}); err != nil {
			result.Err = model.NewLocAppError("SqlSessionStore.AnalyticsSessionCount", "store.sql_session.analytics_session_count.app_error", nil, err.Error())
		} else {
			result.Data = c
		}

		storeChannel <- result
		close(storeChannel)
	}()

	return storeChannel
}
<|endoftext|>


<commit_before>// Package ping tries to ping a HTTP server through different ways
// Connection, Session (Head), Get and Post
package ping

import (
	"crypto/tls"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"time"

	"github.com/mehrdadrad/mylg/cli"
)

// Ping represents HTTP ping request
type Ping struct {
	url           string
	host          string
	interval      time.Duration
	timeout       time.Duration
	count         int
	method        string
	uAgent        string
	proxy         *url.URL
	buf           string
	rAddr         net.Addr
	nsTime        time.Duration
	conn          net.Conn
	quiet         bool
	dCompress     bool
	kAlive        bool
	TLSSkipVerify bool
}

// Result holds Ping result
type Result struct {
	StatusCode int
	ConnTime   float64
	TotalTime  float64
	Size       int
	Proto      string
	Server     string
	Status     string
}

// NewPing validate and constructs request object
func NewPing(args string, cfg cli.Config) (*Ping, error) {
	URL, flag := cli.Flag(args)
	// help
	if _, ok := flag["help"]; ok || URL == "" {
		help(cfg)
		return nil, fmt.Errorf("")
	}
	URL = Normalize(URL)
	u, err := url.Parse(URL)
	if err != nil {
		return &Ping{}, fmt.Errorf("cannot parse url")
	}
	sTime := time.Now()
	ipAddr, err := net.ResolveIPAddr("ip", u.Host)
	if err != nil {
		return &Ping{}, fmt.Errorf("cannot resolve %s: Unknown host", u.Host)
	}

	p := &Ping{
		url:    URL,
		host:   u.Host,
		rAddr:  ipAddr,
		nsTime: time.Since(sTime),
	}

	// set count
	p.count = cli.SetFlag(flag, "c", cfg.Hping.Count).(int)
	// set interval
	interval := cli.SetFlag(flag, "i", "0s").(string)
	p.interval, err = time.ParseDuration(interval)
	if err != nil {
		return p, fmt.Errorf("Failed to parse config.hping.interval: %s. Correct syntax is <number>s/ms", err)
	}
	// set timeout
	timeout := cli.SetFlag(flag, "t", cfg.Hping.Timeout).(string)
	p.timeout, err = time.ParseDuration(timeout)
	if err != nil {
		return p, fmt.Errorf("Failed to parse config.hping.timeout: %s. Correct syntax is <number>s/ms", err)
	}
	// set user agent
	p.uAgent = cli.SetFlag(flag, "u", "myLG (http://mylg.io)").(string)
	// set method
	p.method = cli.SetFlag(flag, "m", cfg.Hping.Method).(string)
	p.method = strings.ToUpper(p.method)
	// disable compression
	p.dCompress = cli.SetFlag(flag, "dc", false).(bool)
	// keep alive
	p.kAlive = cli.SetFlag(flag, "k", false).(bool)
	//  TLS skip verify
	p.TLSSkipVerify = cli.SetFlag(flag, "nc", false).(bool)
	// make quiet
	p.quiet = cli.SetFlag(flag, "q", false).(bool)
	// set proxy
	proxy := cli.SetFlag(flag, "p", "").(string)
	if pURL, err := url.Parse(proxy); err == nil {
		p.proxy = pURL
	} else {
		return p, fmt.Errorf("Failed to parse proxy url: %v", err)
	}
	// set buff (post)
	buf := cli.SetFlag(flag, "d", "mylg").(string)
	p.buf = buf
	return p, nil
}

// Normalize fixes scheme
func Normalize(URL string) string {
	re := regexp.MustCompile(`(?i)https{0,1}://`)
	if !re.MatchString(URL) {
		URL = fmt.Sprintf("http://%s", URL)
	}
	return URL
}

// Run tries to ping w/ pretty print
func (p *Ping) Run() {
	if p.method != "GET" && p.method != "POST" && p.method != "HEAD" {
		fmt.Printf("Error: Method '%s' not recognized.\n", p.method)
		return
	}
	var (
		sigCh = make(chan os.Signal, 1)
		c     = make(map[int]float64, 10)
		s     []float64
	)
	// capture interrupt w/ s channel
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	pStrPrefix := "HTTP Response seq=%d, "
	pStrSuffix := "proto=%s, status=%d, size=%d Bytes, time=%.3f ms\n"
	pStrSuffixHead := "proto=%s, status=%d, time=%.3f ms\n"
	fmt.Printf("HPING %s (%s), Method: %s, DNSLookup: %.4f ms\n", p.host, p.rAddr, p.method, p.nsTime.Seconds()*1000)

LOOP:
	for i := 0; i < p.count; i++ {
		if r, err := p.Ping(); err == nil {
			if !p.quiet {
				if p.method != "HEAD" {
					fmt.Printf(pStrPrefix+pStrSuffix, i, r.Proto, r.StatusCode, r.Size, r.TotalTime*1000)
				} else {
					fmt.Printf(pStrPrefix+pStrSuffixHead, i, r.Proto, r.StatusCode, r.TotalTime*1000)
				}
			} else {
				fmt.Printf(".")
			}
			c[r.StatusCode]++
			s = append(s, r.TotalTime*1000)
		} else {
			c[-1]++
			if !p.quiet {
				errmsg := strings.Split(err.Error(), ": ")
				fmt.Printf(pStrPrefix+"%s\n", i, errmsg[len(errmsg)-1])
			} else {
				fmt.Printf("!")
			}
		}
		select {
		case <-sigCh:
			break LOOP
		default:
		}
		time.Sleep(p.interval)
	}
	// print statistics
	printStats(c, s, p.host)
}

// printStats prints out the footer
func printStats(c map[int]float64, s []float64, host string) {
	var r = make(map[string]float64, 5)

	// total replied requests
	for k, v := range c {
		if k < 0 {
			continue
		}
		r["sum"] += v
	}

	for _, v := range s {
		// maximum
		if r["max"] < v {
			r["max"] = v
		}
		// minimum
		if r["min"] > v || r["min"] == 0 {
			r["min"] = v
		}
		// average
		if r["avg"] == 0 {
			r["avg"] = v
		} else {
			r["avg"] = (r["avg"] + v) / 2
		}
	}

	totalReq := r["sum"] + c[-1]
	failPct := 100 - (100*r["sum"])/totalReq

	fmt.Printf("\n--- %s HTTP ping statistics --- \n", host)
	fmt.Printf("%.0f requests transmitted, %.0f replies received, %.0f%% requests failed\n", totalReq, r["sum"], failPct)
	fmt.Printf("HTTP Round-trip min/avg/max = %.2f/%.2f/%.2f ms\n", r["min"], r["avg"], r["max"])
	for k, v := range c {
		if k < 0 {
			continue
		}
		progress := fmt.Sprintf("%-20s", strings.Repeat("\u2588", int(v*100/(totalReq)/5)))
		fmt.Printf("HTTP Code [%d] responses : [%s] %.2f%% \n", k, progress, v*100/(totalReq))
	}
}

// Ping tries to ping a web server through http
func (p *Ping) Ping() (Result, error) {
	var (
		r     Result
		sTime time.Time
		resp  *http.Response
		req   *http.Request
		err   error
	)

	tr := &http.Transport{
		DisableKeepAlives:  !p.kAlive,
		DisableCompression: p.dCompress,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: p.TLSSkipVerify,
		},
	}

	if p.proxy.String() != "" {
		tr.Proxy = http.ProxyURL(p.proxy)
	}

	client := &http.Client{
		Timeout:   p.timeout,
		Transport: tr,
	}

	sTime = time.Now()

	if p.method == "POST" {
		r.Size = len(p.buf)
		reader := strings.NewReader(p.buf)
		req, err = http.NewRequest(p.method, p.url, reader)
	} else {
		req, err = http.NewRequest(p.method, p.url, nil)
	}

	if err != nil {
		return r, err
	}

	req.Header.Add("User-Agent", p.uAgent)

	resp, err = client.Do(req)

	if err != nil {
		return r, err
	}
	defer resp.Body.Close()

	r.TotalTime = time.Since(sTime).Seconds()

	if p.method == "GET" {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return r, err
		}
		r.Size = len(body)
	} else {
		io.Copy(ioutil.Discard, resp.Body)
	}

	r.StatusCode = resp.StatusCode
	r.Proto = resp.Proto
	return r, nil
}

// help shows ping help
func help(cfg cli.Config) {
	fmt.Printf(`
    usage:
          hping url [options]

    options:
          -c   count        Send 'count' requests (default: %d)
          -t   timeout      Set a time limit for requests in ms/s (default is %s)
          -i   interval     Set a wait time between sending each request in ms/s
          -m   method       HTTP methods: GET/POST/HEAD (default: %s)
          -d   data         Sending the given data (text/json) (default: "%s")
          -p   proxy server Set proxy http://url:port
          -u   user agenet  Set user agent
          -q                Quiet reqular output
          -k                Enable keep alive
          -dc               Disable compression
          -nc               Don’t check the server certificate
		  `,
		cfg.Hping.Count,
		cfg.Hping.Timeout,
		cfg.Hping.Method,
		cfg.Hping.Data)
}
<commit_msg>add http trace, optimize code<commit_after>// Package ping tries to ping a HTTP server through different ways
// Connection, Session (Head), Get and Post
package ping

import (
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httptrace"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"time"

	"github.com/mehrdadrad/mylg/cli"
)

var stdout *os.File

// Ping represents HTTP ping request
type Ping struct {
	url           string
	host          string
	interval      time.Duration
	timeout       time.Duration
	count         int
	method        string
	uAgent        string
	proxy         *url.URL
	buf           string
	rAddr         net.Addr
	nsTime        time.Duration
	conn          net.Conn
	quiet         bool
	dCompress     bool
	kAlive        bool
	TLSSkipVerify bool
	tracerEnabled bool
	fmtJSON       bool
}

// Result holds Ping result
type Result struct {
	StatusCode int
	ConnTime   float64
	TotalTime  float64
	Size       int
	Proto      string
	Server     string
	Status     string
}

// NewPing validate and constructs request object
func NewPing(args string, cfg cli.Config) (*Ping, error) {
	URL, flag := cli.Flag(args)
	// help
	if _, ok := flag["help"]; ok || URL == "" {
		help(cfg)
		return nil, fmt.Errorf("")
	}
	URL = Normalize(URL)
	u, err := url.Parse(URL)
	if err != nil {
		return &Ping{}, fmt.Errorf("cannot parse url")
	}
	sTime := time.Now()
	ipAddr, err := net.ResolveIPAddr("ip", u.Host)
	if err != nil {
		return &Ping{}, fmt.Errorf("cannot resolve %s: Unknown host", u.Host)
	}

	p := &Ping{
		url:           URL,
		host:          u.Host,
		rAddr:         ipAddr,
		count:         cli.SetFlag(flag, "c", cfg.Hping.Count).(int),
		tracerEnabled: cli.SetFlag(flag, "trace", false).(bool),
		fmtJSON:       cli.SetFlag(flag, "json", false).(bool),
		uAgent:        cli.SetFlag(flag, "u", "myLG (http://mylg.io)").(string),
		dCompress:     cli.SetFlag(flag, "dc", false).(bool),
		kAlive:        cli.SetFlag(flag, "k", false).(bool),
		TLSSkipVerify: cli.SetFlag(flag, "nc", false).(bool),
		quiet:         cli.SetFlag(flag, "q", false).(bool),
		nsTime:        time.Since(sTime),
	}

	// set interval
	interval := cli.SetFlag(flag, "i", "0s").(string)
	p.interval, err = time.ParseDuration(interval)
	if err != nil {
		return p, fmt.Errorf("Failed to parse interval: %s. Correct syntax is <number>s/ms", err)
	}
	// set timeout
	timeout := cli.SetFlag(flag, "t", cfg.Hping.Timeout).(string)
	p.timeout, err = time.ParseDuration(timeout)
	if err != nil {
		return p, fmt.Errorf("Failed to parse timeout: %s. Correct syntax is <number>s/ms", err)
	}
	// set method
	p.method = cli.SetFlag(flag, "m", cfg.Hping.Method).(string)
	p.method = strings.ToUpper(p.method)
	// set proxy
	proxy := cli.SetFlag(flag, "p", "").(string)
	if pURL, err := url.Parse(proxy); err == nil {
		p.proxy = pURL
	} else {
		return p, fmt.Errorf("Failed to parse proxy url: %v", err)
	}
	// set buff (post)
	buf := cli.SetFlag(flag, "d", "mylg").(string)
	p.buf = buf

	if p.fmtJSON {
		muteStdout()
	}

	return p, nil
}

// Normalize fixes scheme
func Normalize(URL string) string {
	re := regexp.MustCompile(`(?i)https{0,1}://`)
	if !re.MatchString(URL) {
		URL = fmt.Sprintf("http://%s", URL)
	}
	return URL
}

// Run tries to ping w/ pretty print
func (p *Ping) Run() {
	if p.method != "GET" && p.method != "POST" && p.method != "HEAD" {
		fmt.Printf("Error: Method '%s' not recognized.\n", p.method)
		return
	}
	var (
		sigCh = make(chan os.Signal, 1)
		c     = make(map[int]float64, 10)
		s     []float64
	)
	// capture interrupt w/ s channel
	signal.Notify(sigCh, os.Interrupt)
	defer signal.Stop(sigCh)

	pStrPrefix := "HTTP Response seq=%d, "
	pStrSuffix := "proto=%s, status=%d, size=%d Bytes, time=%.3f ms\n"
	pStrSuffixHead := "proto=%s, status=%d, time=%.3f ms\n"
	fmt.Printf("HPING %s (%s), Method: %s, DNSLookup: %.4f ms\n", p.host, p.rAddr, p.method, p.nsTime.Seconds()*1e3)

LOOP:
	for i := 0; i < p.count; i++ {
		if r, err := p.Ping(); err == nil {
			if !p.quiet {
				if p.method != "HEAD" {
					fmt.Printf(pStrPrefix+pStrSuffix, i, r.Proto, r.StatusCode, r.Size, r.TotalTime*1e3)
				} else {
					fmt.Printf(pStrPrefix+pStrSuffixHead, i, r.Proto, r.StatusCode, r.TotalTime*1e3)
				}
			} else {
				fmt.Printf(".")
			}
			c[r.StatusCode]++
			s = append(s, r.TotalTime*1e3)
		} else {
			c[-1]++
			if !p.quiet {
				errmsg := strings.Split(err.Error(), ": ")
				fmt.Printf(pStrPrefix+"%s\n", i, errmsg[len(errmsg)-1])
			} else {
				fmt.Printf("!")
			}
		}
		select {
		case <-sigCh:
			break LOOP
		default:
		}
		time.Sleep(p.interval)
	}

	// print statistics
	if p.fmtJSON {
		unMuteStdout()
		p.printStatsJSON(c, s)
	} else {
		p.printStats(c, s)
	}
}

// printStats prints out the footer
func (p *Ping) printStats(c map[int]float64, s []float64) {

	r := calcStats(c, s)

	totalReq := r["sum"] + c[-1]
	failPct := 100 - (100*r["sum"])/totalReq

	fmt.Printf("\n--- %s HTTP ping statistics --- \n", p.host)
	fmt.Printf("%.0f requests transmitted, %.0f replies received, %.0f%% requests failed\n", totalReq, r["sum"], failPct)
	fmt.Printf("HTTP Round-trip min/avg/max = %.2f/%.2f/%.2f ms\n", r["min"], r["avg"], r["max"])
	for k, v := range c {
		if k < 0 {
			continue
		}
		progress := fmt.Sprintf("%-20s", strings.Repeat("\u2588", int(v*100/(totalReq)/5)))
		fmt.Printf("HTTP Code [%d] responses : [%s] %.2f%% \n", k, progress, v*100/(totalReq))
	}
}

// printStats prints out in json format
func (p *Ping) printStatsJSON(c map[int]float64, s []float64) {
	var statusCode = make(map[int]float64, 10)

	r := calcStats(c, s)

	totalReq := r["sum"] + c[-1]
	failPct := 100 - (100*r["sum"])/totalReq

	for k, v := range c {
		if k < 0 {
			continue
		}
		statusCode[k] = v * 100 / (totalReq)
	}

	trace := struct {
		Host      string  `json:"host"`
		DNSLookup float64 `json:"dnslookup"`
		Count     int     `json:"count"`

		Min float64 `json:"min"`
		Avg float64 `json:"avg"`
		Max float64 `json:"max"`

		Failure     float64         `json:"failure"`
		StatusCodes map[int]float64 `json:"statuscodes"`
	}{
		p.host,
		p.nsTime.Seconds() * 1e3,
		p.count,

		r["min"],
		r["avg"],
		r["max"],

		failPct,
		statusCode,
	}

	b, err := json.Marshal(trace)
	if err != nil {

	}

	fmt.Println(string(b))
}

// Ping tries to ping a web server through http
func (p *Ping) Ping() (Result, error) {
	var (
		r     Result
		sTime time.Time
		resp  *http.Response
		req   *http.Request
		err   error
	)

	tr := &http.Transport{
		DisableKeepAlives:  !p.kAlive,
		DisableCompression: p.dCompress,
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: p.TLSSkipVerify,
		},
	}

	if p.proxy.String() != "" {
		tr.Proxy = http.ProxyURL(p.proxy)
	}

	client := &http.Client{
		Timeout:   p.timeout,
		Transport: tr,
	}

	sTime = time.Now()

	if p.method == "POST" {
		r.Size = len(p.buf)
		reader := strings.NewReader(p.buf)
		req, err = http.NewRequest(p.method, p.url, reader)
	} else {
		req, err = http.NewRequest(p.method, p.url, nil)
	}

	if err != nil {
		return r, err
	}

	// customized header
	req.Header.Add("User-Agent", p.uAgent)
	// context, tracert
	if p.tracerEnabled && !p.quiet {
		req = req.WithContext(httptrace.WithClientTrace(req.Context(), tracer()))
	}
	resp, err = client.Do(req)

	if err != nil {
		return r, err
	}
	defer resp.Body.Close()

	r.TotalTime = time.Since(sTime).Seconds()

	if p.method == "GET" {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return r, err
		}
		r.Size = len(body)
	} else {
		io.Copy(ioutil.Discard, resp.Body)
	}

	r.StatusCode = resp.StatusCode
	r.Proto = resp.Proto
	return r, nil
}

func tracer() *httptrace.ClientTrace {
	var (
		begin   = time.Now()
		elapsed time.Duration
	)

	return &httptrace.ClientTrace{
		ConnectDone: func(network, addr string, err error) {
			elapsed = time.Since(begin)
			begin = time.Now()
			fmt.Printf("# connection completed to %s in %.3f ms\n", addr, elapsed.Seconds()*1e3)
		},
		GotFirstResponseByte: func() {
			elapsed = time.Since(begin)
			begin = time.Now()
			fmt.Printf("# read first byte in %.3f ms\n", elapsed.Seconds()*1e3)
		},
	}
}

func calcStats(c map[int]float64, s []float64) map[string]float64 {
	var r = make(map[string]float64, 5)

	// total replied requests
	for k, v := range c {
		if k < 0 {
			continue
		}
		r["sum"] += v
	}

	for _, v := range s {
		// maximum
		if r["max"] < v {
			r["max"] = v
		}
		// minimum
		if r["min"] > v || r["min"] == 0 {
			r["min"] = v
		}
		// average
		if r["avg"] == 0 {
			r["avg"] = v
		} else {
			r["avg"] = (r["avg"] + v) / 2
		}
	}
	return r
}

func muteStdout() {
	stdout = os.Stdout
	_, w, _ := os.Pipe()
	os.Stdout = w
}

func unMuteStdout() {
	os.Stdout = stdout
}

// help shows ping help
func help(cfg cli.Config) {
	fmt.Printf(`
    usage:
          hping url [options]

    options:
          -c   count        Send 'count' requests (default: %d)
          -t   timeout      Set a time limit for requests in ms/s (default is %s)
          -i   interval     Set a wait time between sending each request in ms/s
          -m   method       HTTP methods: GET/POST/HEAD (default: %s)
          -d   data         Sending the given data (text/json) (default: "%s")
          -p   proxy server Set proxy http://url:port
          -u   user agent   Set user agent
          -q                Quiet reqular output
          -k                Enable keep alive
          -dc               Disable compression
          -nc               Don’t check the server certificate
          -trace            Provides the events within client requests
          -json             Export statistics as json format
		  `,
		cfg.Hping.Count,
		cfg.Hping.Timeout,
		cfg.Hping.Method,
		cfg.Hping.Data)
}
<|endoftext|>


<commit_before>// Copyright 2018 The go-hep 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 rdict

import (
	"fmt"
	"sort"
	"sync"

	"go-hep.org/x/hep/groot/rbytes"
)

// Streamers stores all the streamers available at runtime.
var Streamers = &streamerDb{
	db: make(map[streamerDbKey]rbytes.StreamerInfo),
}

type streamerDbKey struct {
	class   string
	version int
}

type streamerDb struct {
	sync.RWMutex
	db map[streamerDbKey]rbytes.StreamerInfo
}

func (db *streamerDb) Get(class string, vers int) (rbytes.StreamerInfo, bool) {
	db.RLock()
	defer db.RUnlock()
	switch {
	case vers < 0:
		var slice []rbytes.StreamerInfo
		for k, v := range db.db {
			if k.class == class {
				slice = append(slice, v)
			}
		}
		if len(slice) == 0 {
			return nil, false
		}
		sort.Slice(slice, func(i, j int) bool {
			return slice[i].ClassVersion() < slice[j].ClassVersion()
		})
		return slice[len(slice)-1], true
	default:
		key := streamerDbKey{
			class:   class,
			version: vers,
		}

		streamer, ok := db.db[key]
		if !ok {
			return nil, false
		}
		return streamer, true
	}
}

// FIXME(sbinet): ROOT changed its checksum behaviour at some point.
// our reference ROOT files have been caught in the middle of this migration.
// disable the check for duplicate streamers with different checksums for now.
const checkdups = false

func (db *streamerDb) Add(streamer rbytes.StreamerInfo) {
	db.Lock()
	defer db.Unlock()

	key := streamerDbKey{
		class:   streamer.Name(),
		version: streamer.ClassVersion(),
	}

	if checkdups {
		old, dup := db.db[key]
		if dup {
			if old.CheckSum() != streamer.CheckSum() {
				panic(fmt.Errorf("rdict: StreamerInfo class=%q version=%d with checksum=%d (got checksum=%d)",
					streamer.Name(), streamer.ClassVersion(), streamer.CheckSum(), old.CheckSum(),
				))
			}
			return
		}
	}

	db.db[key] = streamer
}
<commit_msg>groot/rdict: make streamerDb implement StreamerInfoContext<commit_after>// Copyright 2018 The go-hep 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 rdict

import (
	"fmt"
	"sort"
	"sync"

	"github.com/pkg/errors"
	"go-hep.org/x/hep/groot/rbytes"
)

// Streamers stores all the streamers available at runtime.
var Streamers = &streamerDb{
	db: make(map[streamerDbKey]rbytes.StreamerInfo),
}

type streamerDbKey struct {
	class   string
	version int
}

type streamerDb struct {
	sync.RWMutex
	db map[streamerDbKey]rbytes.StreamerInfo
}

func (db *streamerDb) StreamerInfo(name string, vers int) (rbytes.StreamerInfo, error) {
	si, ok := db.Get(name, vers)
	if !ok {
		return nil, errors.Errorf("rdict: no streamer for %q", name)
	}
	return si, nil
}

func (db *streamerDb) Get(class string, vers int) (rbytes.StreamerInfo, bool) {
	db.RLock()
	defer db.RUnlock()
	switch {
	case vers < 0:
		var slice []rbytes.StreamerInfo
		for k, v := range db.db {
			if k.class == class {
				slice = append(slice, v)
			}
		}
		if len(slice) == 0 {
			return nil, false
		}
		sort.Slice(slice, func(i, j int) bool {
			return slice[i].ClassVersion() < slice[j].ClassVersion()
		})
		return slice[len(slice)-1], true
	default:
		key := streamerDbKey{
			class:   class,
			version: vers,
		}

		streamer, ok := db.db[key]
		if !ok {
			return nil, false
		}
		return streamer, true
	}
}

// FIXME(sbinet): ROOT changed its checksum behaviour at some point.
// our reference ROOT files have been caught in the middle of this migration.
// disable the check for duplicate streamers with different checksums for now.
const checkdups = false

func (db *streamerDb) Add(streamer rbytes.StreamerInfo) {
	db.Lock()
	defer db.Unlock()

	key := streamerDbKey{
		class:   streamer.Name(),
		version: streamer.ClassVersion(),
	}

	if checkdups {
		old, dup := db.db[key]
		if dup {
			if old.CheckSum() != streamer.CheckSum() {
				panic(fmt.Errorf("rdict: StreamerInfo class=%q version=%d with checksum=%d (got checksum=%d)",
					streamer.Name(), streamer.ClassVersion(), streamer.CheckSum(), old.CheckSum(),
				))
			}
			return
		}
	}

	db.db[key] = streamer
}

var (
	_ rbytes.StreamerInfoContext = (*streamerDb)(nil)
)
<|endoftext|>


<commit_before>package gruff

import (
	"github.com/google/uuid"
)

const ARGUMENT_TYPE_PRO_TRUTH int = 1
const ARGUMENT_TYPE_CON_TRUTH int = 2
const ARGUMENT_TYPE_PRO_RELEVANCE int = 3
const ARGUMENT_TYPE_CON_RELEVANCE int = 4
const ARGUMENT_TYPE_PRO_IMPACT int = 5
const ARGUMENT_TYPE_CON_IMPACT int = 6

/*
  An Argument connects a Claim to another Claim or Argument
  That is:
     a Claim can be used as an ARGUMENT to either prove or disprove the truth of a claim,
     or to modify the relevance or impact of another argument.

  The TYPE of the argument indicates how the claim (or CLAIM) is being used:
    PRO TRUTH: The Claim is a claim that is being used to prove the truth of another claim
      Ex: "The defendant was in Cincinatti on the date of the murder"
    CON TRUTH: The Claim is used as evidence against another claim
      Ex: "The defendant was hospitalized on the date of the murder"
    PRO RELEVANCE: The Claim is being used to show that another Argument is relevant
      Ex: "The murder occurred in Cincinatti"
    CON RELEVANCE: The Claim is being used to show that another Argument is irrelevant
      Ex: "The murder occurred in the same hospital in which the defendant was hospitalized"
    PRO IMPACT: The Claim is being used to show the importance of another Argument
      Ex: "This argument clearly shows that the defendant has no alibi"
    CON IMPACT: The Claim is being used to diminish the importance of another argument
      Ex: "There is no evidence that the defendant ever left their room"

  A quick explanation of the fields:
    Claim: The Debate (or claim) that is being used as an argument
    Target Claim: The "parent" Claim against which a pro/con truth argument is being made
    Target Argument: In the case of a relevance or impact argument, the argument to which it refers
*/
type Argument struct {
	Identifier
	TargetClaimID    *NullableUUID `json:"targetClaimId,omitempty" sql:"type:uuid"`
	TargetClaim      *Claim        `json:"targetClaim,omitempty"`
	TargetArgumentID *NullableUUID `json:"targetArgId,omitempty" sql:"type:uuid"`
	TargetArgument   *Argument     `json:"targetArg,omitempty"`
	ClaimID          uuid.UUID     `json:"claimId" sql:"type:uuid;not null"`
	Claim            *Claim        `json:"claim,omitempty"`
	Title            string        `json:"title" sql:"not null" valid:"length(3|1000),required"`
	Description      string        `json:"desc" valid:"length(3|4000)"`
	Type             int           `json:"type" sql:"not null"`
	Relevance        float64       `json:"relevance"`
	Impact           float64       `json:"impact"`
	ProRelevance     []Argument    `json:"prorelev,omitempty"`
	ConRelevance     []Argument    `json:"conrelev,omitempty"`
	ProImpact        []Argument    `json:"proimpact,omitempty"`
	ConImpact        []Argument    `json:"conimpact,omitempty"`
}

func (a Argument) ValidateForCreate() GruffError {
	err := a.ValidateField("Title")
	if err != nil {
		return err
	}
	err = a.ValidateField("Description")
	if err != nil {
		return err
	}
	err = a.ValidateField("Type")
	if err != nil {
		return err
	}
	err = a.ValidateIDs()
	if err != nil {
		return err
	}
	err = a.ValidateType()
	if err != nil {
		return err
	}
	return nil
}

func (a Argument) ValidateForUpdate() GruffError {
	return a.ValidateForCreate()
}

func (a Argument) ValidateField(f string) GruffError {
	err := ValidateStructField(a, f)
	return err
}

func (a Argument) ValidateIDs() GruffError {
	if a.ClaimID == uuid.Nil {
		return NewBusinessError("ClaimID: non zero value required;")
	}
	if (a.TargetClaimID == nil || a.TargetClaimID.UUID == uuid.Nil) &&
		(a.TargetArgumentID == nil || a.TargetArgumentID.UUID == uuid.Nil) {
		return NewBusinessError("An Argument must have a target Claim or target Argument ID")
	}
	if a.TargetClaimID != nil && a.TargetArgumentID != nil {
		return NewBusinessError("An Argument can have only one target Claim or target Argument ID")

	}
	return nil
}

func (a Argument) ValidateType() GruffError {
	switch a.Type {
	case ARGUMENT_TYPE_PRO_TRUTH, ARGUMENT_TYPE_CON_TRUTH:
		if a.TargetClaimID == nil || a.TargetClaimID.UUID == uuid.Nil {
			return NewBusinessError("A pro or con truth argument must refer to a target claim")
		}
	case ARGUMENT_TYPE_PRO_RELEVANCE,
		ARGUMENT_TYPE_CON_RELEVANCE,
		ARGUMENT_TYPE_PRO_IMPACT,
		ARGUMENT_TYPE_CON_IMPACT:
		if a.TargetArgumentID == nil || a.TargetArgumentID.UUID == uuid.Nil {
			return NewBusinessError("An impact or relevance argument must refer to a target argument")
		}
	default:
		return NewBusinessError("Type: invalid;")
	}
	return nil
}
<commit_msg>Just added a comment to help explain impact vs relevance<commit_after>package gruff

import (
	"github.com/google/uuid"
)

const ARGUMENT_TYPE_PRO_TRUTH int = 1
const ARGUMENT_TYPE_CON_TRUTH int = 2
const ARGUMENT_TYPE_PRO_RELEVANCE int = 3
const ARGUMENT_TYPE_CON_RELEVANCE int = 4
const ARGUMENT_TYPE_PRO_IMPACT int = 5
const ARGUMENT_TYPE_CON_IMPACT int = 6

/*
  An Argument connects a Claim to another Claim or Argument
  That is:
     a Claim can be used as an ARGUMENT to either prove or disprove the truth of a claim,
     or to modify the relevance or impact of another argument.

  The TYPE of the argument indicates how the claim (or CLAIM) is being used:
    PRO TRUTH: The Claim is a claim that is being used to prove the truth of another claim
      Ex: "The defendant was in Cincinatti on the date of the murder"
    CON TRUTH: The Claim is used as evidence against another claim
      Ex: "The defendant was hospitalized on the date of the murder"
    PRO RELEVANCE: The Claim is being used to show that another Argument is relevant
      Ex: "The murder occurred in Cincinatti"
    CON RELEVANCE: The Claim is being used to show that another Argument is irrelevant
      Ex: "The murder occurred in the same hospital in which the defendant was hospitalized"
    PRO IMPACT: The Claim is being used to show the importance of another Argument
      Ex: "This argument clearly shows that the defendant has no alibi"
    CON IMPACT: The Claim is being used to diminish the importance of another argument
      Ex: "There is no evidence that the defendant ever left their room"

  A quick explanation of the fields:
    Claim: The Debate (or claim) that is being used as an argument
    Target Claim: The "parent" Claim against which a pro/con truth argument is being made
    Target Argument: In the case of a relevance or impact argument, the argument to which it refers

  To help understand the difference between relevance and impact arguments, imagine an argument is a bullet:
    Impact is the size of your bullet
    Relevance is how well you hit your target

  Scoring:
    Truth: 1.0 = definitely true; 0.5 = equal chance true or false; 0.0 = definitely false. "The world is flat" should have a 0.000000000000000001 truth score.
    Impact: 1.0 = This argument is definitely the most important argument for this side - no need to read any others; 0.5 = This is one more argument to consider; 0.01 = Probably not even worth including in the discussion
    Relevance: 1.0 = Completely germaine and on-topic; 0.5 = Circumstantial or somewhat relevant; 0.01 = Totally off-point, should be ignored

*/
type Argument struct {
	Identifier
	TargetClaimID    *NullableUUID `json:"targetClaimId,omitempty" sql:"type:uuid"`
	TargetClaim      *Claim        `json:"targetClaim,omitempty"`
	TargetArgumentID *NullableUUID `json:"targetArgId,omitempty" sql:"type:uuid"`
	TargetArgument   *Argument     `json:"targetArg,omitempty"`
	ClaimID          uuid.UUID     `json:"claimId" sql:"type:uuid;not null"`
	Claim            *Claim        `json:"claim,omitempty"`
	Title            string        `json:"title" sql:"not null" valid:"length(3|1000),required"`
	Description      string        `json:"desc" valid:"length(3|4000)"`
	Type             int           `json:"type" sql:"not null"`
	Relevance        float64       `json:"relevance"`
	Impact           float64       `json:"impact"`
	ProRelevance     []Argument    `json:"prorelev,omitempty"`
	ConRelevance     []Argument    `json:"conrelev,omitempty"`
	ProImpact        []Argument    `json:"proimpact,omitempty"`
	ConImpact        []Argument    `json:"conimpact,omitempty"`
}

func (a Argument) ValidateForCreate() GruffError {
	err := a.ValidateField("Title")
	if err != nil {
		return err
	}
	err = a.ValidateField("Description")
	if err != nil {
		return err
	}
	err = a.ValidateField("Type")
	if err != nil {
		return err
	}
	err = a.ValidateIDs()
	if err != nil {
		return err
	}
	err = a.ValidateType()
	if err != nil {
		return err
	}
	return nil
}

func (a Argument) ValidateForUpdate() GruffError {
	return a.ValidateForCreate()
}

func (a Argument) ValidateField(f string) GruffError {
	err := ValidateStructField(a, f)
	return err
}

func (a Argument) ValidateIDs() GruffError {
	if a.ClaimID == uuid.Nil {
		return NewBusinessError("ClaimID: non zero value required;")
	}
	if (a.TargetClaimID == nil || a.TargetClaimID.UUID == uuid.Nil) &&
		(a.TargetArgumentID == nil || a.TargetArgumentID.UUID == uuid.Nil) {
		return NewBusinessError("An Argument must have a target Claim or target Argument ID")
	}
	if a.TargetClaimID != nil && a.TargetArgumentID != nil {
		return NewBusinessError("An Argument can have only one target Claim or target Argument ID")

	}
	return nil
}

func (a Argument) ValidateType() GruffError {
	switch a.Type {
	case ARGUMENT_TYPE_PRO_TRUTH, ARGUMENT_TYPE_CON_TRUTH:
		if a.TargetClaimID == nil || a.TargetClaimID.UUID == uuid.Nil {
			return NewBusinessError("A pro or con truth argument must refer to a target claim")
		}
	case ARGUMENT_TYPE_PRO_RELEVANCE,
		ARGUMENT_TYPE_CON_RELEVANCE,
		ARGUMENT_TYPE_PRO_IMPACT,
		ARGUMENT_TYPE_CON_IMPACT:
		if a.TargetArgumentID == nil || a.TargetArgumentID.UUID == uuid.Nil {
			return NewBusinessError("An impact or relevance argument must refer to a target argument")
		}
	default:
		return NewBusinessError("Type: invalid;")
	}
	return nil
}
<|endoftext|>


<commit_before>package check_test

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

	"github.com/adamstegman/go-tracker"

	"github.com/adamstegman/tracker-git-branch-resource/check"
	checktest "github.com/adamstegman/tracker-git-branch-resource/check/test"
)

var _ = Describe("trackerGitBranchCheck", func() {
	var (
		fakeTrackerProjectClient *checktest.FakeTrackerProjectClient
		trackerCheck             check.TrackerGitBranchCheck
	)

	BeforeEach(func() {
		fakeTrackerProjectClient = checktest.NewFakeTrackerProjectClient()
		stories := []tracker.Story{{ID: 9999}, {ID: 5454}, {ID: 1234}}
		fakeTrackerProjectClient.AddStoriesForQuery(stories, tracker.StoriesQuery{State: tracker.StoryStateFinished})
		activities9999 := []tracker.Activity{
			{Highlight: "finished", OccurredAt: 1999999999999},
		}
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities9999, 9999, tracker.ActivityQuery{})
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities9999, 9999, tracker.ActivityQuery{OccurredAfter: 1000000000000})
		activities5454 := []tracker.Activity{
			{Highlight: "finished", OccurredAt: 1545454545454},
		}
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities5454, 5454, tracker.ActivityQuery{})
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities5454, 5454, tracker.ActivityQuery{OccurredAfter: 1000000000000})
		activities1234 := []tracker.Activity{
			{Highlight: "finished", OccurredAt: 1000000000000},
		}
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities1234, 1234, tracker.ActivityQuery{})
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery([]tracker.Activity{}, 1234, tracker.ActivityQuery{OccurredAfter: 1000000000000})

		trackerCheck = check.NewTrackerGitBranchCheck(fakeTrackerProjectClient)
	})

	Context("when no known story is given", func() {
		It("returns the last finished story", func() {
			stories, err := trackerCheck.StoriesFinishedAfterStory(0)
			Expect(err).NotTo(HaveOccurred())
			Expect(stories).To(Equal([]tracker.Story{{ID: 9999}}))
		})
	})

	Context("when a story ID is given", func() {
		It("returns all stories finished after the given story", func() {
			stories, err := trackerCheck.StoriesFinishedAfterStory(1234)
			Expect(err).NotTo(HaveOccurred())
			Expect(stories).To(Equal([]tracker.Story{{ID: 9999}, {ID: 5454}}))
		})
	})
})
<commit_msg>Add missing unit test<commit_after>package check_test

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

	"github.com/adamstegman/go-tracker"

	"github.com/adamstegman/tracker-git-branch-resource/check"
	checktest "github.com/adamstegman/tracker-git-branch-resource/check/test"
)

var _ = Describe("trackerGitBranchCheck", func() {
	var (
		fakeTrackerProjectClient *checktest.FakeTrackerProjectClient
		trackerCheck             check.TrackerGitBranchCheck
	)

	BeforeEach(func() {
		fakeTrackerProjectClient = checktest.NewFakeTrackerProjectClient()
		stories := []tracker.Story{{ID: 9999}, {ID: 5454}, {ID: 1234}}
		fakeTrackerProjectClient.AddStoriesForQuery(stories, tracker.StoriesQuery{State: tracker.StoryStateFinished})
		activities9999 := []tracker.Activity{
			{Highlight: "finished", OccurredAt: 1999999999999},
		}
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities9999, 9999, tracker.ActivityQuery{})
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities9999, 9999, tracker.ActivityQuery{OccurredAfter: 1000000000000})
		activities5454 := []tracker.Activity{
			{Highlight: "finished", OccurredAt: 1545454545454},
		}
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities5454, 5454, tracker.ActivityQuery{})
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities5454, 5454, tracker.ActivityQuery{OccurredAfter: 1000000000000})
		activities1234 := []tracker.Activity{
			{Highlight: "finished", OccurredAt: 1000000000000},
		}
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery(activities1234, 1234, tracker.ActivityQuery{})
		fakeTrackerProjectClient.AddActivityForStoryIDAndQuery([]tracker.Activity{}, 1234, tracker.ActivityQuery{OccurredAfter: 1000000000000})

		trackerCheck = check.NewTrackerGitBranchCheck(fakeTrackerProjectClient)
	})

	Context("when no known story is given", func() {
		It("returns the last finished story", func() {
			stories, err := trackerCheck.StoriesFinishedAfterStory(0)
			Expect(err).NotTo(HaveOccurred())
			Expect(stories).To(Equal([]tracker.Story{{ID: 9999}}))
		})

		Context("and no finished stories are found", func() {
			BeforeEach(func() {
				fakeTrackerProjectClient = checktest.NewFakeTrackerProjectClient()
				fakeTrackerProjectClient.AddStoriesForQuery([]tracker.Story{}, tracker.StoriesQuery{State: tracker.StoryStateFinished})

				trackerCheck = check.NewTrackerGitBranchCheck(fakeTrackerProjectClient)
			})

			It("returns no stories", func() {
				stories, err := trackerCheck.StoriesFinishedAfterStory(0)
				Expect(err).NotTo(HaveOccurred())
				Expect(stories).To(Equal([]tracker.Story{}))
			})
		})
	})

	Context("when a story ID is given", func() {
		It("returns all stories finished after the given story", func() {
			stories, err := trackerCheck.StoriesFinishedAfterStory(1234)
			Expect(err).NotTo(HaveOccurred())
			Expect(stories).To(Equal([]tracker.Story{{ID: 9999}, {ID: 5454}}))
		})
	})
})
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"runtime"
	"strings"
)

var (
	GitCommit   string
	VersionDesc string
)

const (
	Version = "2.5.0"
)

func init() {
	gitCommit := ""
	if len(GitCommit) > 0 {
		gitCommit = "; git " + GitCommit
	}
	VersionDesc = fmt.Sprintf("git-lfs/%s (GitHub; %s %s; go %s%s)",
		Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(runtime.Version(), "go", "", 1),
		gitCommit,
	)
}
<commit_msg>release: version 2.6.0 (take 2)<commit_after>package config

import (
	"fmt"
	"runtime"
	"strings"
)

var (
	GitCommit   string
	VersionDesc string
)

const (
	Version = "2.6.0"
)

func init() {
	gitCommit := ""
	if len(GitCommit) > 0 {
		gitCommit = "; git " + GitCommit
	}
	VersionDesc = fmt.Sprintf("git-lfs/%s (GitHub; %s %s; go %s%s)",
		Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(runtime.Version(), "go", "", 1),
		gitCommit,
	)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package main

import (
	"fmt"
	"reflect"
	"testing"
	"time"

	apps "k8s.io/api/apps/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/diff"
	kubeinformers "k8s.io/client-go/informers"
	k8sfake "k8s.io/client-go/kubernetes/fake"
	core "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"

	samplecontroller "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
	"k8s.io/sample-controller/pkg/client/clientset/versioned/fake"
	informers "k8s.io/sample-controller/pkg/client/informers/externalversions"
)

var (
	alwaysReady        = func() bool { return true }
	noResyncPeriodFunc = func() time.Duration { return 0 }
)

type fixture struct {
	t *testing.T

	client     *fake.Clientset
	kubeclient *k8sfake.Clientset
	// Objects to put in the store.
	fooLister        []*samplecontroller.Foo
	deploymentLister []*apps.Deployment
	// Actions expected to happen on the client.
	kubeactions []core.Action
	actions     []core.Action
	// Objects from here preloaded into NewSimpleFake.
	kubeobjects []runtime.Object
	objects     []runtime.Object
}

func newFixture(t *testing.T) *fixture {
	f := &fixture{}
	f.t = t
	f.objects = []runtime.Object{}
	f.kubeobjects = []runtime.Object{}
	return f
}

func newFoo(name string, replicas *int32) *samplecontroller.Foo {
	return &samplecontroller.Foo{
		TypeMeta: metav1.TypeMeta{APIVersion: samplecontroller.SchemeGroupVersion.String()},
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: metav1.NamespaceDefault,
		},
		Spec: samplecontroller.FooSpec{
			DeploymentName: fmt.Sprintf("%s-deployment", name),
			Replicas:       replicas,
		},
	}
}

func (f *fixture) newController() (*Controller, informers.SharedInformerFactory, kubeinformers.SharedInformerFactory) {
	f.client = fake.NewSimpleClientset(f.objects...)
	f.kubeclient = k8sfake.NewSimpleClientset(f.kubeobjects...)

	i := informers.NewSharedInformerFactory(f.client, noResyncPeriodFunc())
	k8sI := kubeinformers.NewSharedInformerFactory(f.kubeclient, noResyncPeriodFunc())

	c := NewController(f.kubeclient, f.client,
		k8sI.Apps().V1().Deployments(), i.Samplecontroller().V1alpha1().Foos())

	c.foosSynced = alwaysReady
	c.deploymentsSynced = alwaysReady
	c.recorder = &record.FakeRecorder{}

	for _, f := range f.fooLister {
		i.Samplecontroller().V1alpha1().Foos().Informer().GetIndexer().Add(f)
	}

	for _, d := range f.deploymentLister {
		k8sI.Apps().V1().Deployments().Informer().GetIndexer().Add(d)
	}

	return c, i, k8sI
}

func (f *fixture) run(fooName string) {
	f.runController(fooName, true, false)
}

func (f *fixture) runExpectError(fooName string) {
	f.runController(fooName, true, true)
}

func (f *fixture) runController(fooName string, startInformers bool, expectError bool) {
	c, i, k8sI := f.newController()
	if startInformers {
		stopCh := make(chan struct{})
		defer close(stopCh)
		i.Start(stopCh)
		k8sI.Start(stopCh)
	}

	err := c.syncHandler(fooName)
	if !expectError && err != nil {
		f.t.Errorf("error syncing foo: %v", err)
	} else if expectError && err == nil {
		f.t.Error("expected error syncing foo, got nil")
	}

	actions := filterInformerActions(f.client.Actions())
	for i, action := range actions {
		if len(f.actions) < i+1 {
			f.t.Errorf("%d unexpected actions: %+v", len(actions)-len(f.actions), actions[i:])
			break
		}

		expectedAction := f.actions[i]
		checkAction(expectedAction, action, f.t)
	}

	if len(f.actions) > len(actions) {
		f.t.Errorf("%d additional expected actions:%+v", len(f.actions)-len(actions), f.actions[len(actions):])
	}

	k8sActions := filterInformerActions(f.kubeclient.Actions())
	for i, action := range k8sActions {
		if len(f.kubeactions) < i+1 {
			f.t.Errorf("%d unexpected actions: %+v", len(k8sActions)-len(f.kubeactions), k8sActions[i:])
			break
		}

		expectedAction := f.kubeactions[i]
		checkAction(expectedAction, action, f.t)
	}

	if len(f.kubeactions) > len(k8sActions) {
		f.t.Errorf("%d additional expected actions:%+v", len(f.kubeactions)-len(k8sActions), f.kubeactions[len(k8sActions):])
	}
}

// checkAction verifies that expected and actual actions are equal and both have
// same attached resources
func checkAction(expected, actual core.Action, t *testing.T) {
	if !(expected.Matches(actual.GetVerb(), actual.GetResource().Resource) && actual.GetSubresource() == expected.GetSubresource()) {
		t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expected, actual)
		return
	}

	if reflect.TypeOf(actual) != reflect.TypeOf(expected) {
		t.Errorf("Action has wrong type. Expected: %t. Got: %t", expected, actual)
		return
	}

	switch a := actual.(type) {
	case core.CreateAction:
		e, _ := expected.(core.CreateAction)
		expObject := e.GetObject()
		object := a.GetObject()

		if !reflect.DeepEqual(expObject, object) {
			t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
				a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintDiff(expObject, object))
		}
	case core.UpdateAction:
		e, _ := expected.(core.UpdateAction)
		expObject := e.GetObject()
		object := a.GetObject()

		if !reflect.DeepEqual(expObject, object) {
			t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
				a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintDiff(expObject, object))
		}
	case core.PatchAction:
		e, _ := expected.(core.PatchAction)
		expPatch := e.GetPatch()
		patch := a.GetPatch()

		if !reflect.DeepEqual(expPatch, expPatch) {
			t.Errorf("Action %s %s has wrong patch\nDiff:\n %s",
				a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintDiff(expPatch, patch))
		}
	}
}

// filterInformerActions filters list and watch actions for testing resources.
// Since list and watch don't change resource state we can filter it to lower
// nose level in our tests.
func filterInformerActions(actions []core.Action) []core.Action {
	ret := []core.Action{}
	for _, action := range actions {
		if len(action.GetNamespace()) == 0 &&
			(action.Matches("list", "foos") ||
				action.Matches("watch", "foos") ||
				action.Matches("list", "deployments") ||
				action.Matches("watch", "deployments")) {
			continue
		}
		ret = append(ret, action)
	}

	return ret
}

func (f *fixture) expectCreateDeploymentAction(d *apps.Deployment) {
	f.kubeactions = append(f.kubeactions, core.NewCreateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d))
}

func (f *fixture) expectUpdateDeploymentAction(d *apps.Deployment) {
	f.kubeactions = append(f.kubeactions, core.NewUpdateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d))
}

func (f *fixture) expectUpdateFooStatusAction(foo *samplecontroller.Foo) {
	action := core.NewUpdateAction(schema.GroupVersionResource{Resource: "foos"}, foo.Namespace, foo)
	// TODO: Until #38113 is merged, we can't use Subresource
	//action.Subresource = "status"
	f.actions = append(f.actions, action)
}

func getKey(foo *samplecontroller.Foo, t *testing.T) string {
	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(foo)
	if err != nil {
		t.Errorf("Unexpected error getting key for foo %v: %v", foo.Name, err)
		return ""
	}
	return key
}

func TestCreatesDeployment(t *testing.T) {
	f := newFixture(t)
	foo := newFoo("test", int32Ptr(1))

	f.fooLister = append(f.fooLister, foo)
	f.objects = append(f.objects, foo)

	expDeployment := newDeployment(foo)
	f.expectCreateDeploymentAction(expDeployment)
	f.expectUpdateFooStatusAction(foo)

	f.run(getKey(foo, t))
}

func TestDoNothing(t *testing.T) {
	f := newFixture(t)
	foo := newFoo("test", int32Ptr(1))
	d := newDeployment(foo)

	f.fooLister = append(f.fooLister, foo)
	f.objects = append(f.objects, foo)
	f.deploymentLister = append(f.deploymentLister, d)
	f.kubeobjects = append(f.kubeobjects, d)

	f.expectUpdateFooStatusAction(foo)
	f.run(getKey(foo, t))
}

func TestUpdateDeployment(t *testing.T) {
	f := newFixture(t)
	foo := newFoo("test", int32Ptr(1))
	d := newDeployment(foo)

	// Update replicas
	foo.Spec.Replicas = int32Ptr(2)
	expDeployment := newDeployment(foo)

	f.fooLister = append(f.fooLister, foo)
	f.objects = append(f.objects, foo)
	f.deploymentLister = append(f.deploymentLister, d)
	f.kubeobjects = append(f.kubeobjects, d)

	f.expectUpdateFooStatusAction(foo)
	f.expectUpdateDeploymentAction(expDeployment)
	f.run(getKey(foo, t))
}

func TestNotControlledByUs(t *testing.T) {
	f := newFixture(t)
	foo := newFoo("test", int32Ptr(1))
	d := newDeployment(foo)

	d.ObjectMeta.OwnerReferences = []metav1.OwnerReference{}

	f.fooLister = append(f.fooLister, foo)
	f.objects = append(f.objects, foo)
	f.deploymentLister = append(f.deploymentLister, d)
	f.kubeobjects = append(f.kubeobjects, d)

	f.runExpectError(getKey(foo, t))
}

func int32Ptr(i int32) *int32 { return &i }
<commit_msg>fix patch compare in test<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package main

import (
	"fmt"
	"reflect"
	"testing"
	"time"

	apps "k8s.io/api/apps/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/diff"
	kubeinformers "k8s.io/client-go/informers"
	k8sfake "k8s.io/client-go/kubernetes/fake"
	core "k8s.io/client-go/testing"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/record"

	samplecontroller "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1"
	"k8s.io/sample-controller/pkg/client/clientset/versioned/fake"
	informers "k8s.io/sample-controller/pkg/client/informers/externalversions"
)

var (
	alwaysReady        = func() bool { return true }
	noResyncPeriodFunc = func() time.Duration { return 0 }
)

type fixture struct {
	t *testing.T

	client     *fake.Clientset
	kubeclient *k8sfake.Clientset
	// Objects to put in the store.
	fooLister        []*samplecontroller.Foo
	deploymentLister []*apps.Deployment
	// Actions expected to happen on the client.
	kubeactions []core.Action
	actions     []core.Action
	// Objects from here preloaded into NewSimpleFake.
	kubeobjects []runtime.Object
	objects     []runtime.Object
}

func newFixture(t *testing.T) *fixture {
	f := &fixture{}
	f.t = t
	f.objects = []runtime.Object{}
	f.kubeobjects = []runtime.Object{}
	return f
}

func newFoo(name string, replicas *int32) *samplecontroller.Foo {
	return &samplecontroller.Foo{
		TypeMeta: metav1.TypeMeta{APIVersion: samplecontroller.SchemeGroupVersion.String()},
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: metav1.NamespaceDefault,
		},
		Spec: samplecontroller.FooSpec{
			DeploymentName: fmt.Sprintf("%s-deployment", name),
			Replicas:       replicas,
		},
	}
}

func (f *fixture) newController() (*Controller, informers.SharedInformerFactory, kubeinformers.SharedInformerFactory) {
	f.client = fake.NewSimpleClientset(f.objects...)
	f.kubeclient = k8sfake.NewSimpleClientset(f.kubeobjects...)

	i := informers.NewSharedInformerFactory(f.client, noResyncPeriodFunc())
	k8sI := kubeinformers.NewSharedInformerFactory(f.kubeclient, noResyncPeriodFunc())

	c := NewController(f.kubeclient, f.client,
		k8sI.Apps().V1().Deployments(), i.Samplecontroller().V1alpha1().Foos())

	c.foosSynced = alwaysReady
	c.deploymentsSynced = alwaysReady
	c.recorder = &record.FakeRecorder{}

	for _, f := range f.fooLister {
		i.Samplecontroller().V1alpha1().Foos().Informer().GetIndexer().Add(f)
	}

	for _, d := range f.deploymentLister {
		k8sI.Apps().V1().Deployments().Informer().GetIndexer().Add(d)
	}

	return c, i, k8sI
}

func (f *fixture) run(fooName string) {
	f.runController(fooName, true, false)
}

func (f *fixture) runExpectError(fooName string) {
	f.runController(fooName, true, true)
}

func (f *fixture) runController(fooName string, startInformers bool, expectError bool) {
	c, i, k8sI := f.newController()
	if startInformers {
		stopCh := make(chan struct{})
		defer close(stopCh)
		i.Start(stopCh)
		k8sI.Start(stopCh)
	}

	err := c.syncHandler(fooName)
	if !expectError && err != nil {
		f.t.Errorf("error syncing foo: %v", err)
	} else if expectError && err == nil {
		f.t.Error("expected error syncing foo, got nil")
	}

	actions := filterInformerActions(f.client.Actions())
	for i, action := range actions {
		if len(f.actions) < i+1 {
			f.t.Errorf("%d unexpected actions: %+v", len(actions)-len(f.actions), actions[i:])
			break
		}

		expectedAction := f.actions[i]
		checkAction(expectedAction, action, f.t)
	}

	if len(f.actions) > len(actions) {
		f.t.Errorf("%d additional expected actions:%+v", len(f.actions)-len(actions), f.actions[len(actions):])
	}

	k8sActions := filterInformerActions(f.kubeclient.Actions())
	for i, action := range k8sActions {
		if len(f.kubeactions) < i+1 {
			f.t.Errorf("%d unexpected actions: %+v", len(k8sActions)-len(f.kubeactions), k8sActions[i:])
			break
		}

		expectedAction := f.kubeactions[i]
		checkAction(expectedAction, action, f.t)
	}

	if len(f.kubeactions) > len(k8sActions) {
		f.t.Errorf("%d additional expected actions:%+v", len(f.kubeactions)-len(k8sActions), f.kubeactions[len(k8sActions):])
	}
}

// checkAction verifies that expected and actual actions are equal and both have
// same attached resources
func checkAction(expected, actual core.Action, t *testing.T) {
	if !(expected.Matches(actual.GetVerb(), actual.GetResource().Resource) && actual.GetSubresource() == expected.GetSubresource()) {
		t.Errorf("Expected\n\t%#v\ngot\n\t%#v", expected, actual)
		return
	}

	if reflect.TypeOf(actual) != reflect.TypeOf(expected) {
		t.Errorf("Action has wrong type. Expected: %t. Got: %t", expected, actual)
		return
	}

	switch a := actual.(type) {
	case core.CreateAction:
		e, _ := expected.(core.CreateAction)
		expObject := e.GetObject()
		object := a.GetObject()

		if !reflect.DeepEqual(expObject, object) {
			t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
				a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintDiff(expObject, object))
		}
	case core.UpdateAction:
		e, _ := expected.(core.UpdateAction)
		expObject := e.GetObject()
		object := a.GetObject()

		if !reflect.DeepEqual(expObject, object) {
			t.Errorf("Action %s %s has wrong object\nDiff:\n %s",
				a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintDiff(expObject, object))
		}
	case core.PatchAction:
		e, _ := expected.(core.PatchAction)
		expPatch := e.GetPatch()
		patch := a.GetPatch()

		if !reflect.DeepEqual(expPatch, patch) {
			t.Errorf("Action %s %s has wrong patch\nDiff:\n %s",
				a.GetVerb(), a.GetResource().Resource, diff.ObjectGoPrintDiff(expPatch, patch))
		}
	}
}

// filterInformerActions filters list and watch actions for testing resources.
// Since list and watch don't change resource state we can filter it to lower
// nose level in our tests.
func filterInformerActions(actions []core.Action) []core.Action {
	ret := []core.Action{}
	for _, action := range actions {
		if len(action.GetNamespace()) == 0 &&
			(action.Matches("list", "foos") ||
				action.Matches("watch", "foos") ||
				action.Matches("list", "deployments") ||
				action.Matches("watch", "deployments")) {
			continue
		}
		ret = append(ret, action)
	}

	return ret
}

func (f *fixture) expectCreateDeploymentAction(d *apps.Deployment) {
	f.kubeactions = append(f.kubeactions, core.NewCreateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d))
}

func (f *fixture) expectUpdateDeploymentAction(d *apps.Deployment) {
	f.kubeactions = append(f.kubeactions, core.NewUpdateAction(schema.GroupVersionResource{Resource: "deployments"}, d.Namespace, d))
}

func (f *fixture) expectUpdateFooStatusAction(foo *samplecontroller.Foo) {
	action := core.NewUpdateAction(schema.GroupVersionResource{Resource: "foos"}, foo.Namespace, foo)
	// TODO: Until #38113 is merged, we can't use Subresource
	//action.Subresource = "status"
	f.actions = append(f.actions, action)
}

func getKey(foo *samplecontroller.Foo, t *testing.T) string {
	key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(foo)
	if err != nil {
		t.Errorf("Unexpected error getting key for foo %v: %v", foo.Name, err)
		return ""
	}
	return key
}

func TestCreatesDeployment(t *testing.T) {
	f := newFixture(t)
	foo := newFoo("test", int32Ptr(1))

	f.fooLister = append(f.fooLister, foo)
	f.objects = append(f.objects, foo)

	expDeployment := newDeployment(foo)
	f.expectCreateDeploymentAction(expDeployment)
	f.expectUpdateFooStatusAction(foo)

	f.run(getKey(foo, t))
}

func TestDoNothing(t *testing.T) {
	f := newFixture(t)
	foo := newFoo("test", int32Ptr(1))
	d := newDeployment(foo)

	f.fooLister = append(f.fooLister, foo)
	f.objects = append(f.objects, foo)
	f.deploymentLister = append(f.deploymentLister, d)
	f.kubeobjects = append(f.kubeobjects, d)

	f.expectUpdateFooStatusAction(foo)
	f.run(getKey(foo, t))
}

func TestUpdateDeployment(t *testing.T) {
	f := newFixture(t)
	foo := newFoo("test", int32Ptr(1))
	d := newDeployment(foo)

	// Update replicas
	foo.Spec.Replicas = int32Ptr(2)
	expDeployment := newDeployment(foo)

	f.fooLister = append(f.fooLister, foo)
	f.objects = append(f.objects, foo)
	f.deploymentLister = append(f.deploymentLister, d)
	f.kubeobjects = append(f.kubeobjects, d)

	f.expectUpdateFooStatusAction(foo)
	f.expectUpdateDeploymentAction(expDeployment)
	f.run(getKey(foo, t))
}

func TestNotControlledByUs(t *testing.T) {
	f := newFixture(t)
	foo := newFoo("test", int32Ptr(1))
	d := newDeployment(foo)

	d.ObjectMeta.OwnerReferences = []metav1.OwnerReference{}

	f.fooLister = append(f.fooLister, foo)
	f.objects = append(f.objects, foo)
	f.deploymentLister = append(f.deploymentLister, d)
	f.kubeobjects = append(f.kubeobjects, d)

	f.runExpectError(getKey(foo, t))
}

func int32Ptr(i int32) *int32 { return &i }
<|endoftext|>


<commit_before>// Copyright 2015 Matthew Collins
//
// 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 steven

import (
	"runtime"

	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/thinkofdeath/steven/protocol"
	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/render/gl"
)

var window *glfw.Window

func init() {
	runtime.LockOSThread()
}

func startWindow() {
	if err := glfw.Init(); err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 2)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	glfw.WindowHint(glfw.Samples, Config.Render.Samples)
	render.MultiSample = Config.Render.Samples > 0

	var err error
	window, err = glfw.CreateWindow(854, 480, "Steven", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()
	if Config.Render.VSync {
		glfw.SwapInterval(1)
	} else {
		glfw.SwapInterval(0)
	}

	window.SetCursorPosCallback(onMouseMove)
	window.SetMouseButtonCallback(onMouseClick)
	window.SetKeyCallback(onKey)
	window.SetScrollCallback(onScroll)
	window.SetFocusCallback(onFocus)

	gl.Init()

	start()

	for !window.ShouldClose() {
		draw()
		window.SwapBuffers()
		glfw.PollEvents()
	}
}

func onScroll(w *glfw.Window, xoff float64, yoff float64) {
	if currentScreen != nil || !ready {
		return
	}
	if yoff < 0 {
		Client.currentHotbarSlot++
	} else {
		Client.currentHotbarSlot--
	}
	if Client.currentHotbarSlot < 0 {
		Client.currentHotbarSlot = 0
	} else if Client.currentHotbarSlot > 8 {
		Client.currentHotbarSlot = 8
	}

	Client.network.Write(&protocol.HeldItemChange{Slot: int16(Client.currentHotbarSlot)})
}

var lockMouse bool

func onFocus(w *glfw.Window, focused bool) {
	if !focused {
		for i := range Client.KeyState {
			Client.KeyState[i] = false
		}
		lockMouse = false
	}
}

func onMouseMove(w *glfw.Window, xpos float64, ypos float64) {
	width, height := w.GetSize()
	if currentScreen != nil {
		fw, fh := w.GetFramebufferSize()
		currentScreen.hover(xpos*(float64(fw)/float64(width)), ypos*(float64(fh)/float64(height)), fw, fh)
		return
	}
	if !lockMouse {
		return
	}
	ww, hh := float64(width/2), float64(height/2)
	w.SetCursorPos(ww, hh)

	s := float64(Config.Game.MouseSensitivity)
	rotate((xpos-ww)/s, (ypos-hh)/s)
}

func onMouseClick(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
	if currentScreen != nil {
		if button != glfw.MouseButtonLeft || action == glfw.Repeat {
			return
		}
		width, height := w.GetSize()
		xpos, ypos := w.GetCursorPos()
		fw, fh := w.GetFramebufferSize()
		currentScreen.click(action == glfw.Press, xpos*(float64(fw)/float64(width)), ypos*(float64(fh)/float64(height)), fw, fh)
		return
	}
	if !Client.chat.enteringText && lockMouse && action != glfw.Repeat && lockMouse {
		Client.MouseAction(button, action == glfw.Press)
	}
	if button == glfw.MouseButtonLeft && action == glfw.Press && !Client.chat.enteringText {
		lockMouse = true
		w.SetInputMode(glfw.CursorMode, glfw.CursorDisabled)
	}
}

type Key int

const (
	KeyForward Key = iota
	KeyBackwards
	KeyLeft
	KeyRight
	KeySprint
	KeyJump
)

func onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if currentScreen != nil {
		return
	}
	if Client.chat.enteringText {
		Client.chat.handleKey(w, key, scancode, action, mods)
		return
	}
	switch key {
	case glfw.KeyEscape:
		if action == glfw.Release {
			setScreen(newGameMenu())
		}
	case glfw.KeyW:
		if action != glfw.Repeat {
			Client.KeyState[KeyForward] = action == glfw.Press
		}
	case glfw.KeyS:
		if action != glfw.Repeat {
			Client.KeyState[KeyBackwards] = action == glfw.Press
		}
	case glfw.KeyA:
		if action != glfw.Repeat {
			Client.KeyState[KeyLeft] = action == glfw.Press
		}
	case glfw.KeyD:
		if action != glfw.Repeat {
			Client.KeyState[KeyRight] = action == glfw.Press
		}
	case glfw.KeyLeftControl:
		if action != glfw.Repeat {
			Client.KeyState[KeySprint] = action == glfw.Press
		}
	case glfw.KeySpace:
		if action != glfw.Repeat {
			Client.KeyState[KeyJump] = action == glfw.Press
		}
	case glfw.KeyF1:
		if action == glfw.Release {
			if Client.scene.IsVisible() {
				Client.scene.Hide()
				Client.hotbarScene.Hide()
			} else {
				Client.scene.Show()
				Client.hotbarScene.Show()
			}
		}
	case glfw.KeyF3:
		if action == glfw.Release {
			Client.toggleDebug()
		}
	case glfw.KeyF5:
		if action == glfw.Release {
			Client.cycleCamera()
		}
	case glfw.KeyTab:
		if action == glfw.Press {
			Client.playerList.set(true)
		} else if action == glfw.Release {
			Client.playerList.set(false)
		}
	case glfw.KeyT, glfw.KeySlash:
		for i := range Client.KeyState {
			Client.KeyState[i] = false
		}
		Client.chat.enteringText = true
		Client.chat.first = true
		if key == glfw.KeySlash {
			Client.chat.inputLine = append(Client.chat.inputLine, '/')
		}
		lockMouse = false
		w.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
		w.SetCharCallback(Client.chat.handleChar)
	}
}
<commit_msg>steven: clean up keystate handling<commit_after>// Copyright 2015 Matthew Collins
//
// 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 steven

import (
	"runtime"

	"github.com/go-gl/glfw/v3.1/glfw"
	"github.com/thinkofdeath/steven/protocol"
	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/render/gl"
)

var window *glfw.Window

func init() {
	runtime.LockOSThread()
}

func startWindow() {
	if err := glfw.Init(); err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 2)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	glfw.WindowHint(glfw.Samples, Config.Render.Samples)
	render.MultiSample = Config.Render.Samples > 0

	var err error
	window, err = glfw.CreateWindow(854, 480, "Steven", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()
	if Config.Render.VSync {
		glfw.SwapInterval(1)
	} else {
		glfw.SwapInterval(0)
	}

	window.SetCursorPosCallback(onMouseMove)
	window.SetMouseButtonCallback(onMouseClick)
	window.SetKeyCallback(onKey)
	window.SetScrollCallback(onScroll)
	window.SetFocusCallback(onFocus)

	gl.Init()

	start()

	for !window.ShouldClose() {
		draw()
		window.SwapBuffers()
		glfw.PollEvents()
	}
}

func onScroll(w *glfw.Window, xoff float64, yoff float64) {
	if currentScreen != nil || !ready {
		return
	}
	if yoff < 0 {
		Client.currentHotbarSlot++
	} else {
		Client.currentHotbarSlot--
	}
	if Client.currentHotbarSlot < 0 {
		Client.currentHotbarSlot = 0
	} else if Client.currentHotbarSlot > 8 {
		Client.currentHotbarSlot = 8
	}

	Client.network.Write(&protocol.HeldItemChange{Slot: int16(Client.currentHotbarSlot)})
}

var lockMouse bool

func onFocus(w *glfw.Window, focused bool) {
	if !focused {
		for i := range Client.KeyState {
			Client.KeyState[i] = false
		}
		lockMouse = false
	}
}

func onMouseMove(w *glfw.Window, xpos float64, ypos float64) {
	width, height := w.GetSize()
	if currentScreen != nil {
		fw, fh := w.GetFramebufferSize()
		currentScreen.hover(xpos*(float64(fw)/float64(width)), ypos*(float64(fh)/float64(height)), fw, fh)
		return
	}
	if !lockMouse {
		return
	}
	ww, hh := float64(width/2), float64(height/2)
	w.SetCursorPos(ww, hh)

	s := float64(Config.Game.MouseSensitivity)
	rotate((xpos-ww)/s, (ypos-hh)/s)
}

func onMouseClick(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
	if currentScreen != nil {
		if button != glfw.MouseButtonLeft || action == glfw.Repeat {
			return
		}
		width, height := w.GetSize()
		xpos, ypos := w.GetCursorPos()
		fw, fh := w.GetFramebufferSize()
		currentScreen.click(action == glfw.Press, xpos*(float64(fw)/float64(width)), ypos*(float64(fh)/float64(height)), fw, fh)
		return
	}
	if !Client.chat.enteringText && lockMouse && action != glfw.Repeat && lockMouse {
		Client.MouseAction(button, action == glfw.Press)
	}
	if button == glfw.MouseButtonLeft && action == glfw.Press && !Client.chat.enteringText {
		lockMouse = true
		w.SetInputMode(glfw.CursorMode, glfw.CursorDisabled)
	}
}

type Key int

const (
	KeyForward Key = iota
	KeyBackwards
	KeyLeft
	KeyRight
	KeySprint
	KeyJump
)

var keyStateMap = map[glfw.Key]Key{
	glfw.KeyW:           KeyForward,
	glfw.KeyS:           KeyBackwards,
	glfw.KeyA:           KeyLeft,
	glfw.KeyD:           KeyRight,
	glfw.KeyLeftControl: KeySprint,
	glfw.KeySpace:       KeyJump,
}

func onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if currentScreen != nil {
		return
	}
	if Client.chat.enteringText {
		Client.chat.handleKey(w, key, scancode, action, mods)
		return
	}

	if k, ok := keyStateMap[key]; action != glfw.Repeat && ok {
		Client.KeyState[k] = action == glfw.Press
	}
	switch key {
	case glfw.KeyEscape:
		if action == glfw.Release {
			setScreen(newGameMenu())
		}
	case glfw.KeyF1:
		if action == glfw.Release {
			if Client.scene.IsVisible() {
				Client.scene.Hide()
				Client.hotbarScene.Hide()
			} else {
				Client.scene.Show()
				Client.hotbarScene.Show()
			}
		}
	case glfw.KeyF3:
		if action == glfw.Release {
			Client.toggleDebug()
		}
	case glfw.KeyF5:
		if action == glfw.Release {
			Client.cycleCamera()
		}
	case glfw.KeyTab:
		if action == glfw.Press {
			Client.playerList.set(true)
		} else if action == glfw.Release {
			Client.playerList.set(false)
		}
	case glfw.KeyT, glfw.KeySlash:
		for i := range Client.KeyState {
			Client.KeyState[i] = false
		}
		Client.chat.enteringText = true
		Client.chat.first = true
		if key == glfw.KeySlash {
			Client.chat.inputLine = append(Client.chat.inputLine, '/')
		}
		lockMouse = false
		w.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
		w.SetCharCallback(Client.chat.handleChar)
	}
}
<|endoftext|>


<commit_before>package dev

import (
	"bufio"
	"errors"
	"io"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/x-formation/pulsekit"
)

// Personal TODO(rjeczalik): document
type Personal struct {
	Patch    string
	Project  string
	Stages   []string
	Revision string
}

var ErrTimeout = errors.New("pulsedev: waiting for command to finish has timed out")

// Exec TODO(rjeczalik): document
type Exec interface {
	// LookPath TODO(rjeczalik): document
	LookPath(string) (string, error)
	// CombinedOutput TODO(rjeczalik): document
	CombinedOutput(string, []string) (io.Writer, io.Reader, func(time.Duration) error, error)
}

type cmdExec struct{}

func (cmdExec) LookPath(file string) (string, error) {
	return exec.LookPath(file)
}

func (cmdExec) CombinedOutput(file string, args []string) (stdin io.Writer,
	stdout io.Reader, wait func(time.Duration) error, err error) {
	cmd := exec.Command(file, args...)
	if stdin, err = cmd.StdinPipe(); err != nil {
		return
	}
	if stdout, err = cmd.StdoutPipe(); err != nil {
		return
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return
	}
	stdout = io.MultiReader(stdout, stderr)
	if err = cmd.Start(); err != nil {
		return
	}
	wait = func(d time.Duration) (err error) {
		done := make(chan error)
		go func() {
			done <- cmd.Wait()
			close(done)
		}()
		select {
		case err, _ = <-done:
		case <-time.After(d):
			err = ErrTimeout
		}
		return
	}
	return
}

// DefaultExec TODO(rjeczalik): document
var DefaultExec Exec = new(cmdExec)

// Tool TODO(rjeczalik): document
type Tool interface {
	// TODO(rjeczalik): document
	Personal(p *Personal) (int64, error)
	SetTimeout(d time.Duration)
}

type tool struct {
	exec Exec
	c    pulse.Client
	url  string
	user string
	pass string
	exe  string
	d    time.Duration
}

func New(c pulse.Client, url, user, pass string) (Tool, error) {
	var err error
	t := &tool{
		exec: DefaultExec,
		c:    c,
		url:  url,
		user: user,
		pass: pass,
		d:    15 * time.Second,
	}
	if t.exe, err = t.exec.LookPath("pulse"); err != nil {
		return nil, err
	}
	if err = t.valid(); err != nil {
		return nil, err
	}
	return t, nil
}

func (t *tool) valid() error {
	for _, args := range [][]string{{"help"}, {"help", "personal"}} {
		_, _, wait, err := t.exec.CombinedOutput(t.exe, args)
		if err != nil {
			return err
		}
		if err = wait(t.d); err != nil {
			return err
		}
	}
	return nil
}

func (t *tool) Personal(p *Personal) (id int64, err error) {
	var (
		line   []byte
		stages []pulse.ProjectStage
		delim  = byte('\n')
		rev    = false
	)
	args := []string{
		"personal",
		"-s", t.url,
		"-u", t.user,
		"-p", t.pass,
		"-r", p.Project,
		"-t", "git",
		"-f", p.Patch,
	}
	if p.Revision != "" {
		args = append(args, "-e", p.Revision)
	}
	if p.Stages != nil {
		stages = make([]pulse.ProjectStage, len(p.Stages))
		for i, s := range p.Stages {
			stages[i], err = t.c.ConfigStage(p.Project, s)
			if err != nil {
				return
			}
			stages[i].Enabled = false
			if err = t.c.SetConfigStage(p.Project, stages[i]); err != nil {
				return
			}
		}
	}
	in, out, wait, err := t.exec.CombinedOutput(t.exe, args)
	if err != nil {
		return
	}
	r := bufio.NewReader(out)
INTERACTIVE:
	for {
		line, err = r.ReadBytes(delim)
		if err == io.EOF {
			continue
		}
		if err != nil {
			break INTERACTIVE
		}
		s := string(line)
		switch delim {
		case '\n':
			if strings.Contains(s, "Continue anyway?") || strings.Contains(s, "Synchronise now?") {
				delim = '>'
			}
			if strings.Contains(s, "Choose revision to build against") {
				delim, rev = '>', true
			}
			i := strings.Index(s, "Patch accepted: personal build")
			if i != -1 {
				id, err = strconv.ParseInt(s[31+i:len(s)-2], 10, 64)
				break INTERACTIVE
			}
			if strings.Contains(s, "Error") || strings.Contains(s, "Exception") {
				err = errors.New(s)
				break INTERACTIVE
			}
		case '>':
			res := []byte("Yes\n")
			if rev {
				res = []byte("1!\n")
			}
			if _, err = in.Write(res); err != nil && err != io.EOF {
				break INTERACTIVE
			}
			delim, rev = '\n', false
		}
	}
	if e := wait(t.d); (err == io.EOF || err == nil) && e != nil {
		err = e
	}
	if stages != nil {
		for i := range stages {
			stages[i].Enabled = true
			if e := t.c.SetConfigStage(p.Project, stages[i]); e != nil && err == nil {
				err = e
			}
		}
	}
	return
}

func (t *tool) SetTimeout(d time.Duration) {
	t.d = d
}
<commit_msg>pulsekit/dev: Fix for recorded TestPersonalOK test<commit_after>package dev

import (
	"bufio"
	"errors"
	"io"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/x-formation/pulsekit"
)

// Personal TODO(rjeczalik): document
type Personal struct {
	Patch    string
	Project  string
	Stages   []string
	Revision string
}

var ErrTimeout = errors.New("pulsedev: waiting for command to finish has timed out")

// Exec TODO(rjeczalik): document
type Exec interface {
	// LookPath TODO(rjeczalik): document
	LookPath(string) (string, error)
	// CombinedOutput TODO(rjeczalik): document
	CombinedOutput(string, []string) (io.Writer, io.Reader, func(time.Duration) error, error)
}

type cmdExec struct{}

func (cmdExec) LookPath(file string) (string, error) {
	return exec.LookPath(file)
}

func (cmdExec) CombinedOutput(file string, args []string) (stdin io.Writer,
	stdout io.Reader, wait func(time.Duration) error, err error) {
	cmd := exec.Command(file, args...)
	if stdin, err = cmd.StdinPipe(); err != nil {
		return
	}
	if stdout, err = cmd.StdoutPipe(); err != nil {
		return
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return
	}
	stdout = io.MultiReader(stdout, stderr)
	if err = cmd.Start(); err != nil {
		return
	}
	wait = func(d time.Duration) (err error) {
		done := make(chan error)
		go func() {
			done <- cmd.Wait()
			close(done)
		}()
		select {
		case err, _ = <-done:
		case <-time.After(d):
			err = ErrTimeout
		}
		return
	}
	return
}

// DefaultExec TODO(rjeczalik): document
var DefaultExec Exec = new(cmdExec)

// Tool TODO(rjeczalik): document
type Tool interface {
	// TODO(rjeczalik): document
	Personal(p *Personal) (int64, error)
	SetTimeout(d time.Duration)
}

type tool struct {
	exec Exec
	c    pulse.Client
	url  string
	user string
	pass string
	exe  string
	d    time.Duration
}

func New(c pulse.Client, url, user, pass string) (Tool, error) {
	var err error
	t := &tool{
		exec: DefaultExec,
		c:    c,
		url:  url,
		user: user,
		pass: pass,
		d:    15 * time.Second,
	}
	if t.exe, err = t.exec.LookPath("pulse"); err != nil {
		return nil, err
	}
	if err = t.valid(); err != nil {
		return nil, err
	}
	return t, nil
}

func (t *tool) valid() error {
	for _, args := range [][]string{{"help"}, {"help", "personal"}} {
		_, _, wait, err := t.exec.CombinedOutput(t.exe, args)
		if err != nil {
			return err
		}
		if err = wait(t.d); err != nil {
			return err
		}
	}
	return nil
}

func (t *tool) Personal(p *Personal) (id int64, err error) {
	var (
		line   []byte
		res    []byte
		stages []pulse.ProjectStage
		delim  = byte('\n')
	)
	args := []string{
		"personal",
		"-s", t.url,
		"-u", t.user,
		"-p", t.pass,
		"-r", p.Project,
		"-t", "git",
		"-f", p.Patch,
	}
	if p.Revision != "" {
		args = append(args, "-e", p.Revision)
	}
	if p.Stages != nil {
		stages = make([]pulse.ProjectStage, len(p.Stages))
		for i, s := range p.Stages {
			stages[i], err = t.c.ConfigStage(p.Project, s)
			if err != nil {
				return
			}
			stages[i].Enabled = false
			if err = t.c.SetConfigStage(p.Project, stages[i]); err != nil {
				return
			}
		}
	}
	in, out, wait, err := t.exec.CombinedOutput(t.exe, args)
	if err != nil {
		return
	}
	r := bufio.NewReader(out)
INTERACTIVE:
	for {
		line, err = r.ReadBytes(delim)
		if err == io.EOF {
			continue
		}
		if err != nil {
			break INTERACTIVE
		}
		s := string(line)
		switch delim {
		case '\n':
			if strings.Contains(s, "Continue anyway?") {
				delim, res = '>', []byte("Yes\n")
			}
			if strings.Contains(s, "Synchronise now?") {
				delim, res = '>', []byte("No\n")
			}
			if strings.Contains(s, "Choose revision to build against") {
				delim, res = '>', []byte("1!\n")
			}
			i := strings.Index(s, "Patch accepted: personal build")
			if i != -1 {
				id, err = strconv.ParseInt(s[31+i:len(s)-2], 10, 64)
				break INTERACTIVE
			}
			if strings.Contains(s, "Error") || strings.Contains(s, "Exception") {
				err = errors.New(s)
				break INTERACTIVE
			}
		case '>':
			if _, err = in.Write(res); err != nil && err != io.EOF {
				break INTERACTIVE
			}
			delim = '\n'
		}
	}
	if e := wait(t.d); (err == io.EOF || err == nil) && e != nil {
		err = e
	}
	if stages != nil {
		for i := range stages {
			stages[i].Enabled = true
			if e := t.c.SetConfigStage(p.Project, stages[i]); e != nil && err == nil {
				err = e
			}
		}
	}
	return
}

func (t *tool) SetTimeout(d time.Duration) {
	t.d = d
}
<|endoftext|>


<commit_before>package external

import "github.com/rackspace/gophercloud/openstack/networking/v2/networks"

type AdminState *bool

// Convenience vars for AdminStateUp values.
var (
	iTrue  = true
	iFalse = false

	Nothing AdminState = nil
	Up      AdminState = &iTrue
	Down    AdminState = &iFalse
)

type CreateOpts struct {
	Parent   networks.CreateOpts
	External bool
}

func (o CreateOpts) ToNetworkCreateMap() map[string]map[string]interface{} {
	outer := o.Parent.ToNetworkCreateMap()

	outer["network"]["router:external"] = o.External

	return outer
}

type UpdateOpts struct {
	Parent   networks.UpdateOpts
	External bool
}

func (o UpdateOpts) ToNetworkUpdateMap() map[string]map[string]interface{} {
	outer := o.Parent.ToNetworkUpdateMap()

	outer["network"]["router:external"] = o.External

	return outer
}
<commit_msg>Adding comments to external ext<commit_after>package external

import "github.com/rackspace/gophercloud/openstack/networking/v2/networks"

// AdminState gives users a solid type to work with for create and update
// operations. It is recommended that users use the `Up` and `Down` enums.
type AdminState *bool

// Convenience vars for AdminStateUp values.
var (
	iTrue  = true
	iFalse = false

	Up   AdminState = &iTrue
	Down AdminState = &iFalse
)

// CreateOpts is the structure used when creating new external network
// resources. It embeds networks.CreateOpts and so inherits all of its required
// and optional fields, with the addition of the External field.
type CreateOpts struct {
	Parent   networks.CreateOpts
	External bool
}

// ToNetworkCreateMap casts a CreateOpts struct to a map.
func (o CreateOpts) ToNetworkCreateMap() map[string]map[string]interface{} {
	outer := o.Parent.ToNetworkCreateMap()

	outer["network"]["router:external"] = o.External

	return outer
}

// UpdateOpts is the structure used when updating existing external network
// resources. It embeds networks.UpdateOpts and so inherits all of its required
// and optional fields, with the addition of the External field.
type UpdateOpts struct {
	Parent   networks.UpdateOpts
	External bool
}

// ToNetworkUpdateMap casts an UpdateOpts struct to a map.
func (o UpdateOpts) ToNetworkUpdateMap() map[string]map[string]interface{} {
	outer := o.Parent.ToNetworkUpdateMap()

	outer["network"]["router:external"] = o.External

	return outer
}
<|endoftext|>


<commit_before>// AWS config libs

package config

import (
	"github.com/evalphobia/aws-sdk-go-wrapper/log"

	"encoding/json"
	"fmt"
	"io/ioutil"
)

const (
	awsConfigFileName = "aws"
)

var (
	config Config
)

func init() {
	SetDefaultConfig()
}

// get parameter from config file
func SetConfig(conf Config) {
	config = conf
}

func GetConfigValue(section, key, df string) string {
	return config.GetConfigValue(section, key, df)
}

// config interface
type Config interface {
	// params(filename, section, key)
	GetConfigValue(string, string, string) string
}

// struct for default config
type DefaultConfig struct {
	config   map[string]interface{}
	rootPath string
}

func NewDefaultConfig(path string) *DefaultConfig {
	c := &DefaultConfig{}
	c.rootPath = path
	return c
}

func SetDefaultConfig() {
	SetConfig(NewDefaultConfig(""))
}

// get parameter from json file
func (c *DefaultConfig) GetConfigValue(section, key, defaultValue string) string {
	if c.config == nil {
		fileName := c.rootPath + "/" + awsConfigFileName + ".json"
		file, e := ioutil.ReadFile(fileName)
		if e != nil {
			log.Error("[config] DefaultConfig File Load error, file="+fileName, e)
			return ""
		}
		json.Unmarshal(file, &c.config)
	}
	value := ParseToString(c.config[key])
	return value
}

// return value
func ParseToString(v interface{}) string {
	switch t := v.(type) {
	case string:
		return t
	case int, int32, int64, uint, uint32, uint64:
		return fmt.Sprintf("%d", t)
	case float32, float64:
		return fmt.Sprintf("%f", t)
	case bool:
		return fmt.Sprintf("%t", t)
	case nil:
		return "<nil>"
	default:
		return fmt.Sprintf("%+v", t)
	}
}
<commit_msg>Modified to use default params when config file not found<commit_after>// AWS config libs

package config

import (
	"github.com/evalphobia/aws-sdk-go-wrapper/log"

	"encoding/json"
	"fmt"
	"io/ioutil"
)

const (
	awsConfigFileName = "aws"
)

var (
	config Config
)

func init() {
	SetDefaultConfig()
}

// get parameter from config file
func SetConfig(conf Config) {
	config = conf
}

func GetConfigValue(section, key, df string) string {
	return config.GetConfigValue(section, key, df)
}

// config interface
type Config interface {
	// params(filename, section, key)
	GetConfigValue(string, string, string) string
}

// struct for default config
type DefaultConfig struct {
	config   map[string]interface{}
	rootPath string
}

func NewDefaultConfig(path string) *DefaultConfig {
	c := &DefaultConfig{}
	c.rootPath = path
	return c
}

func SetDefaultConfig() {
	SetConfig(NewDefaultConfig(""))
}

// get parameter from json file
func (c *DefaultConfig) GetConfigValue(section, key, defaultValue string) string {
	if c.config == nil {
		fileName := c.rootPath + "/" + awsConfigFileName + ".json"
		file, e := ioutil.ReadFile(fileName)
		if e != nil {
			log.Error("[config] DefaultConfig File Load error, file="+fileName, e)
			return defaultValue
		}
		json.Unmarshal(file, &c.config)
	}
	val, ok := c.config[key]
	if ok {
		return ParseToString(val)
	} else {
		return defaultValue
	}
}

// return value
func ParseToString(v interface{}) string {
	switch t := v.(type) {
	case string:
		return t
	case int, int32, int64, uint, uint32, uint64:
		return fmt.Sprintf("%d", t)
	case float32, float64:
		return fmt.Sprintf("%f", t)
	case bool:
		return fmt.Sprintf("%t", t)
	case nil:
		return "<nil>"
	default:
		return fmt.Sprintf("%+v", t)
	}
}
<|endoftext|>