<commit_before>package godbg

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"regexp"
	"runtime/debug"
	"strings"
)

// http://stackoverflow.com/a/23554672/6309 https://vividcortex.com/blog/2013/12/03/go-idiom-package-and-object/
// you design a type with methods as usual, and then you also place matching functions at the package level itself.
// These functions simply delegate to a default instance of the type that’s a private package-level variable, created in an init() function.

// Pdbg allows to print debug message with indent and function name added
type Pdbg struct {
	bout *bytes.Buffer
	berr *bytes.Buffer
	sout *bufio.Writer
	serr *bufio.Writer
}

// Out returns a writer for normal messages.
// By default, os.StdOut
func Out() io.Writer {
	return pdbg.Out()
}

// Out returns a writer for normal messages for a given pdbg instance.
// By default, os.StdOut
func (pdbg *Pdbg) Out() io.Writer {
	if pdbg.sout == nil {
		return os.Stdout
	}
	return pdbg.sout
}

// Err returns a writer for error messages.
// By default, os.StdErr
func Err() io.Writer {
	return pdbg.Err()
}

// Err returns a writer for error messages for a given pdbg instance.
// By default, os.StdErr
func (pdbg *Pdbg) Err() io.Writer {
	if pdbg.serr == nil {
		return os.Stderr
	}
	return pdbg.serr
}

// global pdbg used for printing
var pdbg = &Pdbg{}

// Option set an option for a Pdbg
// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
type Option func(*Pdbg)

// SetBuffers is an option for replacing stdout and stderr by
// bytes buffers (in a bufio.Writer).
// If apdbg is nil, set for the global pdbg instance
func SetBuffers(apdbg *Pdbg) {
	if apdbg == nil {
		apdbg = pdbg
	}
	apdbg.bout = bytes.NewBuffer(nil)
	apdbg.sout = bufio.NewWriter(apdbg.bout)
	apdbg.berr = bytes.NewBuffer(nil)
	apdbg.serr = bufio.NewWriter(apdbg.berr)
}

// NewPdbg creates a PDbg instance, with options
func NewPdbg(options ...Option) *Pdbg {
	newpdbg := &Pdbg{}
	for _, option := range options {
		option(newpdbg)
	}
	return newpdbg
}

// ResetIOs reset the out and err buffer of global pdbg instance
func ResetIOs() {
	pdbg.ResetIOs()
}

// ResetIOs reset the out and err buffer
// (unless they were the default stdout and stderr,
// in which case it does nothing)
func (pdbg *Pdbg) ResetIOs() {
	if pdbg.sout != nil {
		pdbg.bout = bytes.NewBuffer(nil)
		pdbg.sout.Reset(pdbg.bout)
		pdbg.berr = bytes.NewBuffer(nil)
		pdbg.serr.Reset(pdbg.berr)
	}
}

// OutString returns the string for out messages for the global pdbg instance.
// It flushes the out buffer.
// If out is set to os.Stdout, returns an empty string
func OutString() string {
	return pdbg.OutString()
}

// OutString returns the string for out messages for a given pdbg instance.
// It flushes the out buffer.
// If out is set to os.Stdout, returns an empty string
func (pdbg *Pdbg) OutString() string {
	if pdbg.sout == nil {
		return ""
	}
	pdbg.sout.Flush()
	return pdbg.bout.String()
}

// ErrString returns the string for error messages for the global pdbg instance.
// It flushes the err buffer.
// If err is set to os.StdErr, returns an empty string
func ErrString() string {
	return pdbg.ErrString()
}

// ErrString returns the string for error messages for a given pdbg instance.
// It flushes the err buffer.
// If err is set to os.StdErr, returns an empty string
func (pdbg *Pdbg) ErrString() string {
	if pdbg.serr == nil {
		return ""
	}
	pdbg.serr.Flush()
	return pdbg.berr.String()
}

// For instance: github.com/VonC/godbg/_test/_obj_test/gogdb.go:174 (0x44711b)
var rxDbgLine, _ = regexp.Compile(`^.*\.go:(\d+)\s`)
var rxDbgFnct, _ = regexp.Compile(`^\s+(?:.*?\(([^\)]+)\))?\.?([^:]+)`)

func pdbgInc(scanner *bufio.Scanner, dbgLine string) string {
	scanner.Scan()
	line := scanner.Text()
	mf := rxDbgFnct.FindSubmatchIndex([]byte(line))
	// fmt.Printf("lineF '%v', mf '%+v'\n", line, mf)
	if len(mf) == 0 {
		return ""
	}
	dbgFnct := ""
	if mf[2] > -1 {
		dbgFnct = line[mf[2]:mf[3]]
	}
	if dbgFnct != "" {
		dbgFnct = dbgFnct + "."
	}
	dbgFnct = dbgFnct + line[mf[4]:mf[5]]

	return dbgFnct + ":" + dbgLine
}

func pdbgExcluded(dbg string) bool {
	if strings.Contains(dbg, "ReadConfig:") {
		return false
	}
	return false
}

// Pdbgf uses global Pdbg variable for printing strings, with indent and function name
func Pdbgf(format string, args ...interface{}) string {
	return pdbg.Pdbgf(format, args...)
}

// Pdbgf uses custom Pdbg variable for printing strings, with indent and function name
func (pdbg *Pdbg) Pdbgf(format string, args ...interface{}) string {
	msg := fmt.Sprintf(format+"\n", args...)
	msg = strings.TrimSpace(msg)
	bstack := bytes.NewBuffer(debug.Stack())
	// fmt.Printf("%+v\n", bstack)

	scanner := bufio.NewScanner(bstack)
	pmsg := ""
	depth := 0
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, "/_obj_test/") {
			depth = 1
			continue
		}
		if strings.Contains(line, "smartystreets") {
			break
		}
		m := rxDbgLine.FindSubmatchIndex([]byte(line))
		// fmt.Printf("'%s' (%s) => '%+v'\n", line, rxDbgLine.String(), m)
		if len(m) == 0 {
			continue
		}
		if depth > 0 && depth < 4 {
			dbg := pdbgInc(scanner, line[m[2]:m[3]])
			if dbg == "" {
				continue
			}
			if depth == 1 {
				if pdbgExcluded(dbg) {
					return ""
				}
				pmsg = "[" + dbg + "]"
			} else {
				pmsg = pmsg + " (" + dbg + ")"
			}
		}
		depth = depth + 1
	}
	spaces := ""
	if depth >= 2 {
		spaces = strings.Repeat(" ", depth-2)
	}
	// fmt.Printf("spaces '%s', depth '%d'\n", spaces, depth)
	res := pmsg
	pmsg = spaces + pmsg
	msg = pmsg + "\n" + spaces + "  " + msg + "\n"
	// fmt.Printf("MSG '%v'\n", msg)
	fmt.Fprint(pdbg.Err(), fmt.Sprint(msg))
	return res
}
<commit_msg>Comment a non-testable case in pdbgInc()<commit_after>package godbg

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"regexp"
	"runtime/debug"
	"strings"
)

// http://stackoverflow.com/a/23554672/6309 https://vividcortex.com/blog/2013/12/03/go-idiom-package-and-object/
// you design a type with methods as usual, and then you also place matching functions at the package level itself.
// These functions simply delegate to a default instance of the type that’s a private package-level variable, created in an init() function.

// Pdbg allows to print debug message with indent and function name added
type Pdbg struct {
	bout *bytes.Buffer
	berr *bytes.Buffer
	sout *bufio.Writer
	serr *bufio.Writer
}

// Out returns a writer for normal messages.
// By default, os.StdOut
func Out() io.Writer {
	return pdbg.Out()
}

// Out returns a writer for normal messages for a given pdbg instance.
// By default, os.StdOut
func (pdbg *Pdbg) Out() io.Writer {
	if pdbg.sout == nil {
		return os.Stdout
	}
	return pdbg.sout
}

// Err returns a writer for error messages.
// By default, os.StdErr
func Err() io.Writer {
	return pdbg.Err()
}

// Err returns a writer for error messages for a given pdbg instance.
// By default, os.StdErr
func (pdbg *Pdbg) Err() io.Writer {
	if pdbg.serr == nil {
		return os.Stderr
	}
	return pdbg.serr
}

// global pdbg used for printing
var pdbg = &Pdbg{}

// Option set an option for a Pdbg
// http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
type Option func(*Pdbg)

// SetBuffers is an option for replacing stdout and stderr by
// bytes buffers (in a bufio.Writer).
// If apdbg is nil, set for the global pdbg instance
func SetBuffers(apdbg *Pdbg) {
	if apdbg == nil {
		apdbg = pdbg
	}
	apdbg.bout = bytes.NewBuffer(nil)
	apdbg.sout = bufio.NewWriter(apdbg.bout)
	apdbg.berr = bytes.NewBuffer(nil)
	apdbg.serr = bufio.NewWriter(apdbg.berr)
}

// NewPdbg creates a PDbg instance, with options
func NewPdbg(options ...Option) *Pdbg {
	newpdbg := &Pdbg{}
	for _, option := range options {
		option(newpdbg)
	}
	return newpdbg
}

// ResetIOs reset the out and err buffer of global pdbg instance
func ResetIOs() {
	pdbg.ResetIOs()
}

// ResetIOs reset the out and err buffer
// (unless they were the default stdout and stderr,
// in which case it does nothing)
func (pdbg *Pdbg) ResetIOs() {
	if pdbg.sout != nil {
		pdbg.bout = bytes.NewBuffer(nil)
		pdbg.sout.Reset(pdbg.bout)
		pdbg.berr = bytes.NewBuffer(nil)
		pdbg.serr.Reset(pdbg.berr)
	}
}

// OutString returns the string for out messages for the global pdbg instance.
// It flushes the out buffer.
// If out is set to os.Stdout, returns an empty string
func OutString() string {
	return pdbg.OutString()
}

// OutString returns the string for out messages for a given pdbg instance.
// It flushes the out buffer.
// If out is set to os.Stdout, returns an empty string
func (pdbg *Pdbg) OutString() string {
	if pdbg.sout == nil {
		return ""
	}
	pdbg.sout.Flush()
	return pdbg.bout.String()
}

// ErrString returns the string for error messages for the global pdbg instance.
// It flushes the err buffer.
// If err is set to os.StdErr, returns an empty string
func ErrString() string {
	return pdbg.ErrString()
}

// ErrString returns the string for error messages for a given pdbg instance.
// It flushes the err buffer.
// If err is set to os.StdErr, returns an empty string
func (pdbg *Pdbg) ErrString() string {
	if pdbg.serr == nil {
		return ""
	}
	pdbg.serr.Flush()
	return pdbg.berr.String()
}

// For instance: github.com/VonC/godbg/_test/_obj_test/gogdb.go:174 (0x44711b)
var rxDbgLine, _ = regexp.Compile(`^.*\.go:(\d+)\s`)
var rxDbgFnct, _ = regexp.Compile(`^\s+(?:.*?\(([^\)]+)\))?\.?([^:]+)`)

func pdbgInc(scanner *bufio.Scanner, dbgLine string) string {
	scanner.Scan()
	line := scanner.Text()
	mf := rxDbgFnct.FindSubmatchIndex([]byte(line))
	// fmt.Printf("lineF '%v', mf '%+v'\n", line, mf)
	/*if len(mf) == 0 {
		return ""
	}*/
	dbgFnct := ""
	if mf[2] > -1 {
		dbgFnct = line[mf[2]:mf[3]]
	}
	if dbgFnct != "" {
		dbgFnct = dbgFnct + "."
	}
	dbgFnct = dbgFnct + line[mf[4]:mf[5]]

	return dbgFnct + ":" + dbgLine
}

func pdbgExcluded(dbg string) bool {
	if strings.Contains(dbg, "ReadConfig:") {
		return false
	}
	return false
}

// Pdbgf uses global Pdbg variable for printing strings, with indent and function name
func Pdbgf(format string, args ...interface{}) string {
	return pdbg.Pdbgf(format, args...)
}

// Pdbgf uses custom Pdbg variable for printing strings, with indent and function name
func (pdbg *Pdbg) Pdbgf(format string, args ...interface{}) string {
	msg := fmt.Sprintf(format+"\n", args...)
	msg = strings.TrimSpace(msg)
	bstack := bytes.NewBuffer(debug.Stack())
	// fmt.Printf("%+v\n", bstack)

	scanner := bufio.NewScanner(bstack)
	pmsg := ""
	depth := 0
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, "/_obj_test/") {
			depth = 1
			continue
		}
		if strings.Contains(line, "smartystreets") {
			break
		}
		m := rxDbgLine.FindSubmatchIndex([]byte(line))
		// fmt.Printf("'%s' (%s) => '%+v'\n", line, rxDbgLine.String(), m)
		if len(m) == 0 {
			continue
		}
		if depth > 0 && depth < 4 {
			dbg := pdbgInc(scanner, line[m[2]:m[3]])
			if dbg == "" {
				continue
			}
			if depth == 1 {
				if pdbgExcluded(dbg) {
					return ""
				}
				pmsg = "[" + dbg + "]"
			} else {
				pmsg = pmsg + " (" + dbg + ")"
			}
		}
		depth = depth + 1
	}
	spaces := ""
	if depth >= 2 {
		spaces = strings.Repeat(" ", depth-2)
	}
	// fmt.Printf("spaces '%s', depth '%d'\n", spaces, depth)
	res := pmsg
	pmsg = spaces + pmsg
	msg = pmsg + "\n" + spaces + "  " + msg + "\n"
	// fmt.Printf("MSG '%v'\n", msg)
	fmt.Fprint(pdbg.Err(), fmt.Sprint(msg))
	return res
}
<|endoftext|>


<commit_before>package golis

import (
	"log"
	"net"
	"sync"
	"time"
)

//系统变量定义
var (
	GolisHandler IoHandler            //事件处理
	GolisPackage Packager             //拆包封包处理接口
	w            WaitGroupWrapper     //等待退出
	runnable     bool                 //服务运行状态
	rwTimeout    time.Duration    = 0 //超时单位秒
)

//定义waitGroup
type WaitGroupWrapper struct {
	sync.WaitGroup
}

//定义session
type Iosession struct {
	SesionId   uint32   //session唯一表示
	Connection net.Conn //连接
	IsAuth     bool     //是否认证成功
	closed     bool     //是否已经关闭
}

//session写入数据
func (this *Iosession) Write(message interface{}) {
	//触发消息发送事件
	GolisHandler.MessageSent(this, message)
	this.Connection.Write(GolisPackage.Packet(message))
}

//关闭连接
func (this *Iosession) Close() {
	if !this.closed {
		GolisHandler.SessionClosed(this)
		this.closed = true
	}
	this.Connection.Close()
}

//设置读写超时
func SetTimeout(timeoutSec time.Duration) {
	rwTimeout = timeoutSec
}

//拆包封包接口定义
type Packager interface {
	//读取连接数据
	//packageChan 准备好包后交给该chan
	ReadConnData(buffer *Buffer, packageChan chan<- *[]byte)
	//拆包函数
	Unpacket(data []byte) interface{}
	//封包函数
	Packet(msg interface{}) []byte
}

//事件触发接口定义
type IoHandler interface {
	//session打开
	SessionOpened(session *Iosession)
	//session关闭
	SessionClosed(session *Iosession)
	//收到消息时触发
	MessageReceived(session *Iosession, message interface{})
	//消息发送时触发
	MessageSent(session *Iosession, message interface{})
}

//服务器端运行golis
//netPro：运行协议参数，tcp/udp
//laddr ：程序监听ip和端口，如127.0.0.1:8080
func Run(netPro, laddr string) {
	runnable = true
	log.Println("golis is listen port:", laddr)

	netLis, err := net.Listen(netPro, laddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer netLis.Close()
	log.Println("waiting clients...")
	for runnable {
		conn, err := netLis.Accept()
		if err != nil {
			continue
		}
		go connectHandle(conn)
	}

	w.WaitGroup.Wait()
	log.Println("golis is safe exit")
}

//停止服务
func Stop() {
	runnable = false
}

//客户端程序连接服务器
func Dial(netPro, laddr string) {
	runnable = true
	conn, err := net.Dial(netPro, laddr)
	if err != nil {
		log.Fatalln(err)
	}
	go connectHandle(conn)
}

//处理新连接
func connectHandle(conn net.Conn) {
	w.Add(1)
	//声明一个临时缓冲区，用来存储被截断的数据
	ioBuffer := NewBuffer()

	buffer := make([]byte, 512)

	//声明一个管道用于接收解包的数据
	readerChannel := make(chan *[]byte, 16)
	//创建session
	session := Iosession{Connection: conn}
	//触发sessionCreated事件
	GolisHandler.SessionOpened(&session)

	exitChan := make(chan bool)
	go waitData(&session, readerChannel, exitChan)
	defer func() {
		conn.Close()
		ioBuffer = nil
		buffer = nil
		if err := recover(); err != nil {
			log.Println(err)
		}
		w.Done()
	}()

	for runnable && !session.closed {

		n, err := conn.Read(buffer)
		//设置超时
		//resetTimeout(conn)
		ioBuffer.PutBytes(buffer[:n])
		if err == nil {
			GolisPackage.ReadConnData(ioBuffer, readerChannel)
		} else {
			//session已经关闭
			session.Close()
			exitChan <- true
			return
		}
		if !runnable || session.closed {
			//session关闭
			session.Close()
			exitChan <- true
			return
		}

	}

}

func resetTimeout(conn net.Conn) {
	if rwTimeout == 0 {
		conn.SetDeadline(time.Time{})
	} else {
		conn.SetDeadline(time.Now().Add(time.Duration(rwTimeout) * time.Second))
	}
}

//等待数据包
func waitData(session *Iosession, readerChannel chan *[]byte, exitChan chan bool) {
	defer func() {
		close(exitChan)
		close(readerChannel)
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()
	for runnable && !session.closed {
		select {
		case data := <-readerChannel:
			readFromData(session, data)
		case <-exitChan:
			return
		}
	}
}

//从准备好的数据读取并拆包
func readFromData(session *Iosession, data *[]byte) {
	message := GolisPackage.Unpacket(*data) //拆包
	//收到消息到达时触发事件
	GolisHandler.MessageReceived(session, message)
}
<commit_msg>修改sessionId类型为int32<commit_after>package golis

import (
	"log"
	"net"
	"sync"
	"time"
)

//系统变量定义
var (
	GolisHandler IoHandler            //事件处理
	GolisPackage Packager             //拆包封包处理接口
	w            WaitGroupWrapper     //等待退出
	runnable     bool                 //服务运行状态
	rwTimeout    time.Duration    = 0 //超时单位秒
)

//定义waitGroup
type WaitGroupWrapper struct {
	sync.WaitGroup
}

//定义session
type Iosession struct {
	SesionId   int32    //session唯一表示
	Connection net.Conn //连接
	IsAuth     bool     //是否认证成功
	closed     bool     //是否已经关闭
}

//session写入数据
func (this *Iosession) Write(message interface{}) {
	//触发消息发送事件
	GolisHandler.MessageSent(this, message)
	this.Connection.Write(GolisPackage.Packet(message))
}

//关闭连接
func (this *Iosession) Close() {
	if !this.closed {
		GolisHandler.SessionClosed(this)
		this.closed = true
	}
	this.Connection.Close()
}

//设置读写超时
func SetTimeout(timeoutSec time.Duration) {
	rwTimeout = timeoutSec
}

//拆包封包接口定义
type Packager interface {
	//读取连接数据
	//packageChan 准备好包后交给该chan
	ReadConnData(buffer *Buffer, packageChan chan<- *[]byte)
	//拆包函数
	Unpacket(data []byte) interface{}
	//封包函数
	Packet(msg interface{}) []byte
}

//事件触发接口定义
type IoHandler interface {
	//session打开
	SessionOpened(session *Iosession)
	//session关闭
	SessionClosed(session *Iosession)
	//收到消息时触发
	MessageReceived(session *Iosession, message interface{})
	//消息发送时触发
	MessageSent(session *Iosession, message interface{})
}

//服务器端运行golis
//netPro：运行协议参数，tcp/udp
//laddr ：程序监听ip和端口，如127.0.0.1:8080
func Run(netPro, laddr string) {
	runnable = true
	log.Println("golis is listen port:", laddr)

	netLis, err := net.Listen(netPro, laddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer netLis.Close()
	log.Println("waiting clients...")
	for runnable {
		conn, err := netLis.Accept()
		if err != nil {
			continue
		}
		go connectHandle(conn)
	}

	w.WaitGroup.Wait()
	log.Println("golis is safe exit")
}

//停止服务
func Stop() {
	runnable = false
}

//客户端程序连接服务器
func Dial(netPro, laddr string) {
	runnable = true
	conn, err := net.Dial(netPro, laddr)
	if err != nil {
		log.Fatalln(err)
	}
	go connectHandle(conn)
}

//处理新连接
func connectHandle(conn net.Conn) {
	w.Add(1)
	//声明一个临时缓冲区，用来存储被截断的数据
	ioBuffer := NewBuffer()

	buffer := make([]byte, 512)

	//声明一个管道用于接收解包的数据
	readerChannel := make(chan *[]byte, 16)
	//创建session
	session := Iosession{Connection: conn}
	//触发sessionCreated事件
	GolisHandler.SessionOpened(&session)

	exitChan := make(chan bool)
	go waitData(&session, readerChannel, exitChan)
	defer func() {
		conn.Close()
		ioBuffer = nil
		buffer = nil
		if err := recover(); err != nil {
			log.Println(err)
		}
		w.Done()
	}()

	for runnable && !session.closed {

		n, err := conn.Read(buffer)
		//设置超时
		//resetTimeout(conn)
		ioBuffer.PutBytes(buffer[:n])
		if err == nil {
			GolisPackage.ReadConnData(ioBuffer, readerChannel)
		} else {
			//session已经关闭
			session.Close()
			exitChan <- true
			return
		}
		if !runnable || session.closed {
			//session关闭
			session.Close()
			exitChan <- true
			return
		}

	}

}

func resetTimeout(conn net.Conn) {
	if rwTimeout == 0 {
		conn.SetDeadline(time.Time{})
	} else {
		conn.SetDeadline(time.Now().Add(time.Duration(rwTimeout) * time.Second))
	}
}

//等待数据包
func waitData(session *Iosession, readerChannel chan *[]byte, exitChan chan bool) {
	defer func() {
		close(exitChan)
		close(readerChannel)
		if err := recover(); err != nil {
			log.Println(err)
		}
	}()
	for runnable && !session.closed {
		select {
		case data := <-readerChannel:
			readFromData(session, data)
		case <-exitChan:
			return
		}
	}
}

//从准备好的数据读取并拆包
func readFromData(session *Iosession, data *[]byte) {
	message := GolisPackage.Unpacket(*data) //拆包
	//收到消息到达时触发事件
	GolisHandler.MessageReceived(session, message)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

// TODO: update main to permit calling with some log filename.
func main() {
	file := "log.txt"
	f, err := getOrMakeFile(file)
	if err != nil {
		log.Fatal(err)
	}
	// ch will serve as a many-to-one mux for log messages
	ch := writeLog(f)
	http.HandleFunc("/log", handleLog(ch))
	log.Fatal(http.ListenAndServe(":8080", nil))
}

// getOrMakeFile either opens (write-only, in append mode) an existing file, or creates one.
func getOrMakeFile(file string) (*os.File, error) {
	f, err := os.OpenFile(file, os.O_WRONLY|os.O_APPEND, 0660)
	if err != nil {
		e := err.(*os.PathError)
		if os.IsNotExist(e) {
			return os.Create(file)
		}
		return nil, e
	}
	return f, err
}

// handleLog is an http handler which logs the received id, msg to STDOUT
// and writes the msg, id to the given channel.
func handleLog(ch chan string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to parse args: %s", err.Error()), http.StatusBadRequest)
			return
		}
		id := r.FormValue("id")
		msg := r.FormValue("msg")
		if id == "" {
			http.Error(w, "id missing", http.StatusBadRequest)
			return
		}
		if msg == "" {
			http.Error(w, "msg missing", http.StatusBadRequest)
			return
		}
		m := fmt.Sprintf("client %s: %s", id, msg)
		fmt.Fprintf(w, m)
		ch <- m
	}
}

// writeLog will return a channel to write log messages to.  Received messages will
// get appended to the given file.
func writeLog(file *os.File) chan string {
	ch := make(chan string)
	lgr := log.New(file, "golog: ", log.LstdFlags)
	go func() {
		defer file.Close()
		for {
			m, ok := <-ch
			if !ok {
				break
			}
			log.Println(m)
			lgr.Println(m)
		}
	}()

	return ch
}
<commit_msg>Add flag parse for -logfile<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
)

var (
	logfile = flag.String("logfile", "log.txt", "path to log file")
)

func main() {
	flag.Parse()
	f, err := getOrMakeFile(*logfile)
	if err != nil {
		log.Fatal(err)
	}
	// ch will serve as a many-to-one mux for log messages
	ch := writeLog(f)
	http.HandleFunc("/log", handleLog(ch))
	log.Fatal(http.ListenAndServe(":8080", nil))
}

// getOrMakeFile either opens (write-only, in append mode) an existing file, or creates one.
func getOrMakeFile(file string) (*os.File, error) {
	f, err := os.OpenFile(file, os.O_WRONLY|os.O_APPEND, 0660)
	if err != nil {
		e := err.(*os.PathError)
		if os.IsNotExist(e) {
			return os.Create(file)
		}
		return nil, e
	}
	return f, err
}

// handleLog is an http handler which logs the received id, msg to STDOUT
// and writes the msg, id to the given channel.
func handleLog(ch chan string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()
		if err != nil {
			http.Error(w, fmt.Sprintf("failed to parse args: %s", err.Error()), http.StatusBadRequest)
			return
		}
		id := r.FormValue("id")
		msg := r.FormValue("msg")
		if id == "" {
			http.Error(w, "id missing", http.StatusBadRequest)
			return
		}
		if msg == "" {
			http.Error(w, "msg missing", http.StatusBadRequest)
			return
		}
		m := fmt.Sprintf("client %s: %s", id, msg)
		fmt.Fprintf(w, m)
		ch <- m
	}
}

// writeLog will return a channel to write log messages to.  Received messages will
// get appended to the given file.
func writeLog(file *os.File) chan string {
	ch := make(chan string)
	lgr := log.New(file, "golog: ", log.LstdFlags)
	go func() {
		defer file.Close()
		for {
			m, ok := <-ch
			if !ok {
				break
			}
			log.Println(m)
			lgr.Println(m)
		}
	}()

	return ch
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/base64"
	"errors"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
)

// URLCookie - cookie which stores page url
const URLCookie = "X-GoPee-URL"

// GopeeEncPrefix - encoding prefix used while encoding urls
const GopeeEncPrefix = "xox"

// Pre-compile RegEx
var reBase = regexp.MustCompile(`base +href="(.*?)"`)
var reHTML = regexp.MustCompile(`\saction=["']?(.*?)["'\s]|\shref=["']?(.*?)["'\s]|\ssrc=["']?(.*?)["'\s]`)
var reCSS = regexp.MustCompile(`url\(["']?(.*?)["']?\)`)

var reBase64 = regexp.MustCompile("^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=)?$")

var httpClient = &http.Client{}

// Hop-by-hop headers
var hopHeaders = map[string]bool{
	"connection":          true,
	"keep-alive":          true,
	"proxy-authenticate":  true,
	"proxy-authorization": true,
	"te":                true,
	"trailers":          true,
	"transfer-encoding": true,
	"upgrade":           true,
}

// Headers that create problem handling response
// TODO: support gzip compressed response in future
var problemHeaders = map[string]bool{
	"content-security-policy":             true, // sent in response
	"content-security-policy-report-only": true, // sent in response
	"accept-encoding":                     true, // sent in request
}

type proxyManager struct {
	req  *http.Request
	uri  *url.URL
	resp *http.Response
}

func encodeURL(plainURL []byte) string {
	return GopeeEncPrefix + base64.URLEncoding.EncodeToString(plainURL)
}

func decodeURL(encodedURL string) (decodedURI *url.URL, err error) {
	encodedURL = strings.TrimSpace(encodedURL)
	if encodedURL == "" || !strings.HasPrefix(encodedURL, GopeeEncPrefix) {
		err = errors.New("invalid path supplied to decode")
		return nil, err
	}
	encodedURL = strings.TrimLeft(encodedURL, GopeeEncPrefix)
	decoded, err := base64.URLEncoding.DecodeString(encodedURL)
	if err != nil {
		log.Println(err.Error(), " for url ", encodedURL)
		return nil, err
	}
	decodedURI, err = url.Parse(string(decoded))
	if err != nil {
		log.Println("error parsing", string(decoded))
		return nil, err
	}
	return decodedURI, err
}

// ProxyRequest creates a new request to be proxied
func ProxyRequest(r *http.Request, w http.ResponseWriter) {
	var uri *url.URL

	// Path can be of the form
	// /base64-encoded-string
	// /home/ajax.php
	// http://thirdparty.com/resource.js
	path := r.URL.Path[1:]

	if decodedURL, err := decodeURL(path); err == nil {
		// URL rewritten by GoPee
		uri = decodedURL
	} else {
		// Might be a plain-text URL which was not rewritten
		// AJAX request ?
		path += "?" + r.URL.RawQuery
		pathURI, err := url.Parse(path)
		if err != nil {
			log.Println("error parsing", path)
		}
		if pathURI.IsAbs() {
			uri = pathURI
		} else {
			referer, err := url.Parse(r.Referer())
			if err != nil {
				log.Println("error parsing", r.Referer())
			}
			if baseURL, err := decodeURL(referer.Path[1:]); err == nil {
				uri = baseURL.ResolveReference(pathURI)
			}
		}
	}
	// log.Println(uri.String())
	if uri == nil {
		// return a 404
		http.NotFound(w, r)
	} else {
		// try fetching the url
		proxyMan := &proxyManager{r, uri, nil}
		proxyMan.Fetch(w)
	}
}

// Fetch makes the actual request to server and writes data with rewritten URLs to response
func (pm *proxyManager) Fetch(w http.ResponseWriter) (err error) {
	if pm.uri == nil {
		return errors.New("No URI specified to fetch")
	}
	req, _ := http.NewRequest(pm.req.Method, pm.uri.String(), pm.req.Body)
	// Forward request headers, included User-Agent to server
	copyHeader(req.Header, pm.req.Header)
	// Set http client protocol version
	req.Proto = "HTTP/1.1"
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	pm.resp, err = httpClient.Do(req)
	if err != nil {
		log.Println("error fetching", pm.uri.String())
		return err
	}
	defer pm.resp.Body.Close()

	// In case there was a url redirect
	// http -> https or non-www -> www
	pm.uri = pm.resp.Request.URL

	contentType := pm.resp.Header.Get("Content-Type")

	// Forward response headers to client
	copyHeader(w.Header(), pm.resp.Header)

	w.WriteHeader(pm.resp.StatusCode)

	// Rewrite all urls
	if strings.Contains(contentType, "text/html") {
		pm.rewriteHTML(w)
	} else if strings.Contains(contentType, "text/css") {
		pm.rewriteCSS(w)
	} else {
		io.Copy(w, pm.resp.Body)
	}
	return nil
}

// Copy Headers from src to dst ignoring hop-by-hop headers
func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		// Don't copy hop-by-hop headers and problem headers
		if hopHeaders[strings.ToLower(k)] || problemHeaders[strings.ToLower(k)] {
			dst.Del(k) // remove any existing hop-by-hop header
			continue
		}
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

func (pm *proxyManager) rewriteHTML(w http.ResponseWriter) {
	body, _ := ioutil.ReadAll(pm.resp.Body)
	// if there's a <base href> specified in the document
	// use that as base to encode all URLs in the page
	baseHrefMatch := reBase.FindSubmatch(body)
	if len(baseHrefMatch) > 0 {
		var err error
		pm.uri, err = url.Parse(string(baseHrefMatch[1][:]))
		if err != nil {
			log.Println("Error Parsing " + string(baseHrefMatch[1][:]))
		}
	}
	encodedBody := reHTML.ReplaceAllFunc(body, func(s []byte) []byte {
		parts := reHTML.FindSubmatchIndex(s)
		if parts != nil {
			// replace src attribute
			srcIndex := parts[2:4]
			if srcIndex[0] != -1 {
				return pm.rewriteURI(s, srcIndex[0], srcIndex[1])
			}

			// replace href attribute
			hrefIndex := parts[4:6]
			if hrefIndex[0] != -1 {
				return pm.rewriteURI(s, hrefIndex[0], hrefIndex[1])
			}

			// replace form action attribute
			actionIndex := parts[6:8]
			if actionIndex[0] != -1 {
				return pm.rewriteURI(s, actionIndex[0], actionIndex[1])
			}
		}
		return s
	})
	w.Write(encodedBody)
}

func (pm *proxyManager) rewriteCSS(w http.ResponseWriter) {
	body, _ := ioutil.ReadAll(pm.resp.Body)
	encodedBody := reCSS.ReplaceAllFunc(body, func(s []byte) []byte {
		parts := reCSS.FindSubmatchIndex(s)
		if parts != nil {
			// replace url attribute in css
			pathIndex := parts[2:4]
			if pathIndex[0] != -1 {
				return pm.rewriteURI(s, pathIndex[0], pathIndex[1])
			}
		}
		return s
	})
	w.Write(encodedBody)

}

func (pm *proxyManager) rewriteURI(src []byte, start int, end int) []byte {
	relURL := string(src[start:end])
	// keep anchor and javascript links intact
	if relURL == "" || strings.HasPrefix(relURL, "#") || strings.HasPrefix(relURL, "javascript") || strings.HasPrefix(relURL, "data") {
		return src
	}
	// Check if url is relative and make it absolute
	if strings.Index(relURL, "http") != 0 {
		relPath, err := url.Parse(relURL)
		if err != nil {
			return src
		}
		absURL := pm.uri.ResolveReference(relPath).String()
		src = bytes.Replace(src, []byte(relURL), []byte(absURL), -1)
		end = start + len(absURL)
	}
	encodedString := encodeURL(src[start:end])
	return bytes.Replace(src, src[start:end], []byte(encodedString), -1)
}

// Cache templates
var templates = template.Must(template.ParseFiles("home.html"))

func homeHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path[1:] == "" {
		r.ParseForm()
		enteredURL := r.FormValue("url")
		if enteredURL != "" {
			// Check if url attribute is set in GET / POST
			uri, _ := url.Parse(enteredURL)
			// prepend http if not specified
			if uri.Scheme == "" {
				uri.Scheme = "http"
			}
			http.Redirect(w, r, "/"+encodeURL([]byte(uri.String())), 302)
			return
		}
		templates.ExecuteTemplate(w, "home.html", nil)
	} else {
		ProxyRequest(r, w)
	}
}

func main() {
	httpHost := os.Getenv("HOST")
	httpPort := os.Getenv("PORT")
	if httpPort == "" {
		httpPort = "8080"
	}
	http.HandleFunc("/", homeHandler)

	http.HandleFunc("/assets/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, r.URL.Path[1:])
	})

	log.Printf("web proxy listening on %s:%s\n", httpHost, httpPort)

	http.ListenAndServe(httpHost+":"+httpPort, nil)
}
<commit_msg>Fix filtering of hop-by-hop and problem headers<commit_after>package main

import (
	"bytes"
	"encoding/base64"
	"errors"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
)

// URLCookie - cookie which stores page url
const URLCookie = "X-GoPee-URL"

// GopeeEncPrefix - encoding prefix used while encoding urls
const GopeeEncPrefix = "xox"

// Pre-compile RegEx
var reBase = regexp.MustCompile(`base +href="(.*?)"`)
var reHTML = regexp.MustCompile(`\saction=["']?(.*?)["'\s]|\shref=["']?(.*?)["'\s]|\ssrc=["']?(.*?)["'\s]`)
var reCSS = regexp.MustCompile(`url\(["']?(.*?)["']?\)`)

var reBase64 = regexp.MustCompile("^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=)?$")

var httpClient = &http.Client{}

// Hop-by-hop headers
var hopHeaders = map[string]bool{
	"connection":          true,
	"keep-alive":          true,
	"proxy-authenticate":  true,
	"proxy-authorization": true,
	"te":                true,
	"trailers":          true,
	"transfer-encoding": true,
	"upgrade":           true,
}

// Headers that create problem handling response
// TODO: support gzip compressed response in future
var problemHeaders = map[string]bool{
	"content-security-policy":             true, // sent in response
	"content-security-policy-report-only": true, // sent in response
	"accept-encoding":                     true, // sent in request
}

type proxyManager struct {
	req  *http.Request
	uri  *url.URL
	resp *http.Response
}

func encodeURL(plainURL []byte) string {
	return GopeeEncPrefix + base64.URLEncoding.EncodeToString(plainURL)
}

func decodeURL(encodedURL string) (decodedURI *url.URL, err error) {
	encodedURL = strings.TrimSpace(encodedURL)
	if encodedURL == "" || !strings.HasPrefix(encodedURL, GopeeEncPrefix) {
		err = errors.New("invalid path supplied to decode")
		return nil, err
	}
	encodedURL = strings.TrimLeft(encodedURL, GopeeEncPrefix)
	decoded, err := base64.URLEncoding.DecodeString(encodedURL)
	if err != nil {
		log.Println(err.Error(), " for url ", encodedURL)
		return nil, err
	}
	decodedURI, err = url.Parse(string(decoded))
	if err != nil {
		log.Println("error parsing", string(decoded))
		return nil, err
	}
	return decodedURI, err
}

// ProxyRequest creates a new request to be proxied
func ProxyRequest(r *http.Request, w http.ResponseWriter) {
	var uri *url.URL

	// Path can be of the form
	// /base64-encoded-string
	// /home/ajax.php
	// http://thirdparty.com/resource.js
	path := r.URL.Path[1:]

	if decodedURL, err := decodeURL(path); err == nil {
		// URL rewritten by GoPee
		uri = decodedURL
	} else {
		// Might be a plain-text URL which was not rewritten
		// AJAX request ?
		path += "?" + r.URL.RawQuery
		pathURI, err := url.Parse(path)
		if err != nil {
			log.Println("error parsing", path)
		}
		if pathURI.IsAbs() {
			uri = pathURI
		} else {
			referer, err := url.Parse(r.Referer())
			if err != nil {
				log.Println("error parsing", r.Referer())
			}
			if baseURL, err := decodeURL(referer.Path[1:]); err == nil {
				uri = baseURL.ResolveReference(pathURI)
			}
		}
	}
	// log.Println(uri.String())
	if uri == nil {
		// return a 404
		http.NotFound(w, r)
	} else {
		// try fetching the url
		proxyMan := &proxyManager{r, uri, nil}
		proxyMan.Fetch(w)
	}
}

// Fetch makes the actual request to server and writes data with rewritten URLs to response
func (pm *proxyManager) Fetch(w http.ResponseWriter) (err error) {
	if pm.uri == nil {
		return errors.New("No URI specified to fetch")
	}
	req, _ := http.NewRequest(pm.req.Method, pm.uri.String(), pm.req.Body)
	// Forward request headers to server
	copyHeader(req.Header, pm.req.Header)

	// Set http client protocol version
	req.Proto = "HTTP/1.1"
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	pm.resp, err = httpClient.Do(req)
	if err != nil {
		log.Println("error fetching", pm.uri.String())
		return err
	}
	defer pm.resp.Body.Close()

	// In case there was a url redirect
	// http -> https or non-www -> www
	pm.uri = pm.resp.Request.URL

	contentType := pm.resp.Header.Get("Content-Type")

	// Forward response headers to client
	copyHeader(w.Header(), pm.resp.Header)

	w.WriteHeader(pm.resp.StatusCode)

	// Rewrite all urls
	if strings.Contains(contentType, "text/html") {
		pm.rewriteHTML(w)
	} else if strings.Contains(contentType, "text/css") {
		pm.rewriteCSS(w)
	} else {
		io.Copy(w, pm.resp.Body)
	}
	return nil
}

func copyHeader(dst, src http.Header) {
	// Copy Headers from src to dst
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
	// Remove hop-by-hop headers and problem headers
	for h, _ := range hopHeaders {
		dst.Del(h)
	}
	for h, _ := range problemHeaders {
		dst.Del(h)
	}
}

func (pm *proxyManager) rewriteHTML(w http.ResponseWriter) {
	body, _ := ioutil.ReadAll(pm.resp.Body)
	// if there's a <base href> specified in the document
	// use that as base to encode all URLs in the page
	baseHrefMatch := reBase.FindSubmatch(body)
	if len(baseHrefMatch) > 0 {
		var err error
		pm.uri, err = url.Parse(string(baseHrefMatch[1][:]))
		if err != nil {
			log.Println("Error Parsing " + string(baseHrefMatch[1][:]))
		}
	}
	encodedBody := reHTML.ReplaceAllFunc(body, func(s []byte) []byte {
		parts := reHTML.FindSubmatchIndex(s)
		if parts != nil {
			// replace src attribute
			srcIndex := parts[2:4]
			if srcIndex[0] != -1 {
				return pm.rewriteURI(s, srcIndex[0], srcIndex[1])
			}

			// replace href attribute
			hrefIndex := parts[4:6]
			if hrefIndex[0] != -1 {
				return pm.rewriteURI(s, hrefIndex[0], hrefIndex[1])
			}

			// replace form action attribute
			actionIndex := parts[6:8]
			if actionIndex[0] != -1 {
				return pm.rewriteURI(s, actionIndex[0], actionIndex[1])
			}
		}
		return s
	})
	w.Write(encodedBody)
}

func (pm *proxyManager) rewriteCSS(w http.ResponseWriter) {
	body, _ := ioutil.ReadAll(pm.resp.Body)
	encodedBody := reCSS.ReplaceAllFunc(body, func(s []byte) []byte {
		parts := reCSS.FindSubmatchIndex(s)
		if parts != nil {
			// replace url attribute in css
			pathIndex := parts[2:4]
			if pathIndex[0] != -1 {
				return pm.rewriteURI(s, pathIndex[0], pathIndex[1])
			}
		}
		return s
	})
	w.Write(encodedBody)

}

func (pm *proxyManager) rewriteURI(src []byte, start int, end int) []byte {
	relURL := string(src[start:end])
	// keep anchor and javascript links intact
	if relURL == "" || strings.HasPrefix(relURL, "#") || strings.HasPrefix(relURL, "javascript") || strings.HasPrefix(relURL, "data") {
		return src
	}
	// Check if url is relative and make it absolute
	if strings.Index(relURL, "http") != 0 {
		relPath, err := url.Parse(relURL)
		if err != nil {
			return src
		}
		absURL := pm.uri.ResolveReference(relPath).String()
		src = bytes.Replace(src, []byte(relURL), []byte(absURL), -1)
		end = start + len(absURL)
	}
	encodedString := encodeURL(src[start:end])
	return bytes.Replace(src, src[start:end], []byte(encodedString), -1)
}

// Cache templates
var templates = template.Must(template.ParseFiles("home.html"))

func homeHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path[1:] == "" {
		r.ParseForm()
		enteredURL := r.FormValue("url")
		if enteredURL != "" {
			// Check if url attribute is set in GET / POST
			uri, _ := url.Parse(enteredURL)
			// prepend http if not specified
			if uri.Scheme == "" {
				uri.Scheme = "http"
			}
			http.Redirect(w, r, "/"+encodeURL([]byte(uri.String())), 302)
			return
		}
		templates.ExecuteTemplate(w, "home.html", nil)
	} else {
		ProxyRequest(r, w)
	}
}

func main() {
	httpHost := os.Getenv("HOST")
	httpPort := os.Getenv("PORT")
	if httpPort == "" {
		httpPort = "8080"
	}
	http.HandleFunc("/", homeHandler)

	http.HandleFunc("/assets/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, r.URL.Path[1:])
	})

	log.Printf("web proxy listening on %s:%s\n", httpHost, httpPort)

	http.ListenAndServe(httpHost+":"+httpPort, nil)
}
<|endoftext|>


<commit_before>// Package stubs provides testable stubs for clients.
package stubs

// Copyright 2019 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
//
// 	https://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 (
	"context"

	crm "google.golang.org/api/cloudresourcemanager/v1"
)

// ResourceManagerStub provides a stub for the CRM client.
type ResourceManagerStub struct {
	GetPolicyResponse   *crm.Policy
	GetAncestryResponse *crm.GetAncestryResponse
	SavedSetPolicy      *crm.Policy
}

// GetPolicyProject is a stub of Cloud Resource Manager's GetIamPolicy.
func (s *ResourceManagerStub) GetPolicyProject(ctx context.Context, projectID string) (*crm.Policy, error) {
	return s.GetPolicyResponse, nil
}

// SetPolicyProject is a stub of Cloud Resource Manager's SetIamPolicy.
func (s *ResourceManagerStub) SetPolicyProject(ctx context.Context, projectID string, p *crm.Policy) (*crm.Policy, error) {
	s.SavedSetPolicy = p
	return s.SavedSetPolicy, nil
}

// GetProjectAncestry is a stub of Cloud Resource Manager's GetAncestry.
func (s *ResourceManagerStub) GetAncestry(context.Context, string) (*crm.GetAncestryResponse, error) {
	return s.GetAncestryResponse, nil
}
<commit_msg>correct golint error<commit_after>// Package stubs provides testable stubs for clients.
package stubs

// Copyright 2019 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
//
// 	https://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 (
	"context"

	crm "google.golang.org/api/cloudresourcemanager/v1"
)

// ResourceManagerStub provides a stub for the CRM client.
type ResourceManagerStub struct {
	GetPolicyResponse   *crm.Policy
	GetAncestryResponse *crm.GetAncestryResponse
	SavedSetPolicy      *crm.Policy
}

// GetPolicyProject is a stub of Cloud Resource Manager's GetIamPolicy.
func (s *ResourceManagerStub) GetPolicyProject(ctx context.Context, projectID string) (*crm.Policy, error) {
	return s.GetPolicyResponse, nil
}

// SetPolicyProject is a stub of Cloud Resource Manager's SetIamPolicy.
func (s *ResourceManagerStub) SetPolicyProject(ctx context.Context, projectID string, p *crm.Policy) (*crm.Policy, error) {
	s.SavedSetPolicy = p
	return s.SavedSetPolicy, nil
}

// GetAncestry is a stub of Cloud Resource Manager's GetAncestry.
func (s *ResourceManagerStub) GetAncestry(context.Context, string) (*crm.GetAncestryResponse, error) {
	return s.GetAncestryResponse, nil
}
<|endoftext|>


<commit_before>package azurerm

import (
	"fmt"
	"log"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/compute"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/jen20/riviera/azure"
)

func resourceArmAvailabilitySet() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmAvailabilitySetCreate,
		Read:   resourceArmAvailabilitySetRead,
		Update: resourceArmAvailabilitySetCreate,
		Delete: resourceArmAvailabilitySetDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"resource_group_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"location": locationSchema(),

			"platform_update_domain_count": {
				Type:     schema.TypeInt,
				Optional: true,
				Default:  5,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(int)
					if value > 20 {
						errors = append(errors, fmt.Errorf(
							"Maximum value for `platform_update_domain_count` is 20"))
					}
					return
				},
			},

			"platform_fault_domain_count": {
				Type:     schema.TypeInt,
				Optional: true,
				Default:  3,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(int)
					if value > 3 {
						errors = append(errors, fmt.Errorf(
							"Maximum value for (%s) is 3", k))
					}
					return
				},
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmAvailabilitySetCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient)
	availSetClient := client.availSetClient

	log.Printf("[INFO] preparing arguments for Azure ARM Availability Set creation.")

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	updateDomainCount := d.Get("platform_update_domain_count").(int)
	faultDomainCount := d.Get("platform_fault_domain_count").(int)
	tags := d.Get("tags").(map[string]interface{})

	availSet := compute.AvailabilitySet{
		Name:     &name,
		Location: &location,
		Properties: &compute.AvailabilitySetProperties{
			PlatformFaultDomainCount:  azure.Int32(int32(faultDomainCount)),
			PlatformUpdateDomainCount: azure.Int32(int32(updateDomainCount)),
		},
		Tags: expandTags(tags),
	}

	resp, err := availSetClient.CreateOrUpdate(resGroup, name, availSet)
	if err != nil {
		return err
	}

	d.SetId(*resp.ID)

	return resourceArmAvailabilitySetRead(d, meta)
}

func resourceArmAvailabilitySetRead(d *schema.ResourceData, meta interface{}) error {
	availSetClient := meta.(*ArmClient).availSetClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["availabilitySets"]

	resp, err := availSetClient.Get(resGroup, name)
	if err != nil {
		if resp.StatusCode == http.StatusNotFound {
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error making Read request on Azure Availability Set %s: %s", name, err)
	}

	availSet := *resp.Properties
	d.Set("resource_group_name", resGroup)
	d.Set("platform_update_domain_count", availSet.PlatformUpdateDomainCount)
	d.Set("platform_fault_domain_count", availSet.PlatformFaultDomainCount)
	d.Set("name", resp.Name)
	d.Set("location", resp.Location)

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmAvailabilitySetDelete(d *schema.ResourceData, meta interface{}) error {
	availSetClient := meta.(*ArmClient).availSetClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["availabilitySets"]

	_, err = availSetClient.Delete(resGroup, name)

	return err
}
<commit_msg>Force a recreate if the numbers for the AS are changed. (#10545)<commit_after>package azurerm

import (
	"fmt"
	"log"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/compute"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/jen20/riviera/azure"
)

func resourceArmAvailabilitySet() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmAvailabilitySetCreate,
		Read:   resourceArmAvailabilitySetRead,
		Update: resourceArmAvailabilitySetCreate,
		Delete: resourceArmAvailabilitySetDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"resource_group_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"location": locationSchema(),

			"platform_update_domain_count": {
				Type:     schema.TypeInt,
				Optional: true,
				Default:  5,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(int)
					if value > 20 {
						errors = append(errors, fmt.Errorf(
							"Maximum value for `platform_update_domain_count` is 20"))
					}
					return
				},
			},

			"platform_fault_domain_count": {
				Type:     schema.TypeInt,
				Optional: true,
				Default:  3,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(int)
					if value > 3 {
						errors = append(errors, fmt.Errorf(
							"Maximum value for (%s) is 3", k))
					}
					return
				},
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmAvailabilitySetCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient)
	availSetClient := client.availSetClient

	log.Printf("[INFO] preparing arguments for Azure ARM Availability Set creation.")

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	updateDomainCount := d.Get("platform_update_domain_count").(int)
	faultDomainCount := d.Get("platform_fault_domain_count").(int)
	tags := d.Get("tags").(map[string]interface{})

	availSet := compute.AvailabilitySet{
		Name:     &name,
		Location: &location,
		Properties: &compute.AvailabilitySetProperties{
			PlatformFaultDomainCount:  azure.Int32(int32(faultDomainCount)),
			PlatformUpdateDomainCount: azure.Int32(int32(updateDomainCount)),
		},
		Tags: expandTags(tags),
	}

	resp, err := availSetClient.CreateOrUpdate(resGroup, name, availSet)
	if err != nil {
		return err
	}

	d.SetId(*resp.ID)

	return resourceArmAvailabilitySetRead(d, meta)
}

func resourceArmAvailabilitySetRead(d *schema.ResourceData, meta interface{}) error {
	availSetClient := meta.(*ArmClient).availSetClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["availabilitySets"]

	resp, err := availSetClient.Get(resGroup, name)
	if err != nil {
		if resp.StatusCode == http.StatusNotFound {
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error making Read request on Azure Availability Set %s: %s", name, err)
	}

	availSet := *resp.Properties
	d.Set("resource_group_name", resGroup)
	d.Set("platform_update_domain_count", availSet.PlatformUpdateDomainCount)
	d.Set("platform_fault_domain_count", availSet.PlatformFaultDomainCount)
	d.Set("name", resp.Name)
	d.Set("location", resp.Location)

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmAvailabilitySetDelete(d *schema.ResourceData, meta interface{}) error {
	availSetClient := meta.(*ArmClient).availSetClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["availabilitySets"]

	_, err = availSetClient.Delete(resGroup, name)

	return err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"reflect"
	"time"

	"github.com/brutella/gouvr/uvr"
	"github.com/brutella/gouvr/uvr/1611"
	"github.com/brutella/hc/hap"
	"github.com/brutella/hc/model"
	"github.com/brutella/hc/model/accessory"
	"github.com/brutella/hkuvr1611"
	"github.com/brutella/log"

	"github.com/brutella/hkuvr1611/gpio"
	"github.com/brutella/hkuvr1611/mock"
)

func HandlePacket(p uvr1611.Packet) []*accessory.Accessory {
	var sensors []*accessory.Accessory
	inputs := hkuvr1611.InputValuesFromPacket(p)
	for i, v := range inputs {
		s := HandleInputValueWithName(v, fmt.Sprintf("Sensor %d", i+1))
		sensors = append(sensors, s.Accessory)
	}

	outlets := uvr1611.OutletsFromValue(p.Outgoing)
	for i, v := range outlets {
		s := HandleOutletWithName(v, fmt.Sprintf("Outlet %d", i+1))
		sensors = append(sensors, s.Accessory)
	}

	h1, h2 := uvr1611.AreHeatMetersEnabled(p.HeatRegister)
	if h1 == true {
		s := HandleHeatMeterWithName(p.HeatMeter1, "Heat Meter 1")
		sensors = append(sensors, s.Accessory)
	}

	if h2 == true {
		s := HandleHeatMeterWithName(p.HeatMeter2, "Heat Meter 2")
		sensors = append(sensors, s.Accessory)
	}

	return sensors
}

func HandleInputValueWithName(v uvr.Value, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForInputValue(v, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithInputValue(s.Model, v)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}
	return s
}

func HandleOutletWithName(o uvr1611.Outlet, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForOutlet(o, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithOutlet(s.Model, o)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}

	return s
}

func HandleHeatMeterWithName(hm uvr.HeatMeterValue, name string) (s *hkuvr1611.Sensor) {
	return nil
}

func InfoForAccessoryName(name string) model.Info {
	info := model.Info{
		Name:         name,
		Manufacturer: "TA",
		Model:        "UVR1611",
	}

	return info
}

// Access to HAP app
var transport hap.Transport
var uvrAccessory *accessory.Accessory

// List of sensors
var sensors map[string]*hkuvr1611.Sensor

// Timer to remove not reachable accessories
var timer *time.Timer

type Connection interface {
	Close()
}

// This app can connect to the UVR1611 data bus and provide the sensor values to HomeKit clients
//
// Optimizations: To improve the performance on a Raspberry Pi B+, the interrupt handler of the
// gpio pin is removed every time after successfully decoding a packet. This allows other goroutines
// (e.g. HAP server) to do their job more quickly.
func main() {
	var (
		mode    = flag.String("conn", "mock", "Connection type; mock, gpio, replay")
		file    = flag.String("file", "", "Log file from which to replay packets")
		port    = flag.String("port", "P8_07", "GPIO port; default P8_07")
		timeout = flag.Int("timeout", 120, "Timeout in seconds until accessories are not reachable")
	)

	flag.Parse()
	sensors = map[string]*hkuvr1611.Sensor{}

	info := InfoForAccessoryName("UVR1611")
	uvrAccessory = accessory.New(info)

	timer_duration := time.Duration(*timeout) * time.Second
	timer = time.AfterFunc(timer_duration, func() {
		log.Println("[INFO] Not Reachable")
		if transport != nil {
			sensors = map[string]*hkuvr1611.Sensor{}
			transport.Stop()
			transport = nil
		}
	})

	var conn Connection
	callback := func(packet uvr1611.Packet) {
		sensors := HandlePacket(packet)
		if transport == nil {
			var err error
			transport, err = hap.NewIPTransport("00102003", uvrAccessory, sensors...)

			transport.OnStop(func() {
				timer.Stop()
				conn.Close()
			})

			go func() {
				transport.Start()
			}()

			if err != nil {
				log.Fatal(err)
			}
		}
		timer.Reset(timer_duration)
	}

	switch *mode {
	case "mock":
		conn = mock.NewConnection(callback)
	case "replay":
		conn = mock.NewReplayConnection(*file, callback)
	case "gpio":
		conn = gpio.NewConnection(*port, callback)
	default:
		log.Fatal("Incorrect -conn flag")
	}

	select {}
}
<commit_msg>Add new termination handling<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"reflect"
	"time"

	"github.com/brutella/gouvr/uvr"
	"github.com/brutella/gouvr/uvr/1611"
	"github.com/brutella/hc/hap"
	"github.com/brutella/hc/model"
	"github.com/brutella/hc/model/accessory"
	"github.com/brutella/hkuvr1611"
	"github.com/brutella/log"

	"github.com/brutella/hkuvr1611/gpio"
	"github.com/brutella/hkuvr1611/mock"
)

func HandlePacket(p uvr1611.Packet) []*accessory.Accessory {
	var sensors []*accessory.Accessory
	inputs := hkuvr1611.InputValuesFromPacket(p)
	for i, v := range inputs {
		s := HandleInputValueWithName(v, fmt.Sprintf("Sensor %d", i+1))
		sensors = append(sensors, s.Accessory)
	}

	outlets := uvr1611.OutletsFromValue(p.Outgoing)
	for i, v := range outlets {
		s := HandleOutletWithName(v, fmt.Sprintf("Outlet %d", i+1))
		sensors = append(sensors, s.Accessory)
	}

	h1, h2 := uvr1611.AreHeatMetersEnabled(p.HeatRegister)
	if h1 == true {
		s := HandleHeatMeterWithName(p.HeatMeter1, "Heat Meter 1")
		sensors = append(sensors, s.Accessory)
	}

	if h2 == true {
		s := HandleHeatMeterWithName(p.HeatMeter2, "Heat Meter 2")
		sensors = append(sensors, s.Accessory)
	}

	return sensors
}

func HandleInputValueWithName(v uvr.Value, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForInputValue(v, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithInputValue(s.Model, v)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}
	return s
}

func HandleOutletWithName(o uvr1611.Outlet, name string) (s *hkuvr1611.Sensor) {
	var found bool
	if s, found = sensors[name]; found == false {
		s = hkuvr1611.NewSensorForOutlet(o, InfoForAccessoryName(name))
		if s != nil {
			log.Println("[INFO]", reflect.TypeOf(s.Model), "with name", name)
			sensors[name] = s
		}
	} else {
		err := hkuvr1611.UpdateAccessoryWithOutlet(s.Model, o)
		if err != nil {
			log.Println("[ERRO]", err)
		}
	}

	return s
}

func HandleHeatMeterWithName(hm uvr.HeatMeterValue, name string) (s *hkuvr1611.Sensor) {
	return nil
}

func InfoForAccessoryName(name string) model.Info {
	info := model.Info{
		Name:         name,
		Manufacturer: "TA",
		Model:        "UVR1611",
	}

	return info
}

// Access to HAP app
var transport hap.Transport
var uvrAccessory *accessory.Accessory

// List of sensors
var sensors map[string]*hkuvr1611.Sensor

// Timer to remove not reachable accessories
var timer *time.Timer

type Connection interface {
	Close()
}

// This app can connect to the UVR1611 data bus and provide the sensor values to HomeKit clients
//
// Optimizations: To improve the performance on a Raspberry Pi B+, the interrupt handler of the
// gpio pin is removed every time after successfully decoding a packet. This allows other goroutines
// (e.g. HAP server) to do their job more quickly.
func main() {
	var (
		mode    = flag.String("conn", "mock", "Connection type; mock, gpio, replay")
		file    = flag.String("file", "", "Log file from which to replay packets")
		port    = flag.String("port", "P8_07", "GPIO port; default P8_07")
		timeout = flag.Int("timeout", 120, "Timeout in seconds until accessories are not reachable")
	)

	flag.Parse()
	sensors = map[string]*hkuvr1611.Sensor{}

	info := InfoForAccessoryName("UVR1611")
	uvrAccessory = accessory.New(info)

	timer_duration := time.Duration(*timeout) * time.Second
	timer = time.AfterFunc(timer_duration, func() {
		log.Println("[INFO] Not Reachable")
		if transport != nil {
			sensors = map[string]*hkuvr1611.Sensor{}
			transport.Stop()
			transport = nil
		}
	})

	var conn Connection
	callback := func(packet uvr1611.Packet) {
		sensors := HandlePacket(packet)
		if transport == nil {
			var err error
			transport, err = hap.NewIPTransport("00102003", uvrAccessory, sensors...)
			go func() {
				transport.Start()
			}()

			if err != nil {
				log.Fatal(err)
			}
		}
		timer.Reset(timer_duration)
	}

	switch *mode {
	case "mock":
		conn = mock.NewConnection(callback)
	case "replay":
		conn = mock.NewReplayConnection(*file, callback)
	case "gpio":
		conn = gpio.NewConnection(*port, callback)
	default:
		log.Fatal("Incorrect -conn flag")
	}

	hap.OnTermination(func() {
		if transport != nil {
			transport.Stop()
		}
		conn.Close()
		timer.Stop()
		os.Exit(1)
	})

	select {}
}
<|endoftext|>


<commit_before>// +build !windows

package daemon

import (
	"fmt"

	"github.com/docker/docker/container"
	"github.com/docker/docker/libcontainerd"
)

func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) ([]libcontainerd.CreateOption, error) {
	createOptions := []libcontainerd.CreateOption{}

	// Ensure a runtime has been assigned to this container
	if container.HostConfig.Runtime == "" {
		container.HostConfig.Runtime = stockRuntimeName
		container.ToDisk()
	}

	rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime)
	if rt == nil {
		return nil, fmt.Errorf("no such runtime '%s'", container.HostConfig.Runtime)
	}
	if UsingSystemd(daemon.configStore) {
		rt.Args = append(rt.Args, "--systemd-cgroup=true")
	}
	createOptions = append(createOptions, libcontainerd.WithRuntime(rt.Path, rt.Args))

	return createOptions, nil
}
<commit_msg>daemon: honor default runtime when starting containers<commit_after>// +build !windows

package daemon

import (
	"fmt"

	"github.com/docker/docker/container"
	"github.com/docker/docker/libcontainerd"
)

func (daemon *Daemon) getLibcontainerdCreateOptions(container *container.Container) ([]libcontainerd.CreateOption, error) {
	createOptions := []libcontainerd.CreateOption{}

	// Ensure a runtime has been assigned to this container
	if container.HostConfig.Runtime == "" {
		container.HostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
		container.ToDisk()
	}

	rt := daemon.configStore.GetRuntime(container.HostConfig.Runtime)
	if rt == nil {
		return nil, fmt.Errorf("no such runtime '%s'", container.HostConfig.Runtime)
	}
	if UsingSystemd(daemon.configStore) {
		rt.Args = append(rt.Args, "--systemd-cgroup=true")
	}
	createOptions = append(createOptions, libcontainerd.WithRuntime(rt.Path, rt.Args))

	return createOptions, nil
}
<|endoftext|>


<commit_before>package main

import "fmt"

type plotlyDatasetLine struct {
	X    []string  `json:"x"`
	Y    []float64 `json:"y"`
	Name string    `json:"name"`
	Mode string    `json:"mode"`
}

func parseResultsForLineGraph(records <-chan dbRow) []plotlyDatasetLine {
	data := make([]plotlyDatasetLine, 7)

	i := 0
	for row := range records {
		for ball := 0; ball < 7; ball++ {
			if i == 0 {
				data[ball].Mode = "line"
				if ball < 6 {
					data[ball].Name = fmt.Sprintf("Ball %d", ball+1)
				} else {
					data[ball].Name = "Bonus Ball"
				}
			}
			data[ball].X = append(data[ball].X, fmt.Sprintf("%s:%d:%s", row.Date.Format(formatYYYYMMDD), row.Set, row.Machine))
			data[ball].Y = append(data[ball].Y, float64(row.Num[ball]))
		}
		i++
	}

	return data
}

type plotlyDataset3DScatter struct {
	X      []string `json:"x"` // machine:set
	Y      []string `json:"y"` // date
	Z      []int    `json:"z"` // number
	Name   string   `json:"name"`
	Mode   string   `json:"mode"`
	Type   string   `json:"type"`
	Marker marker   `json:"marker"`
}

type marker struct {
	//Colour string `json:"colour"`
	Size    int     `json:"size"`
	Line    line    `json:"line"`
	Opacity float64 `json:"opacity"`
	Symbol  string  `json:"symbol"`
}

type line struct {
	Width float64 `json:"width"`
}

func parseResultsFor3DScatterGraph(records <-chan dbRow) []plotlyDataset3DScatter {
	data := make([]plotlyDataset3DScatter, 7)

	i := 0
	for row := range records {
		for ball := 0; ball < 7; ball++ {
			if i == 0 {
				set := plotlyDataset3DScatter{
					Mode: "markers",
					Type: "scatter3d",
					Marker: marker{
						Size:    3,
						Line:    line{Width: 0.5},
						Opacity: 0.8,
						Symbol:  "circle",
					},
				}

				data[ball] = set
				if ball < 6 {
					data[ball].Name = fmt.Sprintf("Ball %d", ball+1)
				} else {
					data[ball].Name = "Bonus Ball"
				}
			}
			data[ball].X = append(data[ball].X, fmt.Sprintf("%s:%d", row.Machine, row.Set))
			data[ball].Y = append(data[ball].Y, row.Date.Format(formatYYYYMMDD))
			data[ball].Z = append(data[ball].Z, row.Num[ball])
		}
		i++
	}

	return data
}

/*
func parseResultsFor3DScatterGraph(records <-chan dbRow) []plotlyDataset3DScatter {
	data := make([]plotlyDataset3DScatter, 7)

	i := 0
	for row := range records {
		for ball := 0; ball < 7; ball++ {
			if i == 0 {
				set := plotlyDataset3DScatter{
					Mode: "markers",
					Type: "scatter3d",
					Marker: marker{
						Size:    12,
						Line:    line{Width: 0.5},
						Opacity: 0.7,
						Symbol:  "circle",
					},
				}

				data[ball] = set
				if ball < 6 {
					data[ball].Name = fmt.Sprintf("Ball %d", ball+1)
				} else {
					data[ball].Name = "Bonus Ball"
				}
			}
			data[ball].X = append(data[ball].X, row.Set)
			data[ball].Y = append(data[ball].Y, row.Num[ball])
			data[ball].Z = append(data[ball].Z, row.Machine)
		}
		i++
	}

	return data
}
*/
<commit_msg>simplified 3d scatter graph data to use defaults<commit_after>package main

import "fmt"

type plotlyDatasetLine struct {
	X    []string  `json:"x"`
	Y    []float64 `json:"y"`
	Name string    `json:"name"`
	Mode string    `json:"mode"`
}

func parseResultsForLineGraph(records <-chan dbRow) []plotlyDatasetLine {
	data := make([]plotlyDatasetLine, 7)

	i := 0
	for row := range records {
		for ball := 0; ball < 7; ball++ {
			if i == 0 {
				data[ball].Mode = "line"
				if ball < 6 {
					data[ball].Name = fmt.Sprintf("Ball %d", ball+1)
				} else {
					data[ball].Name = "Bonus Ball"
				}
			}
			data[ball].X = append(data[ball].X, fmt.Sprintf("%s:%d:%s", row.Date.Format(formatYYYYMMDD), row.Set, row.Machine))
			data[ball].Y = append(data[ball].Y, float64(row.Num[ball]))
		}
		i++
	}

	return data
}

type plotlyDataset3DScatter struct {
	X    []string `json:"x"` // machine:set
	Y    []string `json:"y"` // date
	Z    []int    `json:"z"` // number
	Name string   `json:"name"`
	Mode string   `json:"mode"`
	Type string   `json:"type"`
}

func parseResultsFor3DScatterGraph(records <-chan dbRow) []plotlyDataset3DScatter {
	data := make([]plotlyDataset3DScatter, 7)

	i := 0
	for row := range records {
		for ball := 0; ball < 7; ball++ {
			if i == 0 {
				set := plotlyDataset3DScatter{
					Mode: "markers",
					Type: "scatter3d",
				}

				data[ball] = set
				if ball < 6 {
					data[ball].Name = fmt.Sprintf("Ball %d", ball+1)
				} else {
					data[ball].Name = "Bonus Ball"
				}
			}
			data[ball].X = append(data[ball].X, fmt.Sprintf("%s:%d", row.Machine, row.Set))
			data[ball].Y = append(data[ball].Y, row.Date.Format(formatYYYYMMDD))
			data[ball].Z = append(data[ball].Z, row.Num[ball])
		}
		i++
	}

	return data
}
<|endoftext|>


<commit_before>// +build !amd64,!arm64 !cgo

package crypto

import (
	"crypto/aes"
	"crypto/cipher"
)

type aesNativeCipher struct {
	cipher.Block
	mode BLOCK_MODE
}

func NewAESCipher(key []byte, mode BLOCK_MODE) (cipher.Block, error) {
	block, err := aes.NewCipher(key)
	if err == nil {
		return &aesNativeCipher{block, mode}, nil
	} else {
		return nil, err
	}
}

func NewAESEncrypter(block cipher.Block, iv []byte) (cipher.Stream, error) {
	aes := block.(*aesNativeCipher)
	switch aes.mode & 0xff {
	case MODE_OFB:
		return cipher.NewOFB(aes, iv), nil
	case MODE_CFB:
		return cipher.NewCFBEncrypter(block, iv), nil
	case MODE_CTR:
		return cipher.NewCTR(block, iv), nil
	}
	return nil, ERR_NOT_IMPLEMENTED
}

func NewAESEncrypter(block cipher.Block, iv []byte) (cipher.Stream, error) {
	aes := block.(*aesNativeCipher)
	switch aes.mode & 0xff {
	case MODE_OFB:
		return cipher.NewOFB(aes, iv), nil
	case MODE_CFB:
		return cipher.NewCFBDecrypter(block, iv), nil
	case MODE_CTR:
		return cipher.NewCTR(block, iv), nil
	}
	return nil, ERR_NOT_IMPLEMENTED
}

// compat impl.
func has_aes_hardware() int {
	return 0
}

func is_NEON_capable() int {
	return 0
}

func dump_cpu_features() []uint32 {
	return nil
}
<commit_msg>fix function name<commit_after>// +build !amd64,!arm64 !cgo

package crypto

import (
	"crypto/aes"
	"crypto/cipher"
)

type aesNativeCipher struct {
	cipher.Block
	mode BLOCK_MODE
}

func NewAESCipher(key []byte, mode BLOCK_MODE) (cipher.Block, error) {
	block, err := aes.NewCipher(key)
	if err == nil {
		return &aesNativeCipher{block, mode}, nil
	} else {
		return nil, err
	}
}

func NewAESEncrypter(block cipher.Block, iv []byte) (cipher.Stream, error) {
	aes := block.(*aesNativeCipher)
	switch aes.mode & 0xff {
	case MODE_OFB:
		return cipher.NewOFB(aes, iv), nil
	case MODE_CFB:
		return cipher.NewCFBEncrypter(block, iv), nil
	case MODE_CTR:
		return cipher.NewCTR(block, iv), nil
	}
	return nil, ERR_NOT_IMPLEMENTED
}

func NewAESDecrypter(block cipher.Block, iv []byte) (cipher.Stream, error) {
	aes := block.(*aesNativeCipher)
	switch aes.mode & 0xff {
	case MODE_OFB:
		return cipher.NewOFB(aes, iv), nil
	case MODE_CFB:
		return cipher.NewCFBDecrypter(block, iv), nil
	case MODE_CTR:
		return cipher.NewCTR(block, iv), nil
	}
	return nil, ERR_NOT_IMPLEMENTED
}

// compat impl.
func has_aes_hardware() int {
	return 0
}

func is_NEON_capable() int {
	return 0
}

func dump_cpu_features() []uint32 {
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

package main

import (
	"context"
	"testing"

	"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/ingress-gce/pkg/annotations"
	backendconfig "k8s.io/ingress-gce/pkg/apis/backendconfig/v1"
	"k8s.io/ingress-gce/pkg/e2e"
	"k8s.io/ingress-gce/pkg/e2e/adapter"
	"k8s.io/ingress-gce/pkg/fuzz"
	"k8s.io/ingress-gce/pkg/fuzz/features"
)

func TestHealthCheck(t *testing.T) {
	t.Parallel()

	pint64 := func(x int64) *int64 { return &x }
	pstring := func(x string) *string { return &x }

	for _, tc := range []struct {
		desc     string
		beConfig *backendconfig.BackendConfig
		want     *backendconfig.HealthCheckConfig
	}{
		{
			desc:     "override healthcheck path",
			beConfig: fuzz.NewBackendConfigBuilder("", "backendconfig-1").Build(),
			want: &backendconfig.HealthCheckConfig{
				CheckIntervalSec:   pint64(7),
				TimeoutSec:         pint64(3),
				HealthyThreshold:   pint64(3),
				UnhealthyThreshold: pint64(5),
				RequestPath:        pstring("/my-path"),
			},
		},
	} {
		tc := tc // Capture tc as we are running this in parallel.
		Framework.RunWithSandbox(tc.desc, t, func(t *testing.T, s *e2e.Sandbox) {
			t.Parallel()

			ctx := context.Background()

			backendConfigAnnotation := map[string]string{
				annotations.BackendConfigKey: `{"default":"backendconfig-1"}`,
			}
			tc.beConfig.Spec.HealthCheck = tc.want

			if _, err := Framework.BackendConfigClient.CloudV1().BackendConfigs(s.Namespace).Create(tc.beConfig); err != nil {
				t.Fatalf("error creating BackendConfig: %v", err)
			}
			t.Logf("BackendConfig created (%s/%s) ", s.Namespace, tc.beConfig.Name)

			_, err := e2e.CreateEchoService(s, "service-1", backendConfigAnnotation)
			if err != nil {
				t.Fatalf("error creating echo service: %v", err)
			}
			t.Logf("Echo service created (%s/%s)", s.Namespace, "service-1")

			ing := fuzz.NewIngressBuilder(s.Namespace, "ingress-1", "").
				DefaultBackend("service-1", intstr.FromInt(80)).
				Build()
			crud := adapter.IngressCRUD{C: Framework.Clientset}
			if _, err := crud.Create(ing); err != nil {
				t.Fatalf("error creating Ingress spec: %v", err)
			}
			t.Logf("Ingress created (%s/%s)", s.Namespace, ing.Name)

			ing, err = e2e.WaitForIngress(s, ing, nil)
			if err != nil {
				t.Fatalf("error waiting for Ingress to stabilize: %v", err)
			}
			t.Logf("GCLB resources created (%s/%s)", s.Namespace, ing.Name)

			vip := ing.Status.LoadBalancer.Ingress[0].IP
			t.Logf("Ingress %s/%s VIP = %s", s.Namespace, ing.Name, vip)
			params := &fuzz.GCLBForVIPParams{VIP: vip, Validators: fuzz.FeatureValidators(features.All)}
			gclb, err := fuzz.GCLBForVIP(context.Background(), Framework.Cloud, params)
			if err != nil {
				t.Fatalf("Error getting GCP resources for LB with IP = %q: %v", vip, err)
			}

			verifyHealthCheck(t, gclb, tc.want)

			// Wait for GCLB resources to be deleted.
			if err := crud.Delete(s.Namespace, ing.Name); err != nil {
				t.Errorf("Delete(%q) = %v, want nil", ing.Name, err)
			}

			deleteOptions := &fuzz.GCLBDeleteOptions{
				SkipDefaultBackend: true,
			}
			t.Logf("Waiting for GCLB resources to be deleted (%s/%s)", s.Namespace, ing.Name)
			if err := e2e.WaitForGCLBDeletion(ctx, Framework.Cloud, gclb, deleteOptions); err != nil {
				t.Errorf("e2e.WaitForGCLBDeletion(...) = %v, want nil", err)
			}
			t.Logf("GCLB resources deleted (%s/%s)", s.Namespace, ing.Name)
		})
	}
}

func verifyHealthCheck(t *testing.T, gclb *fuzz.GCLB, want *backendconfig.HealthCheckConfig) {
	// We assume there is a single service for now. The logic will have to be
	// changed if there is more than one backend service.
	for _, bs := range gclb.BackendService {
		for _, hcURL := range bs.GA.HealthChecks {
			rID, err := cloud.ParseResourceURL(hcURL)
			if err != nil {
				t.Fatalf("cloud.ParseResourceURL(%q) = _, %v; want _, nil", hcURL, err)
			}
			hc, ok := gclb.HealthCheck[*rID.Key]
			if !ok {
				t.Fatalf("HealthCheck %s not found in BackendService %+v", rID.Key, bs)
			}

			// Pull out the field that are in common among the different
			// healthchecks per protocol.
			common := struct {
				port        int64
				requestPath string
			}{}
			switch {
			case hc.GA.Http2HealthCheck != nil:
				common.port = hc.GA.Http2HealthCheck.Port
				common.requestPath = hc.GA.Http2HealthCheck.RequestPath
			case hc.GA.HttpHealthCheck != nil:
				common.port = hc.GA.HttpHealthCheck.Port
				common.requestPath = hc.GA.HttpHealthCheck.RequestPath
			case hc.GA.HttpsHealthCheck != nil:
				common.port = hc.GA.HttpsHealthCheck.Port
				common.requestPath = hc.GA.HttpsHealthCheck.RequestPath
			}

			if want.CheckIntervalSec != nil && hc.GA.CheckIntervalSec != *want.CheckIntervalSec {
				t.Errorf("HealthCheck %v checkIntervalSec = %d, want %d", rID.Key, hc.GA.CheckIntervalSec, *want.CheckIntervalSec)
			}
			if want.TimeoutSec != nil && hc.GA.TimeoutSec != *want.TimeoutSec {
				t.Errorf("HealthCheck %v timeoutSec = %d, want %d", rID.Key, hc.GA.TimeoutSec, *want.TimeoutSec)
			}
			if want.HealthyThreshold != nil && hc.GA.HealthyThreshold != *want.HealthyThreshold {
				t.Errorf("HealthCheck %v healthyThreshold = %d, want %d", rID.Key, hc.GA.HealthyThreshold, *want.HealthyThreshold)
			}
			if want.UnhealthyThreshold != nil && hc.GA.UnhealthyThreshold != *want.UnhealthyThreshold {
				t.Errorf("HealthCheck %v unhealthThreshold = %d, want %d", rID.Key, hc.GA.UnhealthyThreshold, *want.UnhealthyThreshold)
			}
			if want.Type != nil {
				t.Errorf("HealthCheck %v type = %s, want %s", rID.Key, hc.GA.Type, *want.Type)
			}
			if want.Port != nil && common.port != *want.Port {
				t.Errorf("HealthCheck %v port = %d, want %d", rID.Key, common.port, *want.Port)
			}
			if want.RequestPath != nil && common.requestPath != *want.RequestPath {
				t.Errorf("HealthCheck %v requestPath = %q, want %q", rID.Key, common.requestPath, *want.RequestPath)
			}
		}
	}
}
<commit_msg>Add transition test for healthcheck configuration<commit_after>/*
Copyright 2020 The Kubernetes Authors.

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

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

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

package main

import (
	"context"
	"fmt"
	"testing"

	"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/util/retry"
	"k8s.io/ingress-gce/pkg/annotations"
	backendconfig "k8s.io/ingress-gce/pkg/apis/backendconfig/v1"
	"k8s.io/ingress-gce/pkg/e2e"
	"k8s.io/ingress-gce/pkg/e2e/adapter"
	"k8s.io/ingress-gce/pkg/fuzz"
	"k8s.io/ingress-gce/pkg/fuzz/features"
)

func TestHealthCheck(t *testing.T) {
	t.Parallel()

	pint64 := func(x int64) *int64 { return &x }
	pstring := func(x string) *string { return &x }

	for _, tc := range []struct {
		desc     string
		beConfig *backendconfig.BackendConfig
		want     *backendconfig.HealthCheckConfig
	}{
		{
			desc:     "override healthcheck",
			beConfig: fuzz.NewBackendConfigBuilder("", "backendconfig-1").Build(),
			want: &backendconfig.HealthCheckConfig{
				CheckIntervalSec:   pint64(7),
				TimeoutSec:         pint64(3),
				HealthyThreshold:   pint64(3),
				UnhealthyThreshold: pint64(5),
				RequestPath:        pstring("/my-path"),
			},
		},
	} {
		tc := tc // Capture tc as we are running this in parallel.
		Framework.RunWithSandbox(tc.desc, t, func(t *testing.T, s *e2e.Sandbox) {
			t.Parallel()

			ctx := context.Background()

			backendConfigAnnotation := map[string]string{
				annotations.BackendConfigKey: `{"default":"backendconfig-1"}`,
			}
			tc.beConfig.Spec.HealthCheck = tc.want

			becrud := adapter.BackendConfigCRUD{C: Framework.BackendConfigClient}
			tc.beConfig.Namespace = s.Namespace
			if _, err := becrud.Create(tc.beConfig); err != nil {
				t.Fatalf("error creating BackendConfig: %v", err)
			}
			t.Logf("BackendConfig created (%s/%s) ", s.Namespace, tc.beConfig.Name)

			_, err := e2e.CreateEchoService(s, "service-1", backendConfigAnnotation)
			if err != nil {
				t.Fatalf("error creating echo service: %v", err)
			}
			t.Logf("Echo service created (%s/%s)", s.Namespace, "service-1")

			ing := fuzz.NewIngressBuilder(s.Namespace, "ingress-1", "").
				DefaultBackend("service-1", intstr.FromInt(80)).
				Build()
			crud := adapter.IngressCRUD{C: Framework.Clientset}
			if _, err := crud.Create(ing); err != nil {
				t.Fatalf("error creating Ingress spec: %v", err)
			}
			t.Logf("Ingress created (%s/%s)", s.Namespace, ing.Name)

			ing, err = e2e.WaitForIngress(s, ing, nil)
			if err != nil {
				t.Fatalf("error waiting for Ingress to stabilize: %v", err)
			}
			t.Logf("GCLB resources created (%s/%s)", s.Namespace, ing.Name)

			vip := ing.Status.LoadBalancer.Ingress[0].IP
			t.Logf("Ingress %s/%s VIP = %s", s.Namespace, ing.Name, vip)
			params := &fuzz.GCLBForVIPParams{VIP: vip, Validators: fuzz.FeatureValidators(features.All)}
			gclb, err := fuzz.GCLBForVIP(context.Background(), Framework.Cloud, params)
			if err != nil {
				t.Fatalf("Error getting GCP resources for LB with IP = %q: %v", vip, err)
			}
			if err := verifyHealthCheck(t, gclb, tc.want); err != nil {
				t.Fatal(err)
			}

			// Change the configuration and wait for stabilization.
			if err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
				newBEConfig, err := becrud.Get(s.Namespace, tc.beConfig.Name)
				if err != nil {
					t.Fatalf("becrud.Get(%q, %q) = %v, want nil", s.Namespace, tc.beConfig.Name, err)
				}
				newBEConfig.Spec.HealthCheck.RequestPath = pstring("/other-path")
				if _, err := becrud.Update(newBEConfig); err != nil {
					return err
				}
				t.Logf("BackendConfig updated (%s/%s) ", s.Namespace, tc.beConfig.Name)
				return nil
			}); err != nil {
				t.Fatalf("error updating BackendConfig %s/%s: %v", s.Namespace, tc.beConfig.Name, err)
			}

			if err := wait.Poll(transitionPollInterval, transitionPollTimeout, func() (bool, error) {
				err := verifyHealthCheck(t, gclb, tc.want)
				if err == nil {
					return true, nil
				}
				t.Logf("Waiting for healthcheck to be updated: %v", err)
				return false, nil
			}); err != nil {
				t.Fatal(err)
			}

			// Wait for GCLB resources to be deleted.
			if err := crud.Delete(s.Namespace, ing.Name); err != nil {
				t.Errorf("Delete(%q) = %v, want nil", ing.Name, err)
			}

			deleteOptions := &fuzz.GCLBDeleteOptions{
				SkipDefaultBackend: true,
			}
			t.Logf("Waiting for GCLB resources to be deleted (%s/%s)", s.Namespace, ing.Name)
			if err := e2e.WaitForGCLBDeletion(ctx, Framework.Cloud, gclb, deleteOptions); err != nil {
				t.Errorf("e2e.WaitForGCLBDeletion(...) = %v, want nil", err)
			}
			t.Logf("GCLB resources deleted (%s/%s)", s.Namespace, ing.Name)
		})
	}
}

func verifyHealthCheck(t *testing.T, gclb *fuzz.GCLB, want *backendconfig.HealthCheckConfig) error {
	// We assume there is a single service for now. The logic will have to be
	// changed if there is more than one backend service.
	for _, bs := range gclb.BackendService {
		for _, hcURL := range bs.GA.HealthChecks {
			rID, err := cloud.ParseResourceURL(hcURL)
			if err != nil {
				t.Fatalf("cloud.ParseResourceURL(%q) = _, %v; want _, nil", hcURL, err)
			}
			hc, ok := gclb.HealthCheck[*rID.Key]
			if !ok {
				t.Fatalf("HealthCheck %s not found in BackendService %+v", rID.Key, bs)
			}

			// Pull out the field that are in common among the different
			// healthchecks per protocol.
			common := struct {
				port        int64
				requestPath string
			}{}
			switch {
			case hc.GA.Http2HealthCheck != nil:
				common.port = hc.GA.Http2HealthCheck.Port
				common.requestPath = hc.GA.Http2HealthCheck.RequestPath
			case hc.GA.HttpHealthCheck != nil:
				common.port = hc.GA.HttpHealthCheck.Port
				common.requestPath = hc.GA.HttpHealthCheck.RequestPath
			case hc.GA.HttpsHealthCheck != nil:
				common.port = hc.GA.HttpsHealthCheck.Port
				common.requestPath = hc.GA.HttpsHealthCheck.RequestPath
			}

			if want.CheckIntervalSec != nil && hc.GA.CheckIntervalSec != *want.CheckIntervalSec {
				return fmt.Errorf("HealthCheck %v checkIntervalSec = %d, want %d", rID.Key, hc.GA.CheckIntervalSec, *want.CheckIntervalSec)
			}
			if want.TimeoutSec != nil && hc.GA.TimeoutSec != *want.TimeoutSec {
				return fmt.Errorf("HealthCheck %v timeoutSec = %d, want %d", rID.Key, hc.GA.TimeoutSec, *want.TimeoutSec)
			}
			if want.HealthyThreshold != nil && hc.GA.HealthyThreshold != *want.HealthyThreshold {
				return fmt.Errorf("HealthCheck %v healthyThreshold = %d, want %d", rID.Key, hc.GA.HealthyThreshold, *want.HealthyThreshold)
			}
			if want.UnhealthyThreshold != nil && hc.GA.UnhealthyThreshold != *want.UnhealthyThreshold {
				return fmt.Errorf("HealthCheck %v unhealthThreshold = %d, want %d", rID.Key, hc.GA.UnhealthyThreshold, *want.UnhealthyThreshold)
			}
			if want.Type != nil {
				return fmt.Errorf("HealthCheck %v type = %s, want %s", rID.Key, hc.GA.Type, *want.Type)
			}
			if want.Port != nil && common.port != *want.Port {
				return fmt.Errorf("HealthCheck %v port = %d, want %d", rID.Key, common.port, *want.Port)
			}
			if want.RequestPath != nil && common.requestPath != *want.RequestPath {
				return fmt.Errorf("HealthCheck %v requestPath = %q, want %q", rID.Key, common.requestPath, *want.RequestPath)
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"testing"
	"time"

	"gopkg.in/mgo.v2"

	"github.com/stretchr/testify/assert"

	bsonScanner "github.com/Clever/oplog-replay/bson"
)

// simpleDocStruct is for inserting simple Mongo documents
type simpleDocStruct struct {
	key string
}

func getPaddedTime() int {
	time.Sleep(time.Duration(1) * time.Second)
	n := int(time.Now().Unix())
	time.Sleep(time.Duration(2) * time.Second)
	return n
}

func TestComposingWithOplogReplay(t *testing.T) {
	// This test assumes that we're connecting to Mongo replica set. Otherwise, the oplog won't
	// be generated.
	unixTime := getPaddedTime()
	session, err := mgo.Dial("localhost")
	assert.Nil(t, err)
	db := session.DB("myTestDb")
	c := db.C("myCollection")
	assert.Nil(t, c.Insert(&simpleDocStruct{key: "key"}))

	time.Sleep(time.Duration(5) * time.Second)

	assert.Nil(t, c.Insert(&simpleDocStruct{key: "key2"}))
	// Dump at the time we started operations. Should get both operations
	dumpAtTime(t, unixTime, 2, "{ns: {$ne: \"myTestDb.$cmd\"}}")
	// 5 seconds later we should get only one.
	dumpAtTime(t, unixTime+5, 1, "")
}

func TestCollectionFiltering(t *testing.T) {
	// This test assumes that we're connecting to Mongo replica set. Otherwise, the oplog won't
	// be generated.

	unixTime := getPaddedTime()
	session, err := mgo.Dial("localhost")
	assert.Nil(t, err)
	db := session.DB("myTestDb")
	c1, c2, c3 := db.C("myCollection"), db.C("yourCollection"), db.C("ourCollection")

	assert.Nil(t, c1.Insert(&simpleDocStruct{key: "key"}))
	assert.Nil(t, c2.Insert(&simpleDocStruct{key: "key2"}))
	assert.Nil(t, c3.Insert(&simpleDocStruct{key: "key3"}))

	dumpAtTime(t, unixTime, 3, "{ns: {$ne: \"myTestDb.$cmd\"}}")
	dumpAtTime(t, unixTime, 1, "{ns: \"myTestDb.myCollection\"}")
	dumpAtTime(t, unixTime, 2, "{ns: {$nin : [\"myTestDb.myCollection\", \"myTestDb.$cmd\"]}}")
}

func dumpAtTime(t *testing.T, unixTime, expectedResults int, query string) {
	tempDir, err := ioutil.TempDir("/tmp", "oplogDumpTest")
	assert.Nil(t, err)
	defer os.RemoveAll(tempDir)
	assert.Nil(t, runDump(tempDir, "localhost", query, unixTime))

	file, err := os.Open(tempDir + "/local/oplog.rs.bson")
	assert.Nil(t, err)
	scanner := bsonScanner.New(file)
	count := 0
	for scanner.Scan() {
		count = count + 1
	}
	assert.Equal(t, expectedResults, count)
}

func TestCopyBsonFile(t *testing.T) {
	tempDir, err := ioutil.TempDir("/tmp", "oplogDumpTest")
	assert.Nil(t, err)
	defer os.RemoveAll(tempDir)

	// Create a directory structure that mirrors the oplog one the code expects
	err = os.Mkdir(tempDir+"/local", 0744)
	assert.Nil(t, err)
	file, err := os.Create(tempDir + "/local/oplog.rs.bson")
	assert.Nil(t, err)
	assert.Nil(t, ioutil.WriteFile(file.Name(), []byte("test-bson-file"), 0644))

	// Create a file to copy to
	toFile, err := ioutil.TempFile(tempDir, "bsonCopyTest")
	assert.Nil(t, err)
	assert.Nil(t, copyBsonFile(tempDir, toFile.Name()))

	// Check that the data matches
	fileData, err := ioutil.ReadFile(toFile.Name())
	assert.Nil(t, err)
	assert.Equal(t, "test-bson-file", string(fileData))
}
<commit_msg>log all the test errors<commit_after>package main

import (
	"io/ioutil"
	"os"
	"testing"
	"time"

	"gopkg.in/mgo.v2"

	"github.com/stretchr/testify/assert"

	bsonScanner "github.com/Clever/oplog-replay/bson"
)

// simpleDocStruct is for inserting simple Mongo documents
type simpleDocStruct struct {
	key string
}

func getPaddedTime() int {
	time.Sleep(time.Duration(1) * time.Second)
	n := int(time.Now().Unix())
	time.Sleep(time.Duration(2) * time.Second)
	return n
}

func TestComposingWithOplogReplay(t *testing.T) {
	// This test assumes that we're connecting to Mongo replica set. Otherwise, the oplog won't
	// be generated.
	unixTime := getPaddedTime()
	session, err := mgo.Dial("localhost")
	if err != nil {
		t.Log(err.Error())
	}

	assert.Nil(t, err)
	db := session.DB("myTestDb")
	c := db.C("myCollection")
	assert.Nil(t, c.Insert(&simpleDocStruct{key: "key"}))

	time.Sleep(time.Duration(5) * time.Second)

	assert.Nil(t, c.Insert(&simpleDocStruct{key: "key2"}))
	// Dump at the time we started operations. Should get both operations
	dumpAtTime(t, unixTime, 2, "{ns: {$ne: \"myTestDb.$cmd\"}}")
	// 5 seconds later we should get only one.
	dumpAtTime(t, unixTime+5, 1, "")
}

func TestCollectionFiltering(t *testing.T) {
	// This test assumes that we're connecting to Mongo replica set. Otherwise, the oplog won't
	// be generated.

	unixTime := getPaddedTime()
	session, err := mgo.Dial("localhost")

	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)
	db := session.DB("myTestDb")
	c1, c2, c3 := db.C("myCollection"), db.C("yourCollection"), db.C("ourCollection")

	assert.Nil(t, c1.Insert(&simpleDocStruct{key: "key"}))
	assert.Nil(t, c2.Insert(&simpleDocStruct{key: "key2"}))
	assert.Nil(t, c3.Insert(&simpleDocStruct{key: "key3"}))

	dumpAtTime(t, unixTime, 3, "{ns: {$ne: \"myTestDb.$cmd\"}}")
	dumpAtTime(t, unixTime, 1, "{ns: \"myTestDb.myCollection\"}")
	dumpAtTime(t, unixTime, 2, "{ns: {$nin : [\"myTestDb.myCollection\", \"myTestDb.$cmd\"]}}")
}

func dumpAtTime(t *testing.T, unixTime, expectedResults int, query string) {
	tempDir, err := ioutil.TempDir("/tmp", "oplogDumpTest")

	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)
	defer os.RemoveAll(tempDir)
	err = runDump(tempDir, "localhost", query, unixTime)
	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)

	file, err := os.Open(tempDir + "/local/oplog.rs.bson")

	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)
	scanner := bsonScanner.New(file)
	count := 0
	for scanner.Scan() {
		count = count + 1
	}
	assert.Equal(t, expectedResults, count)
}

func TestCopyBsonFile(t *testing.T) {
	tempDir, err := ioutil.TempDir("/tmp", "oplogDumpTest")

	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)
	defer os.RemoveAll(tempDir)

	// Create a directory structure that mirrors the oplog one the code expects
	err = os.Mkdir(tempDir+"/local", 0744)

	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)
	file, err := os.Create(tempDir + "/local/oplog.rs.bson")

	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)
	assert.Nil(t, ioutil.WriteFile(file.Name(), []byte("test-bson-file"), 0644))

	// Create a file to copy to
	toFile, err := ioutil.TempFile(tempDir, "bsonCopyTest")

	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)
	assert.Nil(t, copyBsonFile(tempDir, toFile.Name()))

	// Check that the data matches
	fileData, err := ioutil.ReadFile(toFile.Name())

	if err != nil {
		t.Log(err.Error())
	}
	assert.Nil(t, err)
	assert.Equal(t, "test-bson-file", string(fileData))
}
<|endoftext|>