<commit_before>package obj

import (
	"io"

	minio "github.com/minio/minio-go"
)

// Represents minio client instance for any s3 compatible server.
type minioClient struct {
	*minio.Client
	bucket string
}

// Creates a new minioClient structure and returns
func newMinioClient(endpoint, bucket, id, secret string, secure bool) (*minioClient, error) {
	mclient, err := minio.New(endpoint, id, secret, secure)
	if err != nil {
		return nil, err
	}
	return &minioClient{
		bucket: bucket,
		Client: mclient,
	}, nil
}

// Represents minio writer structure with pipe and the error channel
type minioWriter struct {
	errChan chan error
	pipe    *io.PipeWriter
}

// Creates a new minio writer and a go routine to upload objects to minio server
func newMinioWriter(client *minioClient, name string) *minioWriter {
	reader, writer := io.Pipe()
	w := &minioWriter{
		errChan: make(chan error),
		pipe:    writer,
	}
	go func() {
		_, err := client.PutObject(client.bucket, name, reader, "application/octet-stream")
		if err != nil {
			reader.CloseWithError(err)
		}
		w.errChan <- err
	}()
	return w
}

func (w *minioWriter) Write(p []byte) (int, error) {
	return w.pipe.Write(p)
}

// This will block till upload is done
func (w *minioWriter) Close() error {
	if err := w.pipe.Close(); err != nil {
		return err
	}
	return <-w.errChan
}

func (c *minioClient) Writer(name string) (io.WriteCloser, error) {
	return newMinioWriter(c, name), nil
}

func (c *minioClient) Walk(name string, fn func(name string) error) error {
	recursive := true // Recursively walk by default.

	doneCh := make(chan struct{})
	defer close(doneCh)
	for objInfo := range c.ListObjectsV2(c.bucket, name, recursive, doneCh) {
		if objInfo.Err != nil {
			return objInfo.Err
		}
		if err := fn(objInfo.Key); err != nil {
			return err
		}
	}
	return nil
}

// limitReadCloser implements a closer compatible wrapper
// for a size limited reader.
type limitReadCloser struct {
	io.Reader
	mObj *minio.Object
}

func (l *limitReadCloser) Close() (err error) {
	return l.mObj.Close()
}

func (c *minioClient) Reader(name string, offset uint64, size uint64) (io.ReadCloser, error) {
	obj, err := c.GetObject(c.bucket, name)
	if err != nil {
		return nil, err
	}
	// Seek to an offset to fetch the new reader.
	_, err = obj.Seek(int64(offset), 0)
	if err != nil {
		return nil, err
	}
	if size > 0 {
		return &limitReadCloser{io.LimitReader(obj, int64(size)), obj}, nil
	}
	return obj, nil

}

func (c *minioClient) Delete(name string) error {
	return c.RemoveObject(c.bucket, name)
}

func (c *minioClient) Exists(name string) bool {
	_, err := c.StatObject(c.bucket, name)
	return err == nil
}

func (c *minioClient) isRetryable(err error) bool {
	// Minio client already implements retrying, no
	// need for a caller retry.
	return false
}

func (c *minioClient) IsIgnorable(err error) bool {
	return false
}

// Sentinel error response returned if err is not
// of type *minio.ErrorResponse.
var sentinelErrResp = minio.ErrorResponse{}

func (c *minioClient) IsNotExist(err error) bool {
	errResp := minio.ToErrorResponse(err)
	if errResp == sentinelErrResp {
		return false
	}
	// Treat both object not found and bucket not found as IsNotExist().
	return errResp.Code == "NoSuchKey" || errResp.Code == "NoSuchBucket"
}
<commit_msg>add StatObject<commit_after>package obj

import (
	"io"

	minio "github.com/minio/minio-go"
)

// Represents minio client instance for any s3 compatible server.
type minioClient struct {
	*minio.Client
	bucket string
}

// Creates a new minioClient structure and returns
func newMinioClient(endpoint, bucket, id, secret string, secure bool) (*minioClient, error) {
	mclient, err := minio.New(endpoint, id, secret, secure)
	if err != nil {
		return nil, err
	}
	return &minioClient{
		bucket: bucket,
		Client: mclient,
	}, nil
}

// Represents minio writer structure with pipe and the error channel
type minioWriter struct {
	errChan chan error
	pipe    *io.PipeWriter
}

// Creates a new minio writer and a go routine to upload objects to minio server
func newMinioWriter(client *minioClient, name string) *minioWriter {
	reader, writer := io.Pipe()
	w := &minioWriter{
		errChan: make(chan error),
		pipe:    writer,
	}
	go func() {
		_, err := client.PutObject(client.bucket, name, reader, "application/octet-stream")
		if err != nil {
			reader.CloseWithError(err)
		}
		w.errChan <- err
	}()
	return w
}

func (w *minioWriter) Write(p []byte) (int, error) {
	return w.pipe.Write(p)
}

// This will block till upload is done
func (w *minioWriter) Close() error {
	if err := w.pipe.Close(); err != nil {
		return err
	}
	return <-w.errChan
}

func (c *minioClient) Writer(name string) (io.WriteCloser, error) {
	return newMinioWriter(c, name), nil
}

func (c *minioClient) Walk(name string, fn func(name string) error) error {
	recursive := true // Recursively walk by default.

	doneCh := make(chan struct{})
	defer close(doneCh)
	for objInfo := range c.ListObjectsV2(c.bucket, name, recursive, doneCh) {
		if objInfo.Err != nil {
			return objInfo.Err
		}
		if err := fn(objInfo.Key); err != nil {
			return err
		}
	}
	return nil
}

// limitReadCloser implements a closer compatible wrapper
// for a size limited reader.
type limitReadCloser struct {
	io.Reader
	mObj *minio.Object
}

func (l *limitReadCloser) Close() (err error) {
	return l.mObj.Close()
}

func (c *minioClient) Reader(name string, offset uint64, size uint64) (io.ReadCloser, error) {
	if _, err := c.StatObject(c.bucket, name); err != nil {
		return nil, err
	}
	obj, err := c.GetObject(c.bucket, name)
	if err != nil {
		return nil, err
	}
	// Seek to an offset to fetch the new reader.
	_, err = obj.Seek(int64(offset), 0)
	if err != nil {
		return nil, err
	}
	if size > 0 {
		return &limitReadCloser{io.LimitReader(obj, int64(size)), obj}, nil
	}
	return obj, nil

}

func (c *minioClient) Delete(name string) error {
	return c.RemoveObject(c.bucket, name)
}

func (c *minioClient) Exists(name string) bool {
	_, err := c.StatObject(c.bucket, name)
	return err == nil
}

func (c *minioClient) isRetryable(err error) bool {
	// Minio client already implements retrying, no
	// need for a caller retry.
	return false
}

func (c *minioClient) IsIgnorable(err error) bool {
	return false
}

// Sentinel error response returned if err is not
// of type *minio.ErrorResponse.
var sentinelErrResp = minio.ErrorResponse{}

func (c *minioClient) IsNotExist(err error) bool {
	errResp := minio.ToErrorResponse(err)
	if errResp == sentinelErrResp {
		return false
	}
	// Treat both object not found and bucket not found as IsNotExist().
	return errResp.Code == "NoSuchKey" || errResp.Code == "NoSuchBucket"
}
<|endoftext|>


<commit_before>package frame

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"path/filepath"

	"github.com/mattn/go-colorable"

	"github.com/nyaosorg/go-readline-ny"
	"github.com/nyaosorg/go-windows-consoleicon"

	"github.com/nyaosorg/nyagos/history"
	"github.com/nyaosorg/nyagos/shell"
)

type CmdStreamConsole struct {
	shell.CmdSeeker
	DoPrompt func() (int, error)
	History  *history.Container
	Editor   *readline.Editor
	HistPath string
}

func NewCmdStreamConsole(doPrompt func() (int, error)) *CmdStreamConsole {
	history1 := &history.Container{}
	stream := &CmdStreamConsole{
		History: history1,
		Editor: &readline.Editor{
			History:        history1,
			Prompt:         doPrompt,
			Writer:         colorable.NewColorableStdout(),
			Coloring:       &_Coloring{},
			HistoryCycling: true,
		},
		HistPath: filepath.Join(appDataDir(), "nyagos.history"),
		CmdSeeker: shell.CmdSeeker{
			PlainHistory: []string{},
			Pointer:      -1,
		},
	}
	history1.Load(stream.HistPath)
	history1.Save(stream.HistPath)
	return stream
}

func (stream *CmdStreamConsole) DisableHistory(value bool) bool {
	return stream.History.IgnorePush(value)
}

// endsWithSep returns
//     false when line does not end with `^`
//     true when line ends with `^`
//     false when line ends with `^^`
//     true when line ends with `^^^`
func endsWithSep(line []byte, contMark byte) bool {
	markCount := 0
	for len(line) > 0 && line[len(line)-1] == contMark {
		markCount++
		line = line[:len(line)-1]
	}
	return markCount%2 != 0
}

func (stream *CmdStreamConsole) readLineContinued(ctx context.Context) (string, error) {
	continued := false
	originalPrompt := os.Getenv("PROMPT")
	defer func() {
		if continued {
			os.Setenv("PROMPT", originalPrompt)
			stream.Editor.Coloring.(*_Coloring).defaultBits &^= quotedBit
		}
	}()

	buffer := make([]byte, 0, 256)
	for {
		line, err := stream.Editor.ReadLine(ctx)
		buffer = append(buffer, line...)
		if err != nil {
			return string(buffer), err
		}
		if endsWithSep(buffer, '^') {
			buffer = buffer[:len(buffer)-1]
			buffer = append(buffer, '\r', '\n')
			continued = true
			os.Setenv("PROMPT", "> ")
			continue
		}
		if bytes.Count(buffer, []byte{'"'})%2 != 0 {
			buffer = append(buffer, '\r', '\n')
			continued = true
			os.Setenv("PROMPT", "> ")
			stream.Editor.Coloring.(*_Coloring).defaultBits |= quotedBit
			continue
		}
		return string(buffer), err
	}
}

func (stream *CmdStreamConsole) ReadLine(ctx context.Context) (context.Context, string, error) {
	if stream.Pointer >= 0 {
		if stream.Pointer < len(stream.PlainHistory) {
			stream.Pointer++
			return ctx, stream.PlainHistory[stream.Pointer-1], nil
		}
		stream.Pointer = -1
	}
	var line string
	var err error
	for {
		disabler := colorable.EnableColorsStdout(nil)
		clean, err2 := consoleicon.SetFromExe()
		for {
			line, err = stream.readLineContinued(ctx)
			if err != readline.CtrlC {
				break
			}
			fmt.Fprintln(os.Stderr, err.Error())
		}
		if err2 == nil {
			clean(false)
		}
		disabler()
		if err != nil {
			return ctx, line, err
		}
		var isReplaced bool
		line, isReplaced, err = stream.History.Replace(line)
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			continue
		}
		if isReplaced {
			fmt.Fprintln(os.Stdout, line)
		}
		if line != "" {
			break
		}
	}
	row := history.NewHistoryLine(line)
	stream.History.PushLine(row)
	fd, err := os.OpenFile(stream.HistPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	if err == nil {
		fmt.Fprintln(fd, row.String())
		fd.Close()
	} else {
		fmt.Fprintln(os.Stderr, err.Error())
	}
	stream.PlainHistory = append(stream.PlainHistory, line)
	return ctx, line, err
}
<commit_msg>Do not continue line-input when double-quotations are not enclosed.(#418)<commit_after>package frame

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"path/filepath"

	"github.com/mattn/go-colorable"

	"github.com/nyaosorg/go-readline-ny"
	"github.com/nyaosorg/go-windows-consoleicon"

	"github.com/nyaosorg/nyagos/history"
	"github.com/nyaosorg/nyagos/shell"
)

type CmdStreamConsole struct {
	shell.CmdSeeker
	DoPrompt func() (int, error)
	History  *history.Container
	Editor   *readline.Editor
	HistPath string
}

func NewCmdStreamConsole(doPrompt func() (int, error)) *CmdStreamConsole {
	history1 := &history.Container{}
	stream := &CmdStreamConsole{
		History: history1,
		Editor: &readline.Editor{
			History:        history1,
			Prompt:         doPrompt,
			Writer:         colorable.NewColorableStdout(),
			Coloring:       &_Coloring{},
			HistoryCycling: true,
		},
		HistPath: filepath.Join(appDataDir(), "nyagos.history"),
		CmdSeeker: shell.CmdSeeker{
			PlainHistory: []string{},
			Pointer:      -1,
		},
	}
	history1.Load(stream.HistPath)
	history1.Save(stream.HistPath)
	return stream
}

func (stream *CmdStreamConsole) DisableHistory(value bool) bool {
	return stream.History.IgnorePush(value)
}

// endsWithSep returns
//     false when line does not end with `^`
//     true when line ends with `^`
//     false when line ends with `^^`
//     true when line ends with `^^^`
func endsWithSep(line []byte, contMark byte) bool {
	markCount := 0
	for len(line) > 0 && line[len(line)-1] == contMark {
		markCount++
		line = line[:len(line)-1]
	}
	return markCount%2 != 0
}

func (stream *CmdStreamConsole) readLineContinued(ctx context.Context) (string, error) {
	continued := false
	originalPrompt := os.Getenv("PROMPT")
	buffer := make([]byte, 0, 256)
	for {
		line, err := stream.Editor.ReadLine(ctx)
		buffer = append(buffer, line...)
		if err != nil || !endsWithSep(buffer, '^') {
			if continued {
				os.Setenv("PROMPT", originalPrompt)
				stream.Editor.Coloring.(*_Coloring).defaultBits &^= quotedBit
			}
			return string(buffer), err
		}
		buffer = buffer[:len(buffer)-1]
		buffer = append(buffer, '\r', '\n')
		continued = true
		os.Setenv("PROMPT", "> ")
		if bytes.Count(buffer, []byte{'"'})%2 != 0 {
			stream.Editor.Coloring.(*_Coloring).defaultBits |= quotedBit
		}
	}
}

func (stream *CmdStreamConsole) ReadLine(ctx context.Context) (context.Context, string, error) {
	if stream.Pointer >= 0 {
		if stream.Pointer < len(stream.PlainHistory) {
			stream.Pointer++
			return ctx, stream.PlainHistory[stream.Pointer-1], nil
		}
		stream.Pointer = -1
	}
	var line string
	var err error
	for {
		disabler := colorable.EnableColorsStdout(nil)
		clean, err2 := consoleicon.SetFromExe()
		for {
			line, err = stream.readLineContinued(ctx)
			if err != readline.CtrlC {
				break
			}
			fmt.Fprintln(os.Stderr, err.Error())
		}
		if err2 == nil {
			clean(false)
		}
		disabler()
		if err != nil {
			return ctx, line, err
		}
		var isReplaced bool
		line, isReplaced, err = stream.History.Replace(line)
		if err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			continue
		}
		if isReplaced {
			fmt.Fprintln(os.Stdout, line)
		}
		if line != "" {
			break
		}
	}
	row := history.NewHistoryLine(line)
	stream.History.PushLine(row)
	fd, err := os.OpenFile(stream.HistPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
	if err == nil {
		fmt.Fprintln(fd, row.String())
		fd.Close()
	} else {
		fmt.Fprintln(os.Stderr, err.Error())
	}
	stream.PlainHistory = append(stream.PlainHistory, line)
	return ctx, line, err
}
<|endoftext|>


<commit_before>package main

import (
	"golang.org/x/net/icmp"
	"golang.org/x/net/internal/iana"
	"golang.org/x/net/ipv4"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

type networkMessage struct {
	msg       []byte
	msgType   uint8
	queueable bool
	ts        time.Time
}

type networkConnection struct {
	Conn         *net.UDPConn
	Ip           string
	Port         uint32
	Capability   uint8
	messageQueue [][]byte // Device message queue.
	/*
		Sleep mode/throttle variables. "sleep mode" is actually now just a very reduced packet rate, since we don't know positively
		 when a client is ready to accept packets - we just assume so if we don't receive ICMP Unreachable packets in 5 secs.
	*/
	lastUnreachable time.Time // Last time the device sent an ICMP Unreachable packet.
	nextMessageTime time.Time // The next time that the device is "able" to receive a message.
}

var messageQueue chan networkMessage
var outSockets map[string]networkConnection
var dhcpLeases map[string]string
var netMutex *sync.Mutex

var pingResponse map[string]time.Time // Last time an IP responded to an "echo" response.

const (
	NETWORK_GDL90_STANDARD = 1
	NETWORK_AHRS_FFSIM     = 2
	NETWORK_AHRS_GDL90     = 4
	dhcp_lease_file        = "/var/lib/dhcp/dhcpd.leases"
)

// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
	dat, err := ioutil.ReadFile(dhcp_lease_file)
	ret := make(map[string]string)
	if err != nil {
		return ret, err
	}
	lines := strings.Split(string(dat), "\n")
	open_block := false
	block_ip := ""
	for _, line := range lines {
		spaced := strings.Split(line, " ")
		if len(spaced) > 2 && spaced[0] == "lease" {
			open_block = true
			block_ip = spaced[1]
		} else if open_block && len(spaced) >= 4 && spaced[2] == "client-hostname" {
			hostname := strings.TrimRight(strings.TrimLeft(strings.Join(spaced[3:], " "), "\""), "\";")
			ret[block_ip] = hostname
			open_block = false
		} else if open_block && strings.HasPrefix(spaced[0], "}") { // No hostname.
			open_block = false
			ret[block_ip] = ""
		}
	}
	return ret, nil
}

func isSleeping(k string) bool {
	ipAndPort := strings.Split(k, ":")
	lastPing, ok := pingResponse[ipAndPort[0]]
	// No ping response. Assume disconnected/sleeping device.
	if !ok || time.Since(lastPing) > (10*time.Second) {
		return true
	}
	if time.Since(outSockets[k].lastUnreachable) < (5 * time.Second) {
		return true
	}
	return false
}

// Throttle mode for testing port open and giving some start-up time to the app.
// Throttling is 0.1% data rate for first 15 seconds.
func isThrottled(k string) bool {
	return (rand.Int()%1000 != 0) && time.Since(outSockets[k].lastUnreachable) < (15*time.Second)
}

func sendToAllConnectedClients(msg networkMessage) {
	netMutex.Lock()
	defer netMutex.Unlock()
	for k, netconn := range outSockets {
		// Check if this port is able to accept the type of message we're sending.
		if (netconn.Capability & msg.msgType) == 0 {
			continue
		}
		// Send non-queueable messages immediately, or discard if the client is in sleep mode.
		if !msg.queueable {
			if !isSleeping(k) {
				netconn.Conn.Write(msg.msg) // Write immediately.
			} else {
				log.Printf("sleepy %s\n", k)
			}
		} else {
			// Queue the message if the message is "queueable".
			if len(netconn.messageQueue) >= maxUserMsgQueueSize { // Too many messages queued? Drop the oldest.
				log.Printf("%s:%d - message queue overflow.\n", netconn.Ip, netconn.Port)
				netconn.messageQueue = netconn.messageQueue[1 : maxUserMsgQueueSize-1]
			}
			netconn.messageQueue = append(netconn.messageQueue, msg.msg)
			outSockets[k] = netconn
		}
	}
}

// Just returns the number of DHCP leases for now.
func getNetworkStats() uint {
	ret := uint(len(dhcpLeases))
	globalStatus.Connected_Users = ret
	return ret
}

// See who has a DHCP lease and make a UDP connection to each of them.
func refreshConnectedClients() {
	netMutex.Lock()
	defer netMutex.Unlock()
	validConnections := make(map[string]bool)
	t, err := getDHCPLeases()
	if err != nil {
		log.Printf("getDHCPLeases(): %s\n", err.Error())
		return
	}
	dhcpLeases = t
	// Client connected that wasn't before.
	for ip, hostname := range dhcpLeases {
		for _, networkOutput := range globalSettings.NetworkOutputs {
			ipAndPort := ip + ":" + strconv.Itoa(int(networkOutput.Port))
			if _, ok := outSockets[ipAndPort]; !ok {
				log.Printf("client connected: %s:%d (%s).\n", ip, networkOutput.Port, hostname)
				addr, err := net.ResolveUDPAddr("udp", ipAndPort)
				if err != nil {
					log.Printf("ResolveUDPAddr(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				outConn, err := net.DialUDP("udp", nil, addr)
				if err != nil {
					log.Printf("DialUDP(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				newq := make([][]byte, 0)
				outSockets[ipAndPort] = networkConnection{Conn: outConn, Ip: ip, Port: networkOutput.Port, Capability: networkOutput.Capability, messageQueue: newq}
			}
			validConnections[ipAndPort] = true
		}
	}
	// Client that was connected before that isn't.
	for ipAndPort, conn := range outSockets {
		if _, ok := validConnections[ipAndPort]; !ok {
			log.Printf("removed connection %s.\n", ipAndPort)
			conn.Conn.Close()
			delete(outSockets, ipAndPort)
		}
	}
}

func messageQueueSender() {
	secondTimer := time.NewTicker(5 * time.Second)
	queueTimer := time.NewTicker(400 * time.Microsecond) // 2500 msg/sec
	for {
		select {
		case msg := <-messageQueue:
			sendToAllConnectedClients(msg)
		case <-queueTimer.C:
			netMutex.Lock()
			for k, netconn := range outSockets {
				if len(netconn.messageQueue) > 0 && !isSleeping(k) && !isThrottled(k) {
					tmpConn := netconn
					tmpConn.Conn.Write(tmpConn.messageQueue[0])
					tmpConn.messageQueue = tmpConn.messageQueue[1:]
					outSockets[k] = tmpConn
				}
			}
			netMutex.Unlock()
		case <-secondTimer.C:
			getNetworkStats()
		}
	}
}

func sendMsg(msg []byte, msgType uint8, queueable bool) {
	messageQueue <- networkMessage{msg: msg, msgType: msgType, queueable: queueable, ts: time.Now()}
}

func sendGDL90(msg []byte, queueable bool) {
	sendMsg(msg, NETWORK_GDL90_STANDARD, queueable)
}

func monitorDHCPLeases() {
	//TODO: inotify or dhcp event hook.
	timer := time.NewTicker(30 * time.Second)
	for {
		select {
		case <-timer.C:
			refreshConnectedClients()
		}
	}
}

func icmpEchoSender(c *icmp.PacketConn) {
	timer := time.NewTicker(5 * time.Second)
	for {
		<-timer.C
		// Collect IPs.
		ips := make(map[string]bool)
		for k, _ := range outSockets {
			ipAndPort := strings.Split(k, ":")
			ips[ipAndPort[0]] = true
		}
		// Send to all IPs.
		for ip, _ := range ips {
			wm := icmp.Message{
				Type: ipv4.ICMPTypeEcho, Code: 0,
				Body: &icmp.Echo{
					ID: os.Getpid() & 0xffff, Seq: 1,
					Data: []byte("STRATUX"),
				},
			}
			wb, err := wm.Marshal(nil)
			if err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
			if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(ip)}); err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
		}
	}
}

// Monitor clients going in/out of sleep mode via ICMP unreachable packets.
func sleepMonitor() {
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Printf("error listening for udp - sending data to all ports for all connected clients. err: %s", err)
		return
	}
	go icmpEchoSender(c)
	defer c.Close()
	for {
		buf := make([]byte, 1500)
		n, peer, err := c.ReadFrom(buf)
		if err != nil {
			log.Printf("%s\n", err.Error())
			continue
		}
		msg, err := icmp.ParseMessage(iana.ProtocolICMP, buf[:n])
		if err != nil {
			continue
		}

		ip := peer.String()

		// Look for echo replies, mark it as received.
		if msg.Type == ipv4.ICMPTypeEchoReply {
			pingResponse[ip] = time.Now()
			continue // No further processing needed.
		}

		// Only deal with ICMP Unreachable packets (since that's what iOS and Android seem to be sending whenever the apps are not available).
		if msg.Type != ipv4.ICMPTypeDestinationUnreachable {
			continue
		}
		// Packet parsing.
		mb, err := msg.Body.Marshal(iana.ProtocolICMP)
		if err != nil {
			continue
		}
		if len(mb) < 28 {
			continue
		}

		// The unreachable port.
		port := (uint16(mb[26]) << 8) | uint16(mb[27])
		ipAndPort := ip + ":" + strconv.Itoa(int(port))

		netMutex.Lock()
		p, ok := outSockets[ipAndPort]
		if !ok {
			// Can't do anything, the client isn't even technically connected.
			netMutex.Unlock()
			continue
		}
		p.lastUnreachable = time.Now()
		outSockets[ipAndPort] = p
		netMutex.Unlock()
	}
}

func initNetwork() {
	messageQueue = make(chan networkMessage, 1024) // Buffered channel, 1024 messages.
	outSockets = make(map[string]networkConnection)
	pingResponse = make(map[string]time.Time)
	netMutex = &sync.Mutex{}
	refreshConnectedClients()
	go monitorDHCPLeases()
	go messageQueueSender()
	go sleepMonitor()
}
<commit_msg>Remove debug prints.<commit_after>package main

import (
	"golang.org/x/net/icmp"
	"golang.org/x/net/internal/iana"
	"golang.org/x/net/ipv4"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

type networkMessage struct {
	msg       []byte
	msgType   uint8
	queueable bool
	ts        time.Time
}

type networkConnection struct {
	Conn         *net.UDPConn
	Ip           string
	Port         uint32
	Capability   uint8
	messageQueue [][]byte // Device message queue.
	/*
		Sleep mode/throttle variables. "sleep mode" is actually now just a very reduced packet rate, since we don't know positively
		 when a client is ready to accept packets - we just assume so if we don't receive ICMP Unreachable packets in 5 secs.
	*/
	lastUnreachable time.Time // Last time the device sent an ICMP Unreachable packet.
	nextMessageTime time.Time // The next time that the device is "able" to receive a message.
}

var messageQueue chan networkMessage
var outSockets map[string]networkConnection
var dhcpLeases map[string]string
var netMutex *sync.Mutex

var pingResponse map[string]time.Time // Last time an IP responded to an "echo" response.

const (
	NETWORK_GDL90_STANDARD = 1
	NETWORK_AHRS_FFSIM     = 2
	NETWORK_AHRS_GDL90     = 4
	dhcp_lease_file        = "/var/lib/dhcp/dhcpd.leases"
)

// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
	dat, err := ioutil.ReadFile(dhcp_lease_file)
	ret := make(map[string]string)
	if err != nil {
		return ret, err
	}
	lines := strings.Split(string(dat), "\n")
	open_block := false
	block_ip := ""
	for _, line := range lines {
		spaced := strings.Split(line, " ")
		if len(spaced) > 2 && spaced[0] == "lease" {
			open_block = true
			block_ip = spaced[1]
		} else if open_block && len(spaced) >= 4 && spaced[2] == "client-hostname" {
			hostname := strings.TrimRight(strings.TrimLeft(strings.Join(spaced[3:], " "), "\""), "\";")
			ret[block_ip] = hostname
			open_block = false
		} else if open_block && strings.HasPrefix(spaced[0], "}") { // No hostname.
			open_block = false
			ret[block_ip] = ""
		}
	}
	return ret, nil
}

func isSleeping(k string) bool {
	ipAndPort := strings.Split(k, ":")
	lastPing, ok := pingResponse[ipAndPort[0]]
	// No ping response. Assume disconnected/sleeping device.
	if !ok || time.Since(lastPing) > (10*time.Second) {
		return true
	}
	if time.Since(outSockets[k].lastUnreachable) < (5 * time.Second) {
		return true
	}
	return false
}

// Throttle mode for testing port open and giving some start-up time to the app.
// Throttling is 0.1% data rate for first 15 seconds.
func isThrottled(k string) bool {
	return (rand.Int()%1000 != 0) && time.Since(outSockets[k].lastUnreachable) < (15*time.Second)
}

func sendToAllConnectedClients(msg networkMessage) {
	netMutex.Lock()
	defer netMutex.Unlock()
	for k, netconn := range outSockets {
		// Check if this port is able to accept the type of message we're sending.
		if (netconn.Capability & msg.msgType) == 0 {
			continue
		}
		// Send non-queueable messages immediately, or discard if the client is in sleep mode.
		if !msg.queueable {
			if !isSleeping(k) {
				netconn.Conn.Write(msg.msg) // Write immediately.
			}
		} else {
			// Queue the message if the message is "queueable".
			if len(netconn.messageQueue) >= maxUserMsgQueueSize { // Too many messages queued? Drop the oldest.
				log.Printf("%s:%d - message queue overflow.\n", netconn.Ip, netconn.Port)
				netconn.messageQueue = netconn.messageQueue[1 : maxUserMsgQueueSize-1]
			}
			netconn.messageQueue = append(netconn.messageQueue, msg.msg)
			outSockets[k] = netconn
		}
	}
}

// Just returns the number of DHCP leases for now.
func getNetworkStats() uint {
	ret := uint(len(dhcpLeases))
	globalStatus.Connected_Users = ret
	return ret
}

// See who has a DHCP lease and make a UDP connection to each of them.
func refreshConnectedClients() {
	netMutex.Lock()
	defer netMutex.Unlock()
	validConnections := make(map[string]bool)
	t, err := getDHCPLeases()
	if err != nil {
		log.Printf("getDHCPLeases(): %s\n", err.Error())
		return
	}
	dhcpLeases = t
	// Client connected that wasn't before.
	for ip, hostname := range dhcpLeases {
		for _, networkOutput := range globalSettings.NetworkOutputs {
			ipAndPort := ip + ":" + strconv.Itoa(int(networkOutput.Port))
			if _, ok := outSockets[ipAndPort]; !ok {
				log.Printf("client connected: %s:%d (%s).\n", ip, networkOutput.Port, hostname)
				addr, err := net.ResolveUDPAddr("udp", ipAndPort)
				if err != nil {
					log.Printf("ResolveUDPAddr(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				outConn, err := net.DialUDP("udp", nil, addr)
				if err != nil {
					log.Printf("DialUDP(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				newq := make([][]byte, 0)
				outSockets[ipAndPort] = networkConnection{Conn: outConn, Ip: ip, Port: networkOutput.Port, Capability: networkOutput.Capability, messageQueue: newq}
			}
			validConnections[ipAndPort] = true
		}
	}
	// Client that was connected before that isn't.
	for ipAndPort, conn := range outSockets {
		if _, ok := validConnections[ipAndPort]; !ok {
			log.Printf("removed connection %s.\n", ipAndPort)
			conn.Conn.Close()
			delete(outSockets, ipAndPort)
		}
	}
}

func messageQueueSender() {
	secondTimer := time.NewTicker(5 * time.Second)
	queueTimer := time.NewTicker(400 * time.Microsecond) // 2500 msg/sec
	for {
		select {
		case msg := <-messageQueue:
			sendToAllConnectedClients(msg)
		case <-queueTimer.C:
			netMutex.Lock()
			for k, netconn := range outSockets {
				if len(netconn.messageQueue) > 0 && !isSleeping(k) && !isThrottled(k) {
					tmpConn := netconn
					tmpConn.Conn.Write(tmpConn.messageQueue[0])
					tmpConn.messageQueue = tmpConn.messageQueue[1:]
					outSockets[k] = tmpConn
				}
			}
			netMutex.Unlock()
		case <-secondTimer.C:
			getNetworkStats()
		}
	}
}

func sendMsg(msg []byte, msgType uint8, queueable bool) {
	messageQueue <- networkMessage{msg: msg, msgType: msgType, queueable: queueable, ts: time.Now()}
}

func sendGDL90(msg []byte, queueable bool) {
	sendMsg(msg, NETWORK_GDL90_STANDARD, queueable)
}

func monitorDHCPLeases() {
	//TODO: inotify or dhcp event hook.
	timer := time.NewTicker(30 * time.Second)
	for {
		select {
		case <-timer.C:
			refreshConnectedClients()
		}
	}
}

func icmpEchoSender(c *icmp.PacketConn) {
	timer := time.NewTicker(5 * time.Second)
	for {
		<-timer.C
		// Collect IPs.
		ips := make(map[string]bool)
		for k, _ := range outSockets {
			ipAndPort := strings.Split(k, ":")
			ips[ipAndPort[0]] = true
		}
		// Send to all IPs.
		for ip, _ := range ips {
			wm := icmp.Message{
				Type: ipv4.ICMPTypeEcho, Code: 0,
				Body: &icmp.Echo{
					ID: os.Getpid() & 0xffff, Seq: 1,
					Data: []byte("STRATUX"),
				},
			}
			wb, err := wm.Marshal(nil)
			if err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
			if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(ip)}); err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
		}
	}
}

// Monitor clients going in/out of sleep mode via ICMP unreachable packets.
func sleepMonitor() {
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Printf("error listening for udp - sending data to all ports for all connected clients. err: %s", err)
		return
	}
	go icmpEchoSender(c)
	defer c.Close()
	for {
		buf := make([]byte, 1500)
		n, peer, err := c.ReadFrom(buf)
		if err != nil {
			log.Printf("%s\n", err.Error())
			continue
		}
		msg, err := icmp.ParseMessage(iana.ProtocolICMP, buf[:n])
		if err != nil {
			continue
		}

		ip := peer.String()

		// Look for echo replies, mark it as received.
		if msg.Type == ipv4.ICMPTypeEchoReply {
			pingResponse[ip] = time.Now()
			continue // No further processing needed.
		}

		// Only deal with ICMP Unreachable packets (since that's what iOS and Android seem to be sending whenever the apps are not available).
		if msg.Type != ipv4.ICMPTypeDestinationUnreachable {
			continue
		}
		// Packet parsing.
		mb, err := msg.Body.Marshal(iana.ProtocolICMP)
		if err != nil {
			continue
		}
		if len(mb) < 28 {
			continue
		}

		// The unreachable port.
		port := (uint16(mb[26]) << 8) | uint16(mb[27])
		ipAndPort := ip + ":" + strconv.Itoa(int(port))

		netMutex.Lock()
		p, ok := outSockets[ipAndPort]
		if !ok {
			// Can't do anything, the client isn't even technically connected.
			netMutex.Unlock()
			continue
		}
		p.lastUnreachable = time.Now()
		outSockets[ipAndPort] = p
		netMutex.Unlock()
	}
}

func initNetwork() {
	messageQueue = make(chan networkMessage, 1024) // Buffered channel, 1024 messages.
	outSockets = make(map[string]networkConnection)
	pingResponse = make(map[string]time.Time)
	netMutex = &sync.Mutex{}
	refreshConnectedClients()
	go monitorDHCPLeases()
	go messageQueueSender()
	go sleepMonitor()
}
<|endoftext|>


<commit_before>package golangNeo4jBoltDriver

import (
	"os"
	"testing"

	"github.com/johnnadratowski/golang-neo4j-bolt-driver/log"
	"time"
	"sync"
)

var (
	neo4jConnStr = ""
)

func TestMain(m *testing.M) {
	log.SetLevel(os.Getenv("BOLT_DRIVER_LOG"))

	neo4jConnStr = os.Getenv("NEO4J_BOLT")
	if neo4jConnStr != "" {
		log.Info("Using NEO4J for tests:", neo4jConnStr)
	} else if os.Getenv("ENSURE_NEO4J_BOLT") != "" {
		log.Fatal("Must give NEO4J_BOLT environment variable")
	}

	output := m.Run()

	if neo4jConnStr != "" {
		// If we're using a DB for testing neo, clear it out after all the test runs
		clearNeo()
	}

	os.Exit(output)
}

func clearNeo() {
	driver := NewDriver()
	conn, err := driver.OpenNeo(neo4jConnStr)
	if err != nil {
		panic("Error getting conn to clear DB")
	}

	stmt, err := conn.PrepareNeo(`MATCH (n) DETACH DELETE n`)
	if err != nil {
		panic("Error getting stmt to clear DB")
	}
	defer stmt.Close()

	_, err = stmt.ExecNeo(nil)
	if err != nil {
		panic("Error running query to clear DB")
	}
}

func TestBoltDriverPool_OpenNeo(t *testing.T) {
	if neo4jConnStr == "" {
		t.Skip("Cannot run this test when in recording mode")
	}

	pool, err := NewDriverPool(neo4jConnStr, 25)
	if err != nil {
		t.Fatalf("An error occurred opening driver pool: %#v", err)
	}

	now := time.Now().Unix()
	for i := 0; i < 25; i++ {
		go func() {
			c, err := pool.OpenPool()
			if err != nil {
				t.Fatalf("An error occurred opening conn from pool: %#v", err)
			}
			defer c.Close()
			time.Sleep(time.Millisecond * time.Duration(200))
		}()
	}

	c, err := pool.OpenPool()
	if !(time.Now().Unix()-now < 200) {
		t.Fatalf("An error occurred opening conn from pool at end: %#v", err)
	}
	defer c.Close()
}

func TestBoltDriverPool_Concurrent(t *testing.T) {

	var wg sync.WaitGroup
	wg.Add(2)
	driver, err := NewDriverPool(neo4jConnStr, 2)
	if err != nil {
		t.Fatalf("An error occurred opening driver pool: %#v", err)
	}

	yourTurn := make(chan bool)
	go func() {
		defer wg.Done()

		conn, err := driver.OpenPool()
		if err != nil {
			t.Fatalf("An error occurred opening conn: %s", err)
		}
		defer conn.Close()

		data, _, _, err := conn.QueryNeoAll(`MATCH (n) RETURN n`, nil)
		if err != nil {
			t.Fatalf("An error occurred querying neo: %s", err)
		}

		yourTurn <- true
		<-yourTurn

		if len(data) != 0 {
			t.Fatalf("Expected no data: %#v", data)
		}

		data, _, _, err = conn.QueryNeoAll(`MATCH (n) RETURN n`, nil)
		if err != nil {
			t.Fatalf("An error occurred querying neo: %s", err)
		}

		if len(data) != 1 {
			t.Fatalf("Expected no data: %#v", data)
		}

		yourTurn <- true
		<-yourTurn

		data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil)
		if err != nil {
			t.Fatalf("An error occurred querying neo: %s", err)
		}

		if len(data) != 1 {
			t.Fatalf("Expected no data: %#v", data)
		}

		yourTurn <- true
		<-yourTurn

		data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil)
		if err != nil {
			t.Fatalf("An error occurred querying neo: %s", err)
		}

		if len(data) != 0 {
			t.Fatalf("Expected no data: %#v", data)
		}

		yourTurn <- true
	}()

	go func() {
		defer wg.Done()

		conn, err := driver.OpenPool()
		if err != nil {
			t.Fatalf("An error occurred opening conn: %s", err)
		}
		defer conn.Close()

		<-yourTurn

		_, err = conn.ExecNeo(`CREATE (f:FOO)`, nil)
		if err != nil {
			t.Fatalf("An error occurred creating f neo: %s", err)
		}

		yourTurn <- true
		<-yourTurn

		_, err = conn.ExecNeo(`MATCH (f:FOO) CREATE UNIQUE (f)-[b:BAR]->(c:BAZ)`, nil)
		if err != nil {
			t.Fatalf("An error occurred creating f neo: %s", err)
		}

		yourTurn <- true
		<-yourTurn

		_, err = conn.ExecNeo(`MATCH (:FOO)-[b:BAR]->(:BAZ) DELETE b`, nil)
		if err != nil {
			t.Fatalf("An error occurred creating f neo: %s", err)
		}

		yourTurn <- true
		<-yourTurn

		_, err = conn.ExecNeo(`MATCH (n) DETACH DELETE n`, nil)
		if err != nil {
			t.Fatalf("An error occurred creating f neo: %s", err)
		}
	}()

	wg.Wait()
}

<commit_msg>go fmt<commit_after>package golangNeo4jBoltDriver

import (
	"os"
	"testing"

	"github.com/johnnadratowski/golang-neo4j-bolt-driver/log"
	"sync"
	"time"
)

var (
	neo4jConnStr = ""
)

func TestMain(m *testing.M) {
	log.SetLevel(os.Getenv("BOLT_DRIVER_LOG"))

	neo4jConnStr = os.Getenv("NEO4J_BOLT")
	if neo4jConnStr != "" {
		log.Info("Using NEO4J for tests:", neo4jConnStr)
	} else if os.Getenv("ENSURE_NEO4J_BOLT") != "" {
		log.Fatal("Must give NEO4J_BOLT environment variable")
	}

	output := m.Run()

	if neo4jConnStr != "" {
		// If we're using a DB for testing neo, clear it out after all the test runs
		clearNeo()
	}

	os.Exit(output)
}

func clearNeo() {
	driver := NewDriver()
	conn, err := driver.OpenNeo(neo4jConnStr)
	if err != nil {
		panic("Error getting conn to clear DB")
	}

	stmt, err := conn.PrepareNeo(`MATCH (n) DETACH DELETE n`)
	if err != nil {
		panic("Error getting stmt to clear DB")
	}
	defer stmt.Close()

	_, err = stmt.ExecNeo(nil)
	if err != nil {
		panic("Error running query to clear DB")
	}
}

func TestBoltDriverPool_OpenNeo(t *testing.T) {
	if neo4jConnStr == "" {
		t.Skip("Cannot run this test when in recording mode")
	}

	pool, err := NewDriverPool(neo4jConnStr, 25)
	if err != nil {
		t.Fatalf("An error occurred opening driver pool: %#v", err)
	}

	now := time.Now().Unix()
	for i := 0; i < 25; i++ {
		go func() {
			c, err := pool.OpenPool()
			if err != nil {
				t.Fatalf("An error occurred opening conn from pool: %#v", err)
			}
			defer c.Close()
			time.Sleep(time.Millisecond * time.Duration(200))
		}()
	}

	c, err := pool.OpenPool()
	if !(time.Now().Unix()-now < 200) {
		t.Fatalf("An error occurred opening conn from pool at end: %#v", err)
	}
	defer c.Close()
}

func TestBoltDriverPool_Concurrent(t *testing.T) {

	var wg sync.WaitGroup
	wg.Add(2)
	driver, err := NewDriverPool(neo4jConnStr, 2)
	if err != nil {
		t.Fatalf("An error occurred opening driver pool: %#v", err)
	}

	yourTurn := make(chan bool)
	go func() {
		defer wg.Done()

		conn, err := driver.OpenPool()
		if err != nil {
			t.Fatalf("An error occurred opening conn: %s", err)
		}
		defer conn.Close()

		data, _, _, err := conn.QueryNeoAll(`MATCH (n) RETURN n`, nil)
		if err != nil {
			t.Fatalf("An error occurred querying neo: %s", err)
		}

		yourTurn <- true
		<-yourTurn

		if len(data) != 0 {
			t.Fatalf("Expected no data: %#v", data)
		}

		data, _, _, err = conn.QueryNeoAll(`MATCH (n) RETURN n`, nil)
		if err != nil {
			t.Fatalf("An error occurred querying neo: %s", err)
		}

		if len(data) != 1 {
			t.Fatalf("Expected no data: %#v", data)
		}

		yourTurn <- true
		<-yourTurn

		data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil)
		if err != nil {
			t.Fatalf("An error occurred querying neo: %s", err)
		}

		if len(data) != 1 {
			t.Fatalf("Expected no data: %#v", data)
		}

		yourTurn <- true
		<-yourTurn

		data, _, _, err = conn.QueryNeoAll(`MATCH path=(:FOO)-[:BAR]->(:BAZ) RETURN path`, nil)
		if err != nil {
			t.Fatalf("An error occurred querying neo: %s", err)
		}

		if len(data) != 0 {
			t.Fatalf("Expected no data: %#v", data)
		}

		yourTurn <- true
	}()

	go func() {
		defer wg.Done()

		conn, err := driver.OpenPool()
		if err != nil {
			t.Fatalf("An error occurred opening conn: %s", err)
		}
		defer conn.Close()

		<-yourTurn

		_, err = conn.ExecNeo(`CREATE (f:FOO)`, nil)
		if err != nil {
			t.Fatalf("An error occurred creating f neo: %s", err)
		}

		yourTurn <- true
		<-yourTurn

		_, err = conn.ExecNeo(`MATCH (f:FOO) CREATE UNIQUE (f)-[b:BAR]->(c:BAZ)`, nil)
		if err != nil {
			t.Fatalf("An error occurred creating f neo: %s", err)
		}

		yourTurn <- true
		<-yourTurn

		_, err = conn.ExecNeo(`MATCH (:FOO)-[b:BAR]->(:BAZ) DELETE b`, nil)
		if err != nil {
			t.Fatalf("An error occurred creating f neo: %s", err)
		}

		yourTurn <- true
		<-yourTurn

		_, err = conn.ExecNeo(`MATCH (n) DETACH DELETE n`, nil)
		if err != nil {
			t.Fatalf("An error occurred creating f neo: %s", err)
		}
	}()

	wg.Wait()
}
<|endoftext|>


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

package html

import (
	"fmt"
)

// context describes the state an HTML parser must be in when it reaches the
// portion of HTML produced by evaluating a particular template node.
//
// The zero value of type context is the start context for a template that
// produces an HTML fragment as defined at
// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
// where the context element is null.
type context struct {
	state   state
	delim   delim
	urlPart urlPart
	jsCtx   jsCtx
	attr    attr
	element element
	err     *Error
}

// eq returns whether two contexts are equal.
func (c context) eq(d context) bool {
	return c.state == d.state &&
		c.delim == d.delim &&
		c.urlPart == d.urlPart &&
		c.jsCtx == d.jsCtx &&
		c.attr == d.attr &&
		c.element == d.element &&
		c.err == d.err
}

// mangle produces an identifier that includes a suffix that distinguishes it
// from template names mangled with different contexts.
func (c context) mangle(templateName string) string {
	// The mangled name for the default context is the input templateName.
	if c.state == stateText {
		return templateName
	}
	s := templateName + "$htmltemplate_" + c.state.String()
	if c.delim != 0 {
		s += "_" + c.delim.String()
	}
	if c.urlPart != 0 {
		s += "_" + c.urlPart.String()
	}
	if c.jsCtx != 0 {
		s += "_" + c.jsCtx.String()
	}
	if c.attr != 0 {
		s += "_" + c.attr.String()
	}
	if c.element != 0 {
		s += "_" + c.element.String()
	}
	return s
}

// state describes a high-level HTML parser state.
//
// It bounds the top of the element stack, and by extension the HTML insertion
// mode, but also contains state that does not correspond to anything in the
// HTML5 parsing algorithm because a single token production in the HTML
// grammar may contain embedded actions in a template. For instance, the quoted
// HTML attribute produced by
//

// is a single token in HTML's grammar but in a template spans several nodes.
type state uint8

const (
	// stateText is parsed character data. An HTML parser is in
	// this state when its parse position is outside an HTML tag,
	// directive, comment, and special element body.
	stateText state = iota
	// stateTag occurs before an HTML attribute or the end of a tag.
	stateTag
	// stateAttrName occurs inside an attribute name.
	// It occurs between the ^'s in ` ^name^ = value`.
	stateAttrName
	// stateAfterName occurs after an attr name has ended but before any
	// equals sign. It occurs between the ^'s in ` name^ ^= value`.
	stateAfterName
	// stateBeforeValue occurs after the equals sign but before the value.
	// It occurs between the ^'s in ` name =^ ^value`.
	stateBeforeValue
	// stateHTMLCmt occurs inside an .
	stateHTMLCmt
	// stateRCDATA occurs inside an RCDATA element (<textarea> or <title>)
	// as described at http://dev.w3.org/html5/spec/syntax.html#elements-0
	stateRCDATA
	// stateAttr occurs inside an HTML attribute whose content is text.
	stateAttr
	// stateURL occurs inside an HTML attribute whose content is a URL.
	stateURL
	// stateJS occurs inside an event handler or script element.
	stateJS
	// stateJSDqStr occurs inside a JavaScript double quoted string.
	stateJSDqStr
	// stateJSSqStr occurs inside a JavaScript single quoted string.
	stateJSSqStr
	// stateJSRegexp occurs inside a JavaScript regexp literal.
	stateJSRegexp
	// stateJSBlockCmt occurs inside a JavaScript /* block comment */.
	stateJSBlockCmt
	// stateJSLineCmt occurs inside a JavaScript // line comment.
	stateJSLineCmt
	// stateCSS occurs inside a


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

package runtime

import "unsafe"

// sigtrampPC is the PC at the beginning of the jmpdefer assembly function.
// The traceback needs to recognize it on link register architectures.
var sigtrampPC uintptr

var sigtramp struct{} // assembly function

func init() {
	sigtrampPC = funcPC(sigtramp)
	systraceback = traceback_windows
}

func traceback_windows(f *_func, frame *stkframe, gp *g, printing bool, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer) (changed, aborted bool) {
	// The main traceback thinks it has found a function. Check this.

	// Windows exception handlers run on the actual g stack (there is room
	// dedicated to this below the usual "bottom of stack"), not on a separate
	// stack. As a result, we have to be able to unwind past the exception
	// handler when called to unwind during stack growth inside the handler.
	// Recognize the frame at the call to sighandler in sigtramp and unwind
	// using the context argument passed to the call. This is awful.
	if f != nil && f.entry == sigtrampPC && frame.pc > f.entry {
		var r *context
		// Invoke callback so that stack copier sees an uncopyable frame.
		if callback != nil {
			frame.continpc = frame.pc
			frame.argp = 0
			frame.arglen = 0
			if !callback(frame, v) {
				aborted = true
				return
			}
		}
		r = (*context)(unsafe.Pointer(frame.sp + ptrSize))
		frame.pc = contextPC(r)
		frame.sp = contextSP(r)
		frame.lr = 0
		frame.fp = 0
		frame.fn = nil
		if printing && showframe(nil, gp) {
			print("----- exception handler -----\n")
		}
		f = findfunc(frame.pc)
		if f == nil {
			print("runtime: unknown pc ", hex(frame.pc), " after exception handler\n")
			if callback != nil {
				gothrow("unknown pc")
			}
		}
		frame.fn = f
		changed = true
		return
	}

	return
}
<commit_msg>runtime: fix sigtrampPC on Windows<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

// sigtrampPC is the PC at the beginning of the jmpdefer assembly function.
// The traceback needs to recognize it on link register architectures.
var sigtrampPC uintptr

func sigtramp()

func init() {
	sigtrampPC = funcPC(sigtramp)
	systraceback = traceback_windows
}

func traceback_windows(f *_func, frame *stkframe, gp *g, printing bool, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer) (changed, aborted bool) {
	// The main traceback thinks it has found a function. Check this.

	// Windows exception handlers run on the actual g stack (there is room
	// dedicated to this below the usual "bottom of stack"), not on a separate
	// stack. As a result, we have to be able to unwind past the exception
	// handler when called to unwind during stack growth inside the handler.
	// Recognize the frame at the call to sighandler in sigtramp and unwind
	// using the context argument passed to the call. This is awful.
	if f != nil && f.entry == sigtrampPC && frame.pc > f.entry {
		var r *context
		// Invoke callback so that stack copier sees an uncopyable frame.
		if callback != nil {
			frame.continpc = frame.pc
			frame.argp = 0
			frame.arglen = 0
			if !callback(frame, v) {
				aborted = true
				return
			}
		}
		r = (*context)(unsafe.Pointer(frame.sp + ptrSize))
		frame.pc = contextPC(r)
		frame.sp = contextSP(r)
		frame.lr = 0
		frame.fp = 0
		frame.fn = nil
		if printing && showframe(nil, gp) {
			print("----- exception handler -----\n")
		}
		f = findfunc(frame.pc)
		if f == nil {
			print("runtime: unknown pc ", hex(frame.pc), " after exception handler\n")
			if callback != nil {
				gothrow("unknown pc")
			}
		}
		frame.fn = f
		changed = true
		return
	}

	return
}
<|endoftext|>


<commit_before>package task

import (
	"fmt"
	"time"

	"github.com/satori/go.uuid"
)

// Action represents any work to be done when executing a task.
type Action func() error

// TaskObject represents a task that is executable.
type TaskObject struct {
	// ActiveStatus represents a status indicating activation or deactivation.
	ActiveStatus ActiveStatus

	// Error represents the message of an error occured during task execution, if
	// any.
	Error string

	// FinalStatus represents any status that is final. A task having this status
	// will not change its status anymore.
	FinalStatus FinalStatus

	// ID represents the task identifier.
	ID string
}

// TaskService represents a task managing unit being able to act on task
// objects.
type TaskService interface {
	// Create creates a new task object configured with the given action. The
	// task object is immediately returned and its corresponding action is
	// executed asynchronously.
	Create(action Action) (*TaskObject, error)

	// FetchState fetches and returns the current state and status for the given
	// task ID.
	FetchState(taskID string) (*TaskObject, error)

	// MarkAsSucceeded marks the task object as succeeded and persists its state.
	// The returned task object is actually the refreshed version of the provided
	// one.
	MarkAsSucceeded(taskObject *TaskObject) (*TaskObject, error)

	// MarkAsFailedWithError marks the task object as failed, adds information of
	// thegiven error and persists the task objects's state. The returned task
	// object is actually the refreshed version of the provided one.
	MarkAsFailedWithError(taskObject *TaskObject, err error) (*TaskObject, error)

	// PersistState writes the given task object to the configured Storage.
	PersistState(taskObject *TaskObject) error

	// WaitForFinalStatus blocks and waits for the given task to reach a final
	// status. The given closer can end the waiting and thus stop blocking the
	// call to WaitForFinalStatus.
	WaitForFinalStatus(taskID string, closer <-chan struct{}) (*TaskObject, error)
}

// TaskServiceConfig represents the configurations for the task service that is
// going to be created.
type TaskServiceConfig struct {
	Storage Storage

	// WaitSleep represents the time to sleep between state-check cycles.
	WaitSleep time.Duration
}

// DefaultTaskServiceConfig returns a best effort default configuration for the
// task service.
func DefaultTaskServiceConfig() TaskServiceConfig {
	newConfig := TaskServiceConfig{
		Storage:   NewMemoryStorage(),
		WaitSleep: 1 * time.Second,
	}

	return newConfig
}

// NewTaskService returns a new configured task service instance.
func NewTaskService(config TaskServiceConfig) TaskService {
	newTaskService := &taskService{
		TaskServiceConfig: config,
	}

	return newTaskService
}

type taskService struct {
	TaskServiceConfig
}

func (ts *taskService) Create(action Action) (*TaskObject, error) {
	taskObject := &TaskObject{
		ID:           uuid.NewV4().String(),
		ActiveStatus: StatusStarted,
		FinalStatus:  "",
	}

	go func() {
		err := action()
		if err != nil {
			_, markErr := ts.MarkAsFailedWithError(taskObject, err)
			if markErr != nil {
				fmt.Printf("[E] Task.MarkAsFailed failed: %#v\n", maskAny(markErr))
				return
			}
			return
		}

		_, err = ts.MarkAsSucceeded(taskObject)
		if err != nil {
			fmt.Printf("[E] Task.MarkAsSucceeded failed: %#v\n", maskAny(err))
			return
		}
	}()

	err := ts.PersistState(taskObject)
	if err != nil {
		return nil, maskAny(err)
	}

	return taskObject, nil
}

func (ts *taskService) FetchState(taskID string) (*TaskObject, error) {
	var err error

	taskObject, err := ts.Storage.Get(taskID)
	if err != nil {
		return nil, maskAny(err)
	}

	return taskObject, nil
}

func (ts *taskService) MarkAsFailedWithError(taskObject *TaskObject, err error) (*TaskObject, error) {
	taskObject.ActiveStatus = StatusStopped
	taskObject.Error = err.Error()
	taskObject.FinalStatus = StatusFailed

	err = ts.PersistState(taskObject)
	if err != nil {
		return nil, maskAny(err)
	}

	return taskObject, nil
}

func (ts *taskService) MarkAsSucceeded(taskObject *TaskObject) (*TaskObject, error) {
	taskObject.ActiveStatus = StatusStopped
	taskObject.FinalStatus = StatusSucceeded

	err := ts.PersistState(taskObject)
	if err != nil {
		return nil, maskAny(err)
	}

	return taskObject, nil
}

func (ts *taskService) PersistState(taskObject *TaskObject) error {
	err := ts.Storage.Set(taskObject)
	if err != nil {
		return maskAny(err)
	}

	return nil
}

// WaitForFinalStatus acts as described in the interface comments. Note that
// both, task object and error will be nil in case the closer ends waiting for
// the task to reach a final state.
func (ts *taskService) WaitForFinalStatus(taskID string, closer <-chan struct{}) (*TaskObject, error) {
	for {
		select {
		case <-closer:
			return nil, nil
		case <-time.After(1 * time.Second):
			taskObject, err := ts.FetchState(taskID)
			if err != nil {
				return nil, maskAny(err)
			}

			if HasFinalStatus(taskObject) {
				return taskObject, nil
			}
		}
	}
}
<commit_msg>Fix merge error from task-tests-2: Use ts.WaitSleep<commit_after>package task

import (
	"fmt"
	"time"

	"github.com/satori/go.uuid"
)

// Action represents any work to be done when executing a task.
type Action func() error

// TaskObject represents a task that is executable.
type TaskObject struct {
	// ActiveStatus represents a status indicating activation or deactivation.
	ActiveStatus ActiveStatus

	// Error represents the message of an error occured during task execution, if
	// any.
	Error string

	// FinalStatus represents any status that is final. A task having this status
	// will not change its status anymore.
	FinalStatus FinalStatus

	// ID represents the task identifier.
	ID string
}

// TaskService represents a task managing unit being able to act on task
// objects.
type TaskService interface {
	// Create creates a new task object configured with the given action. The
	// task object is immediately returned and its corresponding action is
	// executed asynchronously.
	Create(action Action) (*TaskObject, error)

	// FetchState fetches and returns the current state and status for the given
	// task ID.
	FetchState(taskID string) (*TaskObject, error)

	// MarkAsSucceeded marks the task object as succeeded and persists its state.
	// The returned task object is actually the refreshed version of the provided
	// one.
	MarkAsSucceeded(taskObject *TaskObject) (*TaskObject, error)

	// MarkAsFailedWithError marks the task object as failed, adds information of
	// thegiven error and persists the task objects's state. The returned task
	// object is actually the refreshed version of the provided one.
	MarkAsFailedWithError(taskObject *TaskObject, err error) (*TaskObject, error)

	// PersistState writes the given task object to the configured Storage.
	PersistState(taskObject *TaskObject) error

	// WaitForFinalStatus blocks and waits for the given task to reach a final
	// status. The given closer can end the waiting and thus stop blocking the
	// call to WaitForFinalStatus.
	WaitForFinalStatus(taskID string, closer <-chan struct{}) (*TaskObject, error)
}

// TaskServiceConfig represents the configurations for the task service that is
// going to be created.
type TaskServiceConfig struct {
	Storage Storage

	// WaitSleep represents the time to sleep between state-check cycles.
	WaitSleep time.Duration
}

// DefaultTaskServiceConfig returns a best effort default configuration for the
// task service.
func DefaultTaskServiceConfig() TaskServiceConfig {
	newConfig := TaskServiceConfig{
		Storage:   NewMemoryStorage(),
		WaitSleep: 1 * time.Second,
	}

	return newConfig
}

// NewTaskService returns a new configured task service instance.
func NewTaskService(config TaskServiceConfig) TaskService {
	newTaskService := &taskService{
		TaskServiceConfig: config,
	}

	return newTaskService
}

type taskService struct {
	TaskServiceConfig
}

func (ts *taskService) Create(action Action) (*TaskObject, error) {
	taskObject := &TaskObject{
		ID:           uuid.NewV4().String(),
		ActiveStatus: StatusStarted,
		FinalStatus:  "",
	}

	go func() {
		err := action()
		if err != nil {
			_, markErr := ts.MarkAsFailedWithError(taskObject, err)
			if markErr != nil {
				fmt.Printf("[E] Task.MarkAsFailed failed: %#v\n", maskAny(markErr))
				return
			}
			return
		}

		_, err = ts.MarkAsSucceeded(taskObject)
		if err != nil {
			fmt.Printf("[E] Task.MarkAsSucceeded failed: %#v\n", maskAny(err))
			return
		}
	}()

	err := ts.PersistState(taskObject)
	if err != nil {
		return nil, maskAny(err)
	}

	return taskObject, nil
}

func (ts *taskService) FetchState(taskID string) (*TaskObject, error) {
	var err error

	taskObject, err := ts.Storage.Get(taskID)
	if err != nil {
		return nil, maskAny(err)
	}

	return taskObject, nil
}

func (ts *taskService) MarkAsFailedWithError(taskObject *TaskObject, err error) (*TaskObject, error) {
	taskObject.ActiveStatus = StatusStopped
	taskObject.Error = err.Error()
	taskObject.FinalStatus = StatusFailed

	err = ts.PersistState(taskObject)
	if err != nil {
		return nil, maskAny(err)
	}

	return taskObject, nil
}

func (ts *taskService) MarkAsSucceeded(taskObject *TaskObject) (*TaskObject, error) {
	taskObject.ActiveStatus = StatusStopped
	taskObject.FinalStatus = StatusSucceeded

	err := ts.PersistState(taskObject)
	if err != nil {
		return nil, maskAny(err)
	}

	return taskObject, nil
}

func (ts *taskService) PersistState(taskObject *TaskObject) error {
	err := ts.Storage.Set(taskObject)
	if err != nil {
		return maskAny(err)
	}

	return nil
}

// WaitForFinalStatus acts as described in the interface comments. Note that
// both, task object and error will be nil in case the closer ends waiting for
// the task to reach a final state.
func (ts *taskService) WaitForFinalStatus(taskID string, closer <-chan struct{}) (*TaskObject, error) {
	for {
		select {
		case <-closer:
			return nil, nil
		case <-time.After(ts.WaitSleep):
			taskObject, err := ts.FetchState(taskID)
			if err != nil {
				return nil, maskAny(err)
			}

			if HasFinalStatus(taskObject) {
				return taskObject, nil
			}
		}
	}
}
<|endoftext|>


<commit_before>package db

import (
	"database/sql/driver"
	"time"
)

// ISO8601 is a time.Time layout for the ISO8601 format
const ISO8601 = "2006-01-02T15:04:05-0700"

// Time represents a time.Time that uses ISO8601 for json input/output
// instead of RFC3339
type Time struct {
	time.Time
}

// Now returns the current local time.
func Now() *Time {
	return &Time{Time: time.Now()}
}

// Value - Implementation of valuer for database/sql
func (t *Time) Value() (driver.Value, error) {
	if t == nil {
		return nil, nil
	}

	return t.Format(ISO8601), nil
}

// Scan - Implement the database/sql scanner interface
func (t *Time) Scan(value interface{}) error {
	if value != nil {
		t.Time = value.(time.Time)
	}
	return nil
}

// MarshalJSON implements the json.Marshaler interface
func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(`"` + t.Format(ISO8601) + `"`), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface
func (t *Time) UnmarshalJSON(data []byte) (err error) {
	t.Time, err = time.Parse(`"`+ISO8601+`"`, string(data))
	return
}
<commit_msg>Feat(db.Time): Add Time.Equal()<commit_after>package db

import (
	"database/sql/driver"
	"time"
)

// ISO8601 is a time.Time layout for the ISO8601 format
const ISO8601 = "2006-01-02T15:04:05-0700"

// Time represents a time.Time that uses ISO8601 for json input/output
// instead of RFC3339
type Time struct {
	time.Time
}

// Now returns the current local time.
func Now() *Time {
	return &Time{Time: time.Now()}
}

// Value - Implementation of valuer for database/sql
func (t *Time) Value() (driver.Value, error) {
	if t == nil {
		return nil, nil
	}

	return t.Format(ISO8601), nil
}

// Scan - Implement the database/sql scanner interface
func (t *Time) Scan(value interface{}) error {
	if value != nil {
		t.Time = value.(time.Time)
	}
	return nil
}

// MarshalJSON implements the json.Marshaler interface
func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(`"` + t.Format(ISO8601) + `"`), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface
func (t *Time) UnmarshalJSON(data []byte) (err error) {
	t.Time, err = time.Parse(`"`+ISO8601+`"`, string(data))
	return
}

// Equal check if the given date is equal to the current one
func (t *Time) Equal(u Time) bool {
	return t.Time.Equal(u.Time)
}
<|endoftext|>


<commit_before>package storage

import (
	"net/http"
	"net/http/cookiejar"
	"sync"
)

// Storage is an interface which handles Collector's internal data,
// like visited urls and cookies.
// The default Storage of the Collector is the InMemoryStorage.
// Collector's storage can be changed by calling Collector.SetStorage()
// function.
type Storage interface {
	// Init initializes the storage
	Init() error
	// Visited receives and stores a request ID that is visited by the Collector
	Visited(requestID uint64) error
	// IsVisited returns true if the request was visited before IsVisited
	// is called
	IsVisited(requestID uint64) (bool, error)
	// GetCookieJar returns with cookie jar that implements the
	// http.CookieJar interface
	GetCookieJar() http.CookieJar
	// Close is responsible for closing the internal files and connections
	// of the storage
	Close() error
}

// InMemoryStorage is the default storage backend of colly.
// InMemoryStorage keeps cookies and visited urls in memory
// without persisting data on the disk.
type InMemoryStorage struct {
	visitedURLs map[uint64]bool
	lock        *sync.RWMutex
	jar         *cookiejar.Jar
}

// Init initializes InMemoryStorage
func (s *InMemoryStorage) Init() error {
	if s.visitedURLs == nil {
		s.visitedURLs = make(map[uint64]bool)
	}
	if s.lock == nil {
		s.lock = &sync.RWMutex{}
	}
	if s.jar == nil {
		var err error
		s.jar, err = cookiejar.New(nil)
		return err
	}
	return nil
}

// Visited implements Storage.Visited()
func (s *InMemoryStorage) Visited(requestID uint64) error {
	s.lock.Lock()
	s.visitedURLs[requestID] = true
	s.lock.Unlock()
	return nil
}

// IsVisited implements Storage.IsVisited()
func (s *InMemoryStorage) IsVisited(requestID uint64) (bool, error) {
	s.lock.RLock()
	visited := s.visitedURLs[requestID]
	s.lock.RUnlock()
	return visited, nil
}

// GetCookieJar implements Storage.GetCookieJar()
func (s *InMemoryStorage) GetCookieJar() http.CookieJar {
	return s.jar
}

// Close implements Storage.Close()
func (s *InMemoryStorage) Close() error {
	return nil
}
<commit_msg>[mod] remove Close method from Storage interface<commit_after>package storage

import (
	"net/http"
	"net/http/cookiejar"
	"sync"
)

// Storage is an interface which handles Collector's internal data,
// like visited urls and cookies.
// The default Storage of the Collector is the InMemoryStorage.
// Collector's storage can be changed by calling Collector.SetStorage()
// function.
type Storage interface {
	// Init initializes the storage
	Init() error
	// Visited receives and stores a request ID that is visited by the Collector
	Visited(requestID uint64) error
	// IsVisited returns true if the request was visited before IsVisited
	// is called
	IsVisited(requestID uint64) (bool, error)
	// GetCookieJar returns with cookie jar that implements the
	// http.CookieJar interface
	GetCookieJar() http.CookieJar
}

// InMemoryStorage is the default storage backend of colly.
// InMemoryStorage keeps cookies and visited urls in memory
// without persisting data on the disk.
type InMemoryStorage struct {
	visitedURLs map[uint64]bool
	lock        *sync.RWMutex
	jar         *cookiejar.Jar
}

// Init initializes InMemoryStorage
func (s *InMemoryStorage) Init() error {
	if s.visitedURLs == nil {
		s.visitedURLs = make(map[uint64]bool)
	}
	if s.lock == nil {
		s.lock = &sync.RWMutex{}
	}
	if s.jar == nil {
		var err error
		s.jar, err = cookiejar.New(nil)
		return err
	}
	return nil
}

// Visited implements Storage.Visited()
func (s *InMemoryStorage) Visited(requestID uint64) error {
	s.lock.Lock()
	s.visitedURLs[requestID] = true
	s.lock.Unlock()
	return nil
}

// IsVisited implements Storage.IsVisited()
func (s *InMemoryStorage) IsVisited(requestID uint64) (bool, error) {
	s.lock.RLock()
	visited := s.visitedURLs[requestID]
	s.lock.RUnlock()
	return visited, nil
}

// GetCookieJar implements Storage.GetCookieJar()
func (s *InMemoryStorage) GetCookieJar() http.CookieJar {
	return s.jar
}

// Close implements Storage.Close()
func (s *InMemoryStorage) Close() error {
	return nil
}
<|endoftext|>


<commit_before>package brats_test

import (
	"flag"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/cloudfoundry/libbuildpack"
	"github.com/cloudfoundry/libbuildpack/bratshelper"
	"github.com/cloudfoundry/libbuildpack/cutlass"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

func init() {
	flag.StringVar(&cutlass.DefaultMemory, "memory", "128M", "default memory for pushed apps")
	flag.StringVar(&cutlass.DefaultDisk, "disk", "256M", "default disk for pushed apps")
	flag.Parse()
}

var _ = SynchronizedBeforeSuite(func() []byte {
	// Run once
	return bratshelper.InitBpData().Marshal()
}, func(data []byte) {
	// Run on all nodes
	bratshelper.Data.Unmarshal(data)

	cutlass.SeedRandom()
	cutlass.DefaultStdoutStderr = GinkgoWriter
})

var _ = SynchronizedAfterSuite(func() {
	// Run on all nodes
}, func() {
	// Run once
	Expect(cutlass.DeleteOrphanedRoutes()).To(Succeed())
	Expect(cutlass.DeleteBuildpack(strings.Replace(bratshelper.Data.Cached, "_buildpack", "", 1))).To(Succeed())
	Expect(cutlass.DeleteBuildpack(strings.Replace(bratshelper.Data.Uncached, "_buildpack", "", 1))).To(Succeed())
	Expect(os.Remove(bratshelper.Data.CachedFile)).To(Succeed())
})

func TestBrats(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Brats Suite")
}

func CopyBrats(version string) *cutlass.App {
	dir, err := cutlass.CopyFixture(filepath.Join(bratshelper.Data.BpDir, "fixtures", "brats"))
	Expect(err).ToNot(HaveOccurred())

	if version == "" {
		manifest, err := libbuildpack.NewManifest(bratshelper.Data.BpDir, nil, time.Now())
		Expect(err).ToNot(HaveOccurred())
		dep, err := manifest.DefaultVersion("python")
		Expect(err).ToNot(HaveOccurred())
		version = dep.Version
	}

	data := "python-" + version
	Expect(ioutil.WriteFile(filepath.Join(dir, "runtime.txt"), []byte(data), 0644)).To(Succeed())

	return cutlass.New(dir)
}

func PushApp(app *cutlass.App) {
	Expect(app.Push()).To(Succeed())
	Eventually(app.InstanceStates, 20*time.Second).Should(Equal([]string{"RUNNING"}))
}
<commit_msg>Copy CF_HOME per process in brats tests [#153524941]<commit_after>package brats_test

import (
	"flag"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/cloudfoundry/libbuildpack"
	"github.com/cloudfoundry/libbuildpack/bratshelper"
	"github.com/cloudfoundry/libbuildpack/cutlass"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

func init() {
	flag.StringVar(&cutlass.DefaultMemory, "memory", "128M", "default memory for pushed apps")
	flag.StringVar(&cutlass.DefaultDisk, "disk", "256M", "default disk for pushed apps")
	flag.Parse()
}

var _ = SynchronizedBeforeSuite(func() []byte {
	// Run once
	return bratshelper.InitBpData().Marshal()
}, func(data []byte) {
	// Run on all nodes
	bratshelper.Data.Unmarshal(data)

	Expect(cutlass.CopyCfHome()).To(Succeed())
	cutlass.SeedRandom()
	cutlass.DefaultStdoutStderr = GinkgoWriter
})

var _ = SynchronizedAfterSuite(func() {
	// Run on all nodes
}, func() {
	// Run once
	Expect(cutlass.DeleteOrphanedRoutes()).To(Succeed())
	Expect(cutlass.DeleteBuildpack(strings.Replace(bratshelper.Data.Cached, "_buildpack", "", 1))).To(Succeed())
	Expect(cutlass.DeleteBuildpack(strings.Replace(bratshelper.Data.Uncached, "_buildpack", "", 1))).To(Succeed())
	Expect(os.Remove(bratshelper.Data.CachedFile)).To(Succeed())
})

func TestBrats(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Brats Suite")
}

func CopyBrats(version string) *cutlass.App {
	dir, err := cutlass.CopyFixture(filepath.Join(bratshelper.Data.BpDir, "fixtures", "brats"))
	Expect(err).ToNot(HaveOccurred())

	if version == "" {
		manifest, err := libbuildpack.NewManifest(bratshelper.Data.BpDir, nil, time.Now())
		Expect(err).ToNot(HaveOccurred())
		dep, err := manifest.DefaultVersion("python")
		Expect(err).ToNot(HaveOccurred())
		version = dep.Version
	}

	data := "python-" + version
	Expect(ioutil.WriteFile(filepath.Join(dir, "runtime.txt"), []byte(data), 0644)).To(Succeed())

	return cutlass.New(dir)
}

func PushApp(app *cutlass.App) {
	Expect(app.Push()).To(Succeed())
	Eventually(app.InstanceStates, 20*time.Second).Should(Equal([]string{"RUNNING"}))
}
<|endoftext|>


<commit_before>// Copyright 2015 Deniz Eren. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package dynamostore

import (
	"bytes"
	"encoding/base32"
	"encoding/gob"
	"github.com/crowdmob/goamz/aws"
	"github.com/crowdmob/goamz/dynamodb"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"net/http"
	"strings"
)

type DynamoStore struct {
	Table   *dynamodb.Table
	Codecs  []securecookie.Codec
	Options *sessions.Options // default configuration
}

type DynamoData struct {
	Id   string
	Data []byte
}

func NewDynamoStore(accessKey string, secretKey string, tableName string, region string) (*DynamoStore, error) {
	awsAuth := aws.Auth{
		AccessKey: accessKey,
		SecretKey: secretKey,
	}

	server := dynamodb.New(awsAuth, aws.GetRegion(region))
	table := server.NewTable(tableName, dynamodb.PrimaryKey{KeyAttribute: dynamodb.NewStringAttribute("Id", "")})

	dynStore := &DynamoStore{
		Table:  table,
		Codecs: securecookie.CodecsFromPairs([]byte(secretKey)),
	}

	return dynStore, nil
}

func NewDynamoStoreWithRegionObj(accessKey string, secretKey string, tableName string, region aws.Region) (*DynamoStore, error) {
	awsAuth := aws.Auth{
		AccessKey: accessKey,
		SecretKey: secretKey,
	}

	server := dynamodb.New(awsAuth, region)
	table := server.NewTable(tableName, dynamodb.PrimaryKey{KeyAttribute: dynamodb.NewStringAttribute("Id", "")})

	dynStore := &DynamoStore{
		Table:  table,
		Codecs: securecookie.CodecsFromPairs([]byte(secretKey)),
	}

	return dynStore, nil
}

// Get returns a session for the given name after adding it to the registry.
//
// See gorilla/sessions FilesystemStore.Get().
// or  boj/redistore
func (s *DynamoStore) Get(r *http.Request, name string) (*sessions.Session, error) {
	return sessions.GetRegistry(r).Get(s, name)
}

func (s *DynamoStore) New(r *http.Request, name string) (*sessions.Session, error) {
	var err error
	session := sessions.NewSession(s, name)

	// make a copy
	options := sessions.Options{}
	session.Options = &options
	session.IsNew = true
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
		if err == nil {
			err := s.load(session)
			if err == nil {
				session.IsNew = false
			} else {
				session.IsNew = true
			}
		}
	}

	return session, err
}

// Save adds a single session to the response.
func (s *DynamoStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
	// Marked for deletion.
	if session.Options.MaxAge < 0 {
		if err := s.delete(session); err != nil {
			return err
		}
		http.SetCookie(w, sessions.NewCookie(session.Name(), "", session.Options))
	} else {
		// Build an alphanumeric key for the redis store.
		if session.ID == "" {
			session.ID = strings.TrimRight(base32.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(32)), "=")
		}
		if err := s.save(session); err != nil {
			return err
		}
		encoded, err := securecookie.EncodeMulti(session.Name(), session.ID, s.Codecs...)
		if err != nil {
			return err
		}
		http.SetCookie(w, sessions.NewCookie(session.Name(), encoded, session.Options))
	}
	return nil
}

// save stores the session in redis.
func (s *DynamoStore) save(session *sessions.Session) error {
	// TODO expiration date to be added
	// TODO max length to be added
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(session.Values)
	if err != nil {
		return err
	}
	b := buf.Bytes()

	data := &DynamoData{Id: session.ID, Data: b}
	err = s.Table.PutDocument(&dynamodb.Key{HashKey: session.ID}, data)
	if err != nil {
		return err
	}

	return nil
}

// load reads the session from dynamodb.
// returns error if session data does not exist in dynamodb
func (s *DynamoStore) load(session *sessions.Session) error {
	var sessionData DynamoData
	err := s.Table.GetDocument(&dynamodb.Key{HashKey: session.ID}, &sessionData)
	if err != nil {
		return err
	}

	dec := gob.NewDecoder(bytes.NewBuffer(sessionData.Data))
	return dec.Decode(&session.Values)
}

// delete removes keys from redis if MaxAge<0
func (s *DynamoStore) delete(session *sessions.Session) error {
	err := s.Table.DeleteDocument(&dynamodb.Key{HashKey: session.ID})
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Clearer New function implemented.<commit_after>// Copyright 2015 Deniz Eren. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package dynamostore

import (
	"bytes"
	"encoding/base32"
	"encoding/gob"
	"github.com/crowdmob/goamz/aws"
	"github.com/crowdmob/goamz/dynamodb"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"net/http"
	"strings"
)

type DynamoStore struct {
	Table   *dynamodb.Table
	Codecs  []securecookie.Codec
	Options *sessions.Options // default configuration
}

type DynamoData struct {
	Id   string
	Data []byte
}

func NewDynamoStore(accessKey string, secretKey string, tableName string, region string) (*DynamoStore, error) {
	regionObj := aws.GetRegion(region)
	return NewDynamoStoreWithRegionObj(accessKey, secretKey, tableName, regionObj)
}

func NewDynamoStoreWithRegionObj(accessKey string, secretKey string, tableName string, region aws.Region) (*DynamoStore, error) {
	awsAuth := aws.Auth{
		AccessKey: accessKey,
		SecretKey: secretKey,
	}

	server := dynamodb.New(awsAuth, region)
	table := server.NewTable(tableName, dynamodb.PrimaryKey{KeyAttribute: dynamodb.NewStringAttribute("Id", "")})

	dynStore := &DynamoStore{
		Table:  table,
		Codecs: securecookie.CodecsFromPairs([]byte(secretKey)),
	}

	return dynStore, nil
}

// Get returns a session for the given name after adding it to the registry.
//
// See gorilla/sessions FilesystemStore.Get().
// or  boj/redistore
func (s *DynamoStore) Get(r *http.Request, name string) (*sessions.Session, error) {
	return sessions.GetRegistry(r).Get(s, name)
}

func (s *DynamoStore) New(r *http.Request, name string) (*sessions.Session, error) {
	var err error
	session := sessions.NewSession(s, name)

	// make a copy
	options := sessions.Options{}
	session.Options = &options
	session.IsNew = true
	if c, errCookie := r.Cookie(name); errCookie == nil {
		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
		if err == nil {
			err := s.load(session)
			if err == nil {
				session.IsNew = false
			} else {
				session.IsNew = true
			}
		}
	}

	return session, err
}

// Save adds a single session to the response.
func (s *DynamoStore) Save(r *http.Request, w http.ResponseWriter, session *sessions.Session) error {
	// Marked for deletion.
	if session.Options.MaxAge < 0 {
		if err := s.delete(session); err != nil {
			return err
		}
		http.SetCookie(w, sessions.NewCookie(session.Name(), "", session.Options))
	} else {
		// Build an alphanumeric key for the redis store.
		if session.ID == "" {
			session.ID = strings.TrimRight(base32.StdEncoding.EncodeToString(securecookie.GenerateRandomKey(32)), "=")
		}
		if err := s.save(session); err != nil {
			return err
		}
		encoded, err := securecookie.EncodeMulti(session.Name(), session.ID, s.Codecs...)
		if err != nil {
			return err
		}
		http.SetCookie(w, sessions.NewCookie(session.Name(), encoded, session.Options))
	}
	return nil
}

// save stores the session in redis.
func (s *DynamoStore) save(session *sessions.Session) error {
	// TODO expiration date to be added
	// TODO max length to be added
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(session.Values)
	if err != nil {
		return err
	}
	b := buf.Bytes()

	data := &DynamoData{Id: session.ID, Data: b}
	err = s.Table.PutDocument(&dynamodb.Key{HashKey: session.ID}, data)
	if err != nil {
		return err
	}

	return nil
}

// load reads the session from dynamodb.
// returns error if session data does not exist in dynamodb
func (s *DynamoStore) load(session *sessions.Session) error {
	var sessionData DynamoData
	err := s.Table.GetDocument(&dynamodb.Key{HashKey: session.ID}, &sessionData)
	if err != nil {
		return err
	}

	dec := gob.NewDecoder(bytes.NewBuffer(sessionData.Data))
	return dec.Decode(&session.Values)
}

// delete removes keys from redis if MaxAge<0
func (s *DynamoStore) delete(session *sessions.Session) error {
	err := s.Table.DeleteDocument(&dynamodb.Key{HashKey: session.ID})
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package summary

// BoeSummary is a struct to document the different dispositions
// and announcements that have been published on a certain date
type BoeSummary struct {
	Meta    Metadata `xml:"meta"`
	Diaries []Diary  `xml:"diario"`
}

// Metadata is used to provide metainformation that has been published
// in a certain date. Note that all dates from this struct has the
// format dd/mm/yyyy
type Metadata struct {
	BulletinType        string `xml:"pub"`
	PublicationDate     string `xml:"fecha"`
	LastPublicationDate string `xml:"fechaAnt"`
	NextPublicationDate string `xml:"fechaSig"`
}

// Diary contains the information of the dispositions that conform
// each of the bulletins on a certain date
type Diary struct {
	BulletinNumber string     `xml:"nbo,attr"`
	Summary        PdfSummary `xml:"sumario_nbo"`
	Section        []Section  `xml:"seccion"`
}

// PdfSummary contains information of the pdf summary associated to the bulletin
type PdfSummary struct {
	ID   string  `xml:"id,attr"`
	Info PdfInfo `xml:"urlPdf"`
}

// PdfInfo contains file info, like number of pages and size
type PdfInfo struct {
	SizeBytes  string `xml:"szBytes,attr"`
	SizeKBytes string `xml:"szKBytes,attr"`
	Pages      string `xml:"numPages,attr"`
}

// Section is the set os sections that compose the diary
type Section struct {
	Number      string       `xml:"num,attr"`
	Name        string       `xml:"nombre,attr"`
	Departments []Department `xml:"departamento"`
}

// Department contains the relative data to the various departments  which have
// been published dispositions belonging the current section
type Department struct {
}
<commit_msg>Renamed struct field to make it more verbose<commit_after>package summary

// BoeSummary is a struct to document the different dispositions
// and announcements that have been published on a certain date
type BoeSummary struct {
	Meta    Metadata `xml:"meta"`
	Diaries []Diary  `xml:"diario"`
}

// Metadata is used to provide metainformation that has been published
// in a certain date. Note that all dates from this struct has the
// format dd/mm/yyyy
type Metadata struct {
	BulletinType        string `xml:"pub"`
	PublicationDate     string `xml:"fecha"`
	LastPublicationDate string `xml:"fechaAnt"`
	NextPublicationDate string `xml:"fechaSig"`
}

// Diary contains the information of the dispositions that conform
// each of the bulletins on a certain date
type Diary struct {
	BulletinNumber string     `xml:"nbo,attr"`
	Summary        PdfSummary `xml:"sumario_nbo"`
	Sections       []Section  `xml:"seccion"`
}

// PdfSummary contains information of the pdf summary associated to the bulletin
type PdfSummary struct {
	ID   string  `xml:"id,attr"`
	Info PdfInfo `xml:"urlPdf"`
}

// PdfInfo contains file info, like number of pages and size
type PdfInfo struct {
	SizeBytes  string `xml:"szBytes,attr"`
	SizeKBytes string `xml:"szKBytes,attr"`
	Pages      string `xml:"numPages,attr"`
}

// Section is the set os sections that compose the diary
type Section struct {
	Number      string       `xml:"num,attr"`
	Name        string       `xml:"nombre,attr"`
	Departments []Department `xml:"departamento"`
}

// Department contains the relative data to the various departments  which have
// been published dispositions belonging the current section
type Department struct {
}
<|endoftext|>


<commit_before>package memfs

import (
	"errors"
	"io"
	"os"
)

// Buffer is a usable block of data similar to a file
type Buffer interface {
	io.Reader
	io.Writer
	io.Seeker
	io.Closer
}

// MinBufferSize is the minimal initial allocated buffer size
const MinBufferSize = 512

// ErrTooLarge is thrown if it was not possible to enough memory
var ErrTooLarge = errors.New("Volume too large")

// Buf is a Buffer working on a slice of bytes.
type Buf struct {
	buf *[]byte
	ptr int64
}

// NewBuffer creates a new data volume based on a buffer
func NewBuffer(buf *[]byte) *Buf {
	return &Buf{
		buf: buf,
	}
}

// Seek sets the offset for the next Read or Write on the buffer to offset,
// interpreted according to whence:
// 	0 (os.SEEK_SET) means relative to the origin of the file
// 	1 (os.SEEK_CUR) means relative to the current offset
// 	2 (os.SEEK_END) means relative to the end of the file
// It returns the new offset and an error, if any.
func (v *Buf) Seek(offset int64, whence int) (int64, error) {
	var abs int64
	switch whence {
	case os.SEEK_SET: // Relative to the origin of the file
		abs = offset
	case os.SEEK_CUR: // Relative to the current offset
		abs = int64(v.ptr) + offset
	case os.SEEK_END: // Relative to the end
		abs = int64(len(*v.buf)) + offset
	default:
		return 0, errors.New("Seek: invalid whence")
	}
	if abs < 0 {
		return 0, errors.New("Seek: negative position")
	}
	if abs > int64(len(*v.buf)) {
		return 0, errors.New("Seek: too far")
	}
	v.ptr = abs
	return abs, nil
}

// Write writes len(p) byte to the Buffer.
// It returns the number of bytes written and an error if any.
// Write returns non-nil error when n!=len(p).
func (v *Buf) Write(p []byte) (int, error) {
	l := len(p)
	err := v.grow(l)
	if err != nil {
		return 0, err
	}
	copy((*v.buf)[v.ptr:], p)
	v.ptr += int64(l)
	return l, nil
}

// Close the buffer. Currently no effect.
func (v *Buf) Close() error {
	return nil
}

// Read reads len(p) byte from the Buffer starting at the current offset.
// It returns the number of bytes read and an error if any.
// Returns io.EOF error if pointer is at the end of the Buffer.
func (v *Buf) Read(p []byte) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}
	if v.ptr >= int64(len(*v.buf)) {
		return 0, io.EOF
	}

	n = copy(p, (*v.buf)[v.ptr:])
	v.ptr += int64(n)
	return
}

func (v *Buf) grow(n int) error {
	m := len(*v.buf)
	if (m + n) > cap(*v.buf) {
		size := 2*cap(*v.buf) + MinBufferSize
		if size < n {
			size = n + MinBufferSize
		}
		buf, err := makeSlice(size)
		if err != nil {
			return err
		}
		copy(buf, *v.buf)
		*v.buf = buf
	}
	*v.buf = (*v.buf)[0 : m+n]
	return nil
}

// makeSlice allocates a slice of size n. If the allocation fails, it panics
// with ErrTooLarge.
func makeSlice(n int) (b []byte, err error) {
	// If the make fails, give a known error.
	defer func() {
		if recover() != nil {
			b = nil
			err = ErrTooLarge
			return
		}
	}()
	b = make([]byte, n)
	return
}
<commit_msg>fix(memfs): panic caused by large writes<commit_after>package memfs

import (
	"errors"
	"io"
	"os"
)

// Buffer is a usable block of data similar to a file
type Buffer interface {
	io.Reader
	io.Writer
	io.Seeker
	io.Closer
}

// MinBufferSize is the minimal initial allocated buffer size
const MinBufferSize = 512

// ErrTooLarge is thrown if it was not possible to enough memory
var ErrTooLarge = errors.New("Volume too large")

// Buf is a Buffer working on a slice of bytes.
type Buf struct {
	buf *[]byte
	ptr int64
}

// NewBuffer creates a new data volume based on a buffer
func NewBuffer(buf *[]byte) *Buf {
	return &Buf{
		buf: buf,
	}
}

// Seek sets the offset for the next Read or Write on the buffer to offset,
// interpreted according to whence:
// 	0 (os.SEEK_SET) means relative to the origin of the file
// 	1 (os.SEEK_CUR) means relative to the current offset
// 	2 (os.SEEK_END) means relative to the end of the file
// It returns the new offset and an error, if any.
func (v *Buf) Seek(offset int64, whence int) (int64, error) {
	var abs int64
	switch whence {
	case os.SEEK_SET: // Relative to the origin of the file
		abs = offset
	case os.SEEK_CUR: // Relative to the current offset
		abs = int64(v.ptr) + offset
	case os.SEEK_END: // Relative to the end
		abs = int64(len(*v.buf)) + offset
	default:
		return 0, errors.New("Seek: invalid whence")
	}
	if abs < 0 {
		return 0, errors.New("Seek: negative position")
	}
	if abs > int64(len(*v.buf)) {
		return 0, errors.New("Seek: too far")
	}
	v.ptr = abs
	return abs, nil
}

// Write writes len(p) byte to the Buffer.
// It returns the number of bytes written and an error if any.
// Write returns non-nil error when n!=len(p).
func (v *Buf) Write(p []byte) (int, error) {
	l := len(p)
	err := v.grow(l)
	if err != nil {
		return 0, err
	}
	copy((*v.buf)[v.ptr:], p)
	v.ptr += int64(l)
	return l, nil
}

// Close the buffer. Currently no effect.
func (v *Buf) Close() error {
	return nil
}

// Read reads len(p) byte from the Buffer starting at the current offset.
// It returns the number of bytes read and an error if any.
// Returns io.EOF error if pointer is at the end of the Buffer.
func (v *Buf) Read(p []byte) (n int, err error) {
	if len(p) == 0 {
		return 0, nil
	}
	if v.ptr >= int64(len(*v.buf)) {
		return 0, io.EOF
	}

	n = copy(p, (*v.buf)[v.ptr:])
	v.ptr += int64(n)
	return
}

func (v *Buf) grow(n int) error {
	m := len(*v.buf)
	if (m + n) > cap(*v.buf) {
		size := 2*cap(*v.buf) + MinBufferSize
		if size < m+n {
			size = m + n + MinBufferSize
		}
		buf, err := makeSlice(size)
		if err != nil {
			return err
		}
		copy(buf, *v.buf)
		*v.buf = buf
	}
	*v.buf = (*v.buf)[0 : m+n]
	return nil
}

// makeSlice allocates a slice of size n. If the allocation fails, it panics
// with ErrTooLarge.
func makeSlice(n int) (b []byte, err error) {
	// If the make fails, give a known error.
	defer func() {
		if recover() != nil {
			b = nil
			err = ErrTooLarge
			return
		}
	}()
	b = make([]byte, n)
	return
}
<|endoftext|>


<commit_before>package gitmedia

import (
	"bytes"
	"io"
)

var MediaWarning = []byte("# external\n")

func Encode(writer io.Writer, sha string) (int, error) {
	written, err := writer.Write(MediaWarning)
	if err != nil {
		return written, err
	}

	written2, err := writer.Write([]byte(sha))
	return written + written2, err
}

func Decode(reader io.Reader) (string, error) {
	buf := make([]byte, 100)
	written, err := reader.Read(buf)
	if err != nil {
		return "", err
	}

	return lastNonEmpty(bytes.Split(buf[0:written], []byte("\n"))), nil
}

func lastNonEmpty(parts [][]byte) string {
	idx := len(parts)
	var part []byte
	for len(part) == 0 {
		idx -= 1
		part = parts[idx]
	}
	return string(part)
}
<commit_msg>add an ending linebreak to the meta file that's written to git<commit_after>package gitmedia

import (
	"bytes"
	"io"
)

var MediaWarning = []byte("# external\n")

func Encode(writer io.Writer, sha string) (int, error) {
	written, err := writer.Write(MediaWarning)
	if err != nil {
		return written, err
	}

	written2, err := writer.Write([]byte(sha + "\n"))
	return written + written2, err
}

func Decode(reader io.Reader) (string, error) {
	buf := make([]byte, 100)
	written, err := reader.Read(buf)
	if err != nil {
		return "", err
	}

	return lastNonEmpty(bytes.Split(buf[0:written], []byte("\n"))), nil
}

func lastNonEmpty(parts [][]byte) string {
	idx := len(parts)
	var part []byte
	for len(part) == 0 {
		idx -= 1
		part = parts[idx]
	}
	return string(part)
}
<|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 ogletest

import (
	. "github.com/jacobsa/oglematchers"
	"reflect"
	"testing"
)

func TestRegisterMethodsTest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type MethodsTest struct {
}

func init() { RegisterTestSuite(&MethodsTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *MethodsTest) NoMethods() {
	type foo int
	methods := getMethodsInSourceOrder(reflect.TypeOf(foo(17)))

	ExpectThat(methods, ElementsAre())
}

func (t *MethodsTest) OneMethod() {
	ExpectEq("TODO", "")
}

func (t *MethodsTest) MultipleMethods() {
	ExpectEq("TODO", "")
}

func (t *MethodsTest) MultipleMethodsOnSingleLine() {
	ExpectEq("TODO", "")
}
<commit_msg>MethodsTest.OneMethod<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 ogletest

import (
	. "github.com/jacobsa/oglematchers"
	"reflect"
	"testing"
)

func TestRegisterMethodsTest(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type MethodsTest struct {
}

func init() { RegisterTestSuite(&MethodsTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *MethodsTest) NoMethods() {
	type foo int

	methods := getMethodsInSourceOrder(reflect.TypeOf(foo(17)))
	ExpectThat(methods, ElementsAre())
}

func (t *MethodsTest) OneMethod() {
	type foo int
	func (f foo) Foo() {}

	methods := getMethodsInSourceOrder(reflect.TypeOf(foo(17)))
	AssertThat(methods, ElementsAre(Any()))

	ExpectEq("foo", methods[0].Name)
}

func (t *MethodsTest) MultipleMethods() {
	ExpectEq("TODO", "")
}

func (t *MethodsTest) MultipleMethodsOnSingleLine() {
	ExpectEq("TODO", "")
}
<|endoftext|>