<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net"
	"os"
	"strconv"
	"syscall"
	"time"

	"path/filepath"

	"github.com/mitchellh/go-homedir"
)

const baseDir string = "muck"
const inFile string = "in"
const outFile string = "out"

var (
	connectionName   string
	connectionServer string
	connectionPort   uint
	useSSL           bool
	debugMode        bool
)

func debugLog(log ...string) {
	if debugMode {
		fmt.Println(log)
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Println("Fatal error ", err.Error())
		os.Exit(1)
	}
}

func getTimestamp() string {
	return time.Now().Format("2006-01-02T150405")
}

func initVars() {
	flag.BoolVar(&useSSL, "ssl", false, "Enable ssl")
	flag.BoolVar(&debugMode, "debug", false, "Enable debug")
	flag.Parse()

	args := flag.Args()
	if len(args) != 3 {
		fmt.Println("Usage: mm [--ssl] [--debug] <name> <server> <port>")
		os.Exit(1)
	}
	connectionName = args[0]
	connectionServer = args[1]
	p, err := strconv.Atoi(args[2])
	checkError(err)
	connectionPort = uint(p)

	debugLog("Name:", connectionName)
	debugLog("Server:", connectionServer)
	debugLog("Port:", strconv.Itoa(int(connectionPort)))
	debugLog("SSL?:", strconv.FormatBool(useSSL))
}

func getWorkingDir(main string, sub string) string {
	var home string

	h, err := homedir.Dir()
	checkError(err)
	debugLog("Home directory", h)

	w := filepath.Join(h, main, sub)
	return w
}

func makeInFIFO(file string) {
	if _, err := os.Stat(file); err == nil {
		fmt.Println("FIFO already exists. Unlink or exit")
		fmt.Println("if you run multiple connection with the same name you're gonna have a bad time")
		fmt.Print("Type YES to unlink and recreate: ")
		i := bufio.NewReader(os.Stdin)
		a, err := i.ReadString('\n')
		checkError(err)
		if a != "YES" {
			fmt.Println("Canceling. Please remove FIFO before running")
			os.Exit(1)
		}
		syscall.Unlink(file)
	}

	err := syscall.Mkfifo(file, 0644)
	checkError(err)
}

func readToOutfile(conn net.TCPConn, file os.File) {

}

func main() {
	fmt.Println("~Started at", getTimestamp())
	initVars()

	// Make and move to working directory
	workingDir := getWorkingDir(baseDir, connectionName)
	errMk := os.MkdirAll(workingDir, 0755)
	checkError(errMk)

	errCh := os.Chdir(workingDir)
	checkError(errCh)

	// Make the in FIFO
	makeInFIFO(inFile)
	defer syscall.Unlink(inFile)

	//create connection with inFile to write and outFile to read
	connStr := fmt.Sprintf("%s:%d", connectionServer, connectionPort)
	tcpAddr, err := net.ResolveTCPAddr("tcp4", connStr)
	checkError(err)
	connection, err := net.DialTCP("tcp", nil, tcpAddr)
	checkError(err)
	fmt.Println("~Connected at", getTimestamp())
	defer connection.Close()

	// We keep alive for mucks
	errSka := connection.SetKeepAlive(true)
	checkError(errSka)
	var keepalive time.Duration = 15 * time.Minute
	errSkap := connection.SetKeepAlivePeriod(keepalive)
	checkError(errSkap)

	out, err := os.Create(outFile)
	checkError(err)
	defer out.Close()

	go readToOutfile(connection, out)

	//defer rolling out

}
<commit_msg>minor<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net"
	"os"
	"strconv"
	"syscall"
	"time"

	"path/filepath"

	"github.com/mitchellh/go-homedir"
)

const baseDir string = "muck"
const inFile string = "in"
const outFile string = "out"

var (
	connectionName   string
	connectionServer string
	connectionPort   uint
	useSSL           bool
	debugMode        bool
)

func debugLog(log ...string) {
	if debugMode {
		fmt.Println(log)
	}
}

func checkError(err error) {
	if err != nil {
		fmt.Println("Fatal error ", err.Error())
		os.Exit(1)
	}
}

func getTimestamp() string {
	return time.Now().Format("2006-01-02T150405")
}

func initVars() {
	flag.BoolVar(&useSSL, "ssl", false, "Enable ssl")
	flag.BoolVar(&debugMode, "debug", false, "Enable debug")
	flag.Parse()

	args := flag.Args()
	if len(args) != 3 {
		fmt.Println("Usage: mm [--ssl] [--debug] <name> <server> <port>")
		os.Exit(1)
	}
	connectionName = args[0]
	connectionServer = args[1]
	p, err := strconv.Atoi(args[2])
	checkError(err)
	connectionPort = uint(p)

	debugLog("Name:", connectionName)
	debugLog("Server:", connectionServer)
	debugLog("Port:", strconv.Itoa(int(connectionPort)))
	debugLog("SSL?:", strconv.FormatBool(useSSL))
}

func getWorkingDir(main string, sub string) string {
	h, err := homedir.Dir()
	checkError(err)
	debugLog("Home directory", h)

	w := filepath.Join(h, main, sub)
	return w
}

func makeInFIFO(file string) {
	if _, err := os.Stat(file); err == nil {
		fmt.Println("FIFO already exists. Unlink or exit")
		fmt.Println("if you run multiple connection with the same name you're gonna have a bad time")
		fmt.Print("Type YES to unlink and recreate: ")
		i := bufio.NewReader(os.Stdin)
		a, err := i.ReadString('\n')
		checkError(err)
		if a != "YES" {
			fmt.Println("Canceling. Please remove FIFO before running")
			os.Exit(1)
		}
		syscall.Unlink(file)
	}

	err := syscall.Mkfifo(file, 0644)
	checkError(err)
}

func readToOutfile(conn net.TCPConn, file os.File) {

}

func main() {
	fmt.Println("~Started at", getTimestamp())
	initVars()

	// Make and move to working directory
	workingDir := getWorkingDir(baseDir, connectionName)
	errMk := os.MkdirAll(workingDir, 0755)
	checkError(errMk)

	errCh := os.Chdir(workingDir)
	checkError(errCh)

	// Make the in FIFO
	makeInFIFO(inFile)
	defer syscall.Unlink(inFile)

	//create connection with inFile to write and outFile to read
	connStr := fmt.Sprintf("%s:%d", connectionServer, connectionPort)
	tcpAddr, err := net.ResolveTCPAddr("tcp4", connStr)
	checkError(err)
	connection, err := net.DialTCP("tcp", nil, tcpAddr)
	checkError(err)
	fmt.Println("~Connected at", getTimestamp())
	defer connection.Close()

	// We keep alive for mucks
	errSka := connection.SetKeepAlive(true)
	checkError(errSka)
	var keepalive time.Duration = 15 * time.Minute
	errSkap := connection.SetKeepAlivePeriod(keepalive)
	checkError(errSkap)

	out, err := os.Create(outFile)
	checkError(err)
	defer out.Close()

	go readToOutfile(connection, out)

	//defer rolling out

}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"os"

	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"regexp"
	"strings"

	"github.com/mgutz/ansi"

	"net"
)

var connid = uint64(0)
var mapping = map[string]string{}
var verbose = false
var veryverbose = false

func main() {
	app := cli.NewApp()
	app.Name = "flow-debugproxy"
	app.Usage = "Flow Framework xDebug proxy"
	app.Author = "Dominique Feyer"
	app.Email = "dominique@neos.io"
	app.Version = "0.1.0"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "xdebug, l",
			Value: "127.0.0.1:9000",
			Usage: "Listen address IP and port number",
		},
		cli.StringFlag{
			Name:  "ide, I",
			Value: "127.0.0.1:9010",
			Usage: "Bind address IP and port number",
		},
		cli.StringFlag{
			Name:  "context, c",
			Value: "Development",
			Usage: "The context to run as",
		},
		cli.BoolFlag{
			Name:  "verbose",
			Usage: "Verbose",
		},
		cli.BoolFlag{
			Name:  "vv",
			Usage: "Very verbose",
		},
	}

	app.Action = func(cli *cli.Context) {
		localAddr := cli.String("xdebug")
		remoteAddr := cli.String("ide")
		laddr, err := net.ResolveTCPAddr("tcp", localAddr)
		check(err)
		raddr, err := net.ResolveTCPAddr("tcp", remoteAddr)
		check(err)
		listener, err := net.ListenTCP("tcp", laddr)
		check(err)

		fmt.Printf(c("Debugger from %v\n", "green"), localAddr)
		fmt.Printf(c("IDE from %v\n", "green"), remoteAddr)

		verbose = cli.Bool("verbose")
		veryverbose = cli.Bool("vv")

		if veryverbose {
			verbose = true
		}

		for {
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Printf("Failed to accept connection '%s'\n", err)
				continue
			}
			connid++

			proxy := &proxy{
				lconn:  conn,
				laddr:  laddr,
				raddr:  raddr,
				erred:  false,
				errsig: make(chan bool),
			}
			go proxy.start()
		}
	}

	app.Run(os.Args)
}

//A proxy represents a pair of connections and their state
type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  *net.TCPConn
	erred         bool
	errsig        chan bool
}

func (p *proxy) log(s string, args ...interface{}) {
	if verbose {
		log(s, args...)
	}
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start() {
	defer p.lconn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn = rconn
	defer p.rconn.Close()
	//display both ends
	p.log("Opened %s >>> %s", p.lconn.RemoteAddr().String(), p.rconn.RemoteAddr().String())
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn)
	go p.pipe(p.rconn, p.lconn)
	//wait for close...
	<-p.errsig
	p.log("Closed (%d bytes sent, %d bytes recieved)", p.sentBytes, p.receivedBytes)
}

func (p *proxy) pipe(src, dst *net.TCPConn) {
	//data direction
	var f, h, command string
	isFromDebugger := src == p.lconn
	if isFromDebugger {
		f = "\nDebugger >>> IDE"
	} else {
		f = "\nIDE >>> Debugger"
	}
	h = "%s"
	//directional copy (64k buffer)
	buff := make([]byte, 0xffff)
	for {
		n, err := src.Read(buff)
		if err != nil {
			p.err("Read failed '%s'\n", err)
			return
		}
		b := buff[:n]
		command = "Not really important for us ..."
		p.log(h, f)
		//extract command name
		if isFromDebugger {
			b = applyMappingToXML(b)
		} else {
			commandParts := strings.Fields(fmt.Sprintf(h, b))
			command = commandParts[0]
			if command == "breakpoint_set" {
				file := commandParts[6]
				if verbose {
					p.log("Command: %s", c(command, "blue"))
				}
				fileMapping := mapPath(file)
				b = bytes.Replace(b, []byte(file), []byte(fileMapping), 1)
			}
		}
		//show output
		if veryverbose {
			p.log(h, "\n"+c(fmt.Sprintf(h, b), "blue"))
		} else {
			p.log(h, "")
		}
		//write out result
		n, err = dst.Write(b)
		if err != nil {
			p.err("Write failed '%s'\n", err)
			return
		}
		if isFromDebugger {
			p.sentBytes += uint64(n)
		} else {
			p.receivedBytes += uint64(n)
		}
	}
}

func buildClassNameFromPath(path string) []string {
	// todo add support for PSR4
	r := regexp.MustCompile(`(.*?)/Packages/(.*?)/Classes/(.*).php`)
	match := r.FindStringSubmatch(path)
	basePath := match[1]
	r = regexp.MustCompile(`[\./]`)
	className := r.ReplaceAllString(match[3], "_")
	return []string{basePath, className}
}

func mapPath(originalPath string) string {
	if strings.Contains(originalPath, "/Packages/") {
		parts := buildClassNameFromPath(originalPath)
		codeCacheFileName := parts[0] + "/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/" + parts[1] + ".php"
		realCodeCacheFileName := getRealFilename(codeCacheFileName)
		if _, err := os.Stat(realCodeCacheFileName); err == nil {
			return registerPathMapping(realCodeCacheFileName, originalPath)
		}
	}

	return originalPath
}

func applyMappingToXML(xml []byte) []byte {
	r := regexp.MustCompile(`filename=["]?file://(\S+)/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/([^"]*)\.php`)
	var processedMapping = map[string]bool{}

	for _, match := range r.FindAllStringSubmatch(string(xml), -1) {
		path := match[1] + "/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/" + match[2] + ".php"
		if _, ok := processedMapping[path]; ok == false {
			processedMapping[path] = true
			if originalPath, exist := mapping[path]; exist {
				if veryverbose {
					fmt.Printf("Umpa Lumpa can help you, he know the mapping\n>>> %s\n", originalPath)
				}
			} else {
				if veryverbose {
					fmt.Printf("Umpa Lumpa need to work harder, need to reverse this one\n>>> %s\n", path)
				}
			}
		}
	}

	return xml
}

func registerPathMapping(path string, originalPath string) string {
	dat, err := ioutil.ReadFile(path)
	check(err)
	//check if file contains flow annotation
	if strings.Contains(string(dat), "@Flow\\") {
		if verbose {
			log("%s", c("Our Umpa Lumpa take care of your mapping and they did a great job, they found a proxy for you:", "green"))
			log(">>> %s\n", c(path, "green"))
		}

		if _, exist := mapping[path]; exist == false {
			fmt.Printf("Register new mapping:\n%s\n", path)
			mapping[path] = originalPath
		}
		return path
	}
	return originalPath
}

func getRealFilename(path string) string {
	return strings.TrimPrefix(path, "file://")
}

//helper functions

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func c(str, style string) string {
	return ansi.Color(str, style)
}

func log(f string, args ...interface{}) {
	fmt.Printf(c(f, "green")+"\n", args...)
}

func warn(f string, args ...interface{}) {
	fmt.Printf(c(f, "red")+"\n", args...)
}
<commit_msg>[TASK] First working version of the path mapping<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"os"

	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"

	"github.com/mgutz/ansi"

	"net"
)

var connid = uint64(0)
var mapping = map[string]string{}
var verbose = false
var veryverbose = false
var h = "%s"

func main() {
	app := cli.NewApp()
	app.Name = "flow-debugproxy"
	app.Usage = "Flow Framework xDebug proxy"
	app.Author = "Dominique Feyer"
	app.Email = "dominique@neos.io"
	app.Version = "0.1.0"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "xdebug, l",
			Value: "127.0.0.1:9000",
			Usage: "Listen address IP and port number",
		},
		cli.StringFlag{
			Name:  "ide, I",
			Value: "127.0.0.1:9010",
			Usage: "Bind address IP and port number",
		},
		cli.StringFlag{
			Name:  "context, c",
			Value: "Development",
			Usage: "The context to run as",
		},
		cli.BoolFlag{
			Name:  "verbose",
			Usage: "Verbose",
		},
		cli.BoolFlag{
			Name:  "vv",
			Usage: "Very verbose",
		},
	}

	app.Action = func(cli *cli.Context) {
		localAddr := cli.String("xdebug")
		remoteAddr := cli.String("ide")
		laddr, err := net.ResolveTCPAddr("tcp", localAddr)
		check(err)
		raddr, err := net.ResolveTCPAddr("tcp", remoteAddr)
		check(err)
		listener, err := net.ListenTCP("tcp", laddr)
		check(err)

		fmt.Printf(c("Debugger from %v\n", "green"), localAddr)
		fmt.Printf(c("IDE from %v\n", "green"), remoteAddr)

		verbose = cli.Bool("verbose")
		veryverbose = cli.Bool("vv")

		if veryverbose {
			verbose = true
		}

		for {
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Printf("Failed to accept connection '%s'\n", err)
				continue
			}
			connid++

			proxy := &proxy{
				lconn:  conn,
				laddr:  laddr,
				raddr:  raddr,
				erred:  false,
				errsig: make(chan bool),
			}
			go proxy.start()
		}
	}

	app.Run(os.Args)
}

//A proxy represents a pair of connections and their state
type proxy struct {
	sentBytes     uint64
	receivedBytes uint64
	laddr, raddr  *net.TCPAddr
	lconn, rconn  *net.TCPConn
	erred         bool
	errsig        chan bool
}

func (p *proxy) log(s string, args ...interface{}) {
	if verbose {
		log(s, args...)
	}
}

func (p *proxy) err(s string, err error) {
	if p.erred {
		return
	}
	if err != io.EOF {
		warn(s, err)
	}
	p.errsig <- true
	p.erred = true
}

func (p *proxy) start() {
	defer p.lconn.Close()
	//connect to remote
	rconn, err := net.DialTCP("tcp", nil, p.raddr)
	if err != nil {
		p.err("Remote connection failed: %s", err)
		return
	}
	p.rconn = rconn
	defer p.rconn.Close()
	//display both ends
	p.log("Opened %s >>> %s", p.lconn.RemoteAddr().String(), p.rconn.RemoteAddr().String())
	//bidirectional copy
	go p.pipe(p.lconn, p.rconn)
	go p.pipe(p.rconn, p.lconn)
	//wait for close...
	<-p.errsig
	p.log("Closed (%d bytes sent, %d bytes recieved)", p.sentBytes, p.receivedBytes)
}

func (p *proxy) pipe(src, dst *net.TCPConn) {
	//data direction
	var f, h string
	isFromDebugger := src == p.lconn
	if isFromDebugger {
		f = "\nDebugger >>> IDE\n================"
	} else {
		f = "\nIDE >>> Debugger\n================"
	}
	h = "%s"
	//directional copy (64k buffer)
	buff := make([]byte, 0xffff)
	for {
		n, err := src.Read(buff)
		if err != nil {
			p.err("Read failed '%s'\n", err)
			return
		}
		b := buff[:n]
		p.log(h, f)
		if veryverbose {
			if isFromDebugger {
				p.log("Raw protocol:\n%s\n", c(fmt.Sprintf(h, b), "blue"))
			} else {
				p.log("Raw protocol:\n%s\n", c(fmt.Sprintf(h, debugTextProtocol(b)), "blue"))
			}
		}
		//extract command name
		if isFromDebugger {
			b = applyMappingToXML(b)
		} else {
			b = applyMappingToTextProtocol(b)
		}
		//show output
		if veryverbose {
			if isFromDebugger {
				p.log("Processed protocol:\n%s\n", c(fmt.Sprintf(h, b), "blue"))
			} else {
				p.log("Processed protocol:\n%s\n", c(fmt.Sprintf(h, debugTextProtocol(b)), "blue"))
			}
		} else {
			p.log(h, "")
		}
		//write out result
		n, err = dst.Write(b)
		if err != nil {
			p.err("Write failed '%s'\n", err)
			return
		}
		if isFromDebugger {
			p.sentBytes += uint64(n)
		} else {
			p.receivedBytes += uint64(n)
		}
	}
}

func debugTextProtocol(protocol []byte) []byte {
	return bytes.Trim(bytes.Replace(protocol, []byte("\x00"), []byte("\n"), -1), "\n")
}

func buildClassNameFromPath(path string) []string {
	// todo add support for PSR4
	r := regexp.MustCompile(`(.*?)/Packages/(.*?)/Classes/(.*).php`)
	match := r.FindStringSubmatch(path)
	basePath := match[1]
	r = regexp.MustCompile(`[\./]`)
	className := r.ReplaceAllString(match[3], "_")
	return []string{basePath, className}
}

func mapPath(originalPath string) string {
	if strings.Contains(originalPath, "/Packages/") {
		parts := buildClassNameFromPath(originalPath)
		codeCacheFileName := parts[0] + "/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/" + parts[1] + ".php"
		realCodeCacheFileName := getRealFilename(codeCacheFileName)
		if _, err := os.Stat(realCodeCacheFileName); err == nil {
			return registerPathMapping(realCodeCacheFileName, originalPath)
		}
	}

	return originalPath
}

func applyMappingToTextProtocol(protocol []byte) []byte {
	commandParts := strings.Fields(fmt.Sprintf(h, protocol))
	command := commandParts[0]
	if command == "breakpoint_set" {
		file := commandParts[6]
		if verbose {
			log("Command: %s", c(command, "blue"))
		}
		fileMapping := mapPath(file)
		protocol = bytes.Replace(protocol, []byte(file), []byte("file://"+fileMapping), 1)
	}

	return protocol
}

func applyMappingToXML(xml []byte) []byte {
	r := regexp.MustCompile(`filename=["]?file://(\S+)/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/([^"]*)\.php`)
	var processedMapping = map[string]string{}

	for _, match := range r.FindAllStringSubmatch(string(xml), -1) {
		path := match[1] + "/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/" + match[2] + ".php"
		if _, ok := processedMapping[path]; ok == false {
			if originalPath, exist := mapping[path]; exist {
				if veryverbose {
					log("Umpa Lumpa can help you, he know the mapping\n%s\n%s\n", c(">>> "+fmt.Sprintf(h, path), "yellow"), c(">>> "+fmt.Sprintf(h, getRealFilename(originalPath)), "green"))
				}
				processedMapping[path] = originalPath
			} else {
				originalPath = readOriginalPathFromCache(path)
				processedMapping[path] = originalPath
			}
		}
	}

	for path, originalPath := range processedMapping {
		path = getRealFilename(path)
		originalPath = getRealFilename(originalPath)
		xml = bytes.Replace(xml, []byte(path), []byte(originalPath), -1)
	}
	s := strings.Split(string(xml), "\x00")
	i, err := strconv.Atoi(s[0])
	if err != nil {
		//handle error
		fmt.Println(err)
		os.Exit(2)
	}
	l := len(s[1])
	if i != l {
		xml = bytes.Replace(xml, []byte(strconv.Itoa(i)), []byte(strconv.Itoa(l)), 1)
	}

	return xml
}

func readOriginalPathFromCache(path string) string {
	dat, err := ioutil.ReadFile(path)
	check(err)
	r := regexp.MustCompile(`(?m)^# PathAndFilename: (.*)$`)
	match := r.FindStringSubmatch(string(dat))
	//todo check if the match contain something
	originalPath := match[1]
	if veryverbose {
		log("Umpa Lumpa need to work harder, need to reverse this one\n>>> %s\n>>> %s\n", c(fmt.Sprintf(h, path), "yellow"), c(fmt.Sprintf(h, originalPath), "green"))
	}
	registerPathMapping(path, originalPath)
	return originalPath
}

func registerPathMapping(path string, originalPath string) string {
	dat, err := ioutil.ReadFile(path)
	check(err)
	//check if file contains flow annotation
	if strings.Contains(string(dat), "@Flow\\") {
		if verbose {
			log("%s", c("Our Umpa Lumpa take care of your mapping and they did a great job, they found a proxy for you:", "green"))
			log(">>> %s\n", c(path, "green"))
		}

		if _, exist := mapping[path]; exist == false {
			mapping[path] = originalPath
		}
		return path
	}
	return originalPath
}

func getRealFilename(path string) string {
	return strings.TrimPrefix(path, "file://")
}

//helper functions

func check(err error) {
	if err != nil {
		warn(err.Error())
		os.Exit(1)
	}
}

func c(str, style string) string {
	return ansi.Color(str, style)
}

func log(f string, args ...interface{}) {
	fmt.Printf(c(f, "green")+"\n", args...)
}

func warn(f string, args ...interface{}) {
	fmt.Printf(c(f, "red")+"\n", args...)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/pranavraja/refactor/confirm"
	"github.com/pranavraja/refactor/patch"
	"github.com/vrischmann/termcolor"
	"io"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"
)

func walk(root string, suffix string, filePaths chan<- string) {
	defer close(filePaths)
	entries, err := ioutil.ReadDir(root)
	if err != nil {
		return
	}
	for _, file := range entries {
		if strings.HasPrefix(file.Name(), ".") {
			continue // Ignore hidden files
		}
		fullPath := path.Join(root, file.Name())
		if file.IsDir() {
			nestedFilePaths := make(chan string)
			go walk(fullPath, suffix, nestedFilePaths)
			for f := range nestedFilePaths {
				filePaths <- f
			}
		} else {
			if strings.HasSuffix(fullPath, suffix) {
				filePaths <- fullPath
			}
		}
	}
}

func prettyPrint(filename string, patch *patch.Patch, out io.Writer) {
	fmt.Fprintf(out, "%s\n %s\n %s\n", termcolor.Colored(filename, termcolor.Cyan), termcolor.Colored("-"+patch.Before(), termcolor.Red), termcolor.Colored("+"+patch.After(), termcolor.Green))
}

func confirmPatch(filename string, p *patch.Patch, confirmation confirm.Confirmation) bool {
	prettyPrint(filename, p, os.Stdout)
	if confirmation.Next() {
		return true
	} else {
		fmt.Printf("Continue? ([a]ll/[y]es/[n]o (default no): ")
		var input string
		_, err := fmt.Scanf("%s", &input)
		if err != nil {
			return false
		}
		switch input {
		case "a":
			confirmation.ConfirmAll()
		case "y":
			confirmation.ConfirmOnce()
		default:
			return false
		}
		return confirmation.Next()
	}
}

func main() {
	if len(os.Args) <= 3 {
		println("Example: refactor .rb require import\n  Replaces 'require' with 'import' in all .rb files")
		return
	}
	suffix := os.Args[1]
	find := regexp.MustCompile(os.Args[2])
	replace := []byte(os.Args[3])

	paths := make(chan string)
	go walk(".", suffix, paths)
	var confirmation confirm.Confirmation
	for file := range paths {
		patcher := patch.NewPatcher(file, find, replace)
		err := patcher.Load()
		if err != nil {
			println(err)
			return
		}
		for p := patcher.Next(); p != nil; p = patcher.Next() {
			canProceed := confirmPatch(file, p, confirmation)
			if canProceed {
				patcher.Accept(p)
			} else {
				patcher.Done()
				return
			}
		}
	}
}
<commit_msg>Keep confirmation around if confirmedAll<commit_after>package main

import (
	"fmt"
	"github.com/pranavraja/refactor/confirm"
	"github.com/pranavraja/refactor/patch"
	"github.com/vrischmann/termcolor"
	"io"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strings"
)

func walk(root string, suffix string, filePaths chan<- string) {
	defer close(filePaths)
	entries, err := ioutil.ReadDir(root)
	if err != nil {
		return
	}
	for _, file := range entries {
		if strings.HasPrefix(file.Name(), ".") {
			continue // Ignore hidden files
		}
		fullPath := path.Join(root, file.Name())
		if file.IsDir() {
			nestedFilePaths := make(chan string)
			go walk(fullPath, suffix, nestedFilePaths)
			for f := range nestedFilePaths {
				filePaths <- f
			}
		} else {
			if strings.HasSuffix(fullPath, suffix) {
				filePaths <- fullPath
			}
		}
	}
}

func prettyPrint(filename string, patch *patch.Patch, out io.Writer) {
	fmt.Fprintf(out, "%s\n %s\n %s\n", termcolor.Colored(filename, termcolor.Cyan), termcolor.Colored("-"+patch.Before(), termcolor.Red), termcolor.Colored("+"+patch.After(), termcolor.Green))
}

func confirmPatch(filename string, p *patch.Patch, confirmation *confirm.Confirmation) bool {
	prettyPrint(filename, p, os.Stdout)
	if confirmation.Next() {
		return true
	} else {
		fmt.Printf("Continue? ([a]ll/[y]es/[n]o (default no): ")
		var input string
		_, err := fmt.Scanf("%s", &input)
		if err != nil {
			return false
		}
		switch input {
		case "a":
			confirmation.ConfirmAll()
		case "y":
			confirmation.ConfirmOnce()
		default:
			return false
		}
		return confirmation.Next()
	}
}

func main() {
	if len(os.Args) <= 3 {
		println("Example: refactor .rb require import\n  Replaces 'require' with 'import' in all .rb files")
		return
	}
	suffix := os.Args[1]
	find := regexp.MustCompile(os.Args[2])
	replace := []byte(os.Args[3])

	paths := make(chan string)
	go walk(".", suffix, paths)
	confirmation := new(confirm.Confirmation)
	for file := range paths {
		patcher := patch.NewPatcher(file, find, replace)
		err := patcher.Load()
		if err != nil {
			println(err)
			return
		}
		for p := patcher.Next(); p != nil; p = patcher.Next() {
			canProceed := confirmPatch(file, p, confirmation)
			if canProceed {
				patcher.Accept(p)
			} else {
				patcher.Done()
				return
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	flags "github.com/jessevdk/go-flags"
	"github.com/monochromegane/terminal"
	"github.com/monochromegane/the_platinum_searcher/search"
	"github.com/monochromegane/the_platinum_searcher/search/option"
	"os"
	"runtime"
	"strings"
)

var opts option.Option

func init() {
	if cpu := runtime.NumCPU(); cpu == 1 {
		runtime.GOMAXPROCS(2)
	} else {
		runtime.GOMAXPROCS(cpu)
	}
}

func main() {

	parser := flags.NewParser(&opts, flags.Default)
	parser.Name = "pt"
	parser.Usage = "[OPTIONS] PATTERN [PATH]"

	args, err := parser.Parse()
	if err != nil {
		os.Exit(1)
	}

	opts.Proc = runtime.NumCPU()

	if !terminal.IsTerminal(os.Stdout) {
		opts.NoColor = true
		opts.NoGroup = true
	}

	if len(args) == 0 {
		parser.WriteHelp(os.Stdout)
		os.Exit(1)
	}

	var root = "."
	if len(args) == 2 {
		root = strings.TrimRight(args[1], "\"")
		_, err := os.Lstat(root)
		if err != nil {
			fmt.Printf("%s\n", err)
			os.Exit(1)
		}
	}

	searcher := search.Searcher{root, args[0], &opts}
        err = searcher.Search()
        if err != nil {
                fmt.Printf("%s\n", err)
                os.Exit(1)
        }
}
<commit_msg>Changed error message output to stderr from stdout.<commit_after>package main

import (
	"fmt"
	flags "github.com/jessevdk/go-flags"
	"github.com/monochromegane/terminal"
	"github.com/monochromegane/the_platinum_searcher/search"
	"github.com/monochromegane/the_platinum_searcher/search/option"
	"os"
	"runtime"
	"strings"
)

var opts option.Option

func init() {
	if cpu := runtime.NumCPU(); cpu == 1 {
		runtime.GOMAXPROCS(2)
	} else {
		runtime.GOMAXPROCS(cpu)
	}
}

func main() {

	parser := flags.NewParser(&opts, flags.Default)
	parser.Name = "pt"
	parser.Usage = "[OPTIONS] PATTERN [PATH]"

	args, err := parser.Parse()
	if err != nil {
		os.Exit(1)
	}

	opts.Proc = runtime.NumCPU()

	if !terminal.IsTerminal(os.Stdout) {
		opts.NoColor = true
		opts.NoGroup = true
	}

	if len(args) == 0 {
		parser.WriteHelp(os.Stdout)
		os.Exit(1)
	}

	var root = "."
	if len(args) == 2 {
		root = strings.TrimRight(args[1], "\"")
		_, err := os.Lstat(root)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(1)
		}
	}

	searcher := search.Searcher{root, args[0], &opts}
	err = searcher.Search()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


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

// Command present-tex generates LaTeX/Beamer slides from present.
//
// Usage of present-tex:
//
//   $ present-tex [options] [input-file [output.tex]]
//
// Examples:
//   $ present-tex input.slide > out.tex
//   $ present-tex input.slide out.tex
//   $ present-tex < input.slide > out.tex
//
// Options:
//   -base="": base path for slide templates
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"html/template"
	"io"
	"log"
	"os"
	"path"
	"strings"

	"golang.org/x/tools/present"
)

const (
	basePkg         = "github.com/sbinet/present-tex"
	basePathMessage = `
By default, present-tex locates the slide template files and associated
static content by looking for a %q package
in your Go workspaces (GOPATH).
You may use the -base flag to specify an alternate location.
`
)

func printf(format string, args ...interface{}) (int, error) {
	return fmt.Fprintf(os.Stderr, format, args...)
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `%[1]s - generates LaTeX/Beamer slides from present.

Usage of %[1]s:

$ %[1]s [options] [input-file [output.tex]]

Examples:

$ %[1]s input.slide > out.tex
$ %[1]s input.slide out.tex
$ %[1]s < input.slide > out.tex

Options:
`,
			os.Args[0],
		)
		flag.PrintDefaults()
	}

	tmpldir := ""
	flag.StringVar(&tmpldir, "base", "", "base path for slide templates")

	flag.Parse()

	if tmpldir == "" {
		p, err := build.Default.Import(basePkg, "", build.FindOnly)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't find present-tex files: %v\n", err)
			fmt.Fprintf(os.Stderr, basePathMessage, basePkg)
			os.Exit(1)
		}
		tmpldir = path.Join(p.Dir, "templates")
	}

	var (
		r      io.Reader
		w      io.Writer
		input  = "stdin"
		output = "stdout"
	)

	switch flag.NArg() {
	case 0:
		r = os.Stdin
		w = os.Stdout
	case 1:
		input = flag.Arg(0)
		f, err := os.Open(input)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		printf("input:  [%s]...\n", input)

		r = f
		w = os.Stdout

	case 2:

		input = flag.Arg(0)
		f, err := os.Open(input)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		printf("input:  [%s]...\n", input)

		tex, err := os.Create(output)
		if err != nil {
			log.Fatalf("could not create output file [%s]: %v\n", output, err)
		}
		defer func() {
			err = tex.Close()
			if err != nil {
				log.Fatalf("could not close output file [%s]: %v\n", output, err)
			}
		}()

		r = f
		w = tex

	default:
		flag.Usage()
		os.Exit(2)
	}

	doc, err := present.Parse(r, input, 0)
	if err != nil {
		log.Fatal(err)
	}

	tmpl, err := initTemplates(tmpldir)
	if err != nil {
		log.Fatal(err)
	}

	buf := new(bytes.Buffer)
	err = doc.Render(buf, tmpl)
	if err != nil {
		log.Fatal(err)
	}

	out := unescapeHTML(buf.Bytes())

	_, err = w.Write(out)
	if err != nil {
		log.Fatalf("could not fill output: %v\n", err)
	}
}

func unescapeHTML(data []byte) []byte {
	out := make([]byte, len(data))
	copy(out, data)
	for _, r := range []struct {
		old string
		new string
	}{
		{
			old: "<",
			new: "<",
		},
		{
			old: ">",
			new: ">",
		},
		{
			old: """,
			new: `"`,
		},
		{
			old: """,
			new: `"`,
		},
		{
			old: "&",
			new: "&",
		},
		{
			old: " ",
			new: " ",
		},
	} {
		out = bytes.Replace(out, []byte(r.old), []byte(r.new), -1)
	}
	return out
}

func initTemplates(base string) (*template.Template, error) {
	fname := path.Join(base, "beamer.tmpl")
	tmpl := template.New("").Funcs(funcs).Delims("<<", ">>")
	_, err := tmpl.ParseFiles(fname)
	if err != nil {
		return nil, err
	}

	return tmpl, err
}

// renderElem implements the elem template function, used to render
// sub-templates.
func renderElem(t *template.Template, e present.Elem) (template.HTML, error) {
	var data interface{} = e
	if s, ok := e.(present.Section); ok {
		data = struct {
			present.Section
			Template *template.Template
		}{s, t}
	}
	return execTemplate(t, e.TemplateName(), data)
}

var (
	funcs = template.FuncMap{}
)

func init() {
	funcs["elem"] = renderElem
	funcs["stringFromBytes"] = func(raw []byte) string { return string(raw) }
	funcs["join"] = func(lines []string) string { return strings.Join(lines, "\n") }
	funcs["nodot"] = func(s string) string {
		if strings.HasPrefix(s, ".") {
			return s[1:]
		}
		return s
	}
}

// execTemplate is a helper to execute a template and return the output as a
// template.HTML value.
func execTemplate(t *template.Template, name string, data interface{}) (template.HTML, error) {
	b := new(bytes.Buffer)
	err := t.ExecuteTemplate(b, name, data)
	if err != nil {
		return "", err
	}
	return template.HTML(b.String()), nil
}
<commit_msg>main: more html escape<commit_after>// Copyright 2015 The present-tex Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Command present-tex generates LaTeX/Beamer slides from present.
//
// Usage of present-tex:
//
//   $ present-tex [options] [input-file [output.tex]]
//
// Examples:
//   $ present-tex input.slide > out.tex
//   $ present-tex input.slide out.tex
//   $ present-tex < input.slide > out.tex
//
// Options:
//   -base="": base path for slide templates
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"html/template"
	"io"
	"log"
	"os"
	"path"
	"strings"

	"golang.org/x/tools/present"
)

const (
	basePkg         = "github.com/sbinet/present-tex"
	basePathMessage = `
By default, present-tex locates the slide template files and associated
static content by looking for a %q package
in your Go workspaces (GOPATH).
You may use the -base flag to specify an alternate location.
`
)

func printf(format string, args ...interface{}) (int, error) {
	return fmt.Fprintf(os.Stderr, format, args...)
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, `%[1]s - generates LaTeX/Beamer slides from present.

Usage of %[1]s:

$ %[1]s [options] [input-file [output.tex]]

Examples:

$ %[1]s input.slide > out.tex
$ %[1]s input.slide out.tex
$ %[1]s < input.slide > out.tex

Options:
`,
			os.Args[0],
		)
		flag.PrintDefaults()
	}

	tmpldir := ""
	flag.StringVar(&tmpldir, "base", "", "base path for slide templates")

	flag.Parse()

	if tmpldir == "" {
		p, err := build.Default.Import(basePkg, "", build.FindOnly)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Couldn't find present-tex files: %v\n", err)
			fmt.Fprintf(os.Stderr, basePathMessage, basePkg)
			os.Exit(1)
		}
		tmpldir = path.Join(p.Dir, "templates")
	}

	var (
		r      io.Reader
		w      io.Writer
		input  = "stdin"
		output = "stdout"
	)

	switch flag.NArg() {
	case 0:
		r = os.Stdin
		w = os.Stdout
	case 1:
		input = flag.Arg(0)
		f, err := os.Open(input)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		printf("input:  [%s]...\n", input)

		r = f
		w = os.Stdout

	case 2:

		input = flag.Arg(0)
		f, err := os.Open(input)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		printf("input:  [%s]...\n", input)

		tex, err := os.Create(output)
		if err != nil {
			log.Fatalf("could not create output file [%s]: %v\n", output, err)
		}
		defer func() {
			err = tex.Close()
			if err != nil {
				log.Fatalf("could not close output file [%s]: %v\n", output, err)
			}
		}()

		r = f
		w = tex

	default:
		flag.Usage()
		os.Exit(2)
	}

	doc, err := present.Parse(r, input, 0)
	if err != nil {
		log.Fatal(err)
	}

	tmpl, err := initTemplates(tmpldir)
	if err != nil {
		log.Fatal(err)
	}

	buf := new(bytes.Buffer)
	err = doc.Render(buf, tmpl)
	if err != nil {
		log.Fatal(err)
	}

	out := unescapeHTML(buf.Bytes())

	_, err = w.Write(out)
	if err != nil {
		log.Fatalf("could not fill output: %v\n", err)
	}
}

func unescapeHTML(data []byte) []byte {
	out := make([]byte, len(data))
	copy(out, data)
	for _, r := range []struct {
		old string
		new string
	}{
		{
			old: "<",
			new: "<",
		},
		{
			old: ">",
			new: ">",
		},
		{
			old: "+",
			new: "+",
		},
		{
			old: """,
			new: `"`,
		},
		{
			old: "'",
			new: "'",
		},
		{
			old: """,
			new: `"`,
		},
		{
			old: "&",
			new: "&",
		},
		{
			old: " ",
			new: " ",
		},
	} {
		out = bytes.Replace(out, []byte(r.old), []byte(r.new), -1)
	}
	return out
}

func initTemplates(base string) (*template.Template, error) {
	fname := path.Join(base, "beamer.tmpl")
	tmpl := template.New("").Funcs(funcs).Delims("<<", ">>")
	_, err := tmpl.ParseFiles(fname)
	if err != nil {
		return nil, err
	}

	return tmpl, err
}

// renderElem implements the elem template function, used to render
// sub-templates.
func renderElem(t *template.Template, e present.Elem) (template.HTML, error) {
	var data interface{} = e
	if s, ok := e.(present.Section); ok {
		data = struct {
			present.Section
			Template *template.Template
		}{s, t}
	}
	return execTemplate(t, e.TemplateName(), data)
}

var (
	funcs = template.FuncMap{}
)

func init() {
	funcs["elem"] = renderElem
	funcs["stringFromBytes"] = func(raw []byte) string { return string(raw) }
	funcs["join"] = func(lines []string) string { return strings.Join(lines, "\n") }
	funcs["nodot"] = func(s string) string {
		if strings.HasPrefix(s, ".") {
			return s[1:]
		}
		return s
	}
}

// execTemplate is a helper to execute a template and return the output as a
// template.HTML value.
func execTemplate(t *template.Template, name string, data interface{}) (template.HTML, error) {
	b := new(bytes.Buffer)
	err := t.ExecuteTemplate(b, name, data)
	if err != nil {
		return "", err
	}
	return template.HTML(b.String()), nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"github.com/asaskevich/govalidator"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/unrolled/render"
	"gopkg.in/redis.v3"
	"io/ioutil"
	"net/http"
	"net/url"
)

type Movie struct {
	Title    string
	Actors   string
	Poster   string
	Year     string
	Plot     string
	Director string
	Rating   string `json:"imdbRating"`
	ImdbID   string `json:"imdbID"`
}

func (m *Movie) MarshalBinary() ([]byte, error) {
	return json.Marshal(m)
}

func (m *Movie) UnmarshalBinary(data []byte) error {
	return json.Unmarshal(data, m)
}

func (m *Movie) Save(db *redis.Client) error {
	return db.Set(m.ImdbID, m, 0).Err()
}

type MovieForm struct {
	Title string `valid:"required"`
}

func (f *MovieForm) Decode(r *http.Request) error {
	return decode(r, f)
}

// decodes JSON body of request and runs through validator
func decode(r *http.Request, data interface{}) error {
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(data); err != nil {
		return err
	}
	if _, err := govalidator.ValidateStruct(data); err != nil {
		return err
	}
	return nil
}

func getMovieFromOMDB(title string) (*Movie, error) {

	u, _ := url.Parse("http://omdbapi.com")

	q := u.Query()
	q.Set("t", title)

	u.RawQuery = q.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	movie := &Movie{}
	if err := json.Unmarshal(body, movie); err != nil {
		return nil, err
	}

	return movie, nil
}

func getRandomMovie(db *redis.Client) (*Movie, error) {
	imdbID, err := db.RandomKey().Result()
	if err == redis.Nil {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	return getMovie(db, imdbID)
}

func getMovie(db *redis.Client, imdbID string) (*Movie, error) {
	movie := &Movie{}
	if err := db.Get(imdbID).Scan(movie); err != nil {
		if err == redis.Nil {
			return nil, nil
		} else {
			return nil, err
		}
	}
	return movie, nil
}

func getMovies(db *redis.Client) ([]*Movie, error) {
	result := db.Keys("*")
	if err := result.Err(); err != nil {
		return nil, err
	}
	var movies []*Movie
	for _, imdbID := range result.Val() {
		movie := &Movie{}
		if err := db.Get(imdbID).Scan(movie); err == nil {
			movies = append(movies, movie)
		}
	}
	return movies, nil
}

var (
	env  = flag.String("env", "prod", "environment ('prod' or 'dev')")
	port = flag.String("port", "4000", "server port")
)

const (
	staticURL    = "/static/"
	staticDir    = "./dist/"
	devServerURL = "http://localhost:8080"
	redisAddr    = "localhost:6379"
)

func main() {

	flag.Parse()

	db := redis.NewClient(&redis.Options{
		Addr:     redisAddr,
		Password: "",
		DB:       0,
	})

	_, err := db.Ping().Result()
	if err != nil {
		panic(err)
	}

	router := mux.NewRouter()
	render := render.New()

	// static content
	router.PathPrefix(
		staticURL).Handler(http.StripPrefix(
		staticURL, http.FileServer(http.Dir(staticDir))))

	// index page
	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		var staticHost string
		if *env == "dev" {
			staticHost = devServerURL
		}

		ctx := map[string]string{
			"staticHost": staticHost,
			"env":        *env,
		}

		render.HTML(w, http.StatusOK, "index", ctx)
	})

	// API calls
	api := router.PathPrefix("/api/").Subrouter()

	api.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		movie, err := getRandomMovie(db)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if movie == nil {
			http.NotFound(w, r)
			return
		}
		render.JSON(w, http.StatusOK, movie)
	}).Methods("GET")

	api.HandleFunc("/movie/{id}", func(w http.ResponseWriter, r *http.Request) {
		movie, err := getMovie(db, mux.Vars(r)["id"])
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if movie == nil {
			http.NotFound(w, r)
			return
		}
		render.JSON(w, http.StatusOK, movie)
	}).Methods("GET")

	api.HandleFunc("/movie/{id}", func(w http.ResponseWriter, r *http.Request) {
		if err := db.Del(mux.Vars(r)["id"]).Err(); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		render.Text(w, http.StatusOK, "Deleted")
	}).Methods("DELETE")

	api.HandleFunc("/all/", func(w http.ResponseWriter, r *http.Request) {
		movies, err := getMovies(db)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		render.JSON(w, http.StatusOK, movies)
	}).Methods("GET")

	api.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		f := &MovieForm{}
		if err := f.Decode(r); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		movie, err := getMovieFromOMDB(f.Title)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		if movie.ImdbID == "" {
			http.NotFound(w, r)
			return
		}

		if err := movie.Save(db); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		render.JSON(w, http.StatusOK, movie)
	}).Methods("POST")

	n := negroni.Classic()
	n.UseHandler(router)
	n.Run(":" + *port)

}
<commit_msg>Adding logging<commit_after>package main

import (
	"encoding/json"
	"flag"
	"github.com/asaskevich/govalidator"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"github.com/unrolled/render"
	"gopkg.in/redis.v3"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"runtime"
)

type Logger struct {
	Debug *log.Logger
	Info  *log.Logger
	Warn  *log.Logger
	Error *log.Logger
}

func newLogger() *Logger {

	flag := log.Ldate | log.Ltime | log.Lshortfile

	return &Logger{
		log.New(os.Stdout, "DEBUG: ", flag),
		log.New(os.Stdout, "INFO: ", flag),
		log.New(os.Stdout, "WARN: ", flag),
		log.New(os.Stderr, "ERROR: ", flag),
	}
}

func (l *Logger) WriteErr(w http.ResponseWriter, err error) {
	_, fn, line, _ := runtime.Caller(1)
	l.Error.Printf("%s:%d:%v", fn, line, err)
	http.Error(w, "Sorry, an error has occurred", http.StatusInternalServerError)
}

type Movie struct {
	Title    string
	Actors   string
	Poster   string
	Year     string
	Plot     string
	Director string
	Rating   string `json:"imdbRating"`
	ImdbID   string `json:"imdbID"`
}

func (m *Movie) String() string {
	return m.Title
}

func (m *Movie) MarshalBinary() ([]byte, error) {
	return json.Marshal(m)
}

func (m *Movie) UnmarshalBinary(data []byte) error {
	return json.Unmarshal(data, m)
}

func (m *Movie) Save(db *redis.Client) error {
	return db.Set(m.ImdbID, m, 0).Err()
}

type MovieForm struct {
	Title string `valid:"required"`
}

func (f *MovieForm) Decode(r *http.Request) error {
	return decode(r, f)
}

// decodes JSON body of request and runs through validator
func decode(r *http.Request, data interface{}) error {
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(data); err != nil {
		return err
	}
	if _, err := govalidator.ValidateStruct(data); err != nil {
		return err
	}
	return nil
}

func getMovieFromOMDB(title string) (*Movie, error) {

	u, _ := url.Parse("http://omdbapi.com")

	q := u.Query()
	q.Set("t", title)

	u.RawQuery = q.Encode()

	resp, err := http.Get(u.String())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	movie := &Movie{}
	if err := json.Unmarshal(body, movie); err != nil {
		return nil, err
	}

	return movie, nil
}

func getRandomMovie(db *redis.Client) (*Movie, error) {
	imdbID, err := db.RandomKey().Result()
	if err == redis.Nil {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	return getMovie(db, imdbID)
}

func getMovie(db *redis.Client, imdbID string) (*Movie, error) {
	movie := &Movie{}
	if err := db.Get(imdbID).Scan(movie); err != nil {
		if err == redis.Nil {
			return nil, nil
		} else {
			return nil, err
		}
	}
	return movie, nil
}

func getMovies(db *redis.Client) ([]*Movie, error) {
	result := db.Keys("*")
	if err := result.Err(); err != nil {
		return nil, err
	}
	var movies []*Movie
	for _, imdbID := range result.Val() {
		movie := &Movie{}
		if err := db.Get(imdbID).Scan(movie); err == nil {
			movies = append(movies, movie)
		}
	}
	return movies, nil
}

var (
	env  = flag.String("env", "prod", "environment ('prod' or 'dev')")
	port = flag.String("port", "4000", "server port")
)

const (
	staticURL    = "/static/"
	staticDir    = "./dist/"
	devServerURL = "http://localhost:8080"
	redisAddr    = "localhost:6379"
	serverErrMsg = "Sorry, an error has occurred"
)

func main() {

	flag.Parse()

	db := redis.NewClient(&redis.Options{
		Addr:     redisAddr,
		Password: "",
		DB:       0,
	})

	_, err := db.Ping().Result()
	if err != nil {
		panic(err)
	}

	router := mux.NewRouter()
	render := render.New()
	logger := newLogger()

	// static content
	router.PathPrefix(
		staticURL).Handler(http.StripPrefix(
		staticURL, http.FileServer(http.Dir(staticDir))))

	// index page
	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		var staticHost string
		if *env == "dev" {
			staticHost = devServerURL
		}

		ctx := map[string]string{
			"staticHost": staticHost,
			"env":        *env,
		}

		render.HTML(w, http.StatusOK, "index", ctx)
	})

	// API calls
	api := router.PathPrefix("/api/").Subrouter()

	api.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		movie, err := getRandomMovie(db)
		if err != nil {
			logger.WriteErr(w, err)
			http.Error(w, serverErrMsg, http.StatusInternalServerError)
			return
		}
		if movie == nil {
			http.NotFound(w, r)
			return
		}
		render.JSON(w, http.StatusOK, movie)
	}).Methods("GET")

	api.HandleFunc("/movie/{id}", func(w http.ResponseWriter, r *http.Request) {
		movie, err := getMovie(db, mux.Vars(r)["id"])
		if err != nil {
			logger.WriteErr(w, err)
			return
		}
		if movie == nil {
			http.NotFound(w, r)
			return
		}
		render.JSON(w, http.StatusOK, movie)
	}).Methods("GET")

	api.HandleFunc("/movie/{id}", func(w http.ResponseWriter, r *http.Request) {
		if err := db.Del(mux.Vars(r)["id"]).Err(); err != nil {
			logger.WriteErr(w, err)
			return
		}
		render.Text(w, http.StatusOK, "Movie deleted")
	}).Methods("DELETE")

	api.HandleFunc("/all/", func(w http.ResponseWriter, r *http.Request) {
		movies, err := getMovies(db)
		if err != nil {
			logger.WriteErr(w, err)
			return
		}
		render.JSON(w, http.StatusOK, movies)
	}).Methods("GET")

	api.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		f := &MovieForm{}
		if err := f.Decode(r); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		movie, err := getMovieFromOMDB(f.Title)
		if err != nil {
			logger.WriteErr(w, err)
			return
		}

		if movie.ImdbID == "" {
			logger.Warn.Printf("No movie found for title %s", f.Title)
			http.NotFound(w, r)
			return
		}

		if err := movie.Save(db); err != nil {
			logger.WriteErr(w, err)
			return
		}
		logger.Info.Printf("New movie %s added", movie)
		render.JSON(w, http.StatusOK, movie)

	}).Methods("POST")

	n := negroni.Classic()
	n.UseHandler(router)
	n.Run(":" + *port)

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/jideji/servicelauncher/procs"
	"github.com/jideji/servicelauncher/config"
	"os"
)

func main() {
	action := os.Args[1]
	serviceName := os.Args[2]

	services := config.LoadServices()

	service := services[serviceName]
	if service == nil {
		println(fmt.Sprintf("No service '%s' found", serviceName))
		os.Exit(1)
	}

	pr, err := procs.FindByCommandLine(service.Pattern)
	if err != nil {
		panic(err)
	}

	if action == "stop" || action == "restart" {
		if pr != nil {
			fmt.Printf("Killing process %d.\n", pr.Pid)
			pr.Kill()
			pr = nil
		} else {
			fmt.Println("Not running.")
		}
	}

	if action == "start" || action == "restart" {
		if pr != nil {
			println(fmt.Sprintf("Service '%s' already running. Try restart.", service.Name))
			os.Exit(10)
		}
		p, err := service.Start()
		if err != nil {
			panic(err)
		}
		fmt.Printf("Service '%s' started with pid %d.\n", service.Name, p.Pid)
	}
}
<commit_msg>Added basic argument checking.<commit_after>package main

import (
	"fmt"
	"github.com/jideji/servicelauncher/config"
	"github.com/jideji/servicelauncher/procs"
	"os"
)

func main() {
	if len(os.Args) != 3 {
		fmt.Fprint(os.Stderr, "SYNTAX:\n")
		fmt.Fprintf(os.Stderr, "\t%s <action> <service name>\n", os.Args[0])
		os.Exit(1)
	}

	action := os.Args[1]
	serviceName := os.Args[2]

	services := config.LoadServices()

	service := services[serviceName]
	if service == nil {
		println(fmt.Sprintf("No service named '%s' found.", serviceName))
		os.Exit(10)
	}

	pr, err := procs.FindByCommandLine(service.Pattern)
	if err != nil {
		panic(err)
	}

	if action == "stop" || action == "restart" {
		if pr != nil {
			fmt.Printf("Killing process %d.\n", pr.Pid)
			pr.Kill()
			pr = nil
		} else {
			fmt.Println("Not running.")
		}
	}

	if action == "start" || action == "restart" {
		if pr != nil {
			println(fmt.Sprintf("Service '%s' already running. Try restart.", service.Name))
			os.Exit(11)
		}
		p, err := service.Start()
		if err != nil {
			panic(err)
		}
		fmt.Printf("Service '%s' started with pid %d.\n", service.Name, p.Pid)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"

	"github.com/docker/go-plugins-helpers/authorization"
	"github.com/fsnotify/fsnotify"
)

// DockerAuthZPlugin implements the authorization.Plugin interface.
// Every request received by the Docker daemon will be forwarded to the
// AuthZReq function. The AuthZReq function returns a response that indicates
// whether the request should be allowed or denied.
type DockerAuthZPlugin struct {
	opaURL string
}

// AuthZReq is called when the Docker daemon receives an API request.
// AuthZReq returns an authorization.Response that indicates whether the request should be
// allowed or denied.
func (p DockerAuthZPlugin) AuthZReq(r authorization.Request) authorization.Response {

	fmt.Println("Received request from Docker:", r)

	b, err := IsAllowed(p.opaURL, r)

	if b {
		return authorization.Response{Allow: true}
	} else if err != nil {
		return authorization.Response{Err: err.Error()}
	}

	return authorization.Response{Msg: "request rejected by administrative policy"}
}

// AuthZRes is called before the Docker daemon returns an API response. All responses
// are allowed.
func (p DockerAuthZPlugin) AuthZRes(r authorization.Request) authorization.Response {
	return authorization.Response{Allow: true}
}

// IsAllowed queries the policy that was loaded into OPA and returns (true, nil) if the
// request should be allowed. If the request is not allowed, b will be false and e will
// be set to indicate if an error occurred. This function "fails closed" meaning if an error
// occurs, the request will be rejected.
func IsAllowed(opaURL string, r authorization.Request) (b bool, e error) {

	// Query OPA to see if the request should be allowed.
	resp, err := QueryDataAPI(opaURL, "/opa/example/allow_request", r)
	if err != nil {
		return false, err
	}

	// If the request succeeded, the request should be allowed.
	if resp.StatusCode == 200 {
		return true, nil
	}

	// If the response is undefined, the request should be rejected.
	if IsUndefined(resp) {
		return false, nil
	}

	// Othewrise, an error occured so reject the request and include an error message.
	if resp.StatusCode == 404 {
		return false, fmt.Errorf("policy does not exist")
	}

	return false, fmt.Errorf("unexpected error: %v", resp)
}

// IsUndefined returns true if the http.Response resp from OPA indicates
// an undefined query result
func IsUndefined(resp *http.Response) bool {

	if resp.StatusCode == 404 {
		var v interface{}
		d := json.NewDecoder(resp.Body)
		if err := d.Decode(&v); err == nil {
			if v, ok := v.(map[string]interface{}); ok {
				if v["IsUndefined"] != nil {
					return true
				}
			}
		}
	}

	return false
}

// LoadPolicy reads the policy definition from the path f and upserts it into OPA.
func LoadPolicy(opaURL, f string) error {
	r, err := os.Open(f)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", opaURL+"/policies/example_policy", r)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		d := json.NewDecoder(resp.Body)
		var e map[string]interface{}
		if err := d.Decode(&e); err != nil {
			return err
		}
		return fmt.Errorf("upsert failed (code: %v): %v", e["Code"], e["Message"])
	}

	return nil
}

// WatchPolicy creates a filesystem watch on the path f and waits for changes. When the
// file changes, LoadPolicy is called with the path f.
func WatchPolicy(opaURL, f string) error {

	w, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {
		for {
			select {
			case evt := <-w.Events:
				if evt.Op&fsnotify.Write != 0 {
					if err := LoadPolicy(opaURL, f); err != nil {
						fmt.Println("Error reloading policy definition:", err)
					} else {
						fmt.Println("Reloaded policy definition.")
					}
				}
			}
		}
	}()

	if err := w.Add(f); err != nil {
		return err
	}

	return nil
}

// QueryDataAPI executes a GET request against OPA's Data API. If successful, an http.Response is
// returned. The doc parameter identifies the document defined by the authorization policy. The
// query includes the authorization.Request r as input.
func QueryDataAPI(opaURL string, doc string, r authorization.Request) (*http.Response, error) {

	m := map[string]interface{}{
		"Headers":    r.RequestHeaders,
		"Path":       r.RequestURI,
		"Method":     r.RequestMethod,
		"Body":       r.RequestBody,
		"User":       r.User,
		"AuthMethod": r.UserAuthNMethod,
	}

	if r.RequestHeaders["Content-Type"] == "application/json" {
		var body interface{}
		if err := json.Unmarshal(r.RequestBody, &body); err != nil {
			return nil, err
		}
		m["Body"] = body
	}

	bs, err := json.Marshal(m)
	if err != nil {
		return nil, err
	}

	global := url.QueryEscape(string(bs))

	// The policy declares an input named "request" that is intended to contain
	// the Docker API request.
	url := fmt.Sprintf("%s/data%s?global=request:%s", opaURL, doc, global)

	return http.Get(url)
}

const (
	version = "0.1.0"
)

func main() {

	bindAddr := flag.String("bind-addr", ":8080", "sets the address the plugin will bind to")
	pluginName := flag.String("plugin-name", "docker-authz-plugin", "sets the plugin name that will be registered with Docker")
	opaURL := flag.String("opa-url", "http://localhost:8181/v1", "sets the base URL of OPA's HTTP API")
	policyFile := flag.String("policy-file", "example.rego", "sets the path of the policy file to load")
	vers := flag.Bool("version", false, "print the version of the plugin")

	flag.Parse()

	if *vers {
		fmt.Println(version)
		os.Exit(0)
	}

	p := DockerAuthZPlugin{*opaURL}
	h := authorization.NewHandler(p)

	if err := LoadPolicy(*opaURL, *policyFile); err != nil {
		fmt.Println("Error while loading policy:", err)
		os.Exit(1)
	}

	if err := WatchPolicy(*opaURL, *policyFile); err != nil {
		fmt.Println("Error while starting watch:", err)
		os.Exit(1)
	}

	fmt.Println("Starting server.")

	if err := h.ServeTCP(*pluginName, *bindAddr); err != nil {
		fmt.Println("Error while serving HTTP:", err)
		os.Exit(1)
	}
}
<commit_msg>Fix check for undefined documents<commit_after>// Copyright 2016 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"

	"github.com/docker/go-plugins-helpers/authorization"
	"github.com/fsnotify/fsnotify"
)

// DockerAuthZPlugin implements the authorization.Plugin interface.
// Every request received by the Docker daemon will be forwarded to the
// AuthZReq function. The AuthZReq function returns a response that indicates
// whether the request should be allowed or denied.
type DockerAuthZPlugin struct {
	opaURL string
}

// AuthZReq is called when the Docker daemon receives an API request.
// AuthZReq returns an authorization.Response that indicates whether the request should be
// allowed or denied.
func (p DockerAuthZPlugin) AuthZReq(r authorization.Request) authorization.Response {

	fmt.Println("Received request from Docker:", r)

	b, err := IsAllowed(p.opaURL, r)

	if b {
		return authorization.Response{Allow: true}
	} else if err != nil {
		return authorization.Response{Err: err.Error()}
	}

	return authorization.Response{Msg: "request rejected by administrative policy"}
}

// AuthZRes is called before the Docker daemon returns an API response. All responses
// are allowed.
func (p DockerAuthZPlugin) AuthZRes(r authorization.Request) authorization.Response {
	return authorization.Response{Allow: true}
}

// IsAllowed queries the policy that was loaded into OPA and returns (true, nil) if the
// request should be allowed. If the request is not allowed, b will be false and e will
// be set to indicate if an error occurred. This function "fails closed" meaning if an error
// occurs, the request will be rejected.
func IsAllowed(opaURL string, r authorization.Request) (b bool, e error) {

	// Query OPA to see if the request should be allowed.
	resp, err := QueryDataAPI(opaURL, "/opa/example/allow_request", r)
	if err != nil {
		return false, err
	}

	// If the request succeeded, the request should be allowed.
	if resp.StatusCode == 200 {
		return true, nil
	}

	// If the response is undefined, the request should be rejected.
	if IsUndefined(resp) {
		return false, nil
	}

	// Othewrise, an error occured so reject the request and include an error message.
	if resp.StatusCode == 404 {
		return false, fmt.Errorf("policy does not exist")
	}

	return false, fmt.Errorf("unexpected error: %v", resp)
}

// IsUndefined returns true if the http.Response resp from OPA indicates
// an undefined query result
func IsUndefined(resp *http.Response) bool {
	return resp.StatusCode == 404
}

// LoadPolicy reads the policy definition from the path f and upserts it into OPA.
func LoadPolicy(opaURL, f string) error {
	r, err := os.Open(f)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", opaURL+"/policies/example_policy", r)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		d := json.NewDecoder(resp.Body)
		var e map[string]interface{}
		if err := d.Decode(&e); err != nil {
			return err
		}
		return fmt.Errorf("upsert failed (code: %v): %v", e["Code"], e["Message"])
	}

	return nil
}

// WatchPolicy creates a filesystem watch on the path f and waits for changes. When the
// file changes, LoadPolicy is called with the path f.
func WatchPolicy(opaURL, f string) error {

	w, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {
		for {
			select {
			case evt := <-w.Events:
				if evt.Op&fsnotify.Write != 0 {
					if err := LoadPolicy(opaURL, f); err != nil {
						fmt.Println("Error reloading policy definition:", err)
					} else {
						fmt.Println("Reloaded policy definition.")
					}
				}
			}
		}
	}()

	if err := w.Add(f); err != nil {
		return err
	}

	return nil
}

// QueryDataAPI executes a GET request against OPA's Data API. If successful, an http.Response is
// returned. The doc parameter identifies the document defined by the authorization policy. The
// query includes the authorization.Request r as input.
func QueryDataAPI(opaURL string, doc string, r authorization.Request) (*http.Response, error) {

	m := map[string]interface{}{
		"Headers":    r.RequestHeaders,
		"Path":       r.RequestURI,
		"Method":     r.RequestMethod,
		"Body":       r.RequestBody,
		"User":       r.User,
		"AuthMethod": r.UserAuthNMethod,
	}

	if r.RequestHeaders["Content-Type"] == "application/json" {
		var body interface{}
		if err := json.Unmarshal(r.RequestBody, &body); err != nil {
			return nil, err
		}
		m["Body"] = body
	}

	bs, err := json.Marshal(m)
	if err != nil {
		return nil, err
	}

	global := url.QueryEscape(string(bs))

	// The policy declares an input named "request" that is intended to contain
	// the Docker API request.
	url := fmt.Sprintf("%s/data%s?global=request:%s", opaURL, doc, global)

	return http.Get(url)
}

const (
	version = "0.1.0"
)

func main() {

	bindAddr := flag.String("bind-addr", ":8080", "sets the address the plugin will bind to")
	pluginName := flag.String("plugin-name", "docker-authz-plugin", "sets the plugin name that will be registered with Docker")
	opaURL := flag.String("opa-url", "http://localhost:8181/v1", "sets the base URL of OPA's HTTP API")
	policyFile := flag.String("policy-file", "example.rego", "sets the path of the policy file to load")
	vers := flag.Bool("version", false, "print the version of the plugin")

	flag.Parse()

	if *vers {
		fmt.Println(version)
		os.Exit(0)
	}

	p := DockerAuthZPlugin{*opaURL}
	h := authorization.NewHandler(p)

	if err := LoadPolicy(*opaURL, *policyFile); err != nil {
		fmt.Println("Error while loading policy:", err)
		os.Exit(1)
	}

	if err := WatchPolicy(*opaURL, *policyFile); err != nil {
		fmt.Println("Error while starting watch:", err)
		os.Exit(1)
	}

	fmt.Println("Starting server.")

	if err := h.ServeTCP(*pluginName, *bindAddr); err != nil {
		fmt.Println("Error while serving HTTP:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package acceptance_test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	. "github.com/onsi/ginkgo"
	ginkgoConfig "github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"testing"
)

var (
	appDir     string
	config     helpers.Config
	testConfig struct {
		TestUser         string `json:"test_user"`
		TestUserPassword string `json:"test_user_password"`
	}
)

func Auth(username, password string) {
	By("authenticating as " + username)
	cmd := exec.Command("cf", "auth", username, password)
	sess, err := gexec.Start(cmd, nil, nil)
	Expect(err).NotTo(HaveOccurred())
	Eventually(sess.Wait(Timeout_Short)).Should(gexec.Exit(0))
}

func AuthAsAdmin() {
	Auth(config.AdminUser, config.AdminPassword)
}

func TestAcceptance(t *testing.T) {
	RegisterFailHandler(Fail)

	BeforeSuite(func() {
		config = helpers.LoadConfig()

		configPath := helpers.ConfigPath()
		configBytes, err := ioutil.ReadFile(configPath)
		Expect(err).NotTo(HaveOccurred())

		err = json.Unmarshal(configBytes, &testConfig)
		Expect(err).NotTo(HaveOccurred())

		Expect(cf.Cf("api", "--skip-ssl-validation", config.ApiEndpoint).Wait(Timeout_Short)).To(gexec.Exit(0))
		AuthAsAdmin()

		appDir = os.Getenv("APP_DIR")
		Expect(appDir).NotTo(BeEmpty())

		// create binary
		os.Setenv("GOOS", "linux")
		os.Setenv("GOARCH", "amd64")
		binaryPath, err := gexec.Build(appDir)
		Expect(err).NotTo(HaveOccurred())
		err = os.Rename(binaryPath, filepath.Join(appDir, "proxy"))
		Expect(err).NotTo(HaveOccurred())

		rand.Seed(ginkgoConfig.GinkgoConfig.RandomSeed + int64(GinkgoParallelNode()))
	})

	AfterSuite(func() {
		// remove binary
		err := os.Remove(filepath.Join(appDir, "proxy"))
		Expect(err).NotTo(HaveOccurred())
	})

	RunSpecs(t, "Acceptance Suite")
}

func pushApp(appName string) {
	Expect(cf.Cf(
		"push", appName,
		"-p", appDir,
		"-f", filepath.Join(appDir, "manifest.yml"),
		"-c", "./proxy",
		"-b", "binary_buildpack",
	).Wait(Timeout_Push)).To(gexec.Exit(0))
}

func scaleApp(appName string, instances int) {
	Expect(cf.Cf(
		"scale", appName,
		"-i", fmt.Sprintf("%d", instances),
	).Wait(Timeout_Short)).To(gexec.Exit(0))

	// wait for ssh to become available on new instances
	time.Sleep(15 * time.Second)
}

const (
	ip4Regex         = `(?:[0-9]{1,3}\.){3}[0-9]{1,3}`
	ipAddrParseRegex = `inet (` + ip4Regex + `)/24 scope global eth0`
)

func getInstanceIP(appName string, instanceIndex int) string {
	sshSession := cf.Cf(
		"ssh", appName,
		"-i", fmt.Sprintf("%d", instanceIndex),
		"--skip-host-validation",
		"-c", "ip addr",
	)
	Expect(sshSession.Wait(2 * Timeout_Short)).To(gexec.Exit(0))

	addrOut := string(sshSession.Out.Contents())
	matches := regexp.MustCompile(ipAddrParseRegex).FindStringSubmatch(addrOut)
	return matches[1]
}

func curlFromApp(appName string, instanceIndex int, endpoint string, expectSuccess bool) string {
	sshSession := cf.Cf(
		"ssh", appName,
		"-i", fmt.Sprintf("%d", instanceIndex),
		"--skip-host-validation",
		"-c", fmt.Sprintf("curl --connect-timeout 5 %s", endpoint),
	)

	if expectSuccess {
		Expect(sshSession.Wait(2 * Timeout_Short)).To(gexec.Exit(0))
	} else {
		const CURL_EXIT_CODE_COULDNT_RESOLVE_HOST = 6
		const CURL_EXIT_CODE_COULDNT_CONNECT = 7
		const CURL_EXIT_CODE_OPERATION_TIMEDOUT = 28
		Expect(sshSession.Wait(2 * Timeout_Short)).To(gexec.Exit())
		Expect([]int{
			CURL_EXIT_CODE_COULDNT_RESOLVE_HOST,
			CURL_EXIT_CODE_COULDNT_CONNECT,
			CURL_EXIT_CODE_OPERATION_TIMEDOUT,
		}).To(ContainElement(sshSession.ExitCode()))
	}

	return string(sshSession.Out.Contents())
}

func getAppGuid(appName string) string {
	session := cf.Cf("app", appName, "--guid")
	Expect(session.Wait(Timeout_Short)).To(gexec.Exit(0))
	return strings.TrimSpace(string(session.Out.Contents()))
}
<commit_msg>netman cf acceptance test has eventual convergence<commit_after>package acceptance_test

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	. "github.com/onsi/ginkgo"
	ginkgoConfig "github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"testing"
)

var (
	appDir     string
	config     helpers.Config
	testConfig struct {
		TestUser         string `json:"test_user"`
		TestUserPassword string `json:"test_user_password"`
	}
)

func Auth(username, password string) {
	By("authenticating as " + username)
	cmd := exec.Command("cf", "auth", username, password)
	sess, err := gexec.Start(cmd, nil, nil)
	Expect(err).NotTo(HaveOccurred())
	Eventually(sess.Wait(Timeout_Short)).Should(gexec.Exit(0))
}

func AuthAsAdmin() {
	Auth(config.AdminUser, config.AdminPassword)
}

func TestAcceptance(t *testing.T) {
	RegisterFailHandler(Fail)

	BeforeSuite(func() {
		config = helpers.LoadConfig()

		configPath := helpers.ConfigPath()
		configBytes, err := ioutil.ReadFile(configPath)
		Expect(err).NotTo(HaveOccurred())

		err = json.Unmarshal(configBytes, &testConfig)
		Expect(err).NotTo(HaveOccurred())

		Expect(cf.Cf("api", "--skip-ssl-validation", config.ApiEndpoint).Wait(Timeout_Short)).To(gexec.Exit(0))
		AuthAsAdmin()

		appDir = os.Getenv("APP_DIR")
		Expect(appDir).NotTo(BeEmpty())

		// create binary
		os.Setenv("GOOS", "linux")
		os.Setenv("GOARCH", "amd64")
		binaryPath, err := gexec.Build(appDir)
		Expect(err).NotTo(HaveOccurred())
		err = os.Rename(binaryPath, filepath.Join(appDir, "proxy"))
		Expect(err).NotTo(HaveOccurred())

		rand.Seed(ginkgoConfig.GinkgoConfig.RandomSeed + int64(GinkgoParallelNode()))
	})

	AfterSuite(func() {
		// remove binary
		err := os.Remove(filepath.Join(appDir, "proxy"))
		Expect(err).NotTo(HaveOccurred())
	})

	RunSpecs(t, "Acceptance Suite")
}

func pushApp(appName string) {
	Expect(cf.Cf(
		"push", appName,
		"-p", appDir,
		"-f", filepath.Join(appDir, "manifest.yml"),
		"-c", "./proxy",
		"-b", "binary_buildpack",
	).Wait(Timeout_Push)).To(gexec.Exit(0))
}

func scaleApp(appName string, instances int) {
	Expect(cf.Cf(
		"scale", appName,
		"-i", fmt.Sprintf("%d", instances),
	).Wait(Timeout_Short)).To(gexec.Exit(0))

	// wait for ssh to become available on new instances
	time.Sleep(15 * time.Second)
}

const (
	ip4Regex         = `(?:[0-9]{1,3}\.){3}[0-9]{1,3}`
	ipAddrParseRegex = `inet (` + ip4Regex + `)/24 scope global eth0`
)

func getInstanceIP(appName string, instanceIndex int) string {
	sshSession := cf.Cf(
		"ssh", appName,
		"-i", fmt.Sprintf("%d", instanceIndex),
		"--skip-host-validation",
		"-c", "ip addr",
	)
	Expect(sshSession.Wait(2 * Timeout_Short)).To(gexec.Exit(0))

	addrOut := string(sshSession.Out.Contents())
	matches := regexp.MustCompile(ipAddrParseRegex).FindStringSubmatch(addrOut)
	return matches[1]
}

func curlFromApp(appName string, instanceIndex int, endpoint string, expectSuccess bool) string {
	var output string

	tryIt := func() int {
		sshSession := cf.Cf(
			"ssh", appName,
			"-i", fmt.Sprintf("%d", instanceIndex),
			"--skip-host-validation",
			"-c", fmt.Sprintf("curl --connect-timeout 5 %s", endpoint),
		)
		Expect(sshSession.Wait(2 * Timeout_Short)).To(gexec.Exit())
		output = string(sshSession.Out.Contents())
		return sshSession.ExitCode()
	}

	if expectSuccess {
		Eventually(tryIt).Should(Equal(0))
	} else {
		Eventually(func() bool {
			code := tryIt()
			const CURL_EXIT_CODE_COULDNT_RESOLVE_HOST = 6
			const CURL_EXIT_CODE_COULDNT_CONNECT = 7
			const CURL_EXIT_CODE_OPERATION_TIMEDOUT = 28
			switch code {
			case CURL_EXIT_CODE_COULDNT_RESOLVE_HOST, CURL_EXIT_CODE_COULDNT_CONNECT, CURL_EXIT_CODE_OPERATION_TIMEDOUT:
				return true
			default:
				return false
			}
		}).Should(BeTrue())
	}
	return output
}

func getAppGuid(appName string) string {
	session := cf.Cf("app", appName, "--guid")
	Expect(session.Wait(Timeout_Short)).To(gexec.Exit(0))
	return strings.TrimSpace(string(session.Out.Contents()))
}
<|endoftext|>


<commit_before>package decor

import (
	"fmt"
	"time"
	"unicode/utf8"
)

const (
	// DidentRight bit specifies identation direction.
	// |foo   |b     | With DidentRight
	// |   foo|     b| Without DidentRight
	DidentRight = 1 << iota

	// DextraSpace bit adds extra space, makes sense with DSyncWidth only.
	// When DidentRight bit set, the space will be added to the right,
	// otherwise to the left.
	DextraSpace

	// DSyncWidth bit enables same column width synchronization.
	// Effective with multiple bars only.
	DSyncWidth

	// DSyncWidthR is shortcut for DSyncWidth|DidentRight
	DSyncWidthR = DSyncWidth | DidentRight

	// DSyncSpace is shortcut for DSyncWidth|DextraSpace
	DSyncSpace = DSyncWidth | DextraSpace

	// DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DidentRight
	DSyncSpaceR = DSyncWidth | DextraSpace | DidentRight
)

// TimeStyle enum.
type TimeStyle int

// TimeStyle kinds.
const (
	ET_STYLE_GO TimeStyle = iota
	ET_STYLE_HHMMSS
	ET_STYLE_HHMM
	ET_STYLE_MMSS
)

// Statistics consists of progress related statistics, that Decorator
// may need.
type Statistics struct {
	ID        int
	Completed bool
	Total     int64
	Current   int64
}

// Decorator interface.
// A decorator must implement this interface, in order to be used with
// mpb library.
type Decorator interface {
	ConfigSetter
	Synchronizer
	Decor(*Statistics) string
}

// Synchronizer interface.
// All decorators implement this interface implicitly. Its Sync
// method exposes width sync channel, if DSyncWidth bit is set.
type Synchronizer interface {
	Sync() (chan int, bool)
}

// ConfigSetter interface
type ConfigSetter interface {
	SetConfig(config WC) (old WC)
}

// OnCompleteMessenger interface.
// Decorators implementing this interface suppose to return provided
// string on complete event.
type OnCompleteMessenger interface {
	OnCompleteMessage(string)
}

// AmountReceiver interface.
// If decorator needs to receive increment amount, so this is the right
// interface to implement.
type AmountReceiver interface {
	NextAmount(int64, ...time.Duration)
}

// ShutdownListener interface.
// If decorator needs to be notified once upon bar shutdown event, so
// this is the right interface to implement.
type ShutdownListener interface {
	Shutdown()
}

// AverageAdjuster interface.
// Average decorators should implement this interface to provide start
// time adjustment facility, for resume-able tasks.
type AverageAdjuster interface {
	AverageAdjust(time.Time)
}

// CBFunc convenience call back func type.
type CBFunc func(Decorator)

// Global convenience instances of WC with sync width bit set.
var (
	WCSyncWidth  = WC{C: DSyncWidth}
	WCSyncWidthR = WC{C: DSyncWidthR}
	WCSyncSpace  = WC{C: DSyncSpace}
	WCSyncSpaceR = WC{C: DSyncSpaceR}
)

// WC is a struct with two public fields W and C, both of int type.
// W represents width and C represents bit set of width related config.
// A decorator should embed WC, to enable width synchronization.
type WC struct {
	W            int
	C            int
	dynFormat    string
	staticFormat string
	wsync        chan int
}

// FormatMsg formats final message according to WC.W and WC.C.
// Should be called by any Decorator implementation.
func (wc *WC) FormatMsg(msg string) string {
	if (wc.C & DSyncWidth) != 0 {
		wc.wsync <- utf8.RuneCountInString(msg)
		max := <-wc.wsync
		if (wc.C & DextraSpace) != 0 {
			max++
		}
		return fmt.Sprintf(fmt.Sprintf(wc.dynFormat, max), msg)
	}
	return fmt.Sprintf(wc.staticFormat, msg)
}

// Init initializes width related config.
func (wc *WC) Init() {
	wc.dynFormat = "%%"
	if (wc.C & DidentRight) != 0 {
		wc.dynFormat += "-"
	}
	wc.dynFormat += "%ds"
	wc.staticFormat = fmt.Sprintf(wc.dynFormat, wc.W)
	if (wc.C & DSyncWidth) != 0 {
		wc.wsync = make(chan int)
	}
}

// Sync is implementation of Synchronizer interface.
func (wc *WC) Sync() (chan int, bool) {
	return wc.wsync, (wc.C & DSyncWidth) != 0
}

// SetConfig sets new conf and returns old one.
func (wc *WC) SetConfig(conf WC) (old WC) {
	conf.Init()
	old = *wc
	*wc = conf
	return old
}

// OnComplete returns decorator, which wraps provided decorator, with
// sole purpose to display provided message on complete event.
//
//	`decorator` Decorator to wrap
//
//	`message` message to display on complete event
func OnComplete(decorator Decorator, message string) Decorator {
	if d, ok := decorator.(OnCompleteMessenger); ok {
		d.OnCompleteMessage(message)
	}
	return decorator
}
<commit_msg>period<commit_after>package decor

import (
	"fmt"
	"time"
	"unicode/utf8"
)

const (
	// DidentRight bit specifies identation direction.
	// |foo   |b     | With DidentRight
	// |   foo|     b| Without DidentRight
	DidentRight = 1 << iota

	// DextraSpace bit adds extra space, makes sense with DSyncWidth only.
	// When DidentRight bit set, the space will be added to the right,
	// otherwise to the left.
	DextraSpace

	// DSyncWidth bit enables same column width synchronization.
	// Effective with multiple bars only.
	DSyncWidth

	// DSyncWidthR is shortcut for DSyncWidth|DidentRight
	DSyncWidthR = DSyncWidth | DidentRight

	// DSyncSpace is shortcut for DSyncWidth|DextraSpace
	DSyncSpace = DSyncWidth | DextraSpace

	// DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DidentRight
	DSyncSpaceR = DSyncWidth | DextraSpace | DidentRight
)

// TimeStyle enum.
type TimeStyle int

// TimeStyle kinds.
const (
	ET_STYLE_GO TimeStyle = iota
	ET_STYLE_HHMMSS
	ET_STYLE_HHMM
	ET_STYLE_MMSS
)

// Statistics consists of progress related statistics, that Decorator
// may need.
type Statistics struct {
	ID        int
	Completed bool
	Total     int64
	Current   int64
}

// Decorator interface.
// A decorator must implement this interface, in order to be used with
// mpb library.
type Decorator interface {
	ConfigSetter
	Synchronizer
	Decor(*Statistics) string
}

// Synchronizer interface.
// All decorators implement this interface implicitly. Its Sync
// method exposes width sync channel, if DSyncWidth bit is set.
type Synchronizer interface {
	Sync() (chan int, bool)
}

// ConfigSetter interface.
type ConfigSetter interface {
	SetConfig(config WC) (old WC)
}

// OnCompleteMessenger interface.
// Decorators implementing this interface suppose to return provided
// string on complete event.
type OnCompleteMessenger interface {
	OnCompleteMessage(string)
}

// AmountReceiver interface.
// If decorator needs to receive increment amount, so this is the right
// interface to implement.
type AmountReceiver interface {
	NextAmount(int64, ...time.Duration)
}

// ShutdownListener interface.
// If decorator needs to be notified once upon bar shutdown event, so
// this is the right interface to implement.
type ShutdownListener interface {
	Shutdown()
}

// AverageAdjuster interface.
// Average decorators should implement this interface to provide start
// time adjustment facility, for resume-able tasks.
type AverageAdjuster interface {
	AverageAdjust(time.Time)
}

// CBFunc convenience call back func type.
type CBFunc func(Decorator)

// Global convenience instances of WC with sync width bit set.
var (
	WCSyncWidth  = WC{C: DSyncWidth}
	WCSyncWidthR = WC{C: DSyncWidthR}
	WCSyncSpace  = WC{C: DSyncSpace}
	WCSyncSpaceR = WC{C: DSyncSpaceR}
)

// WC is a struct with two public fields W and C, both of int type.
// W represents width and C represents bit set of width related config.
// A decorator should embed WC, to enable width synchronization.
type WC struct {
	W            int
	C            int
	dynFormat    string
	staticFormat string
	wsync        chan int
}

// FormatMsg formats final message according to WC.W and WC.C.
// Should be called by any Decorator implementation.
func (wc *WC) FormatMsg(msg string) string {
	if (wc.C & DSyncWidth) != 0 {
		wc.wsync <- utf8.RuneCountInString(msg)
		max := <-wc.wsync
		if (wc.C & DextraSpace) != 0 {
			max++
		}
		return fmt.Sprintf(fmt.Sprintf(wc.dynFormat, max), msg)
	}
	return fmt.Sprintf(wc.staticFormat, msg)
}

// Init initializes width related config.
func (wc *WC) Init() {
	wc.dynFormat = "%%"
	if (wc.C & DidentRight) != 0 {
		wc.dynFormat += "-"
	}
	wc.dynFormat += "%ds"
	wc.staticFormat = fmt.Sprintf(wc.dynFormat, wc.W)
	if (wc.C & DSyncWidth) != 0 {
		wc.wsync = make(chan int)
	}
}

// Sync is implementation of Synchronizer interface.
func (wc *WC) Sync() (chan int, bool) {
	return wc.wsync, (wc.C & DSyncWidth) != 0
}

// SetConfig sets new conf and returns old one.
func (wc *WC) SetConfig(conf WC) (old WC) {
	conf.Init()
	old = *wc
	*wc = conf
	return old
}

// OnComplete returns decorator, which wraps provided decorator, with
// sole purpose to display provided message on complete event.
//
//	`decorator` Decorator to wrap
//
//	`message` message to display on complete event
func OnComplete(decorator Decorator, message string) Decorator {
	if d, ok := decorator.(OnCompleteMessenger); ok {
		d.OnCompleteMessage(message)
	}
	return decorator
}
<|endoftext|>


<commit_before>package fritz

import (
	"fmt"
	"log"
	"net/http/httptest"
	"net/url"
	"reflect"
	"runtime"
	"testing"

	"github.com/bpicode/fritzctl/mock"
	"github.com/stretchr/testify/assert"
)

// TestFritzAPI test the FRITZ API.
func TestFritzAPI(t *testing.T) {

	serverFactory := func() *httptest.Server {
		return mock.New().UnstartedServer()
	}

	clientFactory := func() *Client {
		cl, err := NewClient("../mock/client_config_template.json")
		assert.NoError(t, err)
		return cl
	}

	testCases := []struct {
		doTest func(t *testing.T, fritz *ahaHTTP, server *httptest.Server)
	}{
		{testGetDeviceList},
		{testAPIGetDeviceListErrorServerDown},
		{testAPISwitchOffByAinWithErrorServerDown},
		{testAPIToggleDeviceErrorServerDownAtToggleStage},
	}
	for _, testCase := range testCases {
		t.Run(fmt.Sprintf("Test aha api %s", runtime.FuncForPC(reflect.ValueOf(testCase.doTest).Pointer()).Name()), func(t *testing.T) {
			server := serverFactory()
			server.Start()
			defer server.Close()
			client := clientFactory()
			u, err := url.Parse(server.URL)
			assert.NoError(t, err)
			client.Config.Net.Protocol = u.Scheme
			client.Config.Net.Host = u.Host
			err = client.Login()
			assert.NoError(t, err)
			ha := HomeAutomation(client).(*ahaHTTP)
			assert.NotNil(t, ha)
			testCase.doTest(t, ha, server)
		})
	}
}

func testGetDeviceList(t *testing.T, fritz *ahaHTTP, server *httptest.Server) {
	devList, err := fritz.ListDevices()
	log.Println(*devList)
	assert.NoError(t, err)
	assert.NotNil(t, devList)
	assert.NotEmpty(t, devList.Devices)
	assert.NotEmpty(t, devList.Devices[0].ID)
	assert.NotEmpty(t, devList.Devices[0].Identifier)
	assert.NotEmpty(t, devList.Devices[0].Functionbitmask)
	assert.NotEmpty(t, devList.Devices[0].Fwversion)
	assert.NotEmpty(t, devList.Devices[0].Manufacturer)
	assert.Equal(t, devList.Devices[0].Present, 1)
	assert.NotEmpty(t, devList.Devices[0].Name)

}

func testAPIGetDeviceListErrorServerDown(t *testing.T, fritz *ahaHTTP, server *httptest.Server) {
	server.Close()
	_, err := fritz.ListDevices()
	assert.Error(t, err)
}

func testAPISwitchOffByAinWithErrorServerDown(t *testing.T, fritz *ahaHTTP, server *httptest.Server) {
	server.Close()
	_, err := fritz.switchForAin("123344", "off")
	assert.Error(t, err)
}

func testAPIToggleDeviceErrorServerDownAtToggleStage(t *testing.T, fritz *ahaHTTP, server *httptest.Server) {
	server.Close()
	_, err := fritz.Toggle("DER device")
	assert.Error(t, err)
}

// TestRounding tests rounding.
func TestRounding(t *testing.T) {
	tcs := []struct {
		expected int64
		number   float64
		name     string
	}{
		{expected: int64(1), number: 0.5, name: "round_point_five"},
		{expected: int64(0), number: 0.4, name: "round_point_four"},
		{expected: int64(0), number: 0.1, name: "round_point_one"},
		{expected: int64(0), number: -0.1, name: "round_minus_point_one"},
		{expected: int64(0), number: -0.499, name: "round_minus_point_four_nine_nine"},
		{expected: int64(156), number: 156, name: "round_one_hundred_fifty_six"},
		{expected: int64(3), number: 3.14, name: "round_pi"},
		{expected: int64(4), number: 3.54, name: "round_three_point_five_four"},
	}
	for _, tc := range tcs {
		t.Run(tc.name, func(t *testing.T) {
			assert.Equal(t, tc.expected, round(tc.number))
		})
	}
}

// TestUnacceptableTempValues asserts that temperatures outside the range of the spec are perceived as invalid.
func TestUnacceptableTempValues(t *testing.T)  {
	assertions := assert.New(t)
	h := HomeAutomation(nil)

	_, err := h.ApplyTemperature(7.5, "1235")
	assertions.Error(err)

	_, err = h.ApplyTemperature(55, "1235")
	assertions.Error(err)
}<commit_msg>Issue #57: gofmt<commit_after>package fritz

import (
	"fmt"
	"log"
	"net/http/httptest"
	"net/url"
	"reflect"
	"runtime"
	"testing"

	"github.com/bpicode/fritzctl/mock"
	"github.com/stretchr/testify/assert"
)

// TestFritzAPI test the FRITZ API.
func TestFritzAPI(t *testing.T) {

	serverFactory := func() *httptest.Server {
		return mock.New().UnstartedServer()
	}

	clientFactory := func() *Client {
		cl, err := NewClient("../mock/client_config_template.json")
		assert.NoError(t, err)
		return cl
	}

	testCases := []struct {
		doTest func(t *testing.T, fritz *ahaHTTP, server *httptest.Server)
	}{
		{testGetDeviceList},
		{testAPIGetDeviceListErrorServerDown},
		{testAPISwitchOffByAinWithErrorServerDown},
		{testAPIToggleDeviceErrorServerDownAtToggleStage},
	}
	for _, testCase := range testCases {
		t.Run(fmt.Sprintf("Test aha api %s", runtime.FuncForPC(reflect.ValueOf(testCase.doTest).Pointer()).Name()), func(t *testing.T) {
			server := serverFactory()
			server.Start()
			defer server.Close()
			client := clientFactory()
			u, err := url.Parse(server.URL)
			assert.NoError(t, err)
			client.Config.Net.Protocol = u.Scheme
			client.Config.Net.Host = u.Host
			err = client.Login()
			assert.NoError(t, err)
			ha := HomeAutomation(client).(*ahaHTTP)
			assert.NotNil(t, ha)
			testCase.doTest(t, ha, server)
		})
	}
}

func testGetDeviceList(t *testing.T, fritz *ahaHTTP, server *httptest.Server) {
	devList, err := fritz.ListDevices()
	log.Println(*devList)
	assert.NoError(t, err)
	assert.NotNil(t, devList)
	assert.NotEmpty(t, devList.Devices)
	assert.NotEmpty(t, devList.Devices[0].ID)
	assert.NotEmpty(t, devList.Devices[0].Identifier)
	assert.NotEmpty(t, devList.Devices[0].Functionbitmask)
	assert.NotEmpty(t, devList.Devices[0].Fwversion)
	assert.NotEmpty(t, devList.Devices[0].Manufacturer)
	assert.Equal(t, devList.Devices[0].Present, 1)
	assert.NotEmpty(t, devList.Devices[0].Name)

}

func testAPIGetDeviceListErrorServerDown(t *testing.T, fritz *ahaHTTP, server *httptest.Server) {
	server.Close()
	_, err := fritz.ListDevices()
	assert.Error(t, err)
}

func testAPISwitchOffByAinWithErrorServerDown(t *testing.T, fritz *ahaHTTP, server *httptest.Server) {
	server.Close()
	_, err := fritz.switchForAin("123344", "off")
	assert.Error(t, err)
}

func testAPIToggleDeviceErrorServerDownAtToggleStage(t *testing.T, fritz *ahaHTTP, server *httptest.Server) {
	server.Close()
	_, err := fritz.Toggle("DER device")
	assert.Error(t, err)
}

// TestRounding tests rounding.
func TestRounding(t *testing.T) {
	tcs := []struct {
		expected int64
		number   float64
		name     string
	}{
		{expected: int64(1), number: 0.5, name: "round_point_five"},
		{expected: int64(0), number: 0.4, name: "round_point_four"},
		{expected: int64(0), number: 0.1, name: "round_point_one"},
		{expected: int64(0), number: -0.1, name: "round_minus_point_one"},
		{expected: int64(0), number: -0.499, name: "round_minus_point_four_nine_nine"},
		{expected: int64(156), number: 156, name: "round_one_hundred_fifty_six"},
		{expected: int64(3), number: 3.14, name: "round_pi"},
		{expected: int64(4), number: 3.54, name: "round_three_point_five_four"},
	}
	for _, tc := range tcs {
		t.Run(tc.name, func(t *testing.T) {
			assert.Equal(t, tc.expected, round(tc.number))
		})
	}
}

// TestUnacceptableTempValues asserts that temperatures outside the range of the spec are perceived as invalid.
func TestUnacceptableTempValues(t *testing.T) {
	assertions := assert.New(t)
	h := HomeAutomation(nil)

	_, err := h.ApplyTemperature(7.5, "1235")
	assertions.Error(err)

	_, err = h.ApplyTemperature(55, "1235")
	assertions.Error(err)
}
<|endoftext|>