<commit_before>// Copyright 2020, Square, Inc.

package cmd

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/square/spincycle/v2/proto"
	"github.com/square/spincycle/v2/spinc/app"
)

const (
	// formatting for outputing request info
	findReqColLen   = 40
	findIdColLen    = 20
	findUserColLen  = 9
	findStateColLen = 9
	findJobsColLen  = 15

	findTimeFmt    = "YYYY-MM-DD HH:MM:SS UTC" // expected time input format
	findTimeFmtStr = "2006-01-02 15:04:05 MST" // expected time input format as the actual format string (input to time.Parse)
)

var (
	findTimeColLen = len(findTimeFmt)
	findUtcIndex   = strings.Index(findTimeFmt, "UTC")
)

type Find struct {
	ctx    app.Context
	filter proto.RequestFilter
}

func NewFind(ctx app.Context) *Find {
	return &Find{
		ctx: ctx,
	}
}

func (c *Find) Prepare() error {
	/* Parse. */
	// See command usage for details about each filter
	validFilters := map[string]bool{
		"type":   true,
		"states": true,
		"user":   true,
		"since":  true,
		"until":  true,
		"limit":  true,
		"offset": true,
	}
	filters := map[string]string{}
	for _, arg := range c.ctx.Command.Args {
		split := strings.SplitN(arg, "=", 2)
		if len(split) != 2 {
			return fmt.Errorf("Invalid command arg: %s: split on = produced %d values, expected 2 (filter=value)", arg, len(split))
		}
		filter := split[0]
		value := split[1]

		if !validFilters[filter] {
			return fmt.Errorf("Invalid filter '%s'", filter)
		}
		if _, ok := filters[filter]; ok {
			return fmt.Errorf("Filter '%s' specified multiple times", filter)
		}
		filters[filter] = value

		if c.ctx.Options.Debug {
			app.Debug("filter '%s'='%s'", filter, value)
		}
	}

	/* Process some args. */
	var err error

	states := []byte{}
	if len(filters["states"]) > 0 {
		for _, state := range strings.Split(filters["states"], ",") {
			val, ok := proto.StateValue[state]
			if !ok {
				expected := make([]string, 0, len(proto.StateValue))
				for k, _ := range proto.StateValue {
					expected = append(expected, k)
				}
				return fmt.Errorf("Invalid state '%s', expected one of: %s", state, strings.Join(expected, ", "))
			}
			states = append(states, val)
		}
	}

	var since time.Time
	if filters["since"] != "" {
		if strings.Index(filters["since"], "UTC") != findUtcIndex {
			return fmt.Errorf("Invalid time %s, expected string 'UTC' at index %d", filters["since"], findUtcIndex)
		}
		since, err = time.Parse(findTimeFmtStr, filters["since"])
		if err != nil {
			return fmt.Errorf("Invalid time %s, expected form '%s'", filters["since"], findTimeFmt)
		}
	}

	var until time.Time
	if filters["until"] != "" {
		if strings.Index(filters["until"], "UTC") != findUtcIndex {
			return fmt.Errorf("Invalid time %s, expected string 'UTC' at index %d", filters["until"], findUtcIndex)
		}
		until, err = time.Parse(findTimeFmtStr, filters["until"])
		if err != nil {
			return fmt.Errorf("Invalid time %s, expected form '%s'", filters["until"], findTimeFmt)
		}
	}

	var limit uint
	if filters["limit"] != "" {
		l, err := strconv.ParseUint(filters["limit"], 10, strconv.IntSize)
		if err != nil {
			return fmt.Errorf("Invalid limit '%s', expected value >= 0", filters["limit"])
		}
		limit = uint(l)
	}

	var offset uint
	if filters["offset"] != "" {
		o, err := strconv.ParseUint(filters["offset"], 10, strconv.IntSize)
		if err != nil {
			return fmt.Errorf("Invalid offset '%s', expected value >= 0", filters["offset"])
		}
		offset = uint(o)
	}

	/* Build the request filter. */
	c.filter = proto.RequestFilter{
		Type:   filters["type"],
		States: states,
		User:   filters["user"],

		Since: since,
		Until: until,

		Limit:  limit,
		Offset: offset,
	}

	return nil
}

func (c *Find) Run() error {
	requests, err := c.ctx.RMClient.FindRequests(c.filter)
	if err != nil {
		return err
	}
	if c.ctx.Options.Debug {
		app.Debug("requests: %#v", requests)
	}

	if c.ctx.Hooks.CommandRunResult != nil {
		c.ctx.Hooks.CommandRunResult(requests, err)
		return nil
	}

	if len(requests) == 0 {
		return nil
	}

	/*
	   ID                   REQUEST                                  USER      STATE     CREATED STARTED FINISHED JOBS            HOST
	   -------------------- 1234567890123456789012345678901234567890 123456789 123456789 ------- ------- -------- 123456789012345 *
	*/
	line := fmt.Sprintf("%%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%s\n",
		findIdColLen, findReqColLen, findUserColLen, findStateColLen, findTimeColLen, findTimeColLen, findTimeColLen, findJobsColLen)

	fmt.Fprintf(c.ctx.Out, line, "ID", "REQUEST", "USER", "STATE", "CREATED", "STARTED", "FINISHED", "JOBS", "HOST")

	for _, r := range requests {
		state, ok := proto.StateName[r.State]
		if !ok {
			state = proto.StateName[proto.STATE_UNKNOWN]
		}

		createdAt := r.CreatedAt.Local().Format(findTimeFmtStr)

		startedAt := "N/A"
		if r.StartedAt != nil {
			startedAt = r.StartedAt.Local().Format(findTimeFmtStr)
		}

		finishedAt := "N/A"
		if r.FinishedAt != nil {
			finishedAt = r.FinishedAt.Local().Format(findTimeFmtStr)
		}

		jobs := fmt.Sprintf("%d / %d", r.FinishedJobs, r.TotalJobs)

		fmt.Fprintf(c.ctx.Out, line,
			SqueezeString(r.Id, findIdColLen, ".."),
			SqueezeString(r.Type, findReqColLen, ".."),
			SqueezeString(r.User, findUserColLen, ".."),
			SqueezeString(state, findStateColLen, ".."),
			createdAt, startedAt, finishedAt,
			SqueezeString(jobs, findJobsColLen, ".."),
			r.JobRunnerURL)
	}

	return nil
}

func (c *Find) Cmd() string {
	if len(c.ctx.Command.Args) > 0 {
		return "find " + strings.Join(c.ctx.Command.Args, " ")
	}
	return "find"
}

func (c *Find) Help() string {
	return fmt.Sprintf(`'spinc find [filter=value]' retrieves and filters requests.

Filters:
  type        type of request to return
  states      comma-separated list of request states to include
  user        return only requests made by this user
  since       return requests created or run after this time
  until       return requests created or run before this time
  limit       limit response to this many requests
  offset      skip the first <offset> requests, ignored if <limit> not set

Times should be formated as '%s'. Time should be specified in UTC.
`, findTimeFmt)
}
<commit_msg>spinc find: set default limit to number of requests<commit_after>// Copyright 2020, Square, Inc.

package cmd

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/square/spincycle/v2/proto"
	"github.com/square/spincycle/v2/spinc/app"
)

const (
	findLimitDefault = 10 // limit to 10 requests by default

	// formatting for outputing request info
	findReqColLen   = 40
	findIdColLen    = 20
	findUserColLen  = 9
	findStateColLen = 9
	findJobsColLen  = 15

	findTimeFmt    = "YYYY-MM-DD HH:MM:SS UTC" // expected time input format
	findTimeFmtStr = "2006-01-02 15:04:05 MST" // expected time input format as the actual format string (input to time.Parse)
)

var (
	findTimeColLen = len(findTimeFmt)
	findUtcIndex   = strings.Index(findTimeFmt, "UTC")
)

type Find struct {
	ctx    app.Context
	filter proto.RequestFilter
}

func NewFind(ctx app.Context) *Find {
	return &Find{
		ctx: ctx,
	}
}

func (c *Find) Prepare() error {
	/* Parse. */
	// See command usage for details about each filter
	validFilters := map[string]bool{
		"type":   true,
		"states": true,
		"user":   true,
		"since":  true,
		"until":  true,
		"limit":  true,
		"offset": true,
	}
	filters := map[string]string{}
	for _, arg := range c.ctx.Command.Args {
		split := strings.SplitN(arg, "=", 2)
		if len(split) != 2 {
			return fmt.Errorf("Invalid command arg: %s: split on = produced %d values, expected 2 (filter=value)", arg, len(split))
		}
		filter := split[0]
		value := split[1]

		if !validFilters[filter] {
			return fmt.Errorf("Invalid filter '%s'", filter)
		}
		if _, ok := filters[filter]; ok {
			return fmt.Errorf("Filter '%s' specified multiple times", filter)
		}
		filters[filter] = value

		if c.ctx.Options.Debug {
			app.Debug("filter '%s'='%s'", filter, value)
		}
	}

	/* Process some args. */
	var err error

	states := []byte{}
	if len(filters["states"]) > 0 {
		for _, state := range strings.Split(filters["states"], ",") {
			val, ok := proto.StateValue[state]
			if !ok {
				expected := make([]string, 0, len(proto.StateValue))
				for k, _ := range proto.StateValue {
					expected = append(expected, k)
				}
				return fmt.Errorf("Invalid state '%s', expected one of: %s", state, strings.Join(expected, ", "))
			}
			states = append(states, val)
		}
	}

	var since time.Time
	if filters["since"] != "" {
		if strings.Index(filters["since"], "UTC") != findUtcIndex {
			return fmt.Errorf("Invalid time %s, expected string 'UTC' at index %d", filters["since"], findUtcIndex)
		}
		since, err = time.Parse(findTimeFmtStr, filters["since"])
		if err != nil {
			return fmt.Errorf("Invalid time %s, expected form '%s'", filters["since"], findTimeFmt)
		}
	}

	var until time.Time
	if filters["until"] != "" {
		if strings.Index(filters["until"], "UTC") != findUtcIndex {
			return fmt.Errorf("Invalid time %s, expected string 'UTC' at index %d", filters["until"], findUtcIndex)
		}
		until, err = time.Parse(findTimeFmtStr, filters["until"])
		if err != nil {
			return fmt.Errorf("Invalid time %s, expected form '%s'", filters["until"], findTimeFmt)
		}
	}

	var limit uint
	if filters["limit"] == "" {
		limit = findLimitDefault
	} else {
		l, err := strconv.ParseUint(filters["limit"], 10, strconv.IntSize)
		if err != nil {
			return fmt.Errorf("Invalid limit '%s', expected value >= 0", filters["limit"])
		}
		limit = uint(l)
	}

	var offset uint
	if filters["offset"] != "" {
		o, err := strconv.ParseUint(filters["offset"], 10, strconv.IntSize)
		if err != nil {
			return fmt.Errorf("Invalid offset '%s', expected value >= 0", filters["offset"])
		}
		offset = uint(o)
	}

	/* Build the request filter. */
	c.filter = proto.RequestFilter{
		Type:   filters["type"],
		States: states,
		User:   filters["user"],

		Since: since,
		Until: until,

		Limit:  limit,
		Offset: offset,
	}

	return nil
}

func (c *Find) Run() error {
	requests, err := c.ctx.RMClient.FindRequests(c.filter)
	if err != nil {
		return err
	}
	if c.ctx.Options.Debug {
		app.Debug("requests: %#v", requests)
	}

	if c.ctx.Hooks.CommandRunResult != nil {
		c.ctx.Hooks.CommandRunResult(requests, err)
		return nil
	}

	if len(requests) == 0 {
		return nil
	}

	/*
	   ID                   REQUEST                                  USER      STATE     CREATED STARTED FINISHED JOBS            HOST
	   -------------------- 1234567890123456789012345678901234567890 123456789 123456789 ------- ------- -------- 123456789012345 *
	*/
	line := fmt.Sprintf("%%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%s\n",
		findIdColLen, findReqColLen, findUserColLen, findStateColLen, findTimeColLen, findTimeColLen, findTimeColLen, findJobsColLen)

	fmt.Fprintf(c.ctx.Out, line, "ID", "REQUEST", "USER", "STATE", "CREATED", "STARTED", "FINISHED", "JOBS", "HOST")

	for _, r := range requests {
		state, ok := proto.StateName[r.State]
		if !ok {
			state = proto.StateName[proto.STATE_UNKNOWN]
		}

		createdAt := r.CreatedAt.Local().Format(findTimeFmtStr)

		startedAt := "N/A"
		if r.StartedAt != nil {
			startedAt = r.StartedAt.Local().Format(findTimeFmtStr)
		}

		finishedAt := "N/A"
		if r.FinishedAt != nil {
			finishedAt = r.FinishedAt.Local().Format(findTimeFmtStr)
		}

		jobs := fmt.Sprintf("%d / %d", r.FinishedJobs, r.TotalJobs)

		fmt.Fprintf(c.ctx.Out, line,
			SqueezeString(r.Id, findIdColLen, ".."),
			SqueezeString(r.Type, findReqColLen, ".."),
			SqueezeString(r.User, findUserColLen, ".."),
			SqueezeString(state, findStateColLen, ".."),
			createdAt, startedAt, finishedAt,
			SqueezeString(jobs, findJobsColLen, ".."),
			r.JobRunnerURL)
	}

	return nil
}

func (c *Find) Cmd() string {
	if len(c.ctx.Command.Args) > 0 {
		return "find " + strings.Join(c.ctx.Command.Args, " ")
	}
	return "find"
}

func (c *Find) Help() string {
	return fmt.Sprintf(`'spinc find [filter=value]' retrieves and filters requests.

Filters:
  type        type of request to return
  states      comma-separated list of request states to include
  user        return only requests made by this user
  since       return requests created or run after this time
  until       return requests created or run before this time
  limit       limit response to this many requests (default: %d)
  offset      skip the first <offset> requests

Times should be formated as '%s'. Time should be specified in UTC.
`, findLimitDefault, findTimeFmt)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/user"
	"path"
	"strings"
	"time"
)

// This gets called every time the data's needed.
// That makes it so you can change stuff while running.

func ReadLines(fn string) ([]string, error) {
	lines := make([]string, 0)

	f, err := os.Open(fn)
	if err != nil {
		return lines, err
	}
	defer f.Close()

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		switch {
		case line == "":
		default:
			lines = append(lines, line)
		}
	}

	return lines, nil
}

type Network struct {
	running bool

	Nick string

	basePath string
	serverIndex int

	conn io.ReadWriteCloser
	logq chan Message
	inq  chan string
	outq chan string
}

func NewNetwork(basePath string) *Network {
	nw := Network{
		running: true,
		basePath: basePath,
		logq: make(chan Message, 20),
	}

	go nw.LogLoop()

	return &nw
}

func (nw *Network) Close() {
	nw.running = false
	close(nw.logq)
	if nw.conn != nil {
		nw.conn.Close()
	}
}

func (nw *Network) WatchOutqDirectory() {
	outqDirname := path.Join(nw.basePath, "outq")

	dir, err := os.Open(outqDirname)
	if err != nil {
		log.Fatal(err)
	}
	defer dir.Close()

	// XXX: Do this with fsnotify
	for nw.running {
		entities, _ := dir.Readdirnames(0)
		for _, fn := range entities {
			pathname := path.Join(outqDirname, fn)
			nw.HandleInfile(pathname)
		}
		_, _ = dir.Seek(0, 0)
		time.Sleep(500 * time.Millisecond)
	}
}

func (nw *Network) HandleInfile(fn string) {
	f, err := os.Open(fn)
	if err != nil {
		return
	}
	defer f.Close()

	// Do this after Open attempt.
	// If Open fails, the file will stick around.
	// Hopefully this is helpful for debugging.
	os.Remove(fn)

	inf := bufio.NewScanner(f)
	for inf.Scan() {
		txt := inf.Text()
		nw.outq <- txt
	}
}

func (nw *Network) LogLoop() {
	logf := NewLogfile(nw.basePath, int(maxlogsize))
	defer logf.Close()

	for m := range nw.logq {
		logf.Log(m.String())
	}
}

func (nw *Network) ServerWriteLoop() {
	for v := range nw.outq {
		m, _ := NewMessage(v)
		nw.logq <- m
		fmt.Fprintln(nw.conn, v)
	}
}

func (nw *Network) NextNick() {
	nicks, err := ReadLines(path.Join(nw.basePath, "nick"))
	if err != nil {
		log.Print(err)
		return
	}

	// Make up some alternates if they weren't provided
	if len(nicks) == 1 {
		nicks = append(nicks, nicks[0] + "_")
		nicks = append(nicks, nicks[0] + "__")
		nicks = append(nicks, nicks[0] + "___")
	}

	nextidx := 0
	for idx, n := range nicks {
		if n == nw.Nick {
			nextidx = idx + 1
		}
	}

	nw.Nick = nicks[nextidx % len(nicks)]
	nw.outq <- "NICK " + nw.Nick
}

func (nw *Network) JoinChannels() {
	chans, err := ReadLines(path.Join(nw.basePath, "channels"))
	if err != nil {
		log.Print(err)
		return
	}

	for _, ch := range chans {
		nw.outq <- "JOIN " + ch
	}
}

func (nw *Network) MessageDispatch() {
	for line := range nw.inq {
		m, err := NewMessage(line)
		if err != nil {
			log.Print(err)
			continue
		}

		nw.logq <- m

		// XXX: Add in a handler subprocess call

		switch m.Command {
		case "PING":
			nw.outq <- "PONG :" + m.Text
			continue
		case "001":
			nw.JoinChannels()
		case "433":
			nw.NextNick()
		case "PRIVMSG":
			if m.Text == "\001VERSION\001" {
				//nw.outq <- "NOTICE " + m.Sender + " :\001VERSION Spongy v8294.003.1R6pl58₄SEσ\001"
				nw.outq <- "NOTICE " + m.Sender + " :\001 VERSION begin 644 version.txt\001"
				nw.outq <- "NOTICE " + m.Sender + " :\001 VERSION F4W!O;F=Y('9E<G-I;VX@.#(Y-\"XP,#,N,5(V<&PU..*\"A%-%SX,`\001"
				nw.outq <- "NOTICE " + m.Sender + " :\001 VERSION `\001"
				nw.outq <- "NOTICE " + m.Sender + " :\001 VERSION end\001"
			}
		}
	}
}

func (nw *Network) ConnectToNextServer() bool {
	servers, err := ReadLines(path.Join(nw.basePath, "server"))
	if err != nil {
		log.Printf("Couldn't find any servers to connect to in %s", nw.basePath)
		return false
	}

	if nw.serverIndex > len(servers) {
		nw.serverIndex = 0
	}
	server := servers[nw.serverIndex]

	switch (server[0]) {
	case '|':
		parts := strings.Split(server[1:], " ")
		nw.conn, err = StartStdioProcess(parts[0], parts[1:])
	case '^':
		nw.conn, err = net.Dial("tcp", server[1:])
	default:
		log.Print("Not validating server certificate!")
		config := &tls.Config{
			InsecureSkipVerify: true,
		}
		nw.conn, err = tls.Dial("tcp", server, config)
	}

	if err != nil {
		log.Print(err)
		return false
	}

	return true
}

func (nw *Network) login() {
	var name string

	names, err := ReadLines(path.Join(nw.basePath, "name"))
	if err == nil {
		name = names[0]
	}

	if name == "" {
		me, err := user.Current()
		if err == nil {
			name = me.Name
		}
	}

	if name == "" {
		name = "Charlie"
	}

	nw.outq <- "USER g g g :" + name
	nw.NextNick()
}

func (nw *Network) Connect(){
	for nw.running {
		if ! nw.ConnectToNextServer() {
			time.Sleep(8 * time.Second)
			continue
		}

		nw.inq = make(chan string, 20)
		nw.outq = make(chan string, 20)

		go nw.ServerWriteLoop()
		go nw.MessageDispatch()
		go nw.WatchOutqDirectory()

		nw.login()

		scanner := bufio.NewScanner(nw.conn)
		for scanner.Scan() {
			nw.inq <- scanner.Text()
		}

		close(nw.inq)
		close(nw.outq)
	}
}

<commit_msg>Add support for network passwords<commit_after>package main

import (
	"bufio"
	"crypto/tls"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/user"
	"path"
	"strings"
	"time"
)

// This gets called every time the data's needed.
// That makes it so you can change stuff while running.

func ReadLines(fn string) ([]string, error) {
	lines := make([]string, 0)

	f, err := os.Open(fn)
	if err != nil {
		return lines, err
	}
	defer f.Close()

	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		switch {
		case line == "":
		default:
			lines = append(lines, line)
		}
	}

	return lines, nil
}

type Network struct {
	running bool

	Nick string

	basePath string
	serverIndex int

	conn io.ReadWriteCloser
	logq chan Message
	inq  chan string
	outq chan string
}

func NewNetwork(basePath string) *Network {
	nw := Network{
		running: true,
		basePath: basePath,
		logq: make(chan Message, 20),
	}

	go nw.LogLoop()

	return &nw
}

func (nw *Network) Close() {
	nw.running = false
	close(nw.logq)
	if nw.conn != nil {
		nw.conn.Close()
	}
}

func (nw *Network) WatchOutqDirectory() {
	outqDirname := path.Join(nw.basePath, "outq")

	dir, err := os.Open(outqDirname)
	if err != nil {
		log.Fatal(err)
	}
	defer dir.Close()

	// XXX: Do this with fsnotify
	for nw.running {
		entities, _ := dir.Readdirnames(0)
		for _, fn := range entities {
			pathname := path.Join(outqDirname, fn)
			nw.HandleInfile(pathname)
		}
		_, _ = dir.Seek(0, 0)
		time.Sleep(500 * time.Millisecond)
	}
}

func (nw *Network) HandleInfile(fn string) {
	f, err := os.Open(fn)
	if err != nil {
		return
	}
	defer f.Close()

	// Do this after Open attempt.
	// If Open fails, the file will stick around.
	// Hopefully this is helpful for debugging.
	os.Remove(fn)

	inf := bufio.NewScanner(f)
	for inf.Scan() {
		txt := inf.Text()
		nw.outq <- txt
	}
}

func (nw *Network) LogLoop() {
	logf := NewLogfile(nw.basePath, int(maxlogsize))
	defer logf.Close()

	for m := range nw.logq {
		logf.Log(m.String())
	}
}

func (nw *Network) ServerWriteLoop() {
	for v := range nw.outq {
		m, _ := NewMessage(v)
		nw.logq <- m
		fmt.Fprintln(nw.conn, v)
	}
}

func (nw *Network) NextNick() {
	nicks, err := ReadLines(path.Join(nw.basePath, "nick"))
	if err != nil {
		log.Print(err)
		return
	}

	// Make up some alternates if they weren't provided
	if len(nicks) == 1 {
		nicks = append(nicks, nicks[0] + "_")
		nicks = append(nicks, nicks[0] + "__")
		nicks = append(nicks, nicks[0] + "___")
	}

	nextidx := 0
	for idx, n := range nicks {
		if n == nw.Nick {
			nextidx = idx + 1
		}
	}

	nw.Nick = nicks[nextidx % len(nicks)]
	nw.outq <- "NICK " + nw.Nick
}

func (nw *Network) JoinChannels() {
	chans, err := ReadLines(path.Join(nw.basePath, "channels"))
	if err != nil {
		log.Print(err)
		return
	}

	for _, ch := range chans {
		nw.outq <- "JOIN " + ch
	}
}

func (nw *Network) MessageDispatch() {
	for line := range nw.inq {
		m, err := NewMessage(line)
		if err != nil {
			log.Print(err)
			continue
		}

		nw.logq <- m

		// XXX: Add in a handler subprocess call

		switch m.Command {
		case "PING":
			nw.outq <- "PONG :" + m.Text
			continue
		case "001":
			nw.JoinChannels()
		case "433":
			nw.NextNick()
		case "PRIVMSG":
			if m.Text == "\001VERSION\001" {
				//nw.outq <- "NOTICE " + m.Sender + " :\001VERSION Spongy v8294.003.1R6pl58₄SEσ\001"
				nw.outq <- "NOTICE " + m.Sender + " :\001 VERSION begin 644 version.txt\001"
				nw.outq <- "NOTICE " + m.Sender + " :\001 VERSION F4W!O;F=Y('9E<G-I;VX@.#(Y-\"XP,#,N,5(V<&PU..*\"A%-%SX,`\001"
				nw.outq <- "NOTICE " + m.Sender + " :\001 VERSION `\001"
				nw.outq <- "NOTICE " + m.Sender + " :\001 VERSION end\001"
			}
		}
	}
}

func (nw *Network) ConnectToNextServer() bool {
	servers, err := ReadLines(path.Join(nw.basePath, "server"))
	if err != nil {
		log.Printf("Couldn't find any servers to connect to in %s", nw.basePath)
		return false
	}

	if nw.serverIndex > len(servers) {
		nw.serverIndex = 0
	}
	server := servers[nw.serverIndex]

	switch (server[0]) {
	case '|':
		parts := strings.Split(server[1:], " ")
		nw.conn, err = StartStdioProcess(parts[0], parts[1:])
	case '^':
		nw.conn, err = net.Dial("tcp", server[1:])
	default:
		log.Print("Not validating server certificate!")
		config := &tls.Config{
			InsecureSkipVerify: true,
		}
		nw.conn, err = tls.Dial("tcp", server, config)
	}

	if err != nil {
		log.Print(err)
		return false
	}

	return true
}

func (nw *Network) login() {
	var name string

	passwd, err := ReadLines(path.Join(nw.basePath, "passwd"))
	if err == nil {
		nw.outq <- "PASS " + passwd[0]
	}

	names, err := ReadLines(path.Join(nw.basePath, "name"))
	if err == nil {
		name = names[0]
	}

	if name == "" {
		me, err := user.Current()
		if err == nil {
			name = me.Name
		}
	}

	if name == "" {
		name = "Charlie"
	}

	nw.outq <- "USER g g g :" + name
	nw.NextNick()
}

func (nw *Network) Connect(){
	for nw.running {
		if ! nw.ConnectToNextServer() {
			time.Sleep(8 * time.Second)
			continue
		}

		nw.inq = make(chan string, 20)
		nw.outq = make(chan string, 20)

		go nw.ServerWriteLoop()
		go nw.MessageDispatch()
		go nw.WatchOutqDirectory()

		nw.login()

		scanner := bufio.NewScanner(nw.conn)
		for scanner.Scan() {
			nw.inq <- scanner.Text()
		}

		close(nw.inq)
		close(nw.outq)
	}
}

<|endoftext|>


<commit_before>// Copyright 2017 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bufio"
	"context"
	"database/sql"
	"flag"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/ngaut/log"
	"github.com/ngaut/pool"
)

var (
	concurrent     = flag.Int("c", 50, "concurrent workers, default: 50")
	sqlCount       = flag.Int("sql-count", 0, "sql count, default read all data from file: 0")
	maxTime        = flag.Int("max-time", 0, "exec max time, default: 0")
	reportInterval = flag.Int("report-interval", 0, "report status interval, default: 0")
	addr           = flag.String("addr", ":4000", "tidb-server addr, default: :4000")
	dbName         = flag.String("db", "test", "db name, default: test")
	user           = flag.String("u", "root", "username, default: root")
	password       = flag.String("p", "", "password, default: empty")
	logLevel       = flag.String("L", "error", "log level, default: error")
	sqlFile        = flag.String("data", "./bench.sql", "SQL data file for bench")
)

var (
	connPool *pool.Cache
	statChan chan *stat
	db       *sql.DB
)

const (
	statChanSize  int = 10000
	queryChanSize int = 10000
)

func init() {
	flag.Parse()
	log.SetLevelByString(*logLevel)
	statChan = make(chan *stat, statChanSize)
	var err error
	db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", *user, *password, *addr, *dbName))
	if err != nil {
		log.Fatal(err)
	}
}

func readQuery(ctx context.Context, queryChan chan string) {
	var querys []string
	file, err := os.Open(*sqlFile)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		file.Close()
		close(queryChan)
	}()
	cnt := 0
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		query := scanner.Text()
		cnt++
		queryChan <- query
		querys = append(querys, query)
		if *sqlCount != 0 && cnt >= *sqlCount {
			break
		}
		select {
		case <-ctx.Done():
			log.Infof("Get %d queries\n", cnt)
			return
		default:
		}
	}
	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
LOOP:
	for cnt < *sqlCount {
		for _, query := range querys {
			cnt++
			queryChan <- query
			if cnt >= *sqlCount {
				break LOOP
			}
			select {
			case <-ctx.Done():
				log.Infof("Get %d queries\n", cnt)
				return
			default:
			}
		}
	}
	log.Infof("Get %d queries\n", cnt)
}

func worker(ctx context.Context, id int, queryChan chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		query, ok := <-queryChan
		if !ok {
			// No more query
			return
		}
		exec(query)
		select {
		case <-ctx.Done():
			return
		default:
		}
	}
}

// Structure for stat result.
type stat struct {
	spend time.Duration
	succ  bool
}

func exec(sqlStmt string) error {
	sql := strings.ToLower(sqlStmt)
	isQuery := strings.HasPrefix(sql, "select")
	// Get time
	startTs := time.Now()
	err := runQuery(sqlStmt, isQuery)
	if err != nil {
		log.Warnf("Exec sql [%s]: %s", sqlStmt, err)
		statChan <- &stat{}
		return err
	}
	statChan <- &stat{spend: time.Now().Sub(startTs), succ: true}
	return nil
}

func runQuery(sqlStmt string, isQuery bool) error {
	if isQuery {
		rows, err := db.Query(sqlStmt)
		defer rows.Close()
		if err != nil {
			return err
		}
		return nil
	}
	_, err := db.Exec(sqlStmt)
	return err
}

func statWorker(wg *sync.WaitGroup, startTs time.Time) {
	defer wg.Done()
	var (
		total       int64
		succ        int64
		spend       time.Duration
		tempStartTs = startTs
		tempTotal   int64
		tempSpend   time.Duration
		tempSucc    int64
	)
	for {
		tempExecTime := time.Now().Sub(tempStartTs)
		if *reportInterval != 0 && tempExecTime.Seconds() >= float64(*reportInterval) {
			log.Infof("Query: %d, Succ: %d, Faild: %d, Time: %v, Avg response time: %.04fms, QPS: %.02f : \n", tempTotal, tempSucc, tempTotal-tempSucc, tempExecTime, (tempSpend.Seconds()*1000)/float64(tempTotal), float64(tempTotal)/tempExecTime.Seconds())
			tempStartTs = time.Now()
			tempTotal = 0
			tempSpend = 0
			tempSucc = 0
		}
		s, ok := <-statChan
		if !ok {
			break
		}
		total++
		tempTotal++
		if s.succ {
			succ++
			tempSucc++
		}
		spend += s.spend
		tempSpend += s.spend
	}
	execTime := time.Now().Sub(startTs)
	log.Info("\n*************************final result***************************\n")
	log.Infof("Total Query: %d, Succ: %d, Faild: %d, Time: %v, Avg response time: %.04fms, QPS: %.02f : \n", total, succ, total-succ, execTime, (spend.Seconds()*1000)/float64(total), float64(total)/execTime.Seconds())
}

func main() {
	// Start
	log.Info("Start Bench")
	queryChan := make(chan string, queryChanSize)
	wg := sync.WaitGroup{}
	wgStat := sync.WaitGroup{}
	// Start N workers
	timeout := time.Duration(*maxTime) * time.Second
	for i := 0; i < *concurrent; i++ {
		wg.Add(1)
		ctx, _ := context.WithTimeout(context.Background(), timeout)
		go worker(ctx, i, queryChan, &wg)
	}

	wgStat.Add(1)
	startTs := time.Now()
	go statWorker(&wgStat, startTs)

	ctxR, _ := context.WithTimeout(context.Background(), timeout)
	go readQuery(ctxR, queryChan)
	wg.Wait()
	close(statChan)
	wgStat.Wait()
	log.Info("Done!")
}
<commit_msg>sql-bench: reomve unused variable<commit_after>// Copyright 2017 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bufio"
	"context"
	"database/sql"
	"flag"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/ngaut/log"
)

var (
	concurrent     = flag.Int("c", 50, "concurrent workers, default: 50")
	sqlCount       = flag.Int("sql-count", 0, "sql count, default read all data from file: 0")
	maxTime        = flag.Int("max-time", 0, "exec max time, default: 0")
	reportInterval = flag.Int("report-interval", 0, "report status interval, default: 0")
	addr           = flag.String("addr", ":4000", "tidb-server addr, default: :4000")
	dbName         = flag.String("db", "test", "db name, default: test")
	user           = flag.String("u", "root", "username, default: root")
	password       = flag.String("p", "", "password, default: empty")
	logLevel       = flag.String("L", "error", "log level, default: error")
	sqlFile        = flag.String("data", "./bench.sql", "SQL data file for bench")
)

var (
	statChan chan *stat
	db       *sql.DB
)

const (
	statChanSize  int = 10000
	queryChanSize int = 10000
)

func init() {
	flag.Parse()
	log.SetLevelByString(*logLevel)
	statChan = make(chan *stat, statChanSize)
	var err error
	db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", *user, *password, *addr, *dbName))
	if err != nil {
		log.Fatal(err)
	}
}

func readQuery(ctx context.Context, queryChan chan string) {
	var querys []string
	file, err := os.Open(*sqlFile)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		file.Close()
		close(queryChan)
	}()
	cnt := 0
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		query := scanner.Text()
		cnt++
		queryChan <- query
		querys = append(querys, query)
		if *sqlCount != 0 && cnt >= *sqlCount {
			break
		}
		select {
		case <-ctx.Done():
			log.Infof("Get %d queries\n", cnt)
			return
		default:
		}
	}
	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
LOOP:
	for cnt < *sqlCount {
		for _, query := range querys {
			cnt++
			queryChan <- query
			if cnt >= *sqlCount {
				break LOOP
			}
			select {
			case <-ctx.Done():
				log.Infof("Get %d queries\n", cnt)
				return
			default:
			}
		}
	}
	log.Infof("Get %d queries\n", cnt)
}

func worker(ctx context.Context, id int, queryChan chan string, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		query, ok := <-queryChan
		if !ok {
			// No more query
			return
		}
		exec(query)
		select {
		case <-ctx.Done():
			return
		default:
		}
	}
}

// Structure for stat result.
type stat struct {
	spend time.Duration
	succ  bool
}

func exec(sqlStmt string) error {
	sql := strings.ToLower(sqlStmt)
	isQuery := strings.HasPrefix(sql, "select")
	// Get time
	startTs := time.Now()
	err := runQuery(sqlStmt, isQuery)
	if err != nil {
		log.Warnf("Exec sql [%s]: %s", sqlStmt, err)
		statChan <- &stat{}
		return err
	}
	statChan <- &stat{spend: time.Now().Sub(startTs), succ: true}
	return nil
}

func runQuery(sqlStmt string, isQuery bool) error {
	if isQuery {
		rows, err := db.Query(sqlStmt)
		defer rows.Close()
		if err != nil {
			return err
		}
		return nil
	}
	_, err := db.Exec(sqlStmt)
	return err
}

func statWorker(wg *sync.WaitGroup, startTs time.Time) {
	defer wg.Done()
	var (
		total       int64
		succ        int64
		spend       time.Duration
		tempStartTs = startTs
		tempTotal   int64
		tempSpend   time.Duration
		tempSucc    int64
	)
	for {
		tempExecTime := time.Now().Sub(tempStartTs)
		if *reportInterval != 0 && tempExecTime.Seconds() >= float64(*reportInterval) {
			log.Infof("Query: %d, Succ: %d, Faild: %d, Time: %v, Avg response time: %.04fms, QPS: %.02f : \n", tempTotal, tempSucc, tempTotal-tempSucc, tempExecTime, (tempSpend.Seconds()*1000)/float64(tempTotal), float64(tempTotal)/tempExecTime.Seconds())
			tempStartTs = time.Now()
			tempTotal = 0
			tempSpend = 0
			tempSucc = 0
		}
		s, ok := <-statChan
		if !ok {
			break
		}
		total++
		tempTotal++
		if s.succ {
			succ++
			tempSucc++
		}
		spend += s.spend
		tempSpend += s.spend
	}
	execTime := time.Now().Sub(startTs)
	log.Info("\n*************************final result***************************\n")
	log.Infof("Total Query: %d, Succ: %d, Faild: %d, Time: %v, Avg response time: %.04fms, QPS: %.02f : \n", total, succ, total-succ, execTime, (spend.Seconds()*1000)/float64(total), float64(total)/execTime.Seconds())
}

func main() {
	// Start
	log.Info("Start Bench")
	queryChan := make(chan string, queryChanSize)
	wg := sync.WaitGroup{}
	wgStat := sync.WaitGroup{}
	// Start N workers
	timeout := time.Duration(*maxTime) * time.Second
	for i := 0; i < *concurrent; i++ {
		wg.Add(1)
		ctx, _ := context.WithTimeout(context.Background(), timeout)
		go worker(ctx, i, queryChan, &wg)
	}

	wgStat.Add(1)
	startTs := time.Now()
	go statWorker(&wgStat, startTs)

	ctxR, _ := context.WithTimeout(context.Background(), timeout)
	go readQuery(ctxR, queryChan)
	wg.Wait()
	close(statChan)
	wgStat.Wait()
	log.Info("Done!")
}
<|endoftext|>


<commit_before>// Copyright 2015 The Cockroach 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.
//
// Author: Peter Mattis (peter@cockroachlabs.com)

package sql_test

import (
	"bytes"
	"database/sql"
	"fmt"
	"math/rand"
	"os"
	"testing"

	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"

	"github.com/cockroachdb/cockroach/security"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/testutils/sqlutils"
)

func benchmarkCockroach(b *testing.B, f func(b *testing.B, db *sql.DB)) {
	s := server.StartTestServer(b)
	defer s.Stop()

	pgUrl, cleanupFn := sqlutils.PGUrl(b, s, security.RootUser, os.TempDir(), "benchmarkCockroach")
	defer cleanupFn()

	db, err := sql.Open("postgres", pgUrl.String())
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec(`CREATE DATABASE IF NOT EXISTS bench`); err != nil {
		b.Fatal(err)
	}

	f(b, db)
}

func benchmarkPostgres(b *testing.B, f func(b *testing.B, db *sql.DB)) {
	// Note: the following uses SSL. To run this, make sure your local
	// Postgres server has SSL enabled. To use Cockroach's checked-in
	// testing certificates for Postgres' SSL, first determine the
	// location of your Postgres server's configuration file:
	// ```
	// $ psql -h localhost -p 5432 -c 'SHOW config_file'
	//                config_file
	// -----------------------------------------
	//  /usr/local/var/postgres/postgresql.conf
	// (1 row)
	//```
	//
	// Now open this file and set the following values:
	// ```
	// $ cat /usr/local/var/postgres/postgresql.conf | grep ssl
	// ssl = on                            # (change requires restart)
	// ssl_cert_file = '/Users/tamird/src/go/src/github.com/cockroachdb/cockroach/resource/test_certs/node.server.crt'             # (change requires restart)
	// ssl_key_file = '/Users/tamird/src/go/src/github.com/cockroachdb/cockroach/resource/test_certs/node.server.key'              # (change requires restart)
	// ssl_ca_file = '/Users/tamird/src/go/src/github.com/cockroachdb/cockroach/resource/test_certs/ca.crt'                        # (change requires restart)
	// ```
	// Where `/Users/tamird/src/go/src/github.com/cockroachdb/cockroach`
	// is replaced with your local Cockroach source directory.
	// Be sure to restart Postgres for this to take effect.

	db, err := sql.Open("postgres", "sslmode=require host=localhost port=5432")
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec(`CREATE SCHEMA IF NOT EXISTS bench`); err != nil {
		b.Fatal(err)
	}

	f(b, db)
}

func benchmarkMySQL(b *testing.B, f func(b *testing.B, db *sql.DB)) {
	db, err := sql.Open("mysql", "root@tcp(localhost:3306)/")
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec(`CREATE DATABASE IF NOT EXISTS bench`); err != nil {
		b.Fatal(err)
	}

	f(b, db)
}

func runBenchmarkSelect1(b *testing.B, db *sql.DB) {
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		rows, err := db.Query(`SELECT 1`)
		if err != nil {
			b.Fatal(err)
		}
		rows.Close()
	}
	b.StopTimer()
}

// benchmarkSelect1 is a benchmark of the simplest SQL query: SELECT 1. This
// query requires no tables, expression analysis, etc. As such, it is measuring
// the overhead of parsing and other non-table processing (e.g. reading
// requests, writing responses).
func benchmarkSelect1(b *testing.B, scheme string) {
	s := &server.TestServer{}
	s.Ctx = server.NewTestContext()
	s.Ctx.Insecure = (scheme == "http" || scheme == "rpc")
	if err := s.Start(); err != nil {
		b.Fatal(err)
	}
	defer s.Stop()

	db, err := sql.Open("cockroach",
		scheme+"://node@"+s.ServingAddr()+"?certs="+s.Ctx.Certs)
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	runBenchmarkSelect1(b, db)
}

func BenchmarkSelect1_HTTP(b *testing.B) {
	benchmarkSelect1(b, "http")
}

func BenchmarkSelect1_HTTPS(b *testing.B) {
	benchmarkSelect1(b, "https")
}

func BenchmarkSelect1_RPC(b *testing.B) {
	benchmarkSelect1(b, "rpc")
}

func BenchmarkSelect1_RPCS(b *testing.B) {
	benchmarkSelect1(b, "rpcs")
}

func BenchmarkSelect1_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkSelect1)
}

func BenchmarkSelect1_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkSelect1)
}

func BenchmarkSelect1_MySQL(b *testing.B) {
	benchmarkMySQL(b, runBenchmarkSelect1)
}

// runBenchmarkInsert benchmarks inserting count rows into a table.
func runBenchmarkInsert(b *testing.B, db *sql.DB, count int) {
	if _, err := db.Exec(`DROP TABLE IF EXISTS bench.insert`); err != nil {
		b.Fatal(err)
	}
	if _, err := db.Exec(`CREATE TABLE bench.insert (k INT PRIMARY KEY)`); err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	var buf bytes.Buffer
	val := 0
	for i := 0; i < b.N; i++ {
		buf.Reset()
		buf.WriteString(`INSERT INTO bench.insert VALUES `)
		for j := 0; j < count; j++ {
			if j > 0 {
				buf.WriteString(", ")
			}
			fmt.Fprintf(&buf, "(%d)", val)
			val++
		}
		if _, err := db.Exec(buf.String()); err != nil {
			b.Fatal(err)
		}
	}
	b.StopTimer()

	if _, err := db.Exec(`DROP TABLE bench.insert`); err != nil {
		b.Fatal(err)
	}
}

func runBenchmarkInsert1(b *testing.B, db *sql.DB) {
	runBenchmarkInsert(b, db, 1)
}

func runBenchmarkInsert10(b *testing.B, db *sql.DB) {
	runBenchmarkInsert(b, db, 10)
}

func runBenchmarkInsert100(b *testing.B, db *sql.DB) {
	runBenchmarkInsert(b, db, 100)
}

func BenchmarkInsert1_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkInsert1)
}

func BenchmarkInsert1_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkInsert1)
}

func BenchmarkInsert10_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkInsert10)
}

func BenchmarkInsert10_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkInsert10)
}

func BenchmarkInsert100_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkInsert100)
}

func BenchmarkInsert100_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkInsert100)
}

func prepareUpdateBenchData(b *testing.B, db *sql.DB, rows int) {
	if _, err := db.Exec(`DROP TABLE IF EXISTS bench.update`); err != nil {
		b.Fatal(err)
	}
	if _, err := db.Exec(`CREATE TABLE bench.update (k INT PRIMARY KEY, v INT)`); err != nil {
		b.Fatal(err)
	}

	var buf bytes.Buffer
	buf.WriteString(`INSERT INTO bench.update VALUES `)
	for i := 0; i < rows; i++ {
		if i > 0 {
			buf.WriteString(", ")
		}
		fmt.Fprintf(&buf, "(%d, %d)", i, i)
	}
	if _, err := db.Exec(buf.String()); err != nil {
		b.Fatal(err)
	}
}

func cleanupUpdateBenchData(b *testing.B, db *sql.DB) {
	if _, err := db.Exec(`DROP TABLE bench.update`); err != nil {
		b.Fatal(err)
	}
}

// runBenchmarkUpdate benchmarks updating a random row.
func runBenchmarkUpdate(b *testing.B, db *sql.DB) {
	rows := 10000
	prepareUpdateBenchData(b, db, rows)
	defer cleanupUpdateBenchData(b, db)

	s := rand.New(rand.NewSource(5432))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		q := fmt.Sprintf(`UPDATE bench.update SET v = v + 1 WHERE k = %d`, s.Intn(rows))
		if _, err := db.Exec(q); err != nil {
			b.Fatal(err)
		}
	}
	b.StopTimer()
}

// runBenchmarkUpdateTxn benchmarks updating a random row in a transaction.
func runBenchmarkUpdateTxn(b *testing.B, db *sql.DB) {
	rows := 10000
	prepareUpdateBenchData(b, db, rows)
	defer cleanupUpdateBenchData(b, db)

	s := rand.New(rand.NewSource(5432))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		q := fmt.Sprintf(
			`BEGIN; UPDATE bench.update SET v = v + 1 WHERE k = %d; COMMIT;`,
			s.Intn(rows))
		if _, err := db.Exec(q); err != nil {
			b.Fatal(err)
		}
	}
	b.StopTimer()
}

// runBenchmarkUpdate2RowsTxn benchmarks updating two random rows in a single transaction.
func runBenchmarkUpdate2RowsTxn(b *testing.B, db *sql.DB) {
	rows := 10000
	prepareUpdateBenchData(b, db, rows)
	defer cleanupUpdateBenchData(b, db)

	s := rand.New(rand.NewSource(5432))

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		q := fmt.Sprintf(
			`BEGIN;
			 UPDATE bench.update SET v = v + 1 WHERE k = %d;
			 UPDATE bench.update SET v = v - 1 WHERE k = %d;
			 COMMIT;`,
			s.Intn(rows),
			s.Intn(rows),
		)
		if _, err := db.Exec(q); err != nil {
			b.Fatal(err)
		}
	}
	b.StopTimer()
}

func BenchmarkUpdate_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkUpdate)
}

func BenchmarkUpdate_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkUpdate)
}

func BenchmarkUpdateTxn_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkUpdateTxn)
}

func BenchmarkUpdateTxn_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkUpdateTxn)
}

func BenchmarkUpdate2RowsTxn_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkUpdate2RowsTxn)
}

func BenchmarkUpdate2RowsTxn_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkUpdate2RowsTxn)
}

// runBenchmarkScan benchmarks scanning a table containing count rows.
func runBenchmarkScan(b *testing.B, db *sql.DB, count int) {
	if _, err := db.Exec(`DROP TABLE IF EXISTS bench.scan`); err != nil {
		b.Fatal(err)
	}
	if _, err := db.Exec(`CREATE TABLE bench.scan (k INT PRIMARY KEY)`); err != nil {
		b.Fatal(err)
	}

	var buf bytes.Buffer
	buf.WriteString(`INSERT INTO bench.scan VALUES `)
	for i := 0; i < count; i++ {
		if i > 0 {
			buf.WriteString(", ")
		}
		fmt.Fprintf(&buf, "(%d)", i)
	}
	if _, err := db.Exec(buf.String()); err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		rows, err := db.Query(`SELECT * FROM bench.scan`)
		if err != nil {
			b.Fatal(err)
		}
		n := 0
		for rows.Next() {
			n++
		}
		rows.Close()
		if err := rows.Err(); err != nil {
			b.Fatal(err)
		}
		if count != n {
			b.Fatalf("unexpected result count: %d != %d", count, n)
		}
	}
	b.StopTimer()

	if _, err := db.Exec(`DROP TABLE bench.scan`); err != nil {
		b.Fatal(err)
	}
}

func runBenchmarkScan1(b *testing.B, db *sql.DB) {
	runBenchmarkScan(b, db, 1)
}

func runBenchmarkScan10(b *testing.B, db *sql.DB) {
	runBenchmarkScan(b, db, 10)
}

func runBenchmarkScan100(b *testing.B, db *sql.DB) {
	runBenchmarkScan(b, db, 100)
}

func BenchmarkScan1_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkScan1)
}

func BenchmarkScan1_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkScan1)
}

func BenchmarkScan10_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkScan10)
}

func BenchmarkScan10_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkScan10)
}

func BenchmarkScan100_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkScan100)
}

func BenchmarkScan100_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkScan100)
}
<commit_msg>Rework the update benchmarks to mirror the insert benchmarks.<commit_after>// Copyright 2015 The Cockroach 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.
//
// Author: Peter Mattis (peter@cockroachlabs.com)

package sql_test

import (
	"bytes"
	"database/sql"
	"fmt"
	"math/rand"
	"os"
	"testing"

	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"

	"github.com/cockroachdb/cockroach/security"
	"github.com/cockroachdb/cockroach/server"
	"github.com/cockroachdb/cockroach/testutils/sqlutils"
)

func benchmarkCockroach(b *testing.B, f func(b *testing.B, db *sql.DB)) {
	s := server.StartTestServer(b)
	defer s.Stop()

	pgUrl, cleanupFn := sqlutils.PGUrl(b, s, security.RootUser, os.TempDir(), "benchmarkCockroach")
	defer cleanupFn()

	db, err := sql.Open("postgres", pgUrl.String())
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec(`CREATE DATABASE IF NOT EXISTS bench`); err != nil {
		b.Fatal(err)
	}

	f(b, db)
}

func benchmarkPostgres(b *testing.B, f func(b *testing.B, db *sql.DB)) {
	// Note: the following uses SSL. To run this, make sure your local
	// Postgres server has SSL enabled. To use Cockroach's checked-in
	// testing certificates for Postgres' SSL, first determine the
	// location of your Postgres server's configuration file:
	// ```
	// $ psql -h localhost -p 5432 -c 'SHOW config_file'
	//                config_file
	// -----------------------------------------
	//  /usr/local/var/postgres/postgresql.conf
	// (1 row)
	//```
	//
	// Now open this file and set the following values:
	// ```
	// $ cat /usr/local/var/postgres/postgresql.conf | grep ssl
	// ssl = on                            # (change requires restart)
	// ssl_cert_file = '/Users/tamird/src/go/src/github.com/cockroachdb/cockroach/resource/test_certs/node.server.crt'             # (change requires restart)
	// ssl_key_file = '/Users/tamird/src/go/src/github.com/cockroachdb/cockroach/resource/test_certs/node.server.key'              # (change requires restart)
	// ssl_ca_file = '/Users/tamird/src/go/src/github.com/cockroachdb/cockroach/resource/test_certs/ca.crt'                        # (change requires restart)
	// ```
	// Where `/Users/tamird/src/go/src/github.com/cockroachdb/cockroach`
	// is replaced with your local Cockroach source directory.
	// Be sure to restart Postgres for this to take effect.

	db, err := sql.Open("postgres", "sslmode=require host=localhost port=5432")
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec(`CREATE SCHEMA IF NOT EXISTS bench`); err != nil {
		b.Fatal(err)
	}

	f(b, db)
}

func benchmarkMySQL(b *testing.B, f func(b *testing.B, db *sql.DB)) {
	db, err := sql.Open("mysql", "root@tcp(localhost:3306)/")
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec(`CREATE DATABASE IF NOT EXISTS bench`); err != nil {
		b.Fatal(err)
	}

	f(b, db)
}

func runBenchmarkSelect1(b *testing.B, db *sql.DB) {
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		rows, err := db.Query(`SELECT 1`)
		if err != nil {
			b.Fatal(err)
		}
		rows.Close()
	}
	b.StopTimer()
}

// benchmarkSelect1 is a benchmark of the simplest SQL query: SELECT 1. This
// query requires no tables, expression analysis, etc. As such, it is measuring
// the overhead of parsing and other non-table processing (e.g. reading
// requests, writing responses).
func benchmarkSelect1(b *testing.B, scheme string) {
	s := &server.TestServer{}
	s.Ctx = server.NewTestContext()
	s.Ctx.Insecure = (scheme == "http" || scheme == "rpc")
	if err := s.Start(); err != nil {
		b.Fatal(err)
	}
	defer s.Stop()

	db, err := sql.Open("cockroach",
		scheme+"://node@"+s.ServingAddr()+"?certs="+s.Ctx.Certs)
	if err != nil {
		b.Fatal(err)
	}
	defer db.Close()

	runBenchmarkSelect1(b, db)
}

func BenchmarkSelect1_HTTP(b *testing.B) {
	benchmarkSelect1(b, "http")
}

func BenchmarkSelect1_HTTPS(b *testing.B) {
	benchmarkSelect1(b, "https")
}

func BenchmarkSelect1_RPC(b *testing.B) {
	benchmarkSelect1(b, "rpc")
}

func BenchmarkSelect1_RPCS(b *testing.B) {
	benchmarkSelect1(b, "rpcs")
}

func BenchmarkSelect1_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkSelect1)
}

func BenchmarkSelect1_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkSelect1)
}

func BenchmarkSelect1_MySQL(b *testing.B) {
	benchmarkMySQL(b, runBenchmarkSelect1)
}

// runBenchmarkInsert benchmarks inserting count rows into a table.
func runBenchmarkInsert(b *testing.B, db *sql.DB, count int) {
	if _, err := db.Exec(`DROP TABLE IF EXISTS bench.insert`); err != nil {
		b.Fatal(err)
	}
	if _, err := db.Exec(`CREATE TABLE bench.insert (k INT PRIMARY KEY)`); err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	var buf bytes.Buffer
	val := 0
	for i := 0; i < b.N; i++ {
		buf.Reset()
		buf.WriteString(`INSERT INTO bench.insert VALUES `)
		for j := 0; j < count; j++ {
			if j > 0 {
				buf.WriteString(", ")
			}
			fmt.Fprintf(&buf, "(%d)", val)
			val++
		}
		if _, err := db.Exec(buf.String()); err != nil {
			b.Fatal(err)
		}
	}
	b.StopTimer()

	if _, err := db.Exec(`DROP TABLE bench.insert`); err != nil {
		b.Fatal(err)
	}
}

func runBenchmarkInsert1(b *testing.B, db *sql.DB) {
	runBenchmarkInsert(b, db, 1)
}

func runBenchmarkInsert10(b *testing.B, db *sql.DB) {
	runBenchmarkInsert(b, db, 10)
}

func runBenchmarkInsert100(b *testing.B, db *sql.DB) {
	runBenchmarkInsert(b, db, 100)
}

func BenchmarkInsert1_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkInsert1)
}

func BenchmarkInsert1_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkInsert1)
}

func BenchmarkInsert10_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkInsert10)
}

func BenchmarkInsert10_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkInsert10)
}

func BenchmarkInsert100_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkInsert100)
}

func BenchmarkInsert100_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkInsert100)
}

func prepareUpdateBenchData(b *testing.B, db *sql.DB, rows int) {
	if _, err := db.Exec(`DROP TABLE IF EXISTS bench.update`); err != nil {
		b.Fatal(err)
	}
	if _, err := db.Exec(`CREATE TABLE bench.update (k INT PRIMARY KEY, v INT)`); err != nil {
		b.Fatal(err)
	}

	var buf bytes.Buffer
	buf.WriteString(`INSERT INTO bench.update VALUES `)
	for i := 0; i < rows; i++ {
		if i > 0 {
			buf.WriteString(", ")
		}
		fmt.Fprintf(&buf, "(%d, %d)", i, i)
	}
	if _, err := db.Exec(buf.String()); err != nil {
		b.Fatal(err)
	}
}

func cleanupUpdateBenchData(b *testing.B, db *sql.DB) {
	if _, err := db.Exec(`DROP TABLE bench.update`); err != nil {
		b.Fatal(err)
	}
}

// runBenchmarkUpdate benchmarks updating count random rows in a table.
func runBenchmarkUpdate(b *testing.B, db *sql.DB, count int) {
	rows := 10000
	prepareUpdateBenchData(b, db, rows)
	defer cleanupUpdateBenchData(b, db)

	s := rand.New(rand.NewSource(5432))

	b.ResetTimer()
	var buf bytes.Buffer
	for i := 0; i < b.N; i++ {
		buf.Reset()
		_, _ = buf.WriteString(`BEGIN; `)
		for j := 0; j < count; j++ {
			fmt.Fprintf(&buf, `UPDATE bench.update SET v = v + 1 WHERE k = %d; `, s.Intn(rows))
		}
		_, _ = buf.WriteString(`COMMIT;`)
		if _, err := db.Exec(buf.String()); err != nil {
			b.Fatal(err)
		}
	}
	b.StopTimer()
}

func runBenchmarkUpdate1(b *testing.B, db *sql.DB) {
	runBenchmarkUpdate(b, db, 1)
}

func runBenchmarkUpdate10(b *testing.B, db *sql.DB) {
	runBenchmarkUpdate(b, db, 10)
}

func runBenchmarkUpdate100(b *testing.B, db *sql.DB) {
	runBenchmarkUpdate(b, db, 100)
}

func BenchmarkUpdate1_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkUpdate1)
}

func BenchmarkUpdate1_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkUpdate1)
}

func BenchmarkUpdate10_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkUpdate10)
}

func BenchmarkUpdate10_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkUpdate10)
}

func BenchmarkUpdate100_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkUpdate100)
}

func BenchmarkUpdate100_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkUpdate100)
}

// runBenchmarkScan benchmarks scanning a table containing count rows.
func runBenchmarkScan(b *testing.B, db *sql.DB, count int) {
	if _, err := db.Exec(`DROP TABLE IF EXISTS bench.scan`); err != nil {
		b.Fatal(err)
	}
	if _, err := db.Exec(`CREATE TABLE bench.scan (k INT PRIMARY KEY)`); err != nil {
		b.Fatal(err)
	}

	var buf bytes.Buffer
	buf.WriteString(`INSERT INTO bench.scan VALUES `)
	for i := 0; i < count; i++ {
		if i > 0 {
			buf.WriteString(", ")
		}
		fmt.Fprintf(&buf, "(%d)", i)
	}
	if _, err := db.Exec(buf.String()); err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		rows, err := db.Query(`SELECT * FROM bench.scan`)
		if err != nil {
			b.Fatal(err)
		}
		n := 0
		for rows.Next() {
			n++
		}
		rows.Close()
		if err := rows.Err(); err != nil {
			b.Fatal(err)
		}
		if count != n {
			b.Fatalf("unexpected result count: %d != %d", count, n)
		}
	}
	b.StopTimer()

	if _, err := db.Exec(`DROP TABLE bench.scan`); err != nil {
		b.Fatal(err)
	}
}

func runBenchmarkScan1(b *testing.B, db *sql.DB) {
	runBenchmarkScan(b, db, 1)
}

func runBenchmarkScan10(b *testing.B, db *sql.DB) {
	runBenchmarkScan(b, db, 10)
}

func runBenchmarkScan100(b *testing.B, db *sql.DB) {
	runBenchmarkScan(b, db, 100)
}

func BenchmarkScan1_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkScan1)
}

func BenchmarkScan1_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkScan1)
}

func BenchmarkScan10_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkScan10)
}

func BenchmarkScan10_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkScan10)
}

func BenchmarkScan100_Cockroach(b *testing.B) {
	benchmarkCockroach(b, runBenchmarkScan100)
}

func BenchmarkScan100_Postgres(b *testing.B) {
	benchmarkPostgres(b, runBenchmarkScan100)
}
<|endoftext|>


<commit_before>package sdl

import (
	"fmt"
	"reflect"
	"strings"
	"testing"
)

// TODO: SysWMInfo
// TODO: RendererInfo
// TODO: AudioCVT
func TestStructABI(t *testing.T) {
	var tests = []struct {
		gStruct interface{}
		cStruct interface{}
	}{
		{AudioSpec{}, cAudioSpec{}},
		{DisplayMode{}, cDisplayMode{}},
		{Palette{}, cPalette{}},
		{PixelFormat{}, cPixelFormat{}},
		{Surface{}, cSurface{}},
		{Version{}, cVersion{}},
		{WindowEvent{}, cWindowEvent{}},

		// EVENTS
		{KeyDownEvent{}, cKeyboardEvent{}},
		{KeyUpEvent{}, cKeyboardEvent{}},
		{MouseButtonEvent{}, cMouseButtonEvent{}},
		{MouseMotionEvent{}, cMouseMotionEvent{}},
		{MouseWheelEvent{}, cMouseWheelEvent{}},
		{TextEditingEvent{}, cTextEditingEvent{}},
		{TextInputEvent{}, cTextInputEvent{}},
		{JoyAxisEvent{}, cJoyAxisEvent{}},
		{JoyBallEvent{}, cJoyBallEvent{}},
		{JoyHatEvent{}, cJoyHatEvent{}},
		{JoyButtonEvent{}, cJoyButtonEvent{}},
		{ControllerAxisEvent{}, cControllerAxisEvent{}},
		{ControllerButtonEvent{}, cControllerButtonEvent{}},
		{ControllerDeviceEvent{}, cControllerDeviceEvent{}},
		{TouchFingerEvent{}, cTouchFingerEvent{}},
		{MultiGestureEvent{}, cMultiGestureEvent{}},
		{DollarGestureEvent{}, cDollarGestureEvent{}},
		{DropEvent{}, cDropEvent{}},
		{UserEvent{}, cUserEvent{}},
		{SysWMEvent{}, cSysWMEvent{}},
	}

	for _, test := range tests {
		testABI(t, test.gStruct, test.cStruct)
	}
}

// TODO: mixer.MusicType
// TODO: mixer.Fading
func TestTypeABI(t *testing.T) {
	var tests = []struct {
		gType interface{}
		cType interface{}
	}{
		{AudioStatus(0), cAudioStatus(0)},
		{ErrorCode(0), cErrorCode(0)},
		{RendererFlip(0), cRendererFlip(0)},
	}

	for _, test := range tests {
		testABI(t, test.gType, test.cType)
	}
}

func testABI(t *testing.T, a, b interface{}) {
	ta, tb := reflect.TypeOf(a), reflect.TypeOf(b)
	if ta.Size() != tb.Size() {
		t.Fatalf("type size mismatch: %s(%d) != %s(%d)",
			ta.Name(), ta.Size(), tb.Name(), tb.Size())
	}
	if ta.Kind() != tb.Kind() {
		t.Fatalf("type kind mismatch: %s=%s != %s=%s",
			ta.Name(), ta.Kind(), tb.Name(), tb.Kind())
	}

	if ta.Kind() == reflect.Struct {
		for i := 0; i < ta.NumField(); i++ {
			f := ta.Field(i)
			if f.Name == "_" {
				// ignore padding fields
				continue
			}
			if err := verifyField(t, f, tb); err != nil {
				dumpStructFormat(t, ta)
				dumpStructFormat(t, tb)
				t.Error(err)
			}
		}
	}
}

func dumpStructFormat(t *testing.T, s reflect.Type) {
	const dFormat = "%5d %30s %8d %8d"
	var sFormat = strings.Replace(dFormat, "d", "s", -1)

	t.Logf(sFormat, "index", "name", "offset", "size")
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		t.Logf(dFormat, i, s.Name()+"."+f.Name, f.Offset, f.Type.Size())
	}
}

func verifyField(t *testing.T, gField reflect.StructField, cType reflect.Type) error {
	var cField = searchField(cType, gField.Name)
	if cField == nil {
		return fmt.Errorf("field not found: %q", gField.Name)
	}
	gOffset, gSize := gField.Offset, gField.Type.Size()
	cOffset, cSize := cField.Offset, cField.Type.Size()
	if cOffset != gOffset || cSize != gSize {
		return fmt.Errorf("field offset/size mismatch %s(%d, %d) != %s(%d, %d)",
			gField.Name, gOffset, gSize,
			cField.Name, cOffset, cSize)
	}
	return nil
}

func searchField(t reflect.Type, gName string) *reflect.StructField {
	for i := 0; i < t.NumField(); i++ {
		var f = t.Field(i)
		// convert c field_name to fieldname
		var cName = strings.Replace(f.Name, "_", "", -1)
		if strings.EqualFold(gName, cName) {
			return &f
		}
	}
	return nil
}
<commit_msg>add disclaimer to sdl test /w version printout<commit_after>package sdl

import (
	"fmt"
	"reflect"
	"strings"
	"testing"
)

// TODO: SysWMInfo
// TODO: RendererInfo
// TODO: AudioCVT
func TestStructABI(t *testing.T) {
	var tests = []struct {
		gStruct interface{}
		cStruct interface{}
	}{
		{AudioSpec{}, cAudioSpec{}},
		{DisplayMode{}, cDisplayMode{}},
		{Palette{}, cPalette{}},
		{PixelFormat{}, cPixelFormat{}},
		{Surface{}, cSurface{}},
		{Version{}, cVersion{}},
		{WindowEvent{}, cWindowEvent{}},

		// EVENTS
		{KeyDownEvent{}, cKeyboardEvent{}},
		{KeyUpEvent{}, cKeyboardEvent{}},
		{MouseButtonEvent{}, cMouseButtonEvent{}},
		{MouseMotionEvent{}, cMouseMotionEvent{}},
		{MouseWheelEvent{}, cMouseWheelEvent{}},
		{TextEditingEvent{}, cTextEditingEvent{}},
		{TextInputEvent{}, cTextInputEvent{}},
		{JoyAxisEvent{}, cJoyAxisEvent{}},
		{JoyBallEvent{}, cJoyBallEvent{}},
		{JoyHatEvent{}, cJoyHatEvent{}},
		{JoyButtonEvent{}, cJoyButtonEvent{}},
		{ControllerAxisEvent{}, cControllerAxisEvent{}},
		{ControllerButtonEvent{}, cControllerButtonEvent{}},
		{ControllerDeviceEvent{}, cControllerDeviceEvent{}},
		{TouchFingerEvent{}, cTouchFingerEvent{}},
		{MultiGestureEvent{}, cMultiGestureEvent{}},
		{DollarGestureEvent{}, cDollarGestureEvent{}},
		{DropEvent{}, cDropEvent{}},
		{UserEvent{}, cUserEvent{}},
		{SysWMEvent{}, cSysWMEvent{}},
	}

	for _, test := range tests {
		testABI(t, test.gStruct, test.cStruct)
	}
}

// TODO: mixer.MusicType
// TODO: mixer.Fading
func TestTypeABI(t *testing.T) {
	var tests = []struct {
		gType interface{}
		cType interface{}
	}{
		{AudioStatus(0), cAudioStatus(0)},
		{ErrorCode(0), cErrorCode(0)},
		{RendererFlip(0), cRendererFlip(0)},
	}

	for _, test := range tests {
		testABI(t, test.gType, test.cType)
	}
}

func testABI(t *testing.T, a, b interface{}) {
	ta, tb := reflect.TypeOf(a), reflect.TypeOf(b)
	if ta.Size() != tb.Size() || edgeCases(a, b) {
		t.Errorf("type size mismatch: %s(%d) != %s(%d)",
			ta.Name(), ta.Size(), tb.Name(), tb.Size())
		t.Fail()
	}
	if ta.Kind() != tb.Kind() {
		t.Errorf("type kind mismatch: %s=%s != %s=%s",
			ta.Name(), ta.Kind(), tb.Name(), tb.Kind())
		t.Fail()
	}

	if ta.Kind() == reflect.Struct {
		for i := 0; i < ta.NumField(); i++ {
			f := ta.Field(i)
			if f.Name == "_" {
				// ignore padding fields
				continue
			}
			if err := verifyField(t, f, tb); err != nil {
				dumpStructFormat(t, ta)
				dumpStructFormat(t, tb)
				t.Error(err)
			}
		}
	}
}

// @note: add checks by SDL version for known edge-cases
func edgeCases(a, b interface{}) bool {
	if !VERSION_ATLEAST(2, 0, 4) {
		if _, ok := a.(MouseWheelEvent); !ok {
			return true
		}
	}

	return false
}

func dumpStructFormat(t *testing.T, s reflect.Type) {
	const dFormat = "%5d %30s %8d %8d"
	var sFormat = strings.Replace(dFormat, "d", "s", -1)

	t.Logf(sFormat, "index", "name", "offset", "size")
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		t.Logf(dFormat, i, s.Name()+"."+f.Name, f.Offset, f.Type.Size())
	}
}

func verifyField(t *testing.T, gField reflect.StructField, cType reflect.Type) error {
	var cField = searchField(cType, gField.Name)
	if cField == nil {
		return fmt.Errorf("field not found: %q", gField.Name)
	}
	gOffset, gSize := gField.Offset, gField.Type.Size()
	cOffset, cSize := cField.Offset, cField.Type.Size()
	if cOffset != gOffset || cSize != gSize {
		return fmt.Errorf("field offset/size mismatch %s(%d, %d) != %s(%d, %d)",
			gField.Name, gOffset, gSize,
			cField.Name, cOffset, cSize)
	}
	return nil
}

func searchField(t reflect.Type, gName string) *reflect.StructField {
	for i := 0; i < t.NumField(); i++ {
		var f = t.Field(i)
		// convert c field_name to fieldname
		var cName = strings.Replace(f.Name, "_", "", -1)
		if strings.EqualFold(gName, cName) {
			return &f
		}
	}
	return nil
}
<|endoftext|>


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

// Package analysisinternal exposes internal-only fields from go/analysis.
package analysisinternal

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
)

func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
	// Get the end position for the type error.
	offset, end := fset.PositionFor(start, false).Offset, start
	if offset >= len(src) {
		return end
	}
	if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 {
		end = start + token.Pos(width)
	}
	return end
}

func ZeroValue(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
	under := typ
	if n, ok := typ.(*types.Named); ok {
		under = n.Underlying()
	}
	switch u := under.(type) {
	case *types.Basic:
		switch {
		case u.Info()&types.IsNumeric != 0:
			return &ast.BasicLit{Kind: token.INT, Value: "0"}
		case u.Info()&types.IsBoolean != 0:
			return &ast.Ident{Name: "false"}
		case u.Info()&types.IsString != 0:
			return &ast.BasicLit{Kind: token.STRING, Value: `""`}
		default:
			panic("unknown basic type")
		}
	case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice:
		return ast.NewIdent("nil")
	case *types.Struct:
		texpr := TypeExpr(fset, f, pkg, typ) // typ because we want the name here.
		if texpr == nil {
			return nil
		}
		return &ast.CompositeLit{
			Type: texpr,
		}
	case *types.Array:
		texpr := TypeExpr(fset, f, pkg, u.Elem())
		if texpr == nil {
			return nil
		}
		return &ast.CompositeLit{
			Type: &ast.ArrayType{
				Elt: texpr,
				Len: &ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("%v", u.Len())},
			},
		}
	}
	return nil
}

func TypeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
	switch t := typ.(type) {
	case *types.Basic:
		switch t.Kind() {
		case types.UnsafePointer:
			return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")}
		default:
			return ast.NewIdent(t.Name())
		}
	case *types.Named:
		if t.Obj().Pkg() == nil {
			return nil
		}
		if t.Obj().Pkg() == pkg {
			return ast.NewIdent(t.Obj().Name())
		}
		pkgName := t.Obj().Pkg().Name()
		// If the file already imports the package under another name, use that.
		for _, group := range astutil.Imports(fset, f) {
			for _, cand := range group {
				if strings.Trim(cand.Path.Value, `"`) == t.Obj().Pkg().Path() {
					if cand.Name != nil && cand.Name.Name != "" {
						pkgName = cand.Name.Name
					}
				}
			}
		}
		if pkgName == "." {
			return ast.NewIdent(t.Obj().Name())
		}
		return &ast.SelectorExpr{
			X:   ast.NewIdent(pkgName),
			Sel: ast.NewIdent(t.Obj().Name()),
		}
	case *types.Pointer:
		return &ast.UnaryExpr{
			Op: token.MUL,
			X:  TypeExpr(fset, f, pkg, t.Elem()),
		}
	default:
		return nil // TODO: anonymous structs, but who does that
	}
}

var GetTypeErrors = func(p interface{}) []types.Error { return nil }
var SetTypeErrors = func(p interface{}, errors []types.Error) {}

type TypeErrorPass string

const (
	NoNewVars      TypeErrorPass = "nonewvars"
	NoResultValues TypeErrorPass = "noresultvalues"
	UndeclaredName TypeErrorPass = "undeclaredname"
)

// StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable.
// Some examples:
//
// Basic Example:
// z := 1
// y := z + x
// If x is undeclared, then this function would return `y := z + x`, so that we
// can insert `x := ` on the line before `y := z + x`.
//
// If stmt example:
// if z == 1 {
// } else if z == y {}
// If y is undeclared, then this function would return `if z == 1 {`, because we cannot
// insert a statement between an if and an else if statement. As a result, we need to find
// the top of the if chain to insert `y := ` before.
func StmtToInsertVarBefore(path []ast.Node) ast.Stmt {
	enclosingIndex := -1
	for i, p := range path {
		if _, ok := p.(ast.Stmt); ok {
			enclosingIndex = i
			break
		}
	}
	if enclosingIndex == -1 {
		return nil
	}
	enclosingStmt := path[enclosingIndex]
	switch enclosingStmt.(type) {
	case *ast.IfStmt:
		// The enclosingStmt is inside of the if declaration,
		// We need to check if we are in an else-if stmt and
		// get the base if statement.
		return baseIfStmt(path, enclosingIndex)
	case *ast.CaseClause:
		// Get the enclosing switch stmt if the enclosingStmt is
		// inside of the case statement.
		for i := enclosingIndex + 1; i < len(path); i++ {
			if node, ok := path[i].(*ast.SwitchStmt); ok {
				return node
			} else if node, ok := path[i].(*ast.TypeSwitchStmt); ok {
				return node
			}
		}
	}
	if len(path) <= enclosingIndex+1 {
		return enclosingStmt.(ast.Stmt)
	}
	// Check if the enclosing statement is inside another node.
	switch expr := path[enclosingIndex+1].(type) {
	case *ast.IfStmt:
		// Get the base if statement.
		return baseIfStmt(path, enclosingIndex+1)
	case *ast.ForStmt:
		if expr.Init == enclosingStmt || expr.Post == enclosingStmt {
			return expr
		}
	}
	return enclosingStmt.(ast.Stmt)
}

// baseIfStmt walks up the if/else-if chain until we get to
// the top of the current if chain.
func baseIfStmt(path []ast.Node, index int) ast.Stmt {
	stmt := path[index]
	for i := index + 1; i < len(path); i++ {
		if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt {
			stmt = node
			continue
		}
		break
	}
	return stmt.(ast.Stmt)
}
<commit_msg>internal/analysisinternal: do not initialize {Get,Set}TypeErrors<commit_after>// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package analysisinternal exposes internal-only fields from go/analysis.
package analysisinternal

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
)

var (
	GetTypeErrors func(p interface{}) []types.Error
	SetTypeErrors func(p interface{}, errors []types.Error)
)

func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
	// Get the end position for the type error.
	offset, end := fset.PositionFor(start, false).Offset, start
	if offset >= len(src) {
		return end
	}
	if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 {
		end = start + token.Pos(width)
	}
	return end
}

func ZeroValue(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
	under := typ
	if n, ok := typ.(*types.Named); ok {
		under = n.Underlying()
	}
	switch u := under.(type) {
	case *types.Basic:
		switch {
		case u.Info()&types.IsNumeric != 0:
			return &ast.BasicLit{Kind: token.INT, Value: "0"}
		case u.Info()&types.IsBoolean != 0:
			return &ast.Ident{Name: "false"}
		case u.Info()&types.IsString != 0:
			return &ast.BasicLit{Kind: token.STRING, Value: `""`}
		default:
			panic("unknown basic type")
		}
	case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice:
		return ast.NewIdent("nil")
	case *types.Struct:
		texpr := TypeExpr(fset, f, pkg, typ) // typ because we want the name here.
		if texpr == nil {
			return nil
		}
		return &ast.CompositeLit{
			Type: texpr,
		}
	case *types.Array:
		texpr := TypeExpr(fset, f, pkg, u.Elem())
		if texpr == nil {
			return nil
		}
		return &ast.CompositeLit{
			Type: &ast.ArrayType{
				Elt: texpr,
				Len: &ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("%v", u.Len())},
			},
		}
	}
	return nil
}

func TypeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
	switch t := typ.(type) {
	case *types.Basic:
		switch t.Kind() {
		case types.UnsafePointer:
			return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")}
		default:
			return ast.NewIdent(t.Name())
		}
	case *types.Named:
		if t.Obj().Pkg() == nil {
			return nil
		}
		if t.Obj().Pkg() == pkg {
			return ast.NewIdent(t.Obj().Name())
		}
		pkgName := t.Obj().Pkg().Name()
		// If the file already imports the package under another name, use that.
		for _, group := range astutil.Imports(fset, f) {
			for _, cand := range group {
				if strings.Trim(cand.Path.Value, `"`) == t.Obj().Pkg().Path() {
					if cand.Name != nil && cand.Name.Name != "" {
						pkgName = cand.Name.Name
					}
				}
			}
		}
		if pkgName == "." {
			return ast.NewIdent(t.Obj().Name())
		}
		return &ast.SelectorExpr{
			X:   ast.NewIdent(pkgName),
			Sel: ast.NewIdent(t.Obj().Name()),
		}
	case *types.Pointer:
		return &ast.UnaryExpr{
			Op: token.MUL,
			X:  TypeExpr(fset, f, pkg, t.Elem()),
		}
	default:
		return nil // TODO: anonymous structs, but who does that
	}
}

type TypeErrorPass string

const (
	NoNewVars      TypeErrorPass = "nonewvars"
	NoResultValues TypeErrorPass = "noresultvalues"
	UndeclaredName TypeErrorPass = "undeclaredname"
)

// StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable.
// Some examples:
//
// Basic Example:
// z := 1
// y := z + x
// If x is undeclared, then this function would return `y := z + x`, so that we
// can insert `x := ` on the line before `y := z + x`.
//
// If stmt example:
// if z == 1 {
// } else if z == y {}
// If y is undeclared, then this function would return `if z == 1 {`, because we cannot
// insert a statement between an if and an else if statement. As a result, we need to find
// the top of the if chain to insert `y := ` before.
func StmtToInsertVarBefore(path []ast.Node) ast.Stmt {
	enclosingIndex := -1
	for i, p := range path {
		if _, ok := p.(ast.Stmt); ok {
			enclosingIndex = i
			break
		}
	}
	if enclosingIndex == -1 {
		return nil
	}
	enclosingStmt := path[enclosingIndex]
	switch enclosingStmt.(type) {
	case *ast.IfStmt:
		// The enclosingStmt is inside of the if declaration,
		// We need to check if we are in an else-if stmt and
		// get the base if statement.
		return baseIfStmt(path, enclosingIndex)
	case *ast.CaseClause:
		// Get the enclosing switch stmt if the enclosingStmt is
		// inside of the case statement.
		for i := enclosingIndex + 1; i < len(path); i++ {
			if node, ok := path[i].(*ast.SwitchStmt); ok {
				return node
			} else if node, ok := path[i].(*ast.TypeSwitchStmt); ok {
				return node
			}
		}
	}
	if len(path) <= enclosingIndex+1 {
		return enclosingStmt.(ast.Stmt)
	}
	// Check if the enclosing statement is inside another node.
	switch expr := path[enclosingIndex+1].(type) {
	case *ast.IfStmt:
		// Get the base if statement.
		return baseIfStmt(path, enclosingIndex+1)
	case *ast.ForStmt:
		if expr.Init == enclosingStmt || expr.Post == enclosingStmt {
			return expr
		}
	}
	return enclosingStmt.(ast.Stmt)
}

// baseIfStmt walks up the if/else-if chain until we get to
// the top of the current if chain.
func baseIfStmt(path []ast.Node, index int) ast.Stmt {
	stmt := path[index]
	for i := index + 1; i < len(path); i++ {
		if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt {
			stmt = node
			continue
		}
		break
	}
	return stmt.(ast.Stmt)
}
<|endoftext|>


<commit_before>package egoscale

import (
	"context"
	"fmt"
	"net/url"
	"strconv"

	"github.com/jinzhu/copier"
)

// ResourceType returns the type of the resource
func (*SecurityGroup) ResourceType() string {
	return "SecurityGroup"
}

// Get loads the given Security Group
func (sg *SecurityGroup) Get(ctx context.Context, client *Client) error {
	if sg.ID == "" && sg.Name == "" {
		return fmt.Errorf("A SecurityGroup may only be searched using ID or Name")
	}

	resp, err := client.List(&SecurityGroup{Name: sg.Name, ID: sg.ID})
	if err != nil {
		return err
	}

	listSize := len(resp)

	if listSize == 0 {
		err := &ErrorResponse{
			ErrorCode: ParamError,
			ErrorText: fmt.Sprintf("SecurityGroup not found id: %s, name: %s", sg.ID, sg.Name),
		}
		return err
	} else if listSize > 1 {
		return fmt.Errorf("More than one SecurityGroup was found. Query: id: %s, name: %s", sg.ID, sg.Name)
	}

	securGroup, ok := resp[0].(*SecurityGroup)
	if !ok {
		return fmt.Errorf("SecurityGroup expected, got %t", resp[0])
	}

	return copier.Copy(sg, securGroup)
}

// ListRequest builds the ListSecurityGroups request
func (sg *SecurityGroup) ListRequest() (ListCommand, error) {
	//TODO add tags
	req := &ListSecurityGroups{
		Account:           sg.Account,
		DomainID:          sg.DomainID,
		ID:                sg.ID,
		ProjectID:         sg.ProjectID,
		SecurityGroupName: sg.Name,
	}

	return req, nil
}

// Delete deletes the given Security Group
func (sg *SecurityGroup) Delete(ctx context.Context, client *Client) error {
	if sg.ID == "" && sg.Name == "" {
		return fmt.Errorf("A SecurityGroup may only be deleted using ID or Name")
	}

	req := &DeleteSecurityGroup{
		Account:   sg.Account,
		DomainID:  sg.DomainID,
		ProjectID: sg.ProjectID,
	}

	if sg.ID != "" {
		req.ID = sg.ID
	} else {
		req.Name = sg.Name
	}

	return client.BooleanRequestWithContext(ctx, req)
}

// APIName returns the CloudStack API command name
func (*CreateSecurityGroup) APIName() string {
	return "createSecurityGroup"
}

func (*CreateSecurityGroup) response() interface{} {
	return new(CreateSecurityGroupResponse)
}

// APIName returns the CloudStack API command name
func (*DeleteSecurityGroup) APIName() string {
	return "deleteSecurityGroup"
}

func (*DeleteSecurityGroup) response() interface{} {
	return new(booleanSyncResponse)
}

// APIName returns the CloudStack API command name
func (*AuthorizeSecurityGroupIngress) APIName() string {
	return "authorizeSecurityGroupIngress"
}

func (*AuthorizeSecurityGroupIngress) asyncResponse() interface{} {
	return new(AuthorizeSecurityGroupIngressResponse)
}

func (req *AuthorizeSecurityGroupIngress) onBeforeSend(params *url.Values) error {
	// ICMP code and type may be zero but can also be omitted...
	if req.Protocol == "ICMP" {
		params.Set("icmpcode", strconv.FormatInt(int64(req.IcmpCode), 10))
		params.Set("icmptype", strconv.FormatInt(int64(req.IcmpType), 10))
	}
	// StartPort may be zero but can also be omitted...
	if req.EndPort != 0 && req.StartPort == 0 {
		params.Set("startport", "0")
	}
	return nil
}

// APIName returns the CloudStack API command name
func (*AuthorizeSecurityGroupEgress) APIName() string {
	return "authorizeSecurityGroupEgress"
}

func (*AuthorizeSecurityGroupEgress) asyncResponse() interface{} {
	return new(AuthorizeSecurityGroupEgressResponse)
}

func (req *AuthorizeSecurityGroupEgress) onBeforeSend(params *url.Values) error {
	return (*AuthorizeSecurityGroupIngress)(req).onBeforeSend(params)
}

// APIName returns the CloudStack API command name
func (*RevokeSecurityGroupIngress) APIName() string {
	return "revokeSecurityGroupIngress"
}

func (*RevokeSecurityGroupIngress) asyncResponse() interface{} {
	return new(booleanAsyncResponse)
}

// APIName returns the CloudStack API command name
func (*RevokeSecurityGroupEgress) APIName() string {
	return "revokeSecurityGroupEgress"
}

func (*RevokeSecurityGroupEgress) asyncResponse() interface{} {
	return new(booleanAsyncResponse)
}

// APIName returns the CloudStack API command name
func (*ListSecurityGroups) APIName() string {
	return "listSecurityGroups"
}

func (*ListSecurityGroups) response() interface{} {
	return new(ListSecurityGroupsResponse)
}

// SetPage sets the current page
func (lsg *ListSecurityGroups) SetPage(page int) {
	lsg.Page = page
}

// SetPageSize sets the page size
func (lsg *ListSecurityGroups) SetPageSize(pageSize int) {
	lsg.PageSize = pageSize
}

func (*ListSecurityGroups) each(resp interface{}, callback IterateItemFunc) {
	sgs, ok := resp.(*ListSecurityGroupsResponse)
	if !ok {
		callback(nil, fmt.Errorf("ListSecurityGroupsResponse expected, got %t", resp))
		return
	}

	for i := range sgs.SecurityGroup {
		if !callback(&sgs.SecurityGroup[i], nil) {
			break
		}
	}
}
<commit_msg>Put icmp check tolower<commit_after>package egoscale

import (
	"context"
	"fmt"
	"net/url"
	"strconv"
	"strings"

	"github.com/jinzhu/copier"
)

// ResourceType returns the type of the resource
func (*SecurityGroup) ResourceType() string {
	return "SecurityGroup"
}

// Get loads the given Security Group
func (sg *SecurityGroup) Get(ctx context.Context, client *Client) error {
	if sg.ID == "" && sg.Name == "" {
		return fmt.Errorf("A SecurityGroup may only be searched using ID or Name")
	}

	resp, err := client.List(&SecurityGroup{Name: sg.Name, ID: sg.ID})
	if err != nil {
		return err
	}

	listSize := len(resp)

	if listSize == 0 {
		err := &ErrorResponse{
			ErrorCode: ParamError,
			ErrorText: fmt.Sprintf("SecurityGroup not found id: %s, name: %s", sg.ID, sg.Name),
		}
		return err
	} else if listSize > 1 {
		return fmt.Errorf("More than one SecurityGroup was found. Query: id: %s, name: %s", sg.ID, sg.Name)
	}

	securGroup, ok := resp[0].(*SecurityGroup)
	if !ok {
		return fmt.Errorf("SecurityGroup expected, got %t", resp[0])
	}

	return copier.Copy(sg, securGroup)
}

// ListRequest builds the ListSecurityGroups request
func (sg *SecurityGroup) ListRequest() (ListCommand, error) {
	//TODO add tags
	req := &ListSecurityGroups{
		Account:           sg.Account,
		DomainID:          sg.DomainID,
		ID:                sg.ID,
		ProjectID:         sg.ProjectID,
		SecurityGroupName: sg.Name,
	}

	return req, nil
}

// Delete deletes the given Security Group
func (sg *SecurityGroup) Delete(ctx context.Context, client *Client) error {
	if sg.ID == "" && sg.Name == "" {
		return fmt.Errorf("A SecurityGroup may only be deleted using ID or Name")
	}

	req := &DeleteSecurityGroup{
		Account:   sg.Account,
		DomainID:  sg.DomainID,
		ProjectID: sg.ProjectID,
	}

	if sg.ID != "" {
		req.ID = sg.ID
	} else {
		req.Name = sg.Name
	}

	return client.BooleanRequestWithContext(ctx, req)
}

// APIName returns the CloudStack API command name
func (*CreateSecurityGroup) APIName() string {
	return "createSecurityGroup"
}

func (*CreateSecurityGroup) response() interface{} {
	return new(CreateSecurityGroupResponse)
}

// APIName returns the CloudStack API command name
func (*DeleteSecurityGroup) APIName() string {
	return "deleteSecurityGroup"
}

func (*DeleteSecurityGroup) response() interface{} {
	return new(booleanSyncResponse)
}

// APIName returns the CloudStack API command name
func (*AuthorizeSecurityGroupIngress) APIName() string {
	return "authorizeSecurityGroupIngress"
}

func (*AuthorizeSecurityGroupIngress) asyncResponse() interface{} {
	return new(AuthorizeSecurityGroupIngressResponse)
}

func (req *AuthorizeSecurityGroupIngress) onBeforeSend(params *url.Values) error {
	// ICMP code and type may be zero but can also be omitted...
	if strings.HasPrefix(strings.ToLower(req.Protocol), "icmp") {
		params.Set("icmpcode", strconv.FormatInt(int64(req.IcmpCode), 10))
		params.Set("icmptype", strconv.FormatInt(int64(req.IcmpType), 10))
	}
	// StartPort may be zero but can also be omitted...
	if req.EndPort != 0 && req.StartPort == 0 {
		params.Set("startport", "0")
	}
	return nil
}

// APIName returns the CloudStack API command name
func (*AuthorizeSecurityGroupEgress) APIName() string {
	return "authorizeSecurityGroupEgress"
}

func (*AuthorizeSecurityGroupEgress) asyncResponse() interface{} {
	return new(AuthorizeSecurityGroupEgressResponse)
}

func (req *AuthorizeSecurityGroupEgress) onBeforeSend(params *url.Values) error {
	return (*AuthorizeSecurityGroupIngress)(req).onBeforeSend(params)
}

// APIName returns the CloudStack API command name
func (*RevokeSecurityGroupIngress) APIName() string {
	return "revokeSecurityGroupIngress"
}

func (*RevokeSecurityGroupIngress) asyncResponse() interface{} {
	return new(booleanAsyncResponse)
}

// APIName returns the CloudStack API command name
func (*RevokeSecurityGroupEgress) APIName() string {
	return "revokeSecurityGroupEgress"
}

func (*RevokeSecurityGroupEgress) asyncResponse() interface{} {
	return new(booleanAsyncResponse)
}

// APIName returns the CloudStack API command name
func (*ListSecurityGroups) APIName() string {
	return "listSecurityGroups"
}

func (*ListSecurityGroups) response() interface{} {
	return new(ListSecurityGroupsResponse)
}

// SetPage sets the current page
func (lsg *ListSecurityGroups) SetPage(page int) {
	lsg.Page = page
}

// SetPageSize sets the page size
func (lsg *ListSecurityGroups) SetPageSize(pageSize int) {
	lsg.PageSize = pageSize
}

func (*ListSecurityGroups) each(resp interface{}, callback IterateItemFunc) {
	sgs, ok := resp.(*ListSecurityGroupsResponse)
	if !ok {
		callback(nil, fmt.Errorf("ListSecurityGroupsResponse expected, got %t", resp))
		return
	}

	for i := range sgs.SecurityGroup {
		if !callback(&sgs.SecurityGroup[i], nil) {
			break
		}
	}
}
<|endoftext|>


<commit_before>package provider

import (
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSource_basic(t *testing.T) {
	dsn := "data.null_data_source.test"
	resource.UnitTest(t, resource.TestCase{
		ProtoV5ProviderFactories: protoV5ProviderFactories(),
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceConfig_basic,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrSet(dsn, "random"),
					resource.TestCheckResourceAttr(dsn, "has_computed_default", "default"),
				),
			},
		},
	})
}

func TestAccDataSource_inputs(t *testing.T) {
	dsn := "data.null_data_source.test"
	resource.UnitTest(t, resource.TestCase{
		ProtoV5ProviderFactories: protoV5ProviderFactories(),
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceConfig_inputs,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrSet(dsn, "random"),
					resource.TestCheckResourceAttr(dsn, "outputs.foo", "bar"),
				),
			},
		},
	})
}

func TestAccTimeOffset_Upgrade_Basic(t *testing.T) {
	dsn := "data.null_data_source.test"

	resource.Test(t, resource.TestCase{
		Steps: []resource.TestStep{
			{
				ExternalProviders: providerVersion311(),
				Config:            testAccDataSourceConfig_basic,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrSet(dsn, "random"),
					resource.TestCheckResourceAttr(dsn, "has_computed_default", "default"),
				),
			},
			{
				ProtoV5ProviderFactories: protoV5ProviderFactories(),
				Config:                   testAccDataSourceConfig_basic,
				PlanOnly:                 true,
			},
			{
				ProtoV5ProviderFactories: protoV5ProviderFactories(),
				Config:                   testAccDataSourceConfig_basic,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrSet(dsn, "random"),
					resource.TestCheckResourceAttr(dsn, "has_computed_default", "default"),
				),
			},
		},
	})
}

func TestAccTimeOffset_Upgrade_Inputs(t *testing.T) {
	dsn := "data.null_data_source.test"

	resource.Test(t, resource.TestCase{
		Steps: []resource.TestStep{
			{
				ExternalProviders: providerVersion311(),
				Config:            testAccDataSourceConfig_inputs,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrSet(dsn, "random"),
					resource.TestCheckResourceAttr(dsn, "outputs.foo", "bar"),
				),
			},
			{
				ProtoV5ProviderFactories: protoV5ProviderFactories(),
				Config:                   testAccDataSourceConfig_inputs,
				PlanOnly:                 true,
			},
			{
				ProtoV5ProviderFactories: protoV5ProviderFactories(),
				Config:                   testAccDataSourceConfig_inputs,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrSet(dsn, "random"),
					resource.TestCheckResourceAttr(dsn, "outputs.foo", "bar"),
				),
			},
		},
	})
}

const testAccDataSourceConfig_basic = `
data "null_data_source" "test" {
}
`

const testAccDataSourceConfig_inputs = `
data "null_data_source" "test" {
  inputs = {
    foo = "bar"
  }
}`
<commit_msg>Remove unnecessary tests<commit_after>package provider

import (
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSource_basic(t *testing.T) {
	dsn := "data.null_data_source.test"
	resource.UnitTest(t, resource.TestCase{
		ProtoV5ProviderFactories: protoV5ProviderFactories(),
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceConfig_basic,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrSet(dsn, "random"),
					resource.TestCheckResourceAttr(dsn, "has_computed_default", "default"),
				),
			},
		},
	})
}

func TestAccDataSource_inputs(t *testing.T) {
	dsn := "data.null_data_source.test"
	resource.UnitTest(t, resource.TestCase{
		ProtoV5ProviderFactories: protoV5ProviderFactories(),
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceConfig_inputs,
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttrSet(dsn, "random"),
					resource.TestCheckResourceAttr(dsn, "outputs.foo", "bar"),
				),
			},
		},
	})
}

const testAccDataSourceConfig_basic = `
data "null_data_source" "test" {
}
`

const testAccDataSourceConfig_inputs = `
data "null_data_source" "test" {
  inputs = {
    foo = "bar"
  }
}`
<|endoftext|>