<commit_before>package main

import (
	"../libgolb"
	"github.com/docopt/docopt-go"
	"github.com/gorilla/mux"
	"io"
	"net/http"
	"os"
	"strconv"
	"strings"
)

func getServer() (server string) {
	server = libgolb.Conf.BackServers[libgolb.RoundRobin]
	libgolb.RoundRobin++
	if libgolb.RoundRobin >= libgolb.NumberBack {
		libgolb.RoundRobin = 0
	}
	return
}

func golbGet(w http.ResponseWriter, req *http.Request) {
	var secondResp *http.Response
	var errsp error

	serv := strings.Split(req.RemoteAddr, ":") // extract just IP without port
	libgolb.Log("misc", "Access From :"+serv[0])
	server, errGS := libgolb.RadixGetString(libgolb.LBClient, serv[0])
	if errGS != nil {
		server = getServer()
	}
	limit := 0
	for limit < libgolb.NumberBack {
		resp, _ := http.NewRequest(req.Method, "http://"+server+req.RequestURI, nil)
		for k, v := range req.Header {
			resp.Header[k] = v
		}
		resp.Header.Set("X-Forwarded-For", req.RemoteAddr)
		secondResp, errsp = http.DefaultClient.Do(resp)
		if errsp != nil {
			libgolb.Log("error", "Connection with the HTTP file server failed: "+errsp.Error())
			server = getServer()
			limit++
		} else {
			break
		}
	}
	if limit >= libgolb.NumberBack {
		libgolb.HttpResponse(w, 500, "Internal server error\n")
		libgolb.Log("error", "No Backend Server avalaible")
		return
	}
	for k, v := range secondResp.Header {
		w.Header().Add(k, strings.Join(v, ""))
	}
	defer secondResp.Body.Close()
	w.Header().Set("Status", "200")
	io.Copy(w, secondResp.Body)
	libgolb.RadixSet(libgolb.LBClient, serv[0], server)
	libgolb.Log("ok", "Answer From :"+serv[0])
	//TTL
	libgolb.RadixExpire(libgolb.LBClient, serv[0], strconv.Itoa(libgolb.Conf.TTL))
	libgolb.LogW3C(w, req, false)
}

func parseArgument(configuration string) {

	// Load configuration
	libgolb.ConfLoad(configuration)
	// Check Redis connection
	redis := libgolb.ConnectToRedis()
	if redis != nil {
		libgolb.Log("error", "Redis connection failed")
		os.Exit(1)
	}

	// Router
	rtr := mux.NewRouter()
	rtr.HandleFunc("/", golbGet).Methods("GET")
	http.Handle("/", rtr)

	// Listening
	libgolb.Log("ok", "Listening on "+libgolb.Conf.Server.Hostname+":"+libgolb.Conf.Server.Port)
	err := http.ListenAndServe(libgolb.Conf.Server.Hostname+":"+libgolb.Conf.Server.Port, nil)
	libgolb.ErrCatcher("ListenAndServe: ", err)
}

func main() {
	usage := `Golb.

Usage:
  golb <configuration>
  golb -h | --help
  golb --version

Options:
  -h --help     Show this screen.
  --version     Show version.`

	arguments, _ := docopt.Parse(usage, nil, true, "GoLB 0.1", false)
	parseArgument(arguments["<configuration>"].(string))
}
<commit_msg>Change Close<commit_after>package main

import (
	"../libgolb"
	"github.com/docopt/docopt-go"
	"github.com/gorilla/mux"
	"io"
	"net/http"
	"os"
	"strconv"
	"strings"
)

func getServer() (server string) {
	server = libgolb.Conf.BackServers[libgolb.RoundRobin]
	libgolb.RoundRobin++
	if libgolb.RoundRobin >= libgolb.NumberBack {
		libgolb.RoundRobin = 0
	}
	return
}

func golbGet(w http.ResponseWriter, req *http.Request) {
	var secondResp *http.Response
	var errsp error

	defer secondResp.Body.Close()
	serv := strings.Split(req.RemoteAddr, ":") // extract just IP without port
	libgolb.Log("misc", "Access From :"+serv[0])
	server, errGS := libgolb.RadixGetString(libgolb.LBClient, serv[0])
	if errGS != nil {
		server = getServer()
	}
	limit := 0
	for limit < libgolb.NumberBack {
		resp, _ := http.NewRequest(req.Method, "http://"+server+req.RequestURI, nil)
		for k, v := range req.Header {
			resp.Header[k] = v
		}
		resp.Header.Set("X-Forwarded-For", req.RemoteAddr)
		secondResp, errsp = http.DefaultClient.Do(resp)
		if errsp != nil {
			libgolb.Log("error", "Connection with the HTTP file server failed: "+errsp.Error())
			server = getServer()
			limit++
		} else {
			break
		}
	}
	if limit >= libgolb.NumberBack {
		libgolb.HttpResponse(w, 500, "Internal server error\n")
		libgolb.Log("error", "No Backend Server avalaible")
		return
	}
	for k, v := range secondResp.Header {
		w.Header().Add(k, strings.Join(v, ""))
	}
	w.Header().Set("Status", "200")
	io.Copy(w, secondResp.Body)
	libgolb.RadixSet(libgolb.LBClient, serv[0], server)
	libgolb.Log("ok", "Answer From :"+serv[0])
	//TTL
	libgolb.RadixExpire(libgolb.LBClient, serv[0], strconv.Itoa(libgolb.Conf.TTL))
	libgolb.LogW3C(w, req, false)
}

func parseArgument(configuration string) {

	// Load configuration
	libgolb.ConfLoad(configuration)
	// Check Redis connection
	redis := libgolb.ConnectToRedis()
	if redis != nil {
		libgolb.Log("error", "Redis connection failed")
		os.Exit(1)
	}

	// Router
	rtr := mux.NewRouter()
	rtr.HandleFunc("/", golbGet).Methods("GET")
	http.Handle("/", rtr)

	// Listening
	libgolb.Log("ok", "Listening on "+libgolb.Conf.Server.Hostname+":"+libgolb.Conf.Server.Port)
	err := http.ListenAndServe(libgolb.Conf.Server.Hostname+":"+libgolb.Conf.Server.Port, nil)
	libgolb.ErrCatcher("ListenAndServe: ", err)
}

func main() {
	usage := `Golb.

Usage:
  golb <configuration>
  golb -h | --help
  golb --version

Options:
  -h --help     Show this screen.
  --version     Show version.`

	arguments, _ := docopt.Parse(usage, nil, true, "GoLB 0.1", false)
	parseArgument(arguments["<configuration>"].(string))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"bitbucket.org/zagrodzki/goscope/hantek6022be"
	"bitbucket.org/zagrodzki/goscope/scope"
	"github.com/kylelemons/gousb/usb"
)

type supportedModel struct {
	check func(*usb.Descriptor) bool
	open  func(*usb.Device) scope.Device
}

var supportedModels = []supportedModel{
	supportedModel{hantek6022be.Supports, hantek6022be.New},
}

func isSupported(d *usb.Descriptor) bool {
	for _, s := range supportedModels {
		if s.check(d) {
			return true
		}
	}
	return false
}

func open(d *usb.Device) scope.Device {
	for _, s := range supportedModels {
		if s.check(d.Descriptor) {
			return s.open(d)
		}
	}
	return nil
}

func must(e error) {
	if e != nil {
		log.Fatalf(e.Error())
	}
}

func main() {
	ctx := usb.NewContext()
	devices, err := ctx.ListDevices(isSupported)
	defer func() {
		for _, d := range devices {
			d.Close()
		}
	}()
	if err != nil {
		log.Fatalf("ctx.ListDevices(): %v", err)
	}
	if len(devices) == 0 {
		log.Fatal("Did not find a valid device")
	}
	for _, d := range devices {
		fmt.Printf("Device found at bus %d addr %d\n", d.Bus, d.Address)
	}
	if len(devices) > 1 {
		fmt.Println("Using the first device listed")
	}
	osc := open(devices[0])
	fmt.Println(osc)
	for _, ch := range osc.Channels() {
		must(ch.SetVoltRange(5))
	}
	data, _, err := osc.ReadData()
	if err != nil {
		log.Fatalf("ReadData: %+v", err)
	}
	fmt.Println("Data:", data)
	osc.StopCapture()
}
<commit_msg>Don't call StopCapture either, not part of the interface.<commit_after>package main

import (
	"fmt"
	"log"

	"bitbucket.org/zagrodzki/goscope/hantek6022be"
	"bitbucket.org/zagrodzki/goscope/scope"
	"github.com/kylelemons/gousb/usb"
)

type supportedModel struct {
	check func(*usb.Descriptor) bool
	open  func(*usb.Device) scope.Device
}

var supportedModels = []supportedModel{
	supportedModel{hantek6022be.Supports, hantek6022be.New},
}

func isSupported(d *usb.Descriptor) bool {
	for _, s := range supportedModels {
		if s.check(d) {
			return true
		}
	}
	return false
}

func open(d *usb.Device) scope.Device {
	for _, s := range supportedModels {
		if s.check(d.Descriptor) {
			return s.open(d)
		}
	}
	return nil
}

func must(e error) {
	if e != nil {
		log.Fatalf(e.Error())
	}
}

func main() {
	ctx := usb.NewContext()
	devices, err := ctx.ListDevices(isSupported)
	defer func() {
		for _, d := range devices {
			d.Close()
		}
	}()
	if err != nil {
		log.Fatalf("ctx.ListDevices(): %v", err)
	}
	if len(devices) == 0 {
		log.Fatal("Did not find a valid device")
	}
	for _, d := range devices {
		fmt.Printf("Device found at bus %d addr %d\n", d.Bus, d.Address)
	}
	if len(devices) > 1 {
		fmt.Println("Using the first device listed")
	}
	osc := open(devices[0])
	fmt.Println(osc)
	for _, ch := range osc.Channels() {
		must(ch.SetVoltRange(5))
	}
	data, _, err := osc.ReadData()
	if err != nil {
		log.Fatalf("ReadData: %+v", err)
	}
	fmt.Println("Data:", data)
}
<|endoftext|>


<commit_before><commit_msg>Improve writer pool documentation<commit_after><|endoftext|>


<commit_before>package tunnel

import (
	"crypto/sha256"
	"errors"
	"fmt"
	"sync"

	"github.com/google/uuid"
	"github.com/micro/go-micro/network/link"
	"github.com/micro/go-micro/transport"
)

// tun represents a network tunnel
type tun struct {
	// the link on top of which we build a tunnel
	link link.Link

	sync.RWMutex

	// to indicate if we're connected or not
	connected bool

	// the send channel for all messages
	send chan *message

	// close channel
	closed chan bool

	// a map of sockets based on Micro-Tunnel-Id
	sockets map[string]*socket
}

// create new tunnel on top of a link
func newTunnel(link link.Link) *tun {
	return &tun{
		link:    link,
		send:    make(chan *message, 128),
		closed:  make(chan bool),
		sockets: make(map[string]*socket),
	}
}

// getSocket returns a socket from the internal socket map.
// It does this based on the Micro-Tunnel-Id and Micro-Tunnel-Session
func (t *tun) getSocket(id, session string) (*socket, bool) {
	// get the socket
	t.RLock()
	s, ok := t.sockets[id+session]
	t.RUnlock()
	return s, ok
}

// newSocket creates a new socket and saves it
func (t *tun) newSocket(id, session string) (*socket, bool) {
	// hash the id
	h := sha256.New()
	h.Write([]byte(id))
	id = fmt.Sprintf("%x", h.Sum(nil))

	// new socket
	s := &socket{
		id:      id,
		session: session,
		closed:  make(chan bool),
		recv:    make(chan *message, 128),
		send:    t.send,
	}

	// save socket
	t.Lock()
	_, ok := t.sockets[id+session]
	if ok {
		// socket already exists
		t.Unlock()
		return nil, false
	}
	t.sockets[id+session] = s
	t.Unlock()

	// return socket
	return s, true
}

// TODO: use tunnel id as part of the session
func (t *tun) newSession() string {
	return uuid.New().String()
}

// process outgoing messages sent by all local sockets
func (t *tun) process() {
	// manage the send buffer
	// all pseudo sockets throw everything down this
	for {
		select {
		case msg := <-t.send:
			nmsg := &transport.Message{
				Header: msg.data.Header,
				Body:   msg.data.Body,
			}

			// set the tunnel id on the outgoing message
			nmsg.Header["Micro-Tunnel-Id"] = msg.id

			// set the session id
			nmsg.Header["Micro-Tunnel-Session"] = msg.session

			// send the message via the interface
			if err := t.link.Send(nmsg); err != nil {
				// no op
				// TODO: do something
			}
		case <-t.closed:
			return
		}
	}
}

// process incoming messages
func (t *tun) listen() {
	for {
		// process anything via the net interface
		msg := new(transport.Message)
		err := t.link.Recv(msg)
		if err != nil {
			return
		}

		// the tunnel id
		id := msg.Header["Micro-Tunnel-Id"]

		// the session id
		session := msg.Header["Micro-Tunnel-Session"]

		// try get it based on just the tunnel id
		// the assumption here is that a listener
		// has no session but its set a listener session
		if len(session) == 0 {
			session = "listener"
		}

		// get the socket based on the tunnel id and session
		// this could be something we dialed in which case
		// we have a session for it otherwise its a listener
		s, exists := t.getSocket(id, session)
		if !exists {
			// drop it, we don't care about
			// messages we don't know about
			continue
		}

		// is the socket closed?
		select {
		case <-s.closed:
			// closed
			delete(t.sockets, id)
			continue
		default:
			// process
		}

		// is the socket new?
		select {
		// if its new the socket is actually blocked waiting
		// for a connection. so we check if its waiting.
		case <-s.wait:
		// if its waiting e.g its new then we close it
		default:
			// set remote address of the socket
			s.remote = msg.Header["Remote"]
			close(s.wait)
		}

		// construct a new transport message
		tmsg := &transport.Message{
			Header: msg.Header,
			Body:   msg.Body,
		}

		// construct the internal message
		imsg := &message{
			id:      id,
			session: session,
			data:    tmsg,
		}

		// append to recv backlog
		// we don't block if we can't pass it on
		select {
		case s.recv <- imsg:
		default:
		}
	}
}

// Close the tunnel
func (t *tun) Close() error {
	t.Lock()
	defer t.Unlock()

	if !t.connected {
		return nil
	}

	select {
	case <-t.closed:
		return nil
	default:
		// close all the sockets
		for _, s := range t.sockets {
			s.Close()
		}
		// close the connection
		close(t.closed)
		t.connected = false
	}

	return nil
}

// Connect the tunnel
func (t *tun) Connect() error {
	t.Lock()
	defer t.Unlock()

	// already connected
	if t.connected {
		return nil
	}

	// set as connected
	t.connected = true
	// create new close channel
	t.closed = make(chan bool)

	// process messages to be sent
	go t.process()
	// process incoming messages
	go t.listen()

	return nil
}

// Dial an address
func (t *tun) Dial(addr string) (Conn, error) {
	c, ok := t.newSocket(addr, t.newSession())
	if !ok {
		return nil, errors.New("error dialing " + addr)
	}
	// set remote
	c.remote = addr
	// set local
	c.local = t.link.Local()

	return c, nil
}

// Accept a connection on the address
func (t *tun) Listen(addr string) (Listener, error) {
	// create a new socket by hashing the address
	c, ok := t.newSocket(addr, "listener")
	if !ok {
		return nil, errors.New("already listening on " + addr)
	}

	// set remote. it will be replaced by the first message received
	c.remote = t.link.Remote()
	// set local
	c.local = addr

	tl := &tunListener{
		addr: addr,
		// the accept channel
		accept: make(chan *socket, 128),
		// the channel to close
		closed: make(chan bool),
		// the connection
		conn: c,
		// the listener socket
		socket: c,
	}

	// this kicks off the internal message processor
	// for the listener so it can create pseudo sockets
	// per session if they do not exist or pass messages
	// to the existign sessions
	go tl.process()

	// return the listener
	return tl, nil
}
<commit_msg>The listener has no session id<commit_after>package tunnel

import (
	"crypto/sha256"
	"errors"
	"fmt"
	"sync"

	"github.com/google/uuid"
	"github.com/micro/go-micro/network/link"
	"github.com/micro/go-micro/transport"
)

// tun represents a network tunnel
type tun struct {
	// the link on top of which we build a tunnel
	link link.Link

	sync.RWMutex

	// to indicate if we're connected or not
	connected bool

	// the send channel for all messages
	send chan *message

	// close channel
	closed chan bool

	// a map of sockets based on Micro-Tunnel-Id
	sockets map[string]*socket
}

// create new tunnel on top of a link
func newTunnel(link link.Link) *tun {
	return &tun{
		link:    link,
		send:    make(chan *message, 128),
		closed:  make(chan bool),
		sockets: make(map[string]*socket),
	}
}

// getSocket returns a socket from the internal socket map.
// It does this based on the Micro-Tunnel-Id and Micro-Tunnel-Session
func (t *tun) getSocket(id, session string) (*socket, bool) {
	// get the socket
	t.RLock()
	s, ok := t.sockets[id+session]
	t.RUnlock()
	return s, ok
}

// newSocket creates a new socket and saves it
func (t *tun) newSocket(id, session string) (*socket, bool) {
	// hash the id
	h := sha256.New()
	h.Write([]byte(id))
	id = fmt.Sprintf("%x", h.Sum(nil))

	// new socket
	s := &socket{
		id:      id,
		session: session,
		closed:  make(chan bool),
		recv:    make(chan *message, 128),
		send:    t.send,
	}

	// save socket
	t.Lock()
	_, ok := t.sockets[id+session]
	if ok {
		// socket already exists
		t.Unlock()
		return nil, false
	}
	t.sockets[id+session] = s
	t.Unlock()

	// return socket
	return s, true
}

// TODO: use tunnel id as part of the session
func (t *tun) newSession() string {
	return uuid.New().String()
}

// process outgoing messages sent by all local sockets
func (t *tun) process() {
	// manage the send buffer
	// all pseudo sockets throw everything down this
	for {
		select {
		case msg := <-t.send:
			nmsg := &transport.Message{
				Header: msg.data.Header,
				Body:   msg.data.Body,
			}

			// set the tunnel id on the outgoing message
			nmsg.Header["Micro-Tunnel-Id"] = msg.id

			// set the session id
			nmsg.Header["Micro-Tunnel-Session"] = msg.session

			// send the message via the interface
			if err := t.link.Send(nmsg); err != nil {
				// no op
				// TODO: do something
			}
		case <-t.closed:
			return
		}
	}
}

// process incoming messages
func (t *tun) listen() {
	for {
		// process anything via the net interface
		msg := new(transport.Message)
		err := t.link.Recv(msg)
		if err != nil {
			return
		}

		// the tunnel id
		id := msg.Header["Micro-Tunnel-Id"]

		// the session id
		session := msg.Header["Micro-Tunnel-Session"]

		// if the session id is blank there's nothing we can do
		// TODO: check this is the case, is there any reason
		// why we'd have a blank session? Is the tunnel
		// used for some other purpose?
		if len(session) == 0 {
			continue
		}

		// get the socket based on the tunnel id and session
		// this could be something we dialed in which case
		// we have a session for it otherwise its a listener
		s, exists := t.getSocket(id, session)
		if !exists {
			// try get it based on just the tunnel id
			// the assumption here is that a listener
			// has no session but its set a listener session
			s, exists = t.getSocket(id, "listener")
			if !exists {
				conti

				// drop it, we don't care about
				// messages we don't know about
				continue
			}
		}

		// is the socket closed?
		select {
		case <-s.closed:
			// closed
			delete(t.sockets, id)
			continue
		default:
			// process
		}

		// is the socket new?
		select {
		// if its new the socket is actually blocked waiting
		// for a connection. so we check if its waiting.
		case <-s.wait:
		// if its waiting e.g its new then we close it
		default:
			// set remote address of the socket
			s.remote = msg.Header["Remote"]
			close(s.wait)
		}

		// construct a new transport message
		tmsg := &transport.Message{
			Header: msg.Header,
			Body:   msg.Body,
		}

		// construct the internal message
		imsg := &message{
			id:      id,
			session: session,
			data:    tmsg,
		}

		// append to recv backlog
		// we don't block if we can't pass it on
		select {
		case s.recv <- imsg:
		default:
		}
	}
}

// Close the tunnel
func (t *tun) Close() error {
	t.Lock()
	defer t.Unlock()

	if !t.connected {
		return nil
	}

	select {
	case <-t.closed:
		return nil
	default:
		// close all the sockets
		for _, s := range t.sockets {
			s.Close()
		}
		// close the connection
		close(t.closed)
		t.connected = false
	}

	return nil
}

// Connect the tunnel
func (t *tun) Connect() error {
	t.Lock()
	defer t.Unlock()

	// already connected
	if t.connected {
		return nil
	}

	// set as connected
	t.connected = true
	// create new close channel
	t.closed = make(chan bool)

	// process messages to be sent
	go t.process()
	// process incoming messages
	go t.listen()

	return nil
}

// Dial an address
func (t *tun) Dial(addr string) (Conn, error) {
	c, ok := t.newSocket(addr, t.newSession())
	if !ok {
		return nil, errors.New("error dialing " + addr)
	}
	// set remote
	c.remote = addr
	// set local
	c.local = t.link.Local()

	return c, nil
}

// Accept a connection on the address
func (t *tun) Listen(addr string) (Listener, error) {
	// create a new socket by hashing the address
	c, ok := t.newSocket(addr, "listener")
	if !ok {
		return nil, errors.New("already listening on " + addr)
	}

	// set remote. it will be replaced by the first message received
	c.remote = t.link.Remote()
	// set local
	c.local = addr

	tl := &tunListener{
		addr: addr,
		// the accept channel
		accept: make(chan *socket, 128),
		// the channel to close
		closed: make(chan bool),
		// the connection
		conn: c,
		// the listener socket
		socket: c,
	}

	// this kicks off the internal message processor
	// for the listener so it can create pseudo sockets
	// per session if they do not exist or pass messages
	// to the existign sessions
	go tl.process()

	// return the listener
	return tl, nil
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package networking

import (
	"fmt"
	"sync"

	"github.com/ava-labs/salticidae-go"

	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/utils"
)

// Connections provides an interface for what a group of connections will
// support.
type Connections interface {
	Add(salticidae.PeerID, ids.ShortID, utils.IPDesc)

	GetPeerID(ids.ShortID) (salticidae.PeerID, bool)
	GetID(salticidae.PeerID) (ids.ShortID, bool)

	ContainsPeerID(salticidae.PeerID) bool
	ContainsID(ids.ShortID) bool
	ContainsIP(utils.IPDesc) bool

	Remove(salticidae.PeerID, ids.ShortID)
	RemovePeerID(salticidae.PeerID)
	RemoveID(ids.ShortID)

	PeerIDs() []salticidae.PeerID
	IDs() ids.ShortSet
	IPs() []utils.IPDesc
	Conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc)

	Len() int
}

type connections struct {
	mux sync.Mutex
	// peerID -> id
	peerIDToID map[[32]byte]ids.ShortID
	// id -> peerID
	idToPeerID map[[20]byte]salticidae.PeerID
	// id -> ip
	idToIP map[[20]byte]utils.IPDesc
}

// NewConnections returns a new and empty connections object
func NewConnections() Connections {
	return &connections{
		peerIDToID: make(map[[32]byte]ids.ShortID),
		idToPeerID: make(map[[20]byte]salticidae.PeerID),
		idToIP:     make(map[[20]byte]utils.IPDesc),
	}
}

// Add Assumes that peer is garbage collected normally
func (c *connections) Add(peer salticidae.PeerID, id ids.ShortID, ip utils.IPDesc) {
	c.mux.Lock()
	defer c.mux.Unlock()

	c.add(peer, id, ip)
}

// GetPeerID returns the peer mapped to the id that is provided if one exists.
func (c *connections) GetPeerID(id ids.ShortID) (salticidae.PeerID, bool) {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.getPeerID(id)
}

// GetID returns the id mapped to the peer that is provided if one exists.
func (c *connections) GetID(peer salticidae.PeerID) (ids.ShortID, bool) {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.getID(peer)
}

// ContainsPeerID returns true if the peer is contained in the connection pool
func (c *connections) ContainsPeerID(peer salticidae.PeerID) bool {
	_, exists := c.GetID(peer)
	return exists
}

// ContainsID returns true if the id is contained in the connection pool
func (c *connections) ContainsID(id ids.ShortID) bool {
	_, exists := c.GetPeerID(id)
	return exists
}

// ContainsIP returns true if the ip is contained in the connection pool
func (c *connections) ContainsIP(ip utils.IPDesc) bool {
	for _, otherIP := range c.IPs() {
		if ip.Equal(otherIP) {
			return true
		}
	}
	return false
}

// Remove ensures that no connection will have any mapping containing [peer] or
// [id].
func (c *connections) Remove(peer salticidae.PeerID, id ids.ShortID) {
	c.mux.Lock()
	defer c.mux.Unlock()

	c.remove(peer, id)
}

// RemovePeerID ensures that no connection will have a mapping containing [peer]
func (c *connections) RemovePeerID(peer salticidae.PeerID) {
	c.mux.Lock()
	defer c.mux.Unlock()

	c.removePeerID(peer)
}

// RemoveID ensures that no connection will have a mapping containing [id]
func (c *connections) RemoveID(id ids.ShortID) {
	c.mux.Lock()
	defer c.mux.Unlock()

	c.removeID(id)
}

// PeerIDs returns the full list of peers contained in this connection pool.
func (c *connections) PeerIDs() []salticidae.PeerID {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.peerIDs()
}

// IDs return the set of IDs that are mapping in this connection pool.
func (c *connections) IDs() ids.ShortSet {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.ids()
}

// IPs return the set of IPs that are mapped in this connection pool.
func (c *connections) IPs() []utils.IPDesc {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.ips()
}

// Conns return the set of connections in this connection pool.
func (c *connections) Conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc) {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.conns()
}

// Len returns the number of elements in the map
func (c *connections) Len() int {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.len()
}

func (c *connections) add(peer salticidae.PeerID, id ids.ShortID, ip utils.IPDesc) {
	c.remove(peer, id)

	key := id.Key()
	c.peerIDToID[toID(peer)] = id
	c.idToPeerID[key] = peer
	c.idToIP[key] = ip
}

func (c *connections) getPeerID(id ids.ShortID) (salticidae.PeerID, bool) {
	peer, exists := c.idToPeerID[id.Key()]
	return peer, exists
}

func (c *connections) getID(peer salticidae.PeerID) (ids.ShortID, bool) {
	id, exists := c.peerIDToID[toID(peer)]
	return id, exists
}

func (c *connections) remove(peer salticidae.PeerID, id ids.ShortID) {
	c.removePeerID(peer)
	c.removeID(id)
}

func (c *connections) removePeerID(peer salticidae.PeerID) {
	peerID := toID(peer)
	if id, exists := c.peerIDToID[peerID]; exists {
		delete(c.peerIDToID, peerID)
		delete(c.idToPeerID, id.Key())
	}
}

func (c *connections) removeID(id ids.ShortID) {
	idKey := id.Key()
	if peer, exists := c.idToPeerID[idKey]; exists {
		delete(c.peerIDToID, toID(peer))
		delete(c.idToPeerID, idKey)
	}
}

func (c *connections) peerIDs() []salticidae.PeerID {
	peers := make([]salticidae.PeerID, 0, len(c.idToPeerID))
	for _, peer := range c.idToPeerID {
		peers = append(peers, peer)
	}
	return peers
}

func (c *connections) ids() ids.ShortSet {
	ids := ids.ShortSet{}
	for _, id := range c.peerIDToID {
		ids.Add(id)
	}
	return ids
}

func (c *connections) ips() []utils.IPDesc {
	ips := make([]utils.IPDesc, 0, len(c.idToIP))
	for _, ip := range c.idToIP {
		ips = append(ips, ip)
	}
	return ips
}

func (c *connections) conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc) {
	peers := make([]salticidae.PeerID, 0, len(c.idToPeerID))
	idList := make([]ids.ShortID, 0, len(c.idToPeerID))
	ips := make([]utils.IPDesc, 0, len(c.idToPeerID))
	for id, peer := range c.idToPeerID {
		idList = append(idList, ids.NewShortID(id))
		peers = append(peers, peer)
		ips = append(ips, c.idToIP[id])
	}
	return peers, idList, ips
}

func (c *connections) len() int { return len(c.idToPeerID) }

func toID(peer salticidae.PeerID) [32]byte {
	ds := salticidae.NewDataStream(false)

	peerInt := peer.AsUInt256()
	peerInt.Serialize(ds)

	size := ds.Size()
	dsb := ds.GetDataInPlace(size)
	idBytes := dsb.Get()

	id := [32]byte{}
	copy(id[:], idBytes)

	ds.Free()
	return id
}

func toIPDesc(addr salticidae.NetAddr) utils.IPDesc {
	ip, err := ToIPDesc(addr)
	HandshakeNet.log.AssertNoError(err)
	return ip
}

// ToIPDesc converts an address to an IP
func ToIPDesc(addr salticidae.NetAddr) (utils.IPDesc, error) {
	ip := salticidae.FromBigEndianU32(addr.GetIP())
	port := salticidae.FromBigEndianU16(addr.GetPort())
	return utils.ToIPDesc(fmt.Sprintf("%d.%d.%d.%d:%d", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip), port))
}
<commit_msg>Properly remove the IP when removing the connection<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package networking

import (
	"fmt"
	"sync"

	"github.com/ava-labs/salticidae-go"

	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/utils"
)

// Connections provides an interface for what a group of connections will
// support.
type Connections interface {
	Add(salticidae.PeerID, ids.ShortID, utils.IPDesc)

	GetPeerID(ids.ShortID) (salticidae.PeerID, bool)
	GetID(salticidae.PeerID) (ids.ShortID, bool)

	ContainsPeerID(salticidae.PeerID) bool
	ContainsID(ids.ShortID) bool
	ContainsIP(utils.IPDesc) bool

	Remove(salticidae.PeerID, ids.ShortID)
	RemovePeerID(salticidae.PeerID)
	RemoveID(ids.ShortID)

	PeerIDs() []salticidae.PeerID
	IDs() ids.ShortSet
	IPs() []utils.IPDesc
	Conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc)

	Len() int
}

type connections struct {
	mux sync.Mutex
	// peerID -> id
	peerIDToID map[[32]byte]ids.ShortID
	// id -> peerID
	idToPeerID map[[20]byte]salticidae.PeerID
	// id -> ip
	idToIP map[[20]byte]utils.IPDesc
}

// NewConnections returns a new and empty connections object
func NewConnections() Connections {
	return &connections{
		peerIDToID: make(map[[32]byte]ids.ShortID),
		idToPeerID: make(map[[20]byte]salticidae.PeerID),
		idToIP:     make(map[[20]byte]utils.IPDesc),
	}
}

// Add Assumes that peer is garbage collected normally
func (c *connections) Add(peer salticidae.PeerID, id ids.ShortID, ip utils.IPDesc) {
	c.mux.Lock()
	defer c.mux.Unlock()

	c.add(peer, id, ip)
}

// GetPeerID returns the peer mapped to the id that is provided if one exists.
func (c *connections) GetPeerID(id ids.ShortID) (salticidae.PeerID, bool) {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.getPeerID(id)
}

// GetID returns the id mapped to the peer that is provided if one exists.
func (c *connections) GetID(peer salticidae.PeerID) (ids.ShortID, bool) {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.getID(peer)
}

// ContainsPeerID returns true if the peer is contained in the connection pool
func (c *connections) ContainsPeerID(peer salticidae.PeerID) bool {
	_, exists := c.GetID(peer)
	return exists
}

// ContainsID returns true if the id is contained in the connection pool
func (c *connections) ContainsID(id ids.ShortID) bool {
	_, exists := c.GetPeerID(id)
	return exists
}

// ContainsIP returns true if the ip is contained in the connection pool
func (c *connections) ContainsIP(ip utils.IPDesc) bool {
	for _, otherIP := range c.IPs() {
		if ip.Equal(otherIP) {
			return true
		}
	}
	return false
}

// Remove ensures that no connection will have any mapping containing [peer] or
// [id].
func (c *connections) Remove(peer salticidae.PeerID, id ids.ShortID) {
	c.mux.Lock()
	defer c.mux.Unlock()

	c.remove(peer, id)
}

// RemovePeerID ensures that no connection will have a mapping containing [peer]
func (c *connections) RemovePeerID(peer salticidae.PeerID) {
	c.mux.Lock()
	defer c.mux.Unlock()

	c.removePeerID(peer)
}

// RemoveID ensures that no connection will have a mapping containing [id]
func (c *connections) RemoveID(id ids.ShortID) {
	c.mux.Lock()
	defer c.mux.Unlock()

	c.removeID(id)
}

// PeerIDs returns the full list of peers contained in this connection pool.
func (c *connections) PeerIDs() []salticidae.PeerID {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.peerIDs()
}

// IDs return the set of IDs that are mapping in this connection pool.
func (c *connections) IDs() ids.ShortSet {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.ids()
}

// IPs return the set of IPs that are mapped in this connection pool.
func (c *connections) IPs() []utils.IPDesc {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.ips()
}

// Conns return the set of connections in this connection pool.
func (c *connections) Conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc) {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.conns()
}

// Len returns the number of elements in the map
func (c *connections) Len() int {
	c.mux.Lock()
	defer c.mux.Unlock()

	return c.len()
}

func (c *connections) add(peer salticidae.PeerID, id ids.ShortID, ip utils.IPDesc) {
	c.remove(peer, id)

	key := id.Key()
	c.peerIDToID[toID(peer)] = id
	c.idToPeerID[key] = peer
	c.idToIP[key] = ip
}

func (c *connections) getPeerID(id ids.ShortID) (salticidae.PeerID, bool) {
	peer, exists := c.idToPeerID[id.Key()]
	return peer, exists
}

func (c *connections) getID(peer salticidae.PeerID) (ids.ShortID, bool) {
	id, exists := c.peerIDToID[toID(peer)]
	return id, exists
}

func (c *connections) remove(peer salticidae.PeerID, id ids.ShortID) {
	c.removeID(id)
	c.removePeerID(peer)
}

func (c *connections) removePeerID(peer salticidae.PeerID) {
	peerID := toID(peer)
	if id, exists := c.peerIDToID[peerID]; exists {
		idKey := id.Key()

		delete(c.peerIDToID, peerID)
		delete(c.idToPeerID, idKey)
		delete(c.idToIP, idKey)
	}
}

func (c *connections) removeID(id ids.ShortID) {
	idKey := id.Key()
	if peer, exists := c.idToPeerID[idKey]; exists {
		delete(c.peerIDToID, toID(peer))
		delete(c.idToPeerID, idKey)
		delete(c.idToIP, idKey)
	}
}

func (c *connections) peerIDs() []salticidae.PeerID {
	peers := make([]salticidae.PeerID, 0, len(c.idToPeerID))
	for _, peer := range c.idToPeerID {
		peers = append(peers, peer)
	}
	return peers
}

func (c *connections) ids() ids.ShortSet {
	ids := ids.ShortSet{}
	for _, id := range c.peerIDToID {
		ids.Add(id)
	}
	return ids
}

func (c *connections) ips() []utils.IPDesc {
	ips := make([]utils.IPDesc, 0, len(c.idToIP))
	for _, ip := range c.idToIP {
		ips = append(ips, ip)
	}
	return ips
}

func (c *connections) conns() ([]salticidae.PeerID, []ids.ShortID, []utils.IPDesc) {
	peers := make([]salticidae.PeerID, 0, len(c.idToPeerID))
	idList := make([]ids.ShortID, 0, len(c.idToPeerID))
	ips := make([]utils.IPDesc, 0, len(c.idToPeerID))
	for id, peer := range c.idToPeerID {
		idList = append(idList, ids.NewShortID(id))
		peers = append(peers, peer)
		ips = append(ips, c.idToIP[id])
	}
	return peers, idList, ips
}

func (c *connections) len() int { return len(c.idToPeerID) }

func toID(peer salticidae.PeerID) [32]byte {
	ds := salticidae.NewDataStream(false)

	peerInt := peer.AsUInt256()
	peerInt.Serialize(ds)

	size := ds.Size()
	dsb := ds.GetDataInPlace(size)
	idBytes := dsb.Get()

	id := [32]byte{}
	copy(id[:], idBytes)

	ds.Free()
	return id
}

func toIPDesc(addr salticidae.NetAddr) utils.IPDesc {
	ip, err := ToIPDesc(addr)
	HandshakeNet.log.AssertNoError(err)
	return ip
}

// ToIPDesc converts an address to an IP
func ToIPDesc(addr salticidae.NetAddr) (utils.IPDesc, error) {
	ip := salticidae.FromBigEndianU32(addr.GetIP())
	port := salticidae.FromBigEndianU16(addr.GetPort())
	return utils.ToIPDesc(fmt.Sprintf("%d.%d.%d.%d:%d", byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip), port))
}
<|endoftext|>


<commit_before>package main

import (
	"time"
	"fmt"
	"math/rand"
	"sort"
)

type compare func(interface{}, interface{}) bool

type Tree struct {
	Left *Tree
	Value interface{}
	Right *Tree
	comp compare
	Levels int
}

func NewTree(f compare) *Tree {
	return &Tree{comp:f}
}

func (t *Tree) Add(v interface{}) bool {
	t.Levels++
	if t.Value == nil {
		t.Value = v
		return true
	}

	if t.comp(t.Value, v) {
		if t.Left == nil {
			t.Left = NewTree(t.comp)
		}
		return t.Left.Add(v)
	}

	if !t.comp(t.Value, v) {
		if t.Right == nil {
			t.Right = NewTree(t.comp)
		}
		return t.Right.Add(v)
	}
	panic("Shouldn't get here")
}

func (t *Tree) walk(ch chan<- interface{})  {
	if t.Left != nil {
		t.Left.walk(ch)
	}
	ch <- t.Value
	if t.Right != nil {
		t.Right.walk(ch)
	}
}

func (t *Tree) Walk() []interface{} {
	ch := make(chan interface{}, t.Levels)

	t.walk(ch)
	close(ch)

	var ar []interface{}
	for item := range ch {
		ar = append(ar, item)
	}
	return ar
}

func main() {
	t := NewTree(func (current, newval interface{}) bool {
		if current.(int) < newval.(int) {
			return false
		}
		return true
	})

	t2 := NewTree(func (current, newval interface{}) bool {
		if current.(int) < newval.(int) {
			return false
		}
		return true
	})

	t3 := NewTree(func (current, newval interface{}) bool {
		if current.(int) < newval.(int) {
			return false
		}
		return true
	})

	intslice := make([]int, 0, 10000)
	for x := 0; x < 10000; x++ {
		intslice = append(intslice, x)
	}
	intslice2 := make([]int, 0, 10000)
	for x := 0; x < 10000; x++ {
		intslice2 = append(intslice2, x)
	}
	intslice3 := make([]int, 0, 10000)
	for x := 0; x < 10000; x++ {
		intslice3 = append(intslice3, x)
	}

	r := RandomSlice{intslice}
	r2 := RandomSlice{intslice2}
	sort.Sort(r)
	sort.Sort(r2)

	ti := time.Now()
	for _, num := range r.Slice {
		t.Add(num)
	}
	fmt.Println(time.Now().Sub(ti))

	ti = time.Now()
	for _, num := range r2.Slice {
		t2.Add(num)
	}
	fmt.Println(time.Now().Sub(ti))

	ti = time.Now()
	for _, num := range intslice3 {
		t3.Add(num)
	}
	fmt.Println(time.Now().Sub(ti))

	ti = time.Now()
	t.Walk()
	fmt.Println(time.Now().Sub(ti))
	ti = time.Now()
	t2.Walk()
	fmt.Println(time.Now().Sub(ti))
	ti = time.Now()
	t3.Walk()
	fmt.Println(time.Now().Sub(ti))
}

type RandomSlice struct {
	Slice []int
}

func (r RandomSlice) Len() int {
	return len(r.Slice)
}

func (RandomSlice) Less(i, j int) bool {
	d := rand.Intn(2)
	if d == 1 { return true }
	return false
}

func (r RandomSlice) Swap(i, j int) {
	r.Slice[i], r.Slice[j] = r.Slice[j], r.Slice[i]
}<commit_msg>Changed array lengths<commit_after>package main

import (
	"time"
	"fmt"
	"math/rand"
	"sort"
)

type compare func(interface{}, interface{}) bool

type Tree struct {
	Left *Tree
	Value interface{}
	Right *Tree
	comp compare
	Levels int
}

func NewTree(f compare) *Tree {
	return &Tree{comp:f}
}

func (t *Tree) Add(v interface{}) bool {
	t.Levels++
	if t.Value == nil {
		t.Value = v
		return true
	}

	if t.comp(t.Value, v) {
		if t.Left == nil {
			t.Left = NewTree(t.comp)
		}
		return t.Left.Add(v)
	}

	if !t.comp(t.Value, v) {
		if t.Right == nil {
			t.Right = NewTree(t.comp)
		}
		return t.Right.Add(v)
	}
	panic("Shouldn't get here")
}

func (t *Tree) walk(ch chan<- interface{})  {
	if t.Left != nil {
		t.Left.walk(ch)
	}
	ch <- t.Value
	if t.Right != nil {
		t.Right.walk(ch)
	}
}

func (t *Tree) Walk() []interface{} {
	ch := make(chan interface{}, t.Levels)

	t.walk(ch)
	close(ch)

	var ar []interface{}
	for item := range ch {
		ar = append(ar, item)
	}
	return ar
}

func main() {
	t := NewTree(func (current, newval interface{}) bool {
		if current.(int) < newval.(int) {
			return false
		}
		return true
	})

	t2 := NewTree(func (current, newval interface{}) bool {
		if current.(int) < newval.(int) {
			return false
		}
		return true
	})

	t3 := NewTree(func (current, newval interface{}) bool {
		if current.(int) < newval.(int) {
			return false
		}
		return true
	})

	intslice := make([]int, 0, 100000)
	for x := 0; x < 100000; x++ {
		intslice = append(intslice, x)
	}
	intslice2 := make([]int, 0, 100000)
	for x := 0; x < 100000; x++ {
		intslice2 = append(intslice2, x)
	}
	intslice3 := make([]int, 0, 100000)
	for x := 0; x < 100000; x++ {
		intslice3 = append(intslice3, x)
	}

	r := RandomSlice{intslice}
	r2 := RandomSlice{intslice2}
	sort.Sort(r)
	sort.Sort(r2)

	ti := time.Now()
	for _, num := range r.Slice {
		t.Add(num)
	}
	fmt.Println(time.Now().Sub(ti))

	ti = time.Now()
	for _, num := range r2.Slice {
		t2.Add(num)
	}
	fmt.Println(time.Now().Sub(ti))

	ti = time.Now()
	for _, num := range intslice3 {
		t3.Add(num)
	}
	fmt.Println(time.Now().Sub(ti))

	ti = time.Now()
	t.Walk()
	fmt.Println(time.Now().Sub(ti))
	ti = time.Now()
	t2.Walk()
	fmt.Println(time.Now().Sub(ti))
	ti = time.Now()
	t3.Walk()
	fmt.Println(time.Now().Sub(ti))
}

type RandomSlice struct {
	Slice []int
}

func (r RandomSlice) Len() int {
	return len(r.Slice)
}

func (RandomSlice) Less(i, j int) bool {
	d := rand.Intn(2)
	if d == 1 { return true }
	return false
}

func (r RandomSlice) Swap(i, j int) {
	r.Slice[i], r.Slice[j] = r.Slice[j], r.Slice[i]
}<|endoftext|>


<commit_before>package grim

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"bytes"
	"log"
	"errors"
	"strings"
)

// Copyright 2015 MediaMath <http://www.mediamath.com>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
var testOwner = "MediaMath"
var testRepo = "grim"

var testHookEvent = hookEvent{
	Owner: testOwner,
	Repo: testRepo,
	EventName: "push",
}
var testEffectiveConfig = &effectiveConfig{
	pendingTemplate: "pending {{.Owner}}",
	errorTemplate:   "error {{.Repo}}",
	failureTemplate: "failure {{.Target}}",
	successTemplate: "success {{.UserName}}",
	hipChatToken: "NOT_EMPTY",
	hipChatRoom: "NON_EMPTY",
}

func TestOnHipChatLoggingGrimError(t *testing.T) {
	var buf bytes.Buffer
	logger := log.New(&buf, "", log.Lshortfile)

	//onHook(string,*effectiveConfig, hookEvent, action hookAction, logger *log.Logg
	onHook("not-used", testEffectiveConfig, testHookEvent, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: 0}, "", errors.New("")
		}, logger)
	loggedContent := fmt.Sprintf("%v", &buf)
	if !strings.Contains(loggedContent, "MediaMathTesting") {
		t.Errorf("Failed to log grim pending")
	}
	if !strings.Contains(loggedContent, "error grim") {
		t.Errorf("Failed to log grim error")
	}
}

func TestOnHipChatLoggingGrimSuccess(t *testing.T) {
	var buf bytes.Buffer
	logger := log.New(&buf, "", log.Lshortfile)

	//onHook(string,*effectiveConfig, hookEvent, action hookAction, logger *log.Logg
	onHook("not-used", testEffectiveConfig, testHookEvent, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: 0}, "", nil
		}, logger)
	loggedContent := fmt.Sprintf("%v", &buf)
	if !strings.Contains(loggedContent, "MediaMathTesting") {
		t.Errorf("Failed to log grim pending")
	}
	if !strings.Contains(loggedContent, "grim success") {
		t.Errorf("Failed to log grim success%v",loggedContent)
	}
}

func TestOnHipChatLoggingGrimFailure(t *testing.T) {
	var buf bytes.Buffer
	logger := log.New(&buf, "", log.Lshortfile)

	//onHook(string,*effectiveConfig, hookEvent, action hookAction, logger *log.Logg
	onHook("not-used", testEffectiveConfig, testHookEvent, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: 1234}, "", nil
		}, logger)
	loggedContent := fmt.Sprintf("%v", &buf)
	if !strings.Contains(loggedContent, "MediaMathTesting") {
		t.Errorf("Failed to log grim pending")
	}
	if !strings.Contains(loggedContent, "grim failure") {
		t.Errorf("Failed to log grim failure%v",loggedContent)
	}
}

func TestOnActionFailure(t *testing.T) {
	tempDir, _ := ioutil.TempDir("", "results-dir-failure")
	defer os.RemoveAll(tempDir)

	doNothingAction(tempDir, testOwner, testRepo, 123, nil)

	if _, err := resultsDirectoryExists(tempDir, testOwner, testRepo); err != nil {
		t.Errorf("|%v|", err)
	}

}

func TestOnActionError(t *testing.T) {
	tempDir, _ := ioutil.TempDir("", "results-dir-error")
	defer os.RemoveAll(tempDir)

	doNothingAction(tempDir, testOwner, testRepo, 0, fmt.Errorf("Bad Bad thing happened"))

	if _, err := resultsDirectoryExists(tempDir, testOwner, testRepo); err != nil {
		t.Errorf("|%v|", err)
	}
}

func TestResultsDirectoryCreatedInOnHook(t *testing.T) {
	tempDir, _ := ioutil.TempDir("", "results-dir-success")
	defer os.RemoveAll(tempDir)

	doNothingAction(tempDir, testOwner, testRepo, 0, nil)

	if _, err := resultsDirectoryExists(tempDir, testOwner, testRepo); err != nil {
		t.Errorf("|%v|", err)
	}
}

func TestHookGetsLogged(t *testing.T) {
	tempDir, _ := ioutil.TempDir("", "results-dir-success")
	defer os.RemoveAll(tempDir)

	hook := hookEvent{Owner: testOwner, Repo: testRepo, StatusRef: "fooooooooooooooooooo"}

	onHook("not-used", &effectiveConfig{resultRoot: tempDir}, hook, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: 0}, "", nil
		}, nil)

	results, _ := resultsDirectoryExists(tempDir, testOwner, testRepo)
	hookFile := filepath.Join(results, "hook.json")

	if _, err := os.Stat(hookFile); os.IsNotExist(err) {
		t.Errorf("%s was not created.", hookFile)
	}

	jsonHookFile, readerr := ioutil.ReadFile(hookFile)
	if readerr != nil {
		t.Errorf("Error reading file %v", readerr)
	}

	var parsed hookEvent
	parseErr := json.Unmarshal(jsonHookFile, &parsed)
	if parseErr != nil {
		t.Errorf("Error parsing: %v", parseErr)
	}

	if hook.Owner != parsed.Owner || hook.Repo != parsed.Repo || hook.StatusRef != parsed.StatusRef {
		t.Errorf("Did not match:\n%v\n%v", hook, parsed)
	}

}

func doNothingAction(tempDir, owner, repo string, exitCode int, returnedErr error) error {
	return onHook("not-used", &effectiveConfig{resultRoot: tempDir}, hookEvent{Owner: owner, Repo: repo}, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: exitCode}, "", returnedErr
		}, nil)
}

func resultsDirectoryExists(tempDir, owner, repo string) (string, error) {
	files, err := ioutil.ReadDir(tempDir)
	if err != nil {
		return "", err
	}

	var fileNames []string
	for _, stat := range files {
		fileNames = append(fileNames, stat.Name())
	}

	repoResults := filepath.Join(tempDir, owner, repo)

	if _, err := os.Stat(repoResults); os.IsNotExist(err) {
		return "", fmt.Errorf("%s was not created: %s", repoResults, fileNames)
	}

	baseFiles, err := ioutil.ReadDir(repoResults)
	if len(baseFiles) != 1 {
		return "", fmt.Errorf("Did not create base name in repo results")
	}

	return filepath.Join(repoResults, baseFiles[0].Name()), nil
}
<commit_msg>fixed error caused by previous commit name change<commit_after>package grim

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
	"bytes"
	"log"
	"errors"
	"strings"
)

// Copyright 2015 MediaMath <http://www.mediamath.com>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
var testOwner = "MediaMath"
var testRepo = "grim"

var testHookEvent = hookEvent{
	Owner: testOwner,
	Repo: testRepo,
	EventName: "push",
}
var testEffectiveConfig = &effectiveConfig{
	pendingTemplate: "pending {{.Owner}}",
	errorTemplate:   "error {{.Repo}}",
	failureTemplate: "failure {{.Target}}",
	successTemplate: "success {{.UserName}}",
	hipChatToken: "NOT_EMPTY",
	hipChatRoom: "NON_EMPTY",
}

func TestOnHipChatLoggingGrimError(t *testing.T) {
	var buf bytes.Buffer
	logger := log.New(&buf, "", log.Lshortfile)

	//onHook(string,*effectiveConfig, hookEvent, action hookAction, logger *log.Logg
	onHook("not-used", testEffectiveConfig, testHookEvent, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: 0}, "", errors.New("")
		}, logger)
	loggedContent := fmt.Sprintf("%v", &buf)
	if !strings.Contains(loggedContent, "MediaMath") {
		t.Errorf("Failed to log grim pending")
	}
	if !strings.Contains(loggedContent, "error grim") {
		t.Errorf("Failed to log grim error")
	}
}

func TestOnHipChatLoggingGrimSuccess(t *testing.T) {
	var buf bytes.Buffer
	logger := log.New(&buf, "", log.Lshortfile)

	//onHook(string,*effectiveConfig, hookEvent, action hookAction, logger *log.Logg
	onHook("not-used", testEffectiveConfig, testHookEvent, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: 0}, "", nil
		}, logger)
	loggedContent := fmt.Sprintf("%v", &buf)
	if !strings.Contains(loggedContent, "MediaMath") {
		t.Errorf("Failed to log grim pending")
	}
	if !strings.Contains(loggedContent, "grim success") {
		t.Errorf("Failed to log grim success%v",loggedContent)
	}
}

func TestOnHipChatLoggingGrimFailure(t *testing.T) {
	var buf bytes.Buffer
	logger := log.New(&buf, "", log.Lshortfile)

	//onHook(string,*effectiveConfig, hookEvent, action hookAction, logger *log.Logg
	onHook("not-used", testEffectiveConfig, testHookEvent, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: 1234}, "", nil
		}, logger)
	loggedContent := fmt.Sprintf("%v", &buf)
	if !strings.Contains(loggedContent, "MediaMath") {
		t.Errorf("Failed to log grim pending")
	}
	if !strings.Contains(loggedContent, "grim failure") {
		t.Errorf("Failed to log grim failure%v",loggedContent)
	}
}

func TestOnActionFailure(t *testing.T) {
	tempDir, _ := ioutil.TempDir("", "results-dir-failure")
	defer os.RemoveAll(tempDir)

	doNothingAction(tempDir, testOwner, testRepo, 123, nil)

	if _, err := resultsDirectoryExists(tempDir, testOwner, testRepo); err != nil {
		t.Errorf("|%v|", err)
	}

}

func TestOnActionError(t *testing.T) {
	tempDir, _ := ioutil.TempDir("", "results-dir-error")
	defer os.RemoveAll(tempDir)

	doNothingAction(tempDir, testOwner, testRepo, 0, fmt.Errorf("Bad Bad thing happened"))

	if _, err := resultsDirectoryExists(tempDir, testOwner, testRepo); err != nil {
		t.Errorf("|%v|", err)
	}
}

func TestResultsDirectoryCreatedInOnHook(t *testing.T) {
	tempDir, _ := ioutil.TempDir("", "results-dir-success")
	defer os.RemoveAll(tempDir)

	doNothingAction(tempDir, testOwner, testRepo, 0, nil)

	if _, err := resultsDirectoryExists(tempDir, testOwner, testRepo); err != nil {
		t.Errorf("|%v|", err)
	}
}

func TestHookGetsLogged(t *testing.T) {
	tempDir, _ := ioutil.TempDir("", "results-dir-success")
	defer os.RemoveAll(tempDir)

	hook := hookEvent{Owner: testOwner, Repo: testRepo, StatusRef: "fooooooooooooooooooo"}

	onHook("not-used", &effectiveConfig{resultRoot: tempDir}, hook, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: 0}, "", nil
		}, nil)

	results, _ := resultsDirectoryExists(tempDir, testOwner, testRepo)
	hookFile := filepath.Join(results, "hook.json")

	if _, err := os.Stat(hookFile); os.IsNotExist(err) {
		t.Errorf("%s was not created.", hookFile)
	}

	jsonHookFile, readerr := ioutil.ReadFile(hookFile)
	if readerr != nil {
		t.Errorf("Error reading file %v", readerr)
	}

	var parsed hookEvent
	parseErr := json.Unmarshal(jsonHookFile, &parsed)
	if parseErr != nil {
		t.Errorf("Error parsing: %v", parseErr)
	}

	if hook.Owner != parsed.Owner || hook.Repo != parsed.Repo || hook.StatusRef != parsed.StatusRef {
		t.Errorf("Did not match:\n%v\n%v", hook, parsed)
	}

}

func doNothingAction(tempDir, owner, repo string, exitCode int, returnedErr error) error {
	return onHook("not-used", &effectiveConfig{resultRoot: tempDir}, hookEvent{Owner: owner, Repo: repo}, func(r string, resultPath string, c *effectiveConfig, h hookEvent) (*executeResult, string, error) {
			return &executeResult{ExitCode: exitCode}, "", returnedErr
		}, nil)
}

func resultsDirectoryExists(tempDir, owner, repo string) (string, error) {
	files, err := ioutil.ReadDir(tempDir)
	if err != nil {
		return "", err
	}

	var fileNames []string
	for _, stat := range files {
		fileNames = append(fileNames, stat.Name())
	}

	repoResults := filepath.Join(tempDir, owner, repo)

	if _, err := os.Stat(repoResults); os.IsNotExist(err) {
		return "", fmt.Errorf("%s was not created: %s", repoResults, fileNames)
	}

	baseFiles, err := ioutil.ReadDir(repoResults)
	if len(baseFiles) != 1 {
		return "", fmt.Errorf("Did not create base name in repo results")
	}

	return filepath.Join(repoResults, baseFiles[0].Name()), nil
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 blob

import (
	"crypto/sha1"
	"fmt"
)

// A Score is the identifier for a blob previously stored by a blob store. It
// consists of a 20-byte SHA-1 hash of the blob's contents, so that with high
// probability two blobs have the same contents if and only if they have the
// same score.
const ScoreLength = 20
type Score [ScoreLength]byte

// Compute the score for the supplied blob. This is primarily intended for use
// by blob store implementations; most users should obtain scores through calls
// to a blob store's Store method.
func ComputeScore(b []byte) (s Score) {
	h := sha1.New()
	h.Write(b)

	slice := h.Sum(nil)
	if len(slice) != ScoreLength {
		panic(
			fmt.Sprintf(
				"Expected %d bytes for SHA-1; got %d",
				ScoreLength,
				len(slice)))
	}

	copy(s[:], slice)
	return
}

// Return a fixed-width hex version of the score's hash, suitable for using
// e.g. as a filename.
func (s Score) Hex() string {
	return fmt.Sprintf("%x", s)
}
<commit_msg>Fixed formatting.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 blob

import (
	"crypto/sha1"
	"fmt"
)

// A Score is the identifier for a blob previously stored by a blob store. It
// consists of a 20-byte SHA-1 hash of the blob's contents, so that with high
// probability two blobs have the same contents if and only if they have the
// same score.
const ScoreLength = 20

type Score [ScoreLength]byte

// Compute the score for the supplied blob. This is primarily intended for use
// by blob store implementations; most users should obtain scores through calls
// to a blob store's Store method.
func ComputeScore(b []byte) (s Score) {
	h := sha1.New()
	h.Write(b)

	slice := h.Sum(nil)
	if len(slice) != ScoreLength {
		panic(
			fmt.Sprintf(
				"Expected %d bytes for SHA-1; got %d",
				ScoreLength,
				len(slice)))
	}

	copy(s[:], slice)
	return
}

// Return a fixed-width hex version of the score's hash, suitable for using
// e.g. as a filename.
func (s Score) Hex() string {
	return fmt.Sprintf("%x", s)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"net"
	"os"
	"time"

	"github.com/gabriel-comeau/multiplayer-game-test/protocol"
	"github.com/gabriel-comeau/multiplayer-game-test/shared"
)

type TestPlayer struct {
	conn     net.Conn
	lastSeq  int64
	playerId int64
}

const (
	NUM_CLIENTS               = 5
	SLEEP_TIME  time.Duration = 33 * time.Millisecond
)

func main() {
	for i := 0; i < NUM_CLIENTS; i++ {
		fmt.Println("Launching client:", i)
		launchClient()
	}

	for {
		time.Sleep(SLEEP_TIME)
	}
}

func launchClient() {
	testPlayer := new(TestPlayer)
	testPlayer.conn, testPlayer.playerId = connectToServer()
	fmt.Printf("Got a uuid of: %v\n", testPlayer.playerId)
	go listenForMessages(testPlayer)
	go runTestPlayer(testPlayer)

}

// This is the "main" game loop for each test player
func runTestPlayer(testPlayer *TestPlayer) {

	// Preset up the timestep stuff so there's a value for the first iteration of the loop
	lastTick := time.Now()
	var dt time.Duration = 0

	for {
		// Generate a random input state
		inputState := generateRandomInputState()
		msg := protocol.CreateSendInputMessage(inputState, testPlayer.lastSeq, dt, testPlayer.playerId)
		testPlayer.conn.Write(msg.Encode())
		testPlayer.lastSeq++

		fmt.Printf("Sending message from client %v: %+v\n", testPlayer.playerId, msg)

		// Get how long it took to do all of this
		now := time.Now()
		dt = now.Sub(lastTick)
		lastTick = now

		if dt < SLEEP_TIME {
			time.Sleep(SLEEP_TIME - dt)
		}

		fmt.Printf("Client %v made it out of sleep loop\n", testPlayer.playerId)
	}
}

// Get a random input state
func generateRandomInputState() *shared.InputState {
	is := new(shared.InputState)
	is.KeyUpDown = coinToss()
	is.KeyDownDown = coinToss()
	is.KeyLeftDown = coinToss()
	is.KeyRightDown = coinToss()

	return is
}

// Do a random "coin toss", returning either true or false randomly
func coinToss() bool {
	rand.Seed(time.Now().UnixNano())
	result := rand.Intn(2)

	if result == 0 {
		return false
	}

	return true
}

// Establish a connection to the game server, return the network connection and the uuid
func connectToServer() (net.Conn, int64) {
	var playerId int64
	conn, err := net.Dial("tcp", shared.HOST+":"+shared.PORT)
	if err != nil {
		panic(err.Error())
	}

	// Now we're going to wait for the server to give us an entity ID
	b := bufio.NewReader(conn)
	for {
		line, err := b.ReadBytes('\n')

		if err != nil {
			conn.Close()
			fmt.Println("Error while trying to accept player id")
			os.Exit(1)
			break
		}

		if string(line) == "" || string(line) == "\n" {
			continue
		}

		message, err := protocol.DecodeMessage(line)
		if err != nil {
			fmt.Println("ERROR during decode: " + err.Error())
			continue
		}

		if message.GetMessageType() == protocol.PLAYER_UUID_MESSAGE {
			typed, ok := message.(*protocol.PlayerUUIDMessage)
			if !ok {
				fmt.Println("Message couldn't be asserted into PlayerUUIDMessage though that was message id")
				conn.Close()
				os.Exit(1)
			}

			playerId = typed.UUID
			break
		} else {
			fmt.Println("Got the wrong type of message - expected PLAYER_UUID_MESSAGE")
			conn.Close()
			os.Exit(1)
		}
	}

	return conn, playerId
}

// Listens for incoming messages from the server, decodes the serialized versions into
// message objects and then pushes them into the message queue.
//
// This is a concurrent function - it runs simultaneously to the main game loop as a goroutine
func listenForMessages(testPlayer *TestPlayer) {
	b := bufio.NewReader(testPlayer.conn)
	for {
		line, err := b.ReadBytes('\n')

		if err != nil {
			testPlayer.conn.Close()
			fmt.Println("ERROR, CLOSING CONN: " + err.Error())
			break
		}

		if string(line) == "" || string(line) == "\n" {
			continue
		}

		// Deal with incoming messages from the server
		message, err := protocol.DecodeMessage(line)
		if err != nil {
			fmt.Println("Error decoding message: " + err.Error())
			continue
		}

		// We don't really care about the messages right now, just print it out
		fmt.Printf("Client: %v recieved world state message: %v\n", testPlayer.playerId, message)
	}
}
<commit_msg>Change loadtest so the inputs are more steady.<commit_after>package main

import (
	"bufio"
	"fmt"
	"math/rand"
	"net"
	"os"
	"time"

	"github.com/gabriel-comeau/multiplayer-game-test/protocol"
	"github.com/gabriel-comeau/multiplayer-game-test/shared"
)

type TestPlayer struct {
	conn     net.Conn
	lastSeq  int64
	playerId int64
}

const (
	NUM_CLIENTS               = 5
	SLEEP_TIME  time.Duration = 33 * time.Millisecond
	COUNTER_MAX int           = 5
)

func main() {
	for i := 0; i < NUM_CLIENTS; i++ {
		fmt.Println("Launching client:", i)
		launchClient()
	}

	for {
		time.Sleep(SLEEP_TIME)
	}
}

func launchClient() {
	testPlayer := new(TestPlayer)
	testPlayer.conn, testPlayer.playerId = connectToServer()
	fmt.Printf("Got a uuid of: %v\n", testPlayer.playerId)
	go listenForMessages(testPlayer)
	go runTestPlayer(testPlayer)

}

// This is the "main" game loop for each test player
func runTestPlayer(testPlayer *TestPlayer) {

	// Preset up the timestep stuff so there's a value for the first iteration of the loop
	lastTick := time.Now()
	var dt time.Duration = 0
	var inputState *shared.InputState
	var counter int = 0

	for {
		// Generate a new random input state if the counter is zero.  We don't want to send
		// a new input state each tick or the movement is too wacky.
		if counter == 0 {
			inputState = generateRandomInputState()
		}

		msg := protocol.CreateSendInputMessage(inputState, testPlayer.lastSeq, dt, testPlayer.playerId)
		testPlayer.conn.Write(msg.Encode())
		testPlayer.lastSeq++

		fmt.Printf("Sending message from client %v: %+v\n", testPlayer.playerId, msg)

		counter++
		if counter > COUNTER_MAX {
			counter = 0
		}

		// Get how long it took to do all of this
		now := time.Now()
		dt = now.Sub(lastTick)
		lastTick = now

		if dt < SLEEP_TIME {
			time.Sleep(SLEEP_TIME - dt)
		}

		fmt.Printf("Client %v made it out of sleep loop\n", testPlayer.playerId)
	}
}

// Get a random input state
func generateRandomInputState() *shared.InputState {
	is := new(shared.InputState)
	is.KeyUpDown = coinToss()
	is.KeyDownDown = coinToss()
	is.KeyLeftDown = coinToss()
	is.KeyRightDown = coinToss()

	return is
}

// Do a random "coin toss", returning either true or false randomly
func coinToss() bool {
	rand.Seed(time.Now().UnixNano())
	result := rand.Intn(2)

	if result == 0 {
		return false
	}

	return true
}

// Establish a connection to the game server, return the network connection and the uuid
func connectToServer() (net.Conn, int64) {
	var playerId int64
	conn, err := net.Dial("tcp", shared.HOST+":"+shared.PORT)
	if err != nil {
		panic(err.Error())
	}

	// Now we're going to wait for the server to give us an entity ID
	b := bufio.NewReader(conn)
	for {
		line, err := b.ReadBytes('\n')

		if err != nil {
			conn.Close()
			fmt.Println("Error while trying to accept player id")
			os.Exit(1)
			break
		}

		if string(line) == "" || string(line) == "\n" {
			continue
		}

		message, err := protocol.DecodeMessage(line)
		if err != nil {
			fmt.Println("ERROR during decode: " + err.Error())
			continue
		}

		if message.GetMessageType() == protocol.PLAYER_UUID_MESSAGE {
			typed, ok := message.(*protocol.PlayerUUIDMessage)
			if !ok {
				fmt.Println("Message couldn't be asserted into PlayerUUIDMessage though that was message id")
				conn.Close()
				os.Exit(1)
			}

			playerId = typed.UUID
			break
		} else {
			fmt.Println("Got the wrong type of message - expected PLAYER_UUID_MESSAGE")
			conn.Close()
			os.Exit(1)
		}
	}

	return conn, playerId
}

// Listens for incoming messages from the server, decodes the serialized versions into
// message objects and then pushes them into the message queue.
//
// This is a concurrent function - it runs simultaneously to the main game loop as a goroutine
func listenForMessages(testPlayer *TestPlayer) {
	b := bufio.NewReader(testPlayer.conn)
	for {
		line, err := b.ReadBytes('\n')

		if err != nil {
			testPlayer.conn.Close()
			fmt.Println("ERROR, CLOSING CONN: " + err.Error())
			break
		}

		if string(line) == "" || string(line) == "\n" {
			continue
		}

		// Deal with incoming messages from the server
		message, err := protocol.DecodeMessage(line)
		if err != nil {
			fmt.Println("Error decoding message: " + err.Error())
			continue
		}

		// We don't really care about the messages right now, just print it out
		fmt.Printf("Client: %v recieved world state message: %v\n", testPlayer.playerId, message)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc_test

import (
	"fmt"
	"os"
	"path/filepath"
	stdtesting "testing"

	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/container/lxc"
	"launchpad.net/juju-core/instance"
	jujutesting "launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/version"
)

func Test(t *stdtesting.T) {
	TestingT(t)
}

type LxcSuite struct {
	testing.LoggingSuite
	containerDir       string
	removedDir         string
	lxcDir             string
	oldContainerDir    string
	oldRemovedDir      string
	oldLxcContainerDir string
}

var _ = Suite(&LxcSuite{})

func (s *LxcSuite) SetUpSuite(c *C) {
	s.LoggingSuite.SetUpSuite(c)
}

func (s *LxcSuite) TearDownSuite(c *C) {
	s.LoggingSuite.TearDownSuite(c)
}

func (s *LxcSuite) SetUpTest(c *C) {
	s.LoggingSuite.SetUpTest(c)
	s.containerDir = c.MkDir()
	s.oldContainerDir = lxc.SetContainerDir(s.containerDir)
	s.removedDir = c.MkDir()
	s.oldRemovedDir = lxc.SetRemovedContainerDir(s.removedDir)
	s.lxcDir = c.MkDir()
	s.oldLxcContainerDir = lxc.SetLxcContainerDir(s.lxcDir)
}

func (s *LxcSuite) TearDownTest(c *C) {
	lxc.SetContainerDir(s.oldContainerDir)
	lxc.SetLxcContainerDir(s.oldLxcContainerDir)
	lxc.SetRemovedContainerDir(s.oldRemovedDir)
	s.LoggingSuite.TearDownTest(c)
}

func StartContainer(c *C, manager lxc.ContainerManager, machineId string) instance.Instance {
	config := testing.EnvironConfig(c)
	stateInfo := jujutesting.FakeStateInfo(machineId)
	apiInfo := jujutesting.FakeAPIInfo(machineId)

	series := "series"
	nonce := "fake-nonce"
	tools := &state.Tools{
		Binary: version.MustParseBinary("2.3.4-foo-bar"),
		URL:    "http://tools.example.com/2.3.4-foo-bar.tgz",
	}

	inst, err := manager.StartContainer(machineId, series, nonce, tools, config, stateInfo, apiInfo)
	c.Assert(err, IsNil)
	return inst
}

func (s *LxcSuite) TestStartContainer(c *C) {
	manager := lxc.NewContainerManager(MockFactory(), "")
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	// Check our container config files.
	testing.AssertNonEmptyFileExists(c, filepath.Join(s.containerDir, name, "lxc.conf"))
	testing.AssertNonEmptyFileExists(c, filepath.Join(s.containerDir, name, "cloud-init"))
	// Check the mount point has been created inside the container.
	testing.AssertDirectoryExists(c, filepath.Join(s.lxcDir, name, "rootfs/var/log/juju"))
}

func (s *LxcSuite) TestStopContainer(c *C) {
	manager := lxc.NewContainerManager(MockFactory(), "")
	instance := StartContainer(c, manager, "1/lxc/0")

	err := manager.StopContainer(instance)
	c.Assert(err, IsNil)

	name := string(instance.Id())
	// Check that the container dir is no longer in the container dir
	testing.AssertDirectoryDoesNotExist(c, filepath.Join(s.containerDir, name))
	// but instead, in the removed container dir
	testing.AssertDirectoryExists(c, filepath.Join(s.removedDir, name))
}

func (s *LxcSuite) TestStopContainerNameClash(c *C) {
	manager := lxc.NewContainerManager(MockFactory(), "")
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	targetDir := filepath.Join(s.removedDir, name)
	err := os.MkdirAll(targetDir, 0755)
	c.Assert(err, IsNil)

	err = manager.StopContainer(instance)
	c.Assert(err, IsNil)

	// Check that the container dir is no longer in the container dir
	testing.AssertDirectoryDoesNotExist(c, filepath.Join(s.containerDir, name))
	// but instead, in the removed container dir with a ".1" suffix as there was already a directory there.
	testing.AssertDirectoryExists(c, filepath.Join(s.removedDir, fmt.Sprintf("%s.1", name)))
}

func (s *LxcSuite) TestNamedManagerPrefix(c *C) {
	manager := lxc.NewContainerManager(MockFactory(), "eric")
	instance := StartContainer(c, manager, "1/lxc/0")
	c.Assert(string(instance.Id()), Equals, "eric-machine-1-lxc-0")
}

func (s *LxcSuite) TestListContainers(c *C) {
	factory := MockFactory()
	foo := lxc.NewContainerManager(factory, "foo")
	bar := lxc.NewContainerManager(factory, "bar")

	foo1 := StartContainer(c, foo, "1/lxc/0")
	foo2 := StartContainer(c, foo, "1/lxc/1")
	foo3 := StartContainer(c, foo, "1/lxc/2")

	bar1 := StartContainer(c, bar, "1/lxc/0")
	bar2 := StartContainer(c, bar, "1/lxc/1")

	result, err := foo.ListContainers()
	c.Assert(err, IsNil)
	testing.MatchInstances(c, result, foo1, foo2, foo3)

	result, err = bar.ListContainers()
	c.Assert(err, IsNil)
	testing.MatchInstances(c, result, bar1, bar2)
}
<commit_msg>Use the new file checkers.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package lxc_test

import (
	"fmt"
	"os"
	"path/filepath"
	stdtesting "testing"

	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/container/lxc"
	"launchpad.net/juju-core/instance"
	jujutesting "launchpad.net/juju-core/juju/testing"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/testing"
	. "launchpad.net/juju-core/testing/checkers"
	"launchpad.net/juju-core/version"
)

func Test(t *stdtesting.T) {
	TestingT(t)
}

type LxcSuite struct {
	testing.LoggingSuite
	containerDir       string
	removedDir         string
	lxcDir             string
	oldContainerDir    string
	oldRemovedDir      string
	oldLxcContainerDir string
}

var _ = Suite(&LxcSuite{})

func (s *LxcSuite) SetUpSuite(c *C) {
	s.LoggingSuite.SetUpSuite(c)
}

func (s *LxcSuite) TearDownSuite(c *C) {
	s.LoggingSuite.TearDownSuite(c)
}

func (s *LxcSuite) SetUpTest(c *C) {
	s.LoggingSuite.SetUpTest(c)
	s.containerDir = c.MkDir()
	s.oldContainerDir = lxc.SetContainerDir(s.containerDir)
	s.removedDir = c.MkDir()
	s.oldRemovedDir = lxc.SetRemovedContainerDir(s.removedDir)
	s.lxcDir = c.MkDir()
	s.oldLxcContainerDir = lxc.SetLxcContainerDir(s.lxcDir)
}

func (s *LxcSuite) TearDownTest(c *C) {
	lxc.SetContainerDir(s.oldContainerDir)
	lxc.SetLxcContainerDir(s.oldLxcContainerDir)
	lxc.SetRemovedContainerDir(s.oldRemovedDir)
	s.LoggingSuite.TearDownTest(c)
}

func StartContainer(c *C, manager lxc.ContainerManager, machineId string) instance.Instance {
	config := testing.EnvironConfig(c)
	stateInfo := jujutesting.FakeStateInfo(machineId)
	apiInfo := jujutesting.FakeAPIInfo(machineId)

	series := "series"
	nonce := "fake-nonce"
	tools := &state.Tools{
		Binary: version.MustParseBinary("2.3.4-foo-bar"),
		URL:    "http://tools.example.com/2.3.4-foo-bar.tgz",
	}

	inst, err := manager.StartContainer(machineId, series, nonce, tools, config, stateInfo, apiInfo)
	c.Assert(err, IsNil)
	return inst
}

func (s *LxcSuite) TestStartContainer(c *C) {
	manager := lxc.NewContainerManager(MockFactory(), "")
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	// Check our container config files.
	c.Assert(filepath.Join(s.containerDir, name, "lxc.conf"), IsNonEmptyFile)
	c.Assert(filepath.Join(s.containerDir, name, "cloud-init"), IsNonEmptyFile)
	// Check the mount point has been created inside the container.
	c.Assert(filepath.Join(s.lxcDir, name, "rootfs/var/log/juju"), IsDirectory)
}

func (s *LxcSuite) TestStopContainer(c *C) {
	manager := lxc.NewContainerManager(MockFactory(), "")
	instance := StartContainer(c, manager, "1/lxc/0")

	err := manager.StopContainer(instance)
	c.Assert(err, IsNil)

	name := string(instance.Id())
	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.containerDir, name), DoesNotExist)
	// but instead, in the removed container dir
	c.Assert(filepath.Join(s.removedDir, name), IsDirectory)
}

func (s *LxcSuite) TestStopContainerNameClash(c *C) {
	manager := lxc.NewContainerManager(MockFactory(), "")
	instance := StartContainer(c, manager, "1/lxc/0")

	name := string(instance.Id())
	targetDir := filepath.Join(s.removedDir, name)
	err := os.MkdirAll(targetDir, 0755)
	c.Assert(err, IsNil)

	err = manager.StopContainer(instance)
	c.Assert(err, IsNil)

	// Check that the container dir is no longer in the container dir
	c.Assert(filepath.Join(s.containerDir, name), DoesNotExist)
	// but instead, in the removed container dir with a ".1" suffix as there was already a directory there.
	c.Assert(filepath.Join(s.removedDir, fmt.Sprintf("%s.1", name)), IsDirectory)
}

func (s *LxcSuite) TestNamedManagerPrefix(c *C) {
	manager := lxc.NewContainerManager(MockFactory(), "eric")
	instance := StartContainer(c, manager, "1/lxc/0")
	c.Assert(string(instance.Id()), Equals, "eric-machine-1-lxc-0")
}

func (s *LxcSuite) TestListContainers(c *C) {
	factory := MockFactory()
	foo := lxc.NewContainerManager(factory, "foo")
	bar := lxc.NewContainerManager(factory, "bar")

	foo1 := StartContainer(c, foo, "1/lxc/0")
	foo2 := StartContainer(c, foo, "1/lxc/1")
	foo3 := StartContainer(c, foo, "1/lxc/2")

	bar1 := StartContainer(c, bar, "1/lxc/0")
	bar2 := StartContainer(c, bar, "1/lxc/1")

	result, err := foo.ListContainers()
	c.Assert(err, IsNil)
	testing.MatchInstances(c, result, foo1, foo2, foo3)

	result, err = bar.ListContainers()
	c.Assert(err, IsNil)
	testing.MatchInstances(c, result, bar1, bar2)
}
<|endoftext|>


<commit_before>package guid

import (
	"database/sql/driver"

	"github.com/pborman/uuid"
)

var (
	//SpaceUUID 空GUID，用于生成不变化的GUID
	SpaceUUID = uuid.Parse("f2093908-9293-41f0-97a6-413e94f788ef")
)

//GUID guid
type GUID string

//Value GUID 实现database/driver中的接口，否则部分场景下会抛出异常。
func (g GUID) Value() (driver.Value, error) {
	return string(g), nil
}

//NewGUID 生成一个唯一的GUID
func NewGUID() GUID {
	return GUID(uuid.New())
}

//NewMD5GUID 根据输入参数生成一个GUID
func NewMD5GUID(str string) GUID {

	return GUID(uuid.NewMD5(SpaceUUID, []byte(str)).String())
}
<commit_msg>guid增加newguidstring<commit_after>package guid

import (
	"database/sql/driver"

	"github.com/pborman/uuid"
)

var (
	//SpaceUUID 空GUID，用于生成不变化的GUID
	SpaceUUID = uuid.Parse("f2093908-9293-41f0-97a6-413e94f788ef")
)

//GUID guid
type GUID string

//Value GUID 实现database/driver中的接口，否则部分场景下会抛出异常。
func (g GUID) Value() (driver.Value, error) {
	return string(g), nil
}

//NewGUID 生成一个唯一的GUID
func NewGUID() GUID {
	return GUID(uuid.New())
}

//NewGUIDString 生成一个GUID string
func NewGUIDString() string {
	return uuid.New()
}

//NewMD5GUID 根据输入参数生成一个GUID
func NewMD5GUID(str string) GUID {

	return GUID(uuid.NewMD5(SpaceUUID, []byte(str)).String())
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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 dbdaemon

import (
	"compress/gzip"
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"cloud.google.com/go/storage"
	"k8s.io/client-go/util/retry"
	"k8s.io/klog/v2"
)

const gsPrefix = "gs://"

// Override library functions for the benefit of unit tests.
var (
	lsnrctl = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "lsnrctl")
	}
	rman = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "rman")
	}
	dgmgrl = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "dgmgrl")
	}
	tnsping = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "tnsping")
	}
	orapwd = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "orapwd")
	}
	impdp = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "impdp")
	}
	expdp = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "expdp")
	}
)

const (
	contentTypePlainText = "plain/text"
	contentTypeGZ        = "application/gzip"
)

// osUtil was defined for tests.
type osUtil interface {
	runCommand(bin string, params []string) error
	isReturnCodeEqual(err error, code int) bool
	createFile(file string, content io.Reader) error
	removeFile(file string) error
}

type osUtilImpl struct {
}

func (o *osUtilImpl) runCommand(bin string, params []string) error {
	ohome := os.Getenv("ORACLE_HOME")
	klog.InfoS("executing command with args", "cmd", bin, "params", params, "ORACLE_SID", os.Getenv("ORACLE_SID"), "ORACLE_HOME", ohome, "TNS_ADMIN", os.Getenv("TNS_ADMIN"))
	switch bin {
	case lsnrctl(ohome), rman(ohome), orapwd(ohome), impdp(ohome), expdp(ohome):
	default:
		klog.InfoS("command not supported", "bin", bin)
		return fmt.Errorf("command %q is not supported", bin)
	}
	cmd := exec.Command(bin)
	cmd.Args = append(cmd.Args, params...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func (o *osUtilImpl) isReturnCodeEqual(err error, code int) bool {
	if exitError, ok := err.(*exec.ExitError); ok {
		return exitError.ExitCode() == code
	}
	return false
}

func (o *osUtilImpl) createFile(file string, content io.Reader) error {
	dir := filepath.Dir(file)
	if err := os.MkdirAll(dir, 0750); err != nil {
		return fmt.Errorf("couldn't create dir err: %v", err)
	}
	f, err := os.Create(file) // truncates if file exists.
	if err != nil {
		return fmt.Errorf("couldn't create file err: %v", err)
	}
	defer func() {
		if err := f.Close(); err != nil {
			klog.Warningf("failed to close %v: %v", f, err)
		}
	}()
	if _, err := io.Copy(f, content); err != nil {
		return fmt.Errorf("copying contents failed: %v", err)
	}
	return nil
}

func (o *osUtilImpl) removeFile(file string) error {
	return os.Remove(file)
}

// GCSUtil contains helper methods for reading/writing GCS objects.
type GCSUtil interface {
	// Download returns an io.ReadCloser for GCS object at given gcsPath.
	Download(ctx context.Context, gcsPath string) (io.ReadCloser, error)
	// UploadFile uploads contents of a file at filepath to gcsPath location in
	// GCS and sets object's contentType.
	// If gcsPath ends with .gz it also compresses the uploaded contents
	// and sets object's content type to application/gzip.
	UploadFile(ctx context.Context, gcsPath, filepath, contentType string) error
	// SplitURI takes a GCS URI and splits it into bucket and object names. If the URI does not have
	// the gs:// scheme, or the URI doesn't specify both a bucket and an object name, returns an error.
	SplitURI(url string) (bucket, name string, err error)
}

type gcsUtilImpl struct{}

func (g *gcsUtilImpl) Download(ctx context.Context, gcsPath string) (io.ReadCloser, error) {
	bucket, name, err := g.SplitURI(gcsPath)
	if err != nil {
		return nil, err
	}

	client, err := storage.NewClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to init GCS client: %v", err)
	}
	defer client.Close()

	reader, err := client.Bucket(bucket).Object(name).NewReader(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to read URL %s: %v", gcsPath, err)
	}

	return reader, nil
}

func (g *gcsUtilImpl) UploadFile(ctx context.Context, gcsPath, filePath, contentType string) error {
	return retry.OnError(retry.DefaultBackoff, func(err error) bool {
		klog.ErrorS(err, "failed to upload a file")
		// tried to cast err to *googleapi.Error with errors.As and wrap the error
		// in uploadFile. returned err is not a *googleapi.Error.
		return err != nil && strings.Contains(err.Error(), "compute: Received 500 ")
	}, func() error {
		return g.uploadFile(ctx, gcsPath, filePath, contentType)
	})

}

// uploadFile is the implementation of UploadFile to be wrapped with retry logic.
func (g *gcsUtilImpl) uploadFile(ctx context.Context, gcsPath, filePath, contentType string) error {
	bucket, name, err := g.SplitURI(gcsPath)
	if err != nil {
		return err
	}

	f, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer func() {
		if err := f.Close(); err != nil {
			klog.Warningf("failed to close %v: %v", f, err)
		}
	}()

	client, err := storage.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("failed to init GCS client: %v", err)
	}
	defer client.Close()

	b := client.Bucket(bucket)
	// check if bucket exists and it is accessible
	/* YOLO
	if _, err := b.Attrs(ctx); err != nil {
		return err
	}
	*/

	gcsWriter := b.Object(name).NewWriter(ctx)
	gcsWriter.ContentType = contentType

	var writer io.WriteCloser = gcsWriter
	if strings.HasSuffix(gcsPath, ".gz") {
		gcsWriter.ContentType = contentTypeGZ
		writer = gzip.NewWriter(gcsWriter)
	}

	_, err = io.Copy(writer, f)
	if err != nil {
		return fmt.Errorf("failed to write file %s to %s: %v", filePath, gcsPath, err)
	}
	if err = writer.Close(); err != nil {
		return fmt.Errorf("failed to complete writing file %s to %s: %v", filePath, gcsPath, err)
	}
	if err = gcsWriter.Close(); err != nil {
		return fmt.Errorf("failed to complete writing file %s to %s: %v", filePath, gcsPath, err)
	}

	return nil
}

func (g *gcsUtilImpl) SplitURI(url string) (bucket, name string, err error) {
	u := strings.TrimPrefix(url, gsPrefix)
	if u == url {
		return "", "", fmt.Errorf("URL %q is missing the %q prefix", url, gsPrefix)
	}
	if i := strings.Index(u, "/"); i >= 2 {
		return u[:i], u[i+1:], nil
	}
	return "", "", fmt.Errorf("URL %q does not specify a bucket and a name", url)
}
<commit_msg>Buffer GCS downloads (#232)<commit_after>// Copyright 2021 Google LLC
//
// 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 dbdaemon

import (
	"bufio"
	"compress/gzip"
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"cloud.google.com/go/storage"
	"k8s.io/client-go/util/retry"
	"k8s.io/klog/v2"
)

const gsPrefix = "gs://"

// Override library functions for the benefit of unit tests.
var (
	lsnrctl = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "lsnrctl")
	}
	rman = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "rman")
	}
	dgmgrl = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "dgmgrl")
	}
	tnsping = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "tnsping")
	}
	orapwd = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "orapwd")
	}
	impdp = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "impdp")
	}
	expdp = func(databaseHome string) string {
		return filepath.Join(databaseHome, "bin", "expdp")
	}
)

const (
	contentTypePlainText = "plain/text"
	contentTypeGZ        = "application/gzip"
)

// osUtil was defined for tests.
type osUtil interface {
	runCommand(bin string, params []string) error
	isReturnCodeEqual(err error, code int) bool
	createFile(file string, content io.Reader) error
	removeFile(file string) error
}

type osUtilImpl struct {
}

func (o *osUtilImpl) runCommand(bin string, params []string) error {
	ohome := os.Getenv("ORACLE_HOME")
	klog.InfoS("executing command with args", "cmd", bin, "params", params, "ORACLE_SID", os.Getenv("ORACLE_SID"), "ORACLE_HOME", ohome, "TNS_ADMIN", os.Getenv("TNS_ADMIN"))
	switch bin {
	case lsnrctl(ohome), rman(ohome), orapwd(ohome), impdp(ohome), expdp(ohome):
	default:
		klog.InfoS("command not supported", "bin", bin)
		return fmt.Errorf("command %q is not supported", bin)
	}
	cmd := exec.Command(bin)
	cmd.Args = append(cmd.Args, params...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func (o *osUtilImpl) isReturnCodeEqual(err error, code int) bool {
	if exitError, ok := err.(*exec.ExitError); ok {
		return exitError.ExitCode() == code
	}
	return false
}

func (o *osUtilImpl) createFile(file string, content io.Reader) error {
	dir := filepath.Dir(file)
	if err := os.MkdirAll(dir, 0750); err != nil {
		return fmt.Errorf("couldn't create dir err: %v", err)
	}
	f, err := os.Create(file) // truncates if file exists.
	if err != nil {
		return fmt.Errorf("couldn't create file err: %v", err)
	}
	w := bufio.NewWriterSize(f, 16*1024*1024)
	defer func() {
		if err := w.Flush(); err != nil {
			klog.Warningf("failed to flush %v: %v", w, err)
		}
		if err := f.Close(); err != nil {
			klog.Warningf("failed to close %v: %v", f, err)
		}
	}()
	if _, err := io.Copy(w, content); err != nil {
		return fmt.Errorf("copying contents failed: %v", err)
	}
	return nil
}

func (o *osUtilImpl) removeFile(file string) error {
	return os.Remove(file)
}

// GCSUtil contains helper methods for reading/writing GCS objects.
type GCSUtil interface {
	// Download returns an io.ReadCloser for GCS object at given gcsPath.
	Download(ctx context.Context, gcsPath string) (io.ReadCloser, error)
	// UploadFile uploads contents of a file at filepath to gcsPath location in
	// GCS and sets object's contentType.
	// If gcsPath ends with .gz it also compresses the uploaded contents
	// and sets object's content type to application/gzip.
	UploadFile(ctx context.Context, gcsPath, filepath, contentType string) error
	// SplitURI takes a GCS URI and splits it into bucket and object names. If the URI does not have
	// the gs:// scheme, or the URI doesn't specify both a bucket and an object name, returns an error.
	SplitURI(url string) (bucket, name string, err error)
}

type gcsUtilImpl struct{}

func (g *gcsUtilImpl) Download(ctx context.Context, gcsPath string) (io.ReadCloser, error) {
	bucket, name, err := g.SplitURI(gcsPath)
	if err != nil {
		return nil, err
	}

	client, err := storage.NewClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to init GCS client: %v", err)
	}
	defer client.Close()

	reader, err := client.Bucket(bucket).Object(name).NewReader(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to read URL %s: %v", gcsPath, err)
	}

	return reader, nil
}

func (g *gcsUtilImpl) UploadFile(ctx context.Context, gcsPath, filePath, contentType string) error {
	return retry.OnError(retry.DefaultBackoff, func(err error) bool {
		klog.ErrorS(err, "failed to upload a file")
		// tried to cast err to *googleapi.Error with errors.As and wrap the error
		// in uploadFile. returned err is not a *googleapi.Error.
		return err != nil && strings.Contains(err.Error(), "compute: Received 500 ")
	}, func() error {
		return g.uploadFile(ctx, gcsPath, filePath, contentType)
	})

}

// uploadFile is the implementation of UploadFile to be wrapped with retry logic.
func (g *gcsUtilImpl) uploadFile(ctx context.Context, gcsPath, filePath, contentType string) error {
	bucket, name, err := g.SplitURI(gcsPath)
	if err != nil {
		return err
	}

	f, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer func() {
		if err := f.Close(); err != nil {
			klog.Warningf("failed to close %v: %v", f, err)
		}
	}()

	client, err := storage.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("failed to init GCS client: %v", err)
	}
	defer client.Close()

	b := client.Bucket(bucket)
	// check if bucket exists and it is accessible
	/* YOLO
	if _, err := b.Attrs(ctx); err != nil {
		return err
	}
	*/

	gcsWriter := b.Object(name).NewWriter(ctx)
	gcsWriter.ContentType = contentType

	var writer io.WriteCloser = gcsWriter
	if strings.HasSuffix(gcsPath, ".gz") {
		gcsWriter.ContentType = contentTypeGZ
		writer = gzip.NewWriter(gcsWriter)
	}

	_, err = io.Copy(writer, f)
	if err != nil {
		return fmt.Errorf("failed to write file %s to %s: %v", filePath, gcsPath, err)
	}
	if err = writer.Close(); err != nil {
		return fmt.Errorf("failed to complete writing file %s to %s: %v", filePath, gcsPath, err)
	}
	if err = gcsWriter.Close(); err != nil {
		return fmt.Errorf("failed to complete writing file %s to %s: %v", filePath, gcsPath, err)
	}

	return nil
}

func (g *gcsUtilImpl) SplitURI(url string) (bucket, name string, err error) {
	u := strings.TrimPrefix(url, gsPrefix)
	if u == url {
		return "", "", fmt.Errorf("URL %q is missing the %q prefix", url, gsPrefix)
	}
	if i := strings.Index(u, "/"); i >= 2 {
		return u[:i], u[i+1:], nil
	}
	return "", "", fmt.Errorf("URL %q does not specify a bucket and a name", url)
}
<|endoftext|>


<commit_before>package hal

/*
 * Copyright 2016-2017 Netflix, 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,
 * 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.
 */

import (
	"database/sql"
	"strings"
	"sync"

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

var sqldbSingleton *sql.DB
var initSqlDbOnce sync.Once
var sqlInitCache map[string]struct{}

const SECRETS_KEY_DSN = "hal.dsn"

// DB returns the database singleton.
func SqlDB() *sql.DB {
	initSqlDbOnce.Do(func() {
		secrets := Secrets()
		dsn := secrets.Get(SECRETS_KEY_DSN)
		if dsn == "" {
			panic("Startup error: SetSqlDB(dsn) must come before any calls to hal.SqlDB()")
		}

		var err error
		sqldbSingleton, err = sql.Open("mysql", strings.TrimSpace(dsn))
		if err != nil {
			log.Fatalf("Could not connect to database: %s\n", err)
		}

		// make sure the connection is in full utf-8 mode
		sqldbSingleton.Exec("SET NAMES utf8mb4")

		err = sqldbSingleton.Ping()
		if err != nil {
			log.Fatalf("Pinging database failed: %s\n", err)
		}

		sqlInitCache = make(map[string]struct{})
	})

	return sqldbSingleton
}

// ForceSqlDBHandle can be used to forcibly replace the DB handle with another
// one, e.g. go-sqlmock. This is mainly here for tests, but it's also useful for
// things like examples/repl to operate with no database.
func ForceSqlDBHandle(db *sql.DB) {
	// trigger the sync.Once so the init code doesn't fire
	initSqlDbOnce.Do(func() {})
	sqldbSingleton = db
}

// SqlInit executes the provided SQL once per runtime.
// Execution is not tracked across restarts so statements still need
// to use CREATE TABLE IF NOT EXISTS or other methods of achieving
// idempotent execution. Errors are returned unmodified, including
// primary key violations, so you may ignore them as needed.
func SqlInit(sqlTxt string) error {
	db := SqlDB()

	// avoid a database round-trip by checking an in-memory cache
	// fall through and hit the DB on cold cache
	if _, exists := sqlInitCache[sqlTxt]; exists {
		return nil
	}

	// clean up a little
	sqlTxt = strings.TrimSpace(sqlTxt)
	sqlTxt = strings.TrimSuffix(sqlTxt, ";")

	// check if it's a simple create table, add engine/charset if unspecified
	lowSql := strings.ToLower(sqlTxt)
	if strings.HasPrefix(lowSql, "create table") && strings.HasSuffix(lowSql, ")") {
		// looks like no engine or charset was specified, add it
		// "utf8" has incomplete support.  "utf8mb4" provides full utf8 support
		// https://mathiasbynens.be/notes/mysql-utf8mb4
		sqlTxt = sqlTxt + " ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
	}

	// execute the statement
	_, err := db.Exec(sqlTxt)
	if err != nil {
		log.Printf("SqlInit() failed on statement '%s':\n%s", sqlTxt, err)
		return err
	}

	sqlInitCache[sqlTxt] = struct{}{}

	return nil
}
<commit_msg>protect access to the map behind SqlInit()<commit_after>package hal

/*
 * Copyright 2016-2017 Netflix, 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,
 * 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.
 */

import (
	"database/sql"
	"strings"
	"sync"

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

var sqldbSingleton *sql.DB
var initSqlDbOnce sync.Once
var sqlMapMutex sync.Mutex
var sqlInitCache map[string]struct{}

const SECRETS_KEY_DSN = "hal.dsn"

// DB returns the database singleton.
func SqlDB() *sql.DB {
	initSqlDbOnce.Do(func() {
		secrets := Secrets()
		dsn := secrets.Get(SECRETS_KEY_DSN)
		if dsn == "" {
			panic("Startup error: SetSqlDB(dsn) must come before any calls to hal.SqlDB()")
		}

		var err error
		sqldbSingleton, err = sql.Open("mysql", strings.TrimSpace(dsn))
		if err != nil {
			log.Fatalf("Could not connect to database: %s\n", err)
		}

		// make sure the connection is in full utf-8 mode
		sqldbSingleton.Exec("SET NAMES utf8mb4")

		err = sqldbSingleton.Ping()
		if err != nil {
			log.Fatalf("Pinging database failed: %s\n", err)
		}

		sqlInitCache = make(map[string]struct{})
	})

	return sqldbSingleton
}

// ForceSqlDBHandle can be used to forcibly replace the DB handle with another
// one, e.g. go-sqlmock. This is mainly here for tests, but it's also useful for
// things like examples/repl to operate with no database.
func ForceSqlDBHandle(db *sql.DB) {
	// trigger the sync.Once so the init code doesn't fire
	initSqlDbOnce.Do(func() {})
	sqldbSingleton = db
}

// SqlInit executes the provided SQL once per runtime.
// Execution is not tracked across restarts so statements still need
// to use CREATE TABLE IF NOT EXISTS or other methods of achieving
// idempotent execution. Errors are returned unmodified, including
// primary key violations, so you may ignore them as needed.
func SqlInit(sqlTxt string) error {
	sqlMapMutex.Lock()
	defer sqlMapMutex.Unlock()

	db := SqlDB()

	// avoid a database round-trip by checking an in-memory cache
	// fall through and hit the DB on cold cache
	if _, exists := sqlInitCache[sqlTxt]; exists {
		return nil
	}

	// clean up a little
	sqlTxt = strings.TrimSpace(sqlTxt)
	sqlTxt = strings.TrimSuffix(sqlTxt, ";")

	// check if it's a simple create table, add engine/charset if unspecified
	lowSql := strings.ToLower(sqlTxt)
	if strings.HasPrefix(lowSql, "create table") && strings.HasSuffix(lowSql, ")") {
		// looks like no engine or charset was specified, add it
		// "utf8" has incomplete support.  "utf8mb4" provides full utf8 support
		// https://mathiasbynens.be/notes/mysql-utf8mb4
		sqlTxt = sqlTxt + " ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
	}

	// execute the statement
	_, err := db.Exec(sqlTxt)
	if err != nil {
		log.Printf("SqlInit() failed on statement '%s':\n%s", sqlTxt, err)
		return err
	}

	sqlInitCache[sqlTxt] = struct{}{}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"github.com/coreos/go-etcd/etcd"
)

func main() {
	client := etcd.NewClient([]string{"http://104.130.8.142:4001"})
	resp, err := client.Get("testcluster", false, false)
	if err != nil {
		log.Fatal(err)
	}
	for _, n := range resp.Node.Nodes {
		log.Printf("%s: %s\n", n.Key, n.Value)
	}
}
<commit_msg>Sort nodes by uuid, add discovery info via flags<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"sort"

	"github.com/coreos/go-etcd/etcd"
)

type NodeGroup []*etcd.Node //NodeGroup is a slice of pointers to etcd Nodes

// Sort Interface implementation methods
func (n NodeGroup) Len() int {
	return len(n)
}

func (n NodeGroup) Less(i, j int) bool {
	if n[i].Key < n[j].Key {
		return true
	}
	return false
}

func (n NodeGroup) Swap(i, j int) {
	n[i], n[j] = n[j], n[i]
}

func Usage() {
	fmt.Printf("Usage: %s\n", os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

func SetupFlags() (discoveryHost, discoveryPath *string) {
	discoveryHost = flag.String("discovery_host",
		"http://127.0.0.1:4001", "Discovery URL:Port")
	discoveryPath = flag.String("discovery_path",
		"",
		"Discovery path i.e. _etcd/registry/uVa2GHOTTxl27eyKk6clBwyaurf7KiWd")

	flag.Parse()

	if *discoveryHost == "" || *discoveryPath == "" {
		Usage()
	}

	return discoveryHost, discoveryPath
}

func main() {
	// Connect to the etcd discovery to pull the nodes
	discoveryHost, discoveryPath := SetupFlags()

	client := etcd.NewClient([]string{*discoveryHost})
	resp, _ := client.Get(*discoveryPath, false, false)

	// Store the pointer to the etcd nodes as a NodeGroup
	group := NodeGroup{}
	for _, n := range resp.Node.Nodes {
		group = append(group, n)
	}

	// Sort the NodeGroup
	sort.Sort(group)

	// Print out sorted NodeGroup by key
	for _, n := range group {
		log.Printf("%s: %s\n", n.Key, n.Value)
	}
}
<|endoftext|>