<commit_before>// Copyright 2013 <huangdongxu1987{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"os"
	"strings"
	"text/template"

	descriptor "github.com/c4pt0r/protoc-gen-go/descriptor"
	generator "github.com/c4pt0r/protoc-gen-go/generator"
)

// option go_generic_services = ???; // defaut is true
const go_generic_services = "go_generic_services"

// pkg name as prefix of service name? // defaut is false
const go_generic_services_use_pkg_name = "go_generic_services_use_pkg_name"

// servicePlugin produce the Service interface.
type servicePlugin struct {
	*generator.Generator
}

// Name returns the name of the plugin.
func (p *servicePlugin) Name() string { return "protorpc" }

// Init is called once after data structures are built but before
// code generation begins.
func (p *servicePlugin) Init(g *generator.Generator) {
	p.Generator = g
}

// Generate produces the code generated by the plugin for this file.
func (p *servicePlugin) GenerateImports(file *generator.FileDescriptor) {
	if !p.getGenericServicesOptions(file) {
		return
	}
	if len(file.Service) > 0 {
		p.P(`import "io"`)
		p.P(`import "log"`)
		p.P(`import "net"`)
		p.P(`import "net/rpc"`)
		p.P(`import "time"`)
		p.P(`import protorpc "github.com/c4pt0r"`)
	}
}

// Generate generates the Service interface.
// rpc service can't handle other proto message!!!
func (p *servicePlugin) Generate(file *generator.FileDescriptor) {
	if !p.getGenericServicesOptions(file) {
		return
	}
	for _, svc := range file.Service {
		p.genServiceInterface(file, svc)
		p.genServiceServer(file, svc)
		p.genServiceClient(file, svc)
	}
}

func (p *servicePlugin) getGenericServicesOptions(
	file *generator.FileDescriptor,
) bool {
	env := go_generic_services

	// try command line first
	// protoc --go_out=go_generic_services=true:. xxx.proto
	if value, ok := p.Generator.Param[env]; ok {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}

	// try environment second
	if value := os.Getenv(strings.ToUpper(env)); value != "" {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}
	if value := os.Getenv(strings.ToLower(env)); value != "" {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}

	// default is ture
	return true
}

func (p *servicePlugin) getGenericServicesOptionsUsePkgName(
	file *generator.FileDescriptor,
) bool {
	env := go_generic_services_use_pkg_name

	// try command line first
	// protoc --go_out=go_generic_services_use_pkg_name=true:. xxx.proto
	if value, ok := p.Generator.Param[env]; ok {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}

	if value := os.Getenv(strings.ToUpper(env)); value != "" {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}
	if value := os.Getenv(strings.ToLower(env)); value != "" {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}

	return false
}

func (p *servicePlugin) genServiceInterface(
	file *generator.FileDescriptor,
	svc *descriptor.ServiceDescriptorProto,
) {
	const serviceInterfaceTmpl = `
type {{.ServiceName}} interface {
	{{.CallMethodList}}
}
`
	const callMethodTmpl = `
{{.MethodName}}(in *{{.ArgsType}}, out *{{.ReplyType}}) error`

	// gen call method list
	var callMethodList string
	for _, m := range svc.Method {
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(callMethodTmpl))
		t.Execute(out, &struct{ ServiceName, MethodName, ArgsType, ReplyType string }{
			ServiceName: generator.CamelCase(svc.GetName()),
			MethodName:  generator.CamelCase(m.GetName()),
			ArgsType:    p.TypeName(p.ObjectNamed(m.GetInputType())),
			ReplyType:   p.TypeName(p.ObjectNamed(m.GetOutputType())),
		})
		callMethodList += out.String()

		p.RecordTypeUse(m.GetInputType())
		p.RecordTypeUse(m.GetOutputType())
	}

	// gen all interface code
	{
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(serviceInterfaceTmpl))
		t.Execute(out, &struct{ ServiceName, CallMethodList string }{
			ServiceName:    generator.CamelCase(svc.GetName()),
			CallMethodList: callMethodList,
		})
		p.P(out.String())
	}
}

func (p *servicePlugin) genServiceServer(
	file *generator.FileDescriptor,
	svc *descriptor.ServiceDescriptorProto,
) {
	const serviceHelperFunTmpl = `
// Accept{{.ServiceName}}Client accepts connections on the listener and serves requests
// for each incoming connection.  Accept blocks; the caller typically
// invokes it in a go statement.
func Accept{{.ServiceName}}Client(lis net.Listener, x {{.ServiceName}}) {
	srv := rpc.NewServer()
	if err := srv.RegisterName("{{.ServiceRegisterName}}", x); err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := lis.Accept()
		if err != nil {
			log.Fatalf("lis.Accept(): %v\n", err)
		}
		go srv.ServeCodec(protorpc.NewServerCodec(conn))
	}
}

// Register{{.ServiceName}} publish the given {{.ServiceName}} implementation on the server.
func Register{{.ServiceName}}(srv *rpc.Server, x {{.ServiceName}}) error {
	if err := srv.RegisterName("{{.ServiceRegisterName}}", x); err != nil {
		return err
	}
	return nil
}

// New{{.ServiceName}}Server returns a new {{.ServiceName}} Server.
func New{{.ServiceName}}Server(x {{.ServiceName}}) *rpc.Server {
	srv := rpc.NewServer()
	if err := srv.RegisterName("{{.ServiceRegisterName}}", x); err != nil {
		log.Fatal(err)
	}
	return srv
}

// ListenAndServe{{.ServiceName}} listen announces on the local network address laddr
// and serves the given {{.ServiceName}} implementation.
func ListenAndServe{{.ServiceName}}(network, addr string, x {{.ServiceName}}) error {
	lis, err := net.Listen(network, addr)
	if err != nil {
		return err
	}
	defer lis.Close()

	srv := rpc.NewServer()
	if err := srv.RegisterName("{{.ServiceRegisterName}}", x); err != nil {
		return err
	}

	for {
		conn, err := lis.Accept()
		if err != nil {
			log.Fatalf("lis.Accept(): %v\n", err)
		}
		go srv.ServeCodec(protorpc.NewServerCodec(conn))
	}
}
`
	{
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(serviceHelperFunTmpl))
		t.Execute(out, &struct{ PackageName, ServiceName, ServiceRegisterName string }{
			PackageName: file.GetPackage(),
			ServiceName: generator.CamelCase(svc.GetName()),
			ServiceRegisterName: p.makeServiceRegisterName(
				file, file.GetPackage(), generator.CamelCase(svc.GetName()),
			),
		})
		p.P(out.String())
	}
}

func (p *servicePlugin) genServiceClient(
	file *generator.FileDescriptor,
	svc *descriptor.ServiceDescriptorProto,
) {
	const clientHelperFuncTmpl = `
type {{.ServiceName}}Client struct {
	*rpc.Client
}

// New{{.ServiceName}}Client returns a {{.ServiceName}} rpc.Client and stub to handle
// requests to the set of {{.ServiceName}} at the other end of the connection.
func New{{.ServiceName}}Client(conn io.ReadWriteCloser) (*{{.ServiceName}}Client, *rpc.Client) {
	c := rpc.NewClientWithCodec(protorpc.NewClientCodec(conn))
	return &{{.ServiceName}}Client{c}, c
}

{{.MethodList}}

// Dial{{.ServiceName}} connects to an {{.ServiceName}} at the specified network address.
func Dial{{.ServiceName}}(network, addr string) (*{{.ServiceName}}Client, *rpc.Client, error) {
	c, err := protorpc.Dial(network, addr)
	if err != nil {
		return nil, nil, err
	}
	return &{{.ServiceName}}Client{c}, c, nil
}

// Dial{{.ServiceName}}Timeout connects to an {{.ServiceName}} at the specified network address.
func Dial{{.ServiceName}}Timeout(network, addr string,
	timeout time.Duration) (*{{.ServiceName}}Client, *rpc.Client, error) {
	c, err := protorpc.DialTimeout(network, addr, timeout)
	if err != nil {
		return nil, nil, err
	}
	return &{{.ServiceName}}Client{c}, c, nil
}
`
	const clientMethodTmpl = `
func (c *{{.ServiceName}}Client) {{.MethodName}}(in *{{.ArgsType}}, out *{{.ReplyType}}) error {
	return c.Call("{{.ServiceRegisterName}}.{{.MethodName}}", in, out)
}`

	// gen client method list
	var methodList string
	for _, m := range svc.Method {
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(clientMethodTmpl))
		t.Execute(out, &struct{ ServiceName, ServiceRegisterName, MethodName, ArgsType, ReplyType string }{
			ServiceName: generator.CamelCase(svc.GetName()),
			ServiceRegisterName: p.makeServiceRegisterName(
				file, file.GetPackage(), generator.CamelCase(svc.GetName()),
			),
			MethodName: generator.CamelCase(m.GetName()),
			ArgsType:   p.TypeName(p.ObjectNamed(m.GetInputType())),
			ReplyType:  p.TypeName(p.ObjectNamed(m.GetOutputType())),
		})
		methodList += out.String()
	}

	// gen all client code
	{
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(clientHelperFuncTmpl))
		t.Execute(out, &struct{ PackageName, ServiceName, MethodList string }{
			PackageName: file.GetPackage(),
			ServiceName: generator.CamelCase(svc.GetName()),
			MethodList:  methodList,
		})
		p.P(out.String())
	}
}

func (p *servicePlugin) makeServiceRegisterName(
	file *generator.FileDescriptor,
	packageName, serviceName string,
) string {
	return packageName + "." + serviceName
}

func init() {
	generator.RegisterPlugin(new(servicePlugin))
}
<commit_msg>fix bug<commit_after>// Copyright 2013 <huangdongxu1987{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"os"
	"strings"
	"text/template"

	descriptor "github.com/c4pt0r/protoc-gen-go/descriptor"
	generator "github.com/c4pt0r/protoc-gen-go/generator"
)

// option go_generic_services = ???; // defaut is true
const go_generic_services = "go_generic_services"

// pkg name as prefix of service name? // defaut is false
const go_generic_services_use_pkg_name = "go_generic_services_use_pkg_name"

// servicePlugin produce the Service interface.
type servicePlugin struct {
	*generator.Generator
}

// Name returns the name of the plugin.
func (p *servicePlugin) Name() string { return "protorpc" }

// Init is called once after data structures are built but before
// code generation begins.
func (p *servicePlugin) Init(g *generator.Generator) {
	p.Generator = g
}

// Generate produces the code generated by the plugin for this file.
func (p *servicePlugin) GenerateImports(file *generator.FileDescriptor) {
	if !p.getGenericServicesOptions(file) {
		return
	}
	if len(file.Service) > 0 {
		p.P(`import "io"`)
		p.P(`import "log"`)
		p.P(`import "net"`)
		p.P(`import "net/rpc"`)
		p.P(`import "time"`)
		p.P(`import protorpc "wpbrpc"`)
	}
}

// Generate generates the Service interface.
// rpc service can't handle other proto message!!!
func (p *servicePlugin) Generate(file *generator.FileDescriptor) {
	if !p.getGenericServicesOptions(file) {
		return
	}
	for _, svc := range file.Service {
		p.genServiceInterface(file, svc)
		p.genServiceServer(file, svc)
		p.genServiceClient(file, svc)
	}
}

func (p *servicePlugin) getGenericServicesOptions(
	file *generator.FileDescriptor,
) bool {
	env := go_generic_services

	// try command line first
	// protoc --go_out=go_generic_services=true:. xxx.proto
	if value, ok := p.Generator.Param[env]; ok {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}

	// try environment second
	if value := os.Getenv(strings.ToUpper(env)); value != "" {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}
	if value := os.Getenv(strings.ToLower(env)); value != "" {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}

	// default is ture
	return true
}

func (p *servicePlugin) getGenericServicesOptionsUsePkgName(
	file *generator.FileDescriptor,
) bool {
	env := go_generic_services_use_pkg_name

	// try command line first
	// protoc --go_out=go_generic_services_use_pkg_name=true:. xxx.proto
	if value, ok := p.Generator.Param[env]; ok {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}

	if value := os.Getenv(strings.ToUpper(env)); value != "" {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}
	if value := os.Getenv(strings.ToLower(env)); value != "" {
		if value == "1" || strings.ToLower(value) == "true" {
			return true
		}
		if value == "0" || strings.ToLower(value) == "false" {
			return false
		}
	}

	return false
}

func (p *servicePlugin) genServiceInterface(
	file *generator.FileDescriptor,
	svc *descriptor.ServiceDescriptorProto,
) {
	const serviceInterfaceTmpl = `
type {{.ServiceName}} interface {
	{{.CallMethodList}}
}
`
	const callMethodTmpl = `
{{.MethodName}}(in *{{.ArgsType}}, out *{{.ReplyType}}) error`

	// gen call method list
	var callMethodList string
	for _, m := range svc.Method {
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(callMethodTmpl))
		t.Execute(out, &struct{ ServiceName, MethodName, ArgsType, ReplyType string }{
			ServiceName: generator.CamelCase(svc.GetName()),
			MethodName:  generator.CamelCase(m.GetName()),
			ArgsType:    p.TypeName(p.ObjectNamed(m.GetInputType())),
			ReplyType:   p.TypeName(p.ObjectNamed(m.GetOutputType())),
		})
		callMethodList += out.String()

		p.RecordTypeUse(m.GetInputType())
		p.RecordTypeUse(m.GetOutputType())
	}

	// gen all interface code
	{
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(serviceInterfaceTmpl))
		t.Execute(out, &struct{ ServiceName, CallMethodList string }{
			ServiceName:    generator.CamelCase(svc.GetName()),
			CallMethodList: callMethodList,
		})
		p.P(out.String())
	}
}

func (p *servicePlugin) genServiceServer(
	file *generator.FileDescriptor,
	svc *descriptor.ServiceDescriptorProto,
) {
	const serviceHelperFunTmpl = `
// Accept{{.ServiceName}}Client accepts connections on the listener and serves requests
// for each incoming connection.  Accept blocks; the caller typically
// invokes it in a go statement.
func Accept{{.ServiceName}}Client(lis net.Listener, x {{.ServiceName}}) {
	srv := rpc.NewServer()
	if err := srv.RegisterName("{{.ServiceRegisterName}}", x); err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := lis.Accept()
		if err != nil {
			log.Fatalf("lis.Accept(): %v\n", err)
		}
		go srv.ServeCodec(protorpc.NewServerCodec(conn))
	}
}

// Register{{.ServiceName}} publish the given {{.ServiceName}} implementation on the server.
func Register{{.ServiceName}}(srv *rpc.Server, x {{.ServiceName}}) error {
	if err := srv.RegisterName("{{.ServiceRegisterName}}", x); err != nil {
		return err
	}
	return nil
}

// New{{.ServiceName}}Server returns a new {{.ServiceName}} Server.
func New{{.ServiceName}}Server(x {{.ServiceName}}) *rpc.Server {
	srv := rpc.NewServer()
	if err := srv.RegisterName("{{.ServiceRegisterName}}", x); err != nil {
		log.Fatal(err)
	}
	return srv
}

// ListenAndServe{{.ServiceName}} listen announces on the local network address laddr
// and serves the given {{.ServiceName}} implementation.
func ListenAndServe{{.ServiceName}}(network, addr string, x {{.ServiceName}}) error {
	lis, err := net.Listen(network, addr)
	if err != nil {
		return err
	}
	defer lis.Close()

	srv := rpc.NewServer()
	if err := srv.RegisterName("{{.ServiceRegisterName}}", x); err != nil {
		return err
	}

	for {
		conn, err := lis.Accept()
		if err != nil {
			log.Fatalf("lis.Accept(): %v\n", err)
		}
		go srv.ServeCodec(protorpc.NewServerCodec(conn))
	}
}
`
	{
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(serviceHelperFunTmpl))
		t.Execute(out, &struct{ PackageName, ServiceName, ServiceRegisterName string }{
			PackageName: file.GetPackage(),
			ServiceName: generator.CamelCase(svc.GetName()),
			ServiceRegisterName: p.makeServiceRegisterName(
				file, file.GetPackage(), generator.CamelCase(svc.GetName()),
			),
		})
		p.P(out.String())
	}
}

func (p *servicePlugin) genServiceClient(
	file *generator.FileDescriptor,
	svc *descriptor.ServiceDescriptorProto,
) {
	const clientHelperFuncTmpl = `
type {{.ServiceName}}Client struct {
	*rpc.Client
}

// New{{.ServiceName}}Client returns a {{.ServiceName}} rpc.Client and stub to handle
// requests to the set of {{.ServiceName}} at the other end of the connection.
func New{{.ServiceName}}Client(conn io.ReadWriteCloser) (*{{.ServiceName}}Client, *rpc.Client) {
	c := rpc.NewClientWithCodec(protorpc.NewClientCodec(conn))
	return &{{.ServiceName}}Client{c}, c
}

{{.MethodList}}

// Dial{{.ServiceName}} connects to an {{.ServiceName}} at the specified network address.
func Dial{{.ServiceName}}(network, addr string) (*{{.ServiceName}}Client, *rpc.Client, error) {
	c, err := protorpc.Dial(network, addr)
	if err != nil {
		return nil, nil, err
	}
	return &{{.ServiceName}}Client{c}, c, nil
}

// Dial{{.ServiceName}}Timeout connects to an {{.ServiceName}} at the specified network address.
func Dial{{.ServiceName}}Timeout(network, addr string,
	timeout time.Duration) (*{{.ServiceName}}Client, *rpc.Client, error) {
	c, err := protorpc.DialTimeout(network, addr, timeout)
	if err != nil {
		return nil, nil, err
	}
	return &{{.ServiceName}}Client{c}, c, nil
}
`
	const clientMethodTmpl = `
func (c *{{.ServiceName}}Client) {{.MethodName}}(in *{{.ArgsType}}, out *{{.ReplyType}}) error {
	return c.Call("{{.ServiceRegisterName}}:{{.MethodOriginName}}", in, out)
}`

	// gen client method list
	var methodList string
	for _, m := range svc.Method {
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(clientMethodTmpl))
		t.Execute(out, &struct{ ServiceName, ServiceRegisterName, MethodName, MethodOriginName, ArgsType, ReplyType string }{
			ServiceName: generator.CamelCase(svc.GetName()),
			ServiceRegisterName: p.makeServiceRegisterName(
				file, file.GetPackage(), svc.GetName(),
			),
			MethodName:       generator.CamelCase(m.GetName()),
			MethodOriginName: m.GetName(),
			ArgsType:         p.TypeName(p.ObjectNamed(m.GetInputType())),
			ReplyType:        p.TypeName(p.ObjectNamed(m.GetOutputType())),
		})
		methodList += out.String()
	}

	// gen all client code
	{
		out := bytes.NewBuffer([]byte{})
		t := template.Must(template.New("").Parse(clientHelperFuncTmpl))
		t.Execute(out, &struct{ PackageName, ServiceName, MethodList string }{
			PackageName: file.GetPackage(),
			ServiceName: generator.CamelCase(svc.GetName()),
			MethodList:  methodList,
		})
		p.P(out.String())
	}
}

func (p *servicePlugin) makeServiceRegisterName(
	file *generator.FileDescriptor,
	packageName, serviceName string,
) string {
	return packageName + "." + serviceName
}

func init() {
	generator.RegisterPlugin(new(servicePlugin))
}
<|endoftext|>


<commit_before>package yaml_test

import (
	"fmt"
	"strings"

	"github.com/goccy/go-yaml"
	"gopkg.in/go-playground/validator.v9"
)

type Person struct {
	Name string `validate:"required"`
	Age  int    `validate:"gte=0,lt=120"`
}

func ExampleStructValidator() {
	yml := `---
- name: john
  age: 20
- name: tom
  age: -1
- name: ken
  age: 10
`
	validate := validator.New()
	dec := yaml.NewDecoder(
		strings.NewReader(yml),
		yaml.Validator(validate),
	)
	var v []*Person
	err := dec.Decode(&v)
	if err == nil {
		panic(err)
	}
	fmt.Printf("%v", err)
	// OUTPUT:
	// [5:8] Key: 'Person.Age' Error:Field validation for 'Age' failed on the 'gte' tag
	//        1 | ---
	//        2 | - name: john
	//        3 |   age: 20
	//        4 | - name: tom
	//     >  5 |   age: -1
	//                  ^
	//        6 | - name: ken
	//        7 |   age: 10
}
<commit_msg>Fix error handling<commit_after>package yaml_test

import (
	"fmt"
	"strings"

	"github.com/goccy/go-yaml"
	"gopkg.in/go-playground/validator.v9"
)

type Person struct {
	Name string `validate:"required"`
	Age  int    `validate:"gte=0,lt=120"`
}

func ExampleStructValidator() {
	yml := `---
- name: john
  age: 20
- name: tom
  age: -1
- name: ken
  age: 10
`
	validate := validator.New()
	dec := yaml.NewDecoder(
		strings.NewReader(yml),
		yaml.Validator(validate),
	)
	var v []*Person
	err := dec.Decode(&v)
	if err == nil {
		panic("expected error")
	}
	fmt.Printf("%v", err)
	// OUTPUT:
	// [5:8] Key: 'Person.Age' Error:Field validation for 'Age' failed on the 'gte' tag
	//        1 | ---
	//        2 | - name: john
	//        3 |   age: 20
	//        4 | - name: tom
	//     >  5 |   age: -1
	//                  ^
	//        6 | - name: ken
	//        7 |   age: 10
}
<|endoftext|>


<commit_before>package esdatapub

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	_ "github.com/mattn/go-oci8"
	"github.com/xtracdev/orapub"
	"os"
	"strings"
)

var connectStr string

func init() {
	var configErrors []string

	user := os.Getenv("DB_USER")
	if user == "" {
		configErrors = append(configErrors, "Configuration missing DB_USER env variable")
	}

	password := os.Getenv("DB_PASSWORD")
	if password == "" {
		configErrors = append(configErrors, "Configuration missing DB_PASSWORD env variable")
	}

	dbhost := os.Getenv("DB_HOST")
	if dbhost == "" {
		configErrors = append(configErrors, "Configuration missing DB_HOST env variable")
	}

	dbPort := os.Getenv("DB_PORT")
	if dbPort == "" {
		configErrors = append(configErrors, "Configuration missing DB_PORT env variable")
	}

	dbSvc := os.Getenv("DB_SVC")
	if dbSvc == "" {
		configErrors = append(configErrors, "Configuration missing DB_SVC env variable")
	}

	if len(configErrors) != 0 {
		log.Fatal(strings.Join(configErrors, "\n"))
	}

	connectStr = fmt.Sprintf("%s/%s@//%s:%s/%s",
		user, password, dbhost, dbPort, dbSvc)

}

func ProcessEventRecords() error {

	publisher := new(orapub.OraPub)
	err := publisher.Connect(connectStr, 5)
	if err != nil {
		log.Warnf("Unable to connect publisher reader")
		return err
	}

	err = publisher.InitializeProcessors()
	if err != nil {
		return err
	}

	publisher.ProcessEvents(true)

	return nil
}
<commit_msg>Remove embedded Oracle driver dependency<commit_after>package esdatapub

import (
	"fmt"
	"os"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/xtracdev/orapub"
)

var connectStr string

func init() {
	var configErrors []string

	user := os.Getenv("DB_USER")
	if user == "" {
		configErrors = append(configErrors, "Configuration missing DB_USER env variable")
	}

	password := os.Getenv("DB_PASSWORD")
	if password == "" {
		configErrors = append(configErrors, "Configuration missing DB_PASSWORD env variable")
	}

	dbhost := os.Getenv("DB_HOST")
	if dbhost == "" {
		configErrors = append(configErrors, "Configuration missing DB_HOST env variable")
	}

	dbPort := os.Getenv("DB_PORT")
	if dbPort == "" {
		configErrors = append(configErrors, "Configuration missing DB_PORT env variable")
	}

	dbSvc := os.Getenv("DB_SVC")
	if dbSvc == "" {
		configErrors = append(configErrors, "Configuration missing DB_SVC env variable")
	}

	if len(configErrors) != 0 {
		log.Fatal(strings.Join(configErrors, "\n"))
	}

	connectStr = fmt.Sprintf("%s/%s@//%s:%s/%s",
		user, password, dbhost, dbPort, dbSvc)

}

func ProcessEventRecords() error {

	publisher := new(orapub.OraPub)
	err := publisher.Connect(connectStr, 5)
	if err != nil {
		log.Warnf("Unable to connect publisher reader")
		return err
	}

	err = publisher.InitializeProcessors()
	if err != nil {
		return err
	}

	publisher.ProcessEvents(true)

	return nil
}
<|endoftext|>


<commit_before>package database

import (
	"encoding/json"
	"fmt"
	"io"
	"path"
	"time"

	"github.com/boltdb/bolt"
	"github.com/hashicorp/raft"
)

type (
	// Database is the lowest level of the gansoi database.
	Database struct {
		db *bolt.DB
	}

	// Command is used to denote which operation should be carried out as a
	// result of a Raft commit.
	Command int

	// LogEntry is an entry in the Raft log (?).
	LogEntry struct {
		Command Command
		Key     string
		Value   []byte
	}
)

const (
	// CommandSet will set a new value in the database.
	CommandSet = iota

	// CommandDelete will delete a key in the database.
	CommandDelete
)

// NewDatabase will instantiate a new database placed in filepath.
func NewDatabase(filepath string) (*Database, error) {
	db, err := bolt.Open(
		path.Join(filepath, "gansoi.db"),
		0600,
		&bolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		return nil, err
	}

	return &Database{
		db: db,
	}, nil
}

// NewLogEntry will return a new LogEntry ready for committing to the Raft log.
func NewLogEntry(cmd Command, key string, value []byte) *LogEntry {
	return &LogEntry{
		Command: cmd,
		Key:     key,
		Value:   value,
	}
}

// Byte is a simple helper, that will marshal the entry to a byte slice.
func (e *LogEntry) Byte() []byte {
	b, _ := json.Marshal(e)

	return b
}

// ProcessLogEntry will process the log entry and apply whatever needs doing.
func (d *Database) ProcessLogEntry(entry *LogEntry) error {
	switch entry.Command {
	case CommandSet:
		tx, err := d.db.Begin(true)
		if err != nil {
			return err
		}

		bucket, err := tx.CreateBucketIfNotExists([]byte("keyvalue"))
		if err != nil {
			tx.Rollback()
			return err
		}

		err = bucket.Put([]byte(entry.Key), entry.Value)
		if err != nil {
			tx.Rollback()
			return err
		}

		err = tx.Commit()
		if err != nil {
			return err
		}

	case CommandDelete:
		tx, err := d.db.Begin(true)
		if err != nil {
			return err
		}

		bucket, err := tx.CreateBucketIfNotExists([]byte("keyvalue"))
		if err != nil {
			tx.Rollback()
			return err
		}

		err = bucket.Delete([]byte(entry.Key))
		if err != nil {
			tx.Rollback()
			return err
		}

		err = tx.Commit()
		if err != nil {
			return err
		}
	}

	return nil
}

// Get will return a value from the generic key/value store.
func (d *Database) Get(key string) ([]byte, error) {
	var value []byte

	err := d.db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte("keyvalue"))
		value = bucket.Get([]byte(key))
		return nil
	})

	return value, err
}

// Apply implements raft.FSM.
func (d *Database) Apply(l *raft.Log) interface{} {
	entry := &LogEntry{}
	err := json.Unmarshal(l.Data, entry)
	if err != nil {
		// This should not happen..?
		panic(err.Error())
	}

	return d.ProcessLogEntry(entry)
}

// Snapshot implements raft.FSM.
func (d *Database) Snapshot() (raft.FSMSnapshot, error) {
	fmt.Printf("Snapshot()\n")

	return &Snapshot{}, nil
}

// Restore implements raft.FSM.
func (d *Database) Restore(io.ReadCloser) error {
	fmt.Printf("Restore()\n")
	return nil
}
<commit_msg>Make sure we have our keyvalue bucket before using it :)<commit_after>package database

import (
	"encoding/json"
	"fmt"
	"io"
	"path"
	"time"

	"github.com/boltdb/bolt"
	"github.com/hashicorp/raft"
)

type (
	// Database is the lowest level of the gansoi database.
	Database struct {
		db *bolt.DB
	}

	// Command is used to denote which operation should be carried out as a
	// result of a Raft commit.
	Command int

	// LogEntry is an entry in the Raft log (?).
	LogEntry struct {
		Command Command
		Key     string
		Value   []byte
	}
)

const (
	// CommandSet will set a new value in the database.
	CommandSet = iota

	// CommandDelete will delete a key in the database.
	CommandDelete
)

// NewDatabase will instantiate a new database placed in filepath.
func NewDatabase(filepath string) (*Database, error) {
	db, err := bolt.Open(
		path.Join(filepath, "gansoi.db"),
		0600,
		&bolt.Options{Timeout: 1 * time.Second})

	db.Update(func(tx *bolt.Tx) error {
		tx.CreateBucketIfNotExists([]byte("keyvalue"))
		return nil
	})

	if err != nil {
		return nil, err
	}

	return &Database{
		db: db,
	}, nil
}

// NewLogEntry will return a new LogEntry ready for committing to the Raft log.
func NewLogEntry(cmd Command, key string, value []byte) *LogEntry {
	return &LogEntry{
		Command: cmd,
		Key:     key,
		Value:   value,
	}
}

// Byte is a simple helper, that will marshal the entry to a byte slice.
func (e *LogEntry) Byte() []byte {
	b, _ := json.Marshal(e)

	return b
}

// ProcessLogEntry will process the log entry and apply whatever needs doing.
func (d *Database) ProcessLogEntry(entry *LogEntry) error {
	switch entry.Command {
	case CommandSet:
		tx, err := d.db.Begin(true)
		if err != nil {
			return err
		}

		bucket, err := tx.CreateBucketIfNotExists([]byte("keyvalue"))
		if err != nil {
			tx.Rollback()
			return err
		}

		err = bucket.Put([]byte(entry.Key), entry.Value)
		if err != nil {
			tx.Rollback()
			return err
		}

		err = tx.Commit()
		if err != nil {
			return err
		}

	case CommandDelete:
		tx, err := d.db.Begin(true)
		if err != nil {
			return err
		}

		bucket, err := tx.CreateBucketIfNotExists([]byte("keyvalue"))
		if err != nil {
			tx.Rollback()
			return err
		}

		err = bucket.Delete([]byte(entry.Key))
		if err != nil {
			tx.Rollback()
			return err
		}

		err = tx.Commit()
		if err != nil {
			return err
		}
	}

	return nil
}

// Get will return a value from the generic key/value store.
func (d *Database) Get(key string) ([]byte, error) {
	var value []byte

	err := d.db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket([]byte("keyvalue"))
		if bucket == nil {
			panic("bucket == nil")
		}

		value = bucket.Get([]byte(key))
		return nil
	})

	return value, err
}

// Apply implements raft.FSM.
func (d *Database) Apply(l *raft.Log) interface{} {
	entry := &LogEntry{}
	err := json.Unmarshal(l.Data, entry)
	if err != nil {
		// This should not happen..?
		panic(err.Error())
	}

	return d.ProcessLogEntry(entry)
}

// Snapshot implements raft.FSM.
func (d *Database) Snapshot() (raft.FSMSnapshot, error) {
	fmt.Printf("Snapshot()\n")

	return &Snapshot{}, nil
}

// Restore implements raft.FSM.
func (d *Database) Restore(io.ReadCloser) error {
	fmt.Printf("Restore()\n")
	return nil
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"time"

	"github.com/anthonynsimon/parrot/errors"
	"github.com/anthonynsimon/parrot/paths"
)

type APIStore struct {
	URL string
}

func New(url string) *APIStore {
	return &APIStore{URL: url}
}

func (a *APIStore) Ping() error {
	js, err := a.request("GET", paths.PingPath, nil)
	if err != nil {
		return err
	}

	if status, ok := js["status"]; !ok || status != "200" {
		return errors.ErrInternal
	}
	return nil
}

func (a *APIStore) Close() error {
	return nil
}

func (a *APIStore) request(method, uri string, data interface{}) (map[string]interface{}, error) {
	encoded, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(method, a.URL+uri, bytes.NewBuffer(encoded))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{
		Timeout: time.Second * 10,
	}

	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	var out map[string]interface{}
	err = json.NewDecoder(res.Body).Decode(&out)
	if err != nil {
		return nil, err
	}

	if v, ok := out["error"]; ok {
		fmt.Println(v)
		return nil, errors.New(res.StatusCode, v.(string))
	}

	return out, nil
}
<commit_msg>Remove debug print<commit_after>package api

import (
	"bytes"
	"encoding/json"
	"net/http"
	"time"

	"github.com/anthonynsimon/parrot/errors"
	"github.com/anthonynsimon/parrot/paths"
)

type APIStore struct {
	URL string
}

func New(url string) *APIStore {
	return &APIStore{URL: url}
}

func (a *APIStore) Ping() error {
	js, err := a.request("GET", paths.PingPath, nil)
	if err != nil {
		return err
	}

	if status, ok := js["status"]; !ok || status != "200" {
		return errors.ErrInternal
	}
	return nil
}

func (a *APIStore) Close() error {
	return nil
}

func (a *APIStore) request(method, uri string, data interface{}) (map[string]interface{}, error) {
	encoded, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(method, a.URL+uri, bytes.NewBuffer(encoded))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{
		Timeout: time.Second * 10,
	}

	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	var out map[string]interface{}
	err = json.NewDecoder(res.Body).Decode(&out)
	if err != nil {
		return nil, err
	}

	if v, ok := out["error"]; ok {
		return nil, errors.New(res.StatusCode, v.(string))
	}

	return out, nil
}
<|endoftext|>


<commit_before>// fix_archives is an application that validates the webpage archives of a
// pageset type and deletes the archives which are found to be deliver
// inconsistent benchmark results.
// See https://code.google.com/p/chromium/issues/detail?id=456883 for more
// details.
package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/skia-dev/glog"
	"skia.googlesource.com/buildbot.git/ct/go/util"
	"skia.googlesource.com/buildbot.git/go/common"
)

var (
	runID                  = flag.String("run_id", "", "The unique run id (typically requester + timestamp).")
	workerNum              = flag.Int("worker_num", 1, "The number of this CT worker. It will be in the {1..100} range.")
	pagesetType            = flag.String("pageset_type", util.PAGESET_TYPE_MOBILE_10k, "The type of pagesets whose archives need to be validated. Eg: 10k, Mobile10k, All.")
	chromiumBuild          = flag.String("chromium_build", "", "The chromium build to use for this validation run.")
	repeatBenchmark        = flag.Int("repeat_benchmark", 5, "The number of times the benchmark should be repeated.")
	benchmarkName          = flag.String("benchmark_name", util.BENCHMARK_REPAINT, "The telemetry benchmark to run on this worker.")
	benchmarkHeaderToCheck = flag.String("benchmark_header_to_check", "mean_frame_time (ms)", "The benchmark header this task will validate.")
	benchmarkArgs          = flag.String("benchmark_args", "--output-format=csv", "The arguments that are passed to the specified benchmark.")
	browserArgs            = flag.String("browser_args", "--disable-setuid-sandbox --enable-threaded-compositing --enable-impl-side-painting", "The arguments that are passed to the browser while running the benchmark.")
)

func main() {
	common.Init()
	defer util.TimeTrack(time.Now(), "Fixing archives")
	defer glog.Flush()

	// Create the task file so that the master knows this worker is still busy.
	util.CreateTaskFile(util.ACTIVITY_FIXING_ARCHIVES)
	defer util.DeleteTaskFile(util.ACTIVITY_FIXING_ARCHIVES)

	if *pagesetType == "" {
		glog.Error("Must specify --pageset_type")
		return
	}
	if *chromiumBuild == "" {
		glog.Error("Must specify --chromium_build")
		return
	}
	if *runID == "" {
		glog.Error("Must specify --run_id")
		return
	}

	// Sync the local chromium checkout.
	if err := util.SyncDir(util.ChromiumSrcDir); err != nil {
		glog.Errorf("Could not gclient sync %s: %s", util.ChromiumSrcDir, err)
		return
	}

	// Instantiate GsUtil object.
	gs, err := util.NewGsUtil(nil)
	if err != nil {
		glog.Error(err)
		return
	}

	// Download the specified chromium build.
	if err := gs.DownloadChromiumBuild(*chromiumBuild); err != nil {
		glog.Error(err)
		return
	}
	// Delete the chromium build to save space when we are done.
	defer os.RemoveAll(filepath.Join(util.ChromiumBuildsDir, *chromiumBuild))
	chromiumBinary := filepath.Join(util.ChromiumBuildsDir, *chromiumBuild, util.BINARY_CHROME)

	// Download pagesets if they do not exist locally.
	if err := gs.DownloadWorkerArtifacts(util.PAGESETS_DIR_NAME, *pagesetType, *workerNum); err != nil {
		glog.Error(err)
		return
	}
	pathToPagesets := filepath.Join(util.PagesetsDir, *pagesetType)

	// Download archives if they do not exist locally.
	if err := gs.DownloadWorkerArtifacts(util.WEB_ARCHIVES_DIR_NAME, *pagesetType, *workerNum); err != nil {
		glog.Error(err)
		return
	}

	// Establish output paths.
	localOutputDir := filepath.Join(util.StorageDir, util.FixArchivesRunsDir, *runID)
	os.RemoveAll(localOutputDir)
	os.MkdirAll(localOutputDir, 0700)
	defer os.RemoveAll(localOutputDir)

	// Construct path to the ct_run_benchmark python script.
	_, currentFile, _, _ := runtime.Caller(0)
	pathToPyFiles := filepath.Join(
		filepath.Dir((filepath.Dir(filepath.Dir(filepath.Dir(currentFile))))),
		"py")

	timeoutSecs := util.PagesetTypeToInfo[*pagesetType].RunBenchmarksTimeoutSecs
	fileInfos, err := ioutil.ReadDir(pathToPagesets)
	if err != nil {
		glog.Errorf("Unable to read the pagesets dir %s: %s", pathToPagesets, err)
		return
	}

	// Location of the WPR logs.
	wprLogs := filepath.Join(util.ChromiumSrcDir, "webpagereplay_logs", "logs.txt")
	// Slice that will contain
	inconsistentArchives := []string{}

	// Loop through all pagesets.
	for _, fileInfo := range fileInfos {
		benchmarkResults := []float64{}
		resourceMissingCounts := []int{}
		pagesetBaseName := filepath.Base(fileInfo.Name())
		if pagesetBaseName == util.TIMESTAMP_FILE_NAME || filepath.Ext(pagesetBaseName) == ".pyc" {
			// Ignore timestamp files and .pyc files.
			continue
		}

		// Convert the filename into a format consumable by the run_benchmarks
		// binary.
		pagesetName := strings.TrimSuffix(pagesetBaseName, filepath.Ext(pagesetBaseName))
		pagesetPath := filepath.Join(pathToPagesets, fileInfo.Name())

		glog.Infof("===== Processing %s =====", pagesetPath)

		// Repeat runs the specified number of times.
		for repeatNum := 1; repeatNum <= *repeatBenchmark; repeatNum++ {
			// Delete webpagereplay_logs before every run.
			os.RemoveAll(wprLogs)

			os.Chdir(pathToPyFiles)
			args := []string{
				util.BINARY_RUN_BENCHMARK,
				fmt.Sprintf("%s.%s", *benchmarkName, util.BenchmarksToPagesetName[*benchmarkName]),
				"--page-set-name=" + pagesetName,
				"--page-set-base-dir=" + pathToPagesets,
				"--also-run-disabled-tests",
			}
			// Add output dir.
			outputDirArgValue := filepath.Join(localOutputDir, pagesetName, strconv.Itoa(repeatNum))
			args = append(args, "--output-dir="+outputDirArgValue)
			// Figure out which browser should be used.
			args = append(args, "--browser=exact", "--browser-executable="+chromiumBinary)
			// Split benchmark args if not empty and append to args.
			if *benchmarkArgs != "" {
				for _, benchmarkArg := range strings.Split(*benchmarkArgs, " ") {
					args = append(args, benchmarkArg)
				}
			}
			// Add browserArgs if not empty to args.
			if *browserArgs != "" {
				args = append(args, "--extra-browser-args="+*browserArgs)
			}
			// Set the PYTHONPATH to the pagesets and the telemetry dirs.
			env := []string{
				fmt.Sprintf("PYTHONPATH=%s:%s:%s:$PYTHONPATH", pathToPagesets, util.TelemetryBinariesDir, util.TelemetrySrcDir),
				"DISPLAY=:0",
			}
			util.ExecuteCmd("python", args, env, time.Duration(timeoutSecs)*time.Second, nil, nil)

			// Examine the results.csv file and store the mean frame time.
			resultsCSV := filepath.Join(outputDirArgValue, "results.csv")
			headers, values, err := getRowsFromCSV(resultsCSV)
			if err != nil {
				glog.Errorf("Could not read %s: %s", resultsCSV, err)
				continue
			}
			for i := range headers {
				if headers[i] == *benchmarkHeaderToCheck {
					value, _ := strconv.ParseFloat(values[i], 64)
					benchmarkResults = append(benchmarkResults, value)
					break
				}
			}

			// Find how many times "Could not replay" showed up in wprLogs.
			content, err := ioutil.ReadFile(wprLogs)
			if err != nil {
				glog.Errorf("Could not read %s: %s", wprLogs, err)
				continue
			}
			resourceMissingCount := strings.Count(string(content), "Could not replay")
			resourceMissingCounts = append(resourceMissingCounts, resourceMissingCount)
		}

		glog.Infof("Benchmark results for %s are: %v", fileInfo.Name(), benchmarkResults)
		percentageChange := getPercentageChange(benchmarkResults)
		glog.Infof("Percentage change of results is: %f", percentageChange)
		glog.Infof("\"Could not replay\" showed up %v times in %s", resourceMissingCounts, wprLogs)
		maxResourceMissingCount := 0
		for _, count := range resourceMissingCounts {
			if maxResourceMissingCount < count {
				maxResourceMissingCount = count
			}
		}
		if percentageChange > 10 || maxResourceMissingCount > 20 {
			glog.Infof("The archive for %s is inconsistent!", fileInfo.Name())
			inconsistentArchives = append(inconsistentArchives, fileInfo.Name())
		}
	}

	if len(inconsistentArchives) > 0 {
		glog.Infof("%d archives are inconsistent!", len(inconsistentArchives))
		glog.Infof("The list of inconsistentArchives is: %v", inconsistentArchives)
		// TODO(rmistry): If this script appears to be reliable then the page sets
		// should be deleted here.
	}
}

func getPercentageChange(values []float64) float64 {
	if len(values) == 0 {
		return 0
	}
	smallest := values[0]
	largest := values[0]
	for _, value := range values {
		if smallest > value {
			smallest = value
		}
		if largest < value {
			largest = value
		}
	}
	diff := largest - smallest
	if smallest == 0 {
		return 0
	}
	return diff / smallest * 100
}

func getRowsFromCSV(csvPath string) ([]string, []string, error) {
	csvFile, err := os.Open(csvPath)
	defer csvFile.Close()
	if err != nil {
		return nil, nil, fmt.Errorf("Could not open %s: %s", csvPath, err)
	}
	reader := csv.NewReader(csvFile)
	reader.FieldsPerRecord = -1
	rawCSVdata, err := reader.ReadAll()
	if err != nil {
		return nil, nil, fmt.Errorf("Could not read %s: %s", csvPath, err)
	}
	if len(rawCSVdata) != 2 {
		return nil, nil, fmt.Errorf("No data in %s", csvPath)
	}
	return rawCSVdata[0], rawCSVdata[1], nil
}
<commit_msg>Tweak percentChange and maxResourceMissingCount thresholds<commit_after>// fix_archives is an application that validates the webpage archives of a
// pageset type and deletes the archives which are found to be deliver
// inconsistent benchmark results.
// See https://code.google.com/p/chromium/issues/detail?id=456883 for more
// details.
package main

import (
	"encoding/csv"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/skia-dev/glog"
	"skia.googlesource.com/buildbot.git/ct/go/util"
	"skia.googlesource.com/buildbot.git/go/common"
)

var (
	runID                  = flag.String("run_id", "", "The unique run id (typically requester + timestamp).")
	workerNum              = flag.Int("worker_num", 1, "The number of this CT worker. It will be in the {1..100} range.")
	pagesetType            = flag.String("pageset_type", util.PAGESET_TYPE_MOBILE_10k, "The type of pagesets whose archives need to be validated. Eg: 10k, Mobile10k, All.")
	chromiumBuild          = flag.String("chromium_build", "", "The chromium build to use for this validation run.")
	repeatBenchmark        = flag.Int("repeat_benchmark", 5, "The number of times the benchmark should be repeated.")
	benchmarkName          = flag.String("benchmark_name", util.BENCHMARK_REPAINT, "The telemetry benchmark to run on this worker.")
	benchmarkHeaderToCheck = flag.String("benchmark_header_to_check", "mean_frame_time (ms)", "The benchmark header this task will validate.")
	benchmarkArgs          = flag.String("benchmark_args", "--output-format=csv", "The arguments that are passed to the specified benchmark.")
	browserArgs            = flag.String("browser_args", "--disable-setuid-sandbox --enable-threaded-compositing --enable-impl-side-painting", "The arguments that are passed to the browser while running the benchmark.")
)

func main() {
	common.Init()
	defer util.TimeTrack(time.Now(), "Fixing archives")
	defer glog.Flush()

	// Create the task file so that the master knows this worker is still busy.
	util.CreateTaskFile(util.ACTIVITY_FIXING_ARCHIVES)
	defer util.DeleteTaskFile(util.ACTIVITY_FIXING_ARCHIVES)

	if *pagesetType == "" {
		glog.Error("Must specify --pageset_type")
		return
	}
	if *chromiumBuild == "" {
		glog.Error("Must specify --chromium_build")
		return
	}
	if *runID == "" {
		glog.Error("Must specify --run_id")
		return
	}

	// Sync the local chromium checkout.
	if err := util.SyncDir(util.ChromiumSrcDir); err != nil {
		glog.Errorf("Could not gclient sync %s: %s", util.ChromiumSrcDir, err)
		return
	}

	// Instantiate GsUtil object.
	gs, err := util.NewGsUtil(nil)
	if err != nil {
		glog.Error(err)
		return
	}

	// Download the specified chromium build.
	if err := gs.DownloadChromiumBuild(*chromiumBuild); err != nil {
		glog.Error(err)
		return
	}
	// Delete the chromium build to save space when we are done.
	defer os.RemoveAll(filepath.Join(util.ChromiumBuildsDir, *chromiumBuild))
	chromiumBinary := filepath.Join(util.ChromiumBuildsDir, *chromiumBuild, util.BINARY_CHROME)

	// Download pagesets if they do not exist locally.
	if err := gs.DownloadWorkerArtifacts(util.PAGESETS_DIR_NAME, *pagesetType, *workerNum); err != nil {
		glog.Error(err)
		return
	}
	pathToPagesets := filepath.Join(util.PagesetsDir, *pagesetType)

	// Download archives if they do not exist locally.
	if err := gs.DownloadWorkerArtifacts(util.WEB_ARCHIVES_DIR_NAME, *pagesetType, *workerNum); err != nil {
		glog.Error(err)
		return
	}

	// Establish output paths.
	localOutputDir := filepath.Join(util.StorageDir, util.FixArchivesRunsDir, *runID)
	os.RemoveAll(localOutputDir)
	os.MkdirAll(localOutputDir, 0700)
	defer os.RemoveAll(localOutputDir)

	// Construct path to the ct_run_benchmark python script.
	_, currentFile, _, _ := runtime.Caller(0)
	pathToPyFiles := filepath.Join(
		filepath.Dir((filepath.Dir(filepath.Dir(filepath.Dir(currentFile))))),
		"py")

	timeoutSecs := util.PagesetTypeToInfo[*pagesetType].RunBenchmarksTimeoutSecs
	fileInfos, err := ioutil.ReadDir(pathToPagesets)
	if err != nil {
		glog.Errorf("Unable to read the pagesets dir %s: %s", pathToPagesets, err)
		return
	}

	// Location of the WPR logs.
	wprLogs := filepath.Join(util.ChromiumSrcDir, "webpagereplay_logs", "logs.txt")
	// Slice that will contain
	inconsistentArchives := []string{}

	// Loop through all pagesets.
	for _, fileInfo := range fileInfos {
		benchmarkResults := []float64{}
		resourceMissingCounts := []int{}
		pagesetBaseName := filepath.Base(fileInfo.Name())
		if pagesetBaseName == util.TIMESTAMP_FILE_NAME || filepath.Ext(pagesetBaseName) == ".pyc" {
			// Ignore timestamp files and .pyc files.
			continue
		}

		// Convert the filename into a format consumable by the run_benchmarks
		// binary.
		pagesetName := strings.TrimSuffix(pagesetBaseName, filepath.Ext(pagesetBaseName))
		pagesetPath := filepath.Join(pathToPagesets, fileInfo.Name())

		glog.Infof("===== Processing %s =====", pagesetPath)

		// Repeat runs the specified number of times.
		for repeatNum := 1; repeatNum <= *repeatBenchmark; repeatNum++ {
			// Delete webpagereplay_logs before every run.
			os.RemoveAll(wprLogs)

			os.Chdir(pathToPyFiles)
			args := []string{
				util.BINARY_RUN_BENCHMARK,
				fmt.Sprintf("%s.%s", *benchmarkName, util.BenchmarksToPagesetName[*benchmarkName]),
				"--page-set-name=" + pagesetName,
				"--page-set-base-dir=" + pathToPagesets,
				"--also-run-disabled-tests",
			}
			// Add output dir.
			outputDirArgValue := filepath.Join(localOutputDir, pagesetName, strconv.Itoa(repeatNum))
			args = append(args, "--output-dir="+outputDirArgValue)
			// Figure out which browser should be used.
			args = append(args, "--browser=exact", "--browser-executable="+chromiumBinary)
			// Split benchmark args if not empty and append to args.
			if *benchmarkArgs != "" {
				for _, benchmarkArg := range strings.Split(*benchmarkArgs, " ") {
					args = append(args, benchmarkArg)
				}
			}
			// Add browserArgs if not empty to args.
			if *browserArgs != "" {
				args = append(args, "--extra-browser-args="+*browserArgs)
			}
			// Set the PYTHONPATH to the pagesets and the telemetry dirs.
			env := []string{
				fmt.Sprintf("PYTHONPATH=%s:%s:%s:$PYTHONPATH", pathToPagesets, util.TelemetryBinariesDir, util.TelemetrySrcDir),
				"DISPLAY=:0",
			}
			util.ExecuteCmd("python", args, env, time.Duration(timeoutSecs)*time.Second, nil, nil)

			// Examine the results.csv file and store the mean frame time.
			resultsCSV := filepath.Join(outputDirArgValue, "results.csv")
			headers, values, err := getRowsFromCSV(resultsCSV)
			if err != nil {
				glog.Errorf("Could not read %s: %s", resultsCSV, err)
				continue
			}
			for i := range headers {
				if headers[i] == *benchmarkHeaderToCheck {
					value, _ := strconv.ParseFloat(values[i], 64)
					benchmarkResults = append(benchmarkResults, value)
					break
				}
			}

			// Find how many times "Could not replay" showed up in wprLogs.
			content, err := ioutil.ReadFile(wprLogs)
			if err != nil {
				glog.Errorf("Could not read %s: %s", wprLogs, err)
				continue
			}
			resourceMissingCount := strings.Count(string(content), "Could not replay")
			resourceMissingCounts = append(resourceMissingCounts, resourceMissingCount)
		}

		glog.Infof("Benchmark results for %s are: %v", fileInfo.Name(), benchmarkResults)
		percentageChange := getPercentageChange(benchmarkResults)
		glog.Infof("Percentage change of results is: %f", percentageChange)
		glog.Infof("\"Could not replay\" showed up %v times in %s", resourceMissingCounts, wprLogs)
		maxResourceMissingCount := 0
		for _, count := range resourceMissingCounts {
			if maxResourceMissingCount < count {
				maxResourceMissingCount = count
			}
		}
		if percentageChange > 5 || maxResourceMissingCount > 50 {
			glog.Infof("The archive for %s is inconsistent!", fileInfo.Name())
			inconsistentArchives = append(inconsistentArchives, fileInfo.Name())
		}
	}

	if len(inconsistentArchives) > 0 {
		glog.Infof("%d archives are inconsistent!", len(inconsistentArchives))
		glog.Infof("The list of inconsistentArchives is: %v", inconsistentArchives)
		// TODO(rmistry): If this script appears to be reliable then the page sets
		// should be deleted here.
	}
}

func getPercentageChange(values []float64) float64 {
	if len(values) == 0 {
		return 0
	}
	smallest := values[0]
	largest := values[0]
	for _, value := range values {
		if smallest > value {
			smallest = value
		}
		if largest < value {
			largest = value
		}
	}
	diff := largest - smallest
	if smallest == 0 {
		return 0
	}
	return diff / smallest * 100
}

func getRowsFromCSV(csvPath string) ([]string, []string, error) {
	csvFile, err := os.Open(csvPath)
	defer csvFile.Close()
	if err != nil {
		return nil, nil, fmt.Errorf("Could not open %s: %s", csvPath, err)
	}
	reader := csv.NewReader(csvFile)
	reader.FieldsPerRecord = -1
	rawCSVdata, err := reader.ReadAll()
	if err != nil {
		return nil, nil, fmt.Errorf("Could not read %s: %s", csvPath, err)
	}
	if len(rawCSVdata) != 2 {
		return nil, nil, fmt.Errorf("No data in %s", csvPath)
	}
	return rawCSVdata[0], rawCSVdata[1], nil
}
<|endoftext|>


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

package action

import "errors"

// Result is the value returned by Forward. It is used in the call of the next
// action, and also when rolling back the actions.
type Result interface{}

// Forward is the function called by the pipeline executor in the forward
// phase.  It receives a FWContext instance, that contains the list of
// parameters given to the pipeline executor and the result of the previous
// action in the pipeline (which will be nil for the first action in the
// pipeline).
type Forward func(context FWContext) (Result, error)

// Backward is the function called by the pipeline executor when in the
// backward phase. It receives the context instance, that contains the list of
// parameters given to the pipeline executor and the result of the forward
// phase.
type Backward func(context BWContext)

// FWContext is the context used in calls to Forward functions (forward phase).
type FWContext struct {
	// Result of the previous action.
	Previous Result

	// List of parameters given to the executor.
	Params []interface{}
}

// BWContext is the context used in calls to Backward functions (backward
// phase).
type BWContext struct {
	// Result of the forward phase (for the current action).
	FWResult Result

	// List of parameters given to the executor.
	Params []interface{}
}

// Action defines actions that should be . It is composed of two functions:
// Forward and Backward.
//
// Each action should do only one thing, and do it well. All information that
// is needed to undo the action should be returned by the Forward function.
type Action struct {
	// Function that will be invoked in the forward phase. This value
	// cannot be nil.
	Forward Forward

	// Function that will be invoked in the backward phase. For actions
	// that are not undoable, this attribute should be nil.
	Backward Backward

	// Minimum number of parameters that this action requires to run.
	MinParams int

	// Result of the action. Stored for use in the backward phase.
	result Result
}

// Pipeline is a list of actions. Each pipeline is atomic: either all actions
// are successfully executed, or none of them are. For that, it's fundamental
// that all actions are really small and atomic.
type Pipeline struct {
	actions []*Action
}

// NewPipeline creates a new pipeline instance with the given list of actions.
func NewPipeline(actions ...*Action) *Pipeline {
	return &Pipeline{actions: actions}
}

// Execute executes the pipeline.
//
// The execution starts in the forward phase, calling the Forward function of
// all actions. If none of the Forward calls return error, the pipeline
// execution ends in the forward phase and is "committed".
//
// If any of the Forward call fail, the executor switches to the backward phase
// (roll back) and call the Backward function for each action completed. It
// does not call the Backward function of the action that has failed.
//
// After rolling back all completed actions, it returns the original error
// returned by the action that failed.
func (p *Pipeline) Execute(params ...interface{}) error {
	var (
		r   Result
		err error
	)
	if len(p.actions) == 0 {
		return errors.New("No actions to execute.")
	}
	fwCtx := FWContext{Params: params}
	for i, a := range p.actions {
		if a.Forward == nil {
			err = errors.New("All actions must define the forward function.")
		} else if len(fwCtx.Params) < a.MinParams {
			err = errors.New("Not enough parameters to call Action.Forward.")
		} else {
			r, err = a.Forward(fwCtx)
			a.result = r
			fwCtx.Previous = r
		}
		if err != nil {
			p.rollback(i-1, params)
			return err
		}
	}
	return nil
}

func (p *Pipeline) rollback(index int, params []interface{}) {
	bwCtx := BWContext{Params: params}
	for i := index; i >= 0; i-- {
		if p.actions[i].Backward != nil {
			bwCtx.FWResult = p.actions[i].result
			p.actions[i].Backward(bwCtx)
		}
	}
}
<commit_msg>action: added a Name to the action.<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package action

import "errors"

// Result is the value returned by Forward. It is used in the call of the next
// action, and also when rolling back the actions.
type Result interface{}

// Forward is the function called by the pipeline executor in the forward
// phase.  It receives a FWContext instance, that contains the list of
// parameters given to the pipeline executor and the result of the previous
// action in the pipeline (which will be nil for the first action in the
// pipeline).
type Forward func(context FWContext) (Result, error)

// Backward is the function called by the pipeline executor when in the
// backward phase. It receives the context instance, that contains the list of
// parameters given to the pipeline executor and the result of the forward
// phase.
type Backward func(context BWContext)

// FWContext is the context used in calls to Forward functions (forward phase).
type FWContext struct {
	// Result of the previous action.
	Previous Result

	// List of parameters given to the executor.
	Params []interface{}
}

// BWContext is the context used in calls to Backward functions (backward
// phase).
type BWContext struct {
	// Result of the forward phase (for the current action).
	FWResult Result

	// List of parameters given to the executor.
	Params []interface{}
}

// Action defines actions that should be . It is composed of two functions:
// Forward and Backward.
//
// Each action should do only one thing, and do it well. All information that
// is needed to undo the action should be returned by the Forward function.
type Action struct {
	// Name is the action name. Used by the log.
	Name string

	// Function that will be invoked in the forward phase. This value
	// cannot be nil.
	Forward Forward

	// Function that will be invoked in the backward phase. For actions
	// that are not undoable, this attribute should be nil.
	Backward Backward

	// Minimum number of parameters that this action requires to run.
	MinParams int

	// Result of the action. Stored for use in the backward phase.
	result Result
}

// Pipeline is a list of actions. Each pipeline is atomic: either all actions
// are successfully executed, or none of them are. For that, it's fundamental
// that all actions are really small and atomic.
type Pipeline struct {
	actions []*Action
}

// NewPipeline creates a new pipeline instance with the given list of actions.
func NewPipeline(actions ...*Action) *Pipeline {
	return &Pipeline{actions: actions}
}

// Execute executes the pipeline.
//
// The execution starts in the forward phase, calling the Forward function of
// all actions. If none of the Forward calls return error, the pipeline
// execution ends in the forward phase and is "committed".
//
// If any of the Forward call fail, the executor switches to the backward phase
// (roll back) and call the Backward function for each action completed. It
// does not call the Backward function of the action that has failed.
//
// After rolling back all completed actions, it returns the original error
// returned by the action that failed.
func (p *Pipeline) Execute(params ...interface{}) error {
	var (
		r   Result
		err error
	)
	if len(p.actions) == 0 {
		return errors.New("No actions to execute.")
	}
	fwCtx := FWContext{Params: params}
	for i, a := range p.actions {
		if a.Forward == nil {
			err = errors.New("All actions must define the forward function.")
		} else if len(fwCtx.Params) < a.MinParams {
			err = errors.New("Not enough parameters to call Action.Forward.")
		} else {
			r, err = a.Forward(fwCtx)
			a.result = r
			fwCtx.Previous = r
		}
		if err != nil {
			p.rollback(i-1, params)
			return err
		}
	}
	return nil
}

func (p *Pipeline) rollback(index int, params []interface{}) {
	bwCtx := BWContext{Params: params}
	for i := index; i >= 0; i-- {
		if p.actions[i].Backward != nil {
			bwCtx.FWResult = p.actions[i].result
			p.actions[i].Backward(bwCtx)
		}
	}
}
<|endoftext|>


<commit_before>package action

import (
	"log"
	"github.com/urfave/cli"
	"os"
)

type DeleteAction struct {
	AbstractAction
}

func (action *DeleteAction) Execute(c *cli.Context) error {
	log.Printf("delete")

	if err := action.PrepareExecution(c, 1); err != nil  {
		return cli.NewExitError(err.Error(), ErrorLocateSourceFiles)
	}
	if err := action.locateSourceFiles(); err != nil {
		return cli.NewExitError(err.Error(), ErrorLocateSourceFiles)
	}

	if err := action.DeleteFiles(); err != nil {
		return cli.NewExitError(err.Error(), ErrorDeleteFiles)
	}
	return nil
}

func (action *DeleteAction) DeleteFiles() error {
	var dirsToRemove = []string{}

	for _, path := range action.locator.SourceFiles {
		action.suppressablePrintf(path + "\n")
		// delete
		if !action.CliContext.Bool("dry-run") {
			stat, err := action.sourcePattern.Fs.Stat(path)
			if !os.IsNotExist(err) {
				if stat.Mode().IsRegular() {
					if err := action.sourcePattern.Fs.Remove(path); err != nil  {
						log.Printf("File %s could not be deleted: %s", path, err.Error())
					}
				} else if stat.Mode().IsDir() {
					dirsToRemove = append(dirsToRemove, path)
				}
			}
		}
	}

	for _, path := range dirsToRemove {
		if err := action.sourcePattern.Fs.Remove(path); err != nil  {
			log.Printf("Directory %s could not be deleted: %s", path, err.Error())
		}
	}
	return nil
}
<commit_msg>Use absolute paths in delete action<commit_after>package action

import (
	"log"
	"github.com/urfave/cli"
	"os"
	"github.com/sandreas/graft/filesystem"
)

type DeleteAction struct {
	AbstractAction
}

func (action *DeleteAction) Execute(c *cli.Context) error {
	log.Printf("delete")

	if err := action.PrepareExecution(c, 1); err != nil  {
		return cli.NewExitError(err.Error(), ErrorLocateSourceFiles)
	}
	if err := action.locateSourceFiles(); err != nil {
		return cli.NewExitError(err.Error(), ErrorLocateSourceFiles)
	}

	if err := action.DeleteFiles(); err != nil {
		return cli.NewExitError(err.Error(), ErrorDeleteFiles)
	}
	return nil
}

func (action *DeleteAction) DeleteFiles() error {
	var dirsToRemove = []string{}

	for _, path := range action.locator.SourceFiles {
		action.suppressablePrintf(path + "\n")
		// delete
		if !action.CliContext.Bool("dry-run") {
			absPath,err  := filesystem.ToAbsIfOsFs(action.sourcePattern.Fs, path)
			if err != nil {
				log.Printf("File %s could not be converted to absolute path: %s", path, err.Error())
			}
			stat, err := action.sourcePattern.Fs.Stat(absPath)
			if !os.IsNotExist(err) {
				if stat.Mode().IsRegular() {
					if err := action.sourcePattern.Fs.Remove(absPath); err != nil  {
						log.Printf("File %s could not be deleted: %s", absPath, err.Error())
					}
				} else if stat.Mode().IsDir() {
					dirsToRemove = append(dirsToRemove, absPath)
				}
			}
		}
	}

	for _, path := range dirsToRemove {
		if err := action.sourcePattern.Fs.Remove(path); err != nil  {
			log.Printf("Directory %s could not be deleted: %s", path, err.Error())
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package flickr

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

const (
	API_ENDPOINT = "https://api.flickr.com/services/rest"
)

type FlickrClient struct {
	ApiKey      string
	ApiSecret   string
	HTTPClient  *http.Client
	EndpointUrl string
	HTTPVerb    string
	Args        url.Values
}

func NewFlickrClient(apiKey string, apiSecret string) *FlickrClient {
	return &FlickrClient{
		ApiKey:     apiKey,
		ApiSecret:  apiSecret,
		HTTPClient: &http.Client{},
		HTTPVerb:   "GET",
		Args:       url.Values{},
	}
}

func (c *FlickrClient) Sign(tokenSecret string) {
	// the "oauth_signature" param should not be included in the signing process
	c.Args.Del("oauth_signature")
	c.Args.Set("oauth_signature", getSignature(c, tokenSecret))
}

func (c *FlickrClient) GetUrl() string {
	return fmt.Sprintf("%s?%s", c.EndpointUrl, c.Args.Encode())
}

type RequestToken struct {
	OauthCallbackConfirmed bool
	OauthToken             string
	OauthTokenSecret       string
}

func (rt *RequestToken) Parse(response string) error {
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return err
	}

	confirmed, _ := strconv.ParseBool(val.Get("oauth_callback_confirmed"))
	rt.OauthCallbackConfirmed = confirmed
	rt.OauthToken = val.Get("oauth_token")
	rt.OauthTokenSecret = val.Get("oauth_token_secret")

	return nil
}

type OAuthToken struct {
	OAuthToken       string
	OAuthTokenSecret string
	UserNsid         string
	Username         string
	Fullname         string
}

func (ot *OAuthToken) Parse(response string) error {
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return err
	}

	ot.OAuthToken = val.Get("oauth_token")
	ot.OAuthTokenSecret = val.Get("oauth_token_secret")
	ot.Fullname = val.Get("fullname")
	ot.UserNsid = val.Get("user_nsid")
	ot.Username = val.Get("username")

	return nil
}

func getSigningBaseString(client *FlickrClient) string {
	request_url := url.QueryEscape(client.EndpointUrl)
	query := url.QueryEscape(client.Args.Encode())

	return fmt.Sprintf("%s&%s&%s", client.HTTPVerb, request_url, query)
}

func getSignature(client *FlickrClient, token_secret string) string {
	key := fmt.Sprintf("%s&%s", url.QueryEscape(client.ApiSecret), url.QueryEscape(token_secret))
	base_string := getSigningBaseString(client)

	mac := hmac.New(sha1.New, []byte(key))
	mac.Write([]byte(base_string))

	ret := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return ret
}

func generateNonce() string {
	rand.Seed(time.Now().UTC().UnixNano())
	var letters = []rune("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
	b := make([]rune, 8)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func getDefaultArgs() url.Values {
	args := url.Values{}
	args.Add("oauth_version", "1.0")
	args.Add("oauth_signature_method", "HMAC-SHA1")
	args.Add("oauth_nonce", generateNonce())
	args.Add("oauth_timestamp", fmt.Sprintf("%d", time.Now().Unix()))

	return args
}

func GetRequestToken(client *FlickrClient) (*RequestToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/request_token"
	client.Args = getDefaultArgs()
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_callback", "oob")

	// we don't have token secret at this stage, pass an empty string
	client.Sign("")

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

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

	token := RequestToken{}
	token.Parse(string(body))

	return &token, nil
}

func GetAuthorizeUrl(client *FlickrClient, reqToken *RequestToken) (string, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/authorize"
	client.Args = url.Values{}
	client.Args.Set("oauth_token", reqToken.OauthToken)
	client.Args.Set("perms", "delete")

	return client.GetUrl(), nil
}

func GetAccessToken(client *FlickrClient, reqToken *RequestToken, oauthVerifier string) (*OAuthToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/access_token"
	client.Args = getDefaultArgs()
	client.Args.Set("oauth_verifier", oauthVerifier)
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_token", reqToken.OauthToken)
	client.Sign(reqToken.OauthTokenSecret)

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

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

	tok := &OAuthToken{}
	err = tok.Parse(string(body))

	return tok, err
}
<commit_msg>added utility methods and xml response interface<commit_after>package flickr

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

const (
	API_ENDPOINT = "https://api.flickr.com/services/rest"
)

type FlickrClient struct {
	ApiKey      string
	ApiSecret   string
	HTTPClient  *http.Client
	EndpointUrl string
	HTTPVerb    string
	Args        url.Values
}

func NewFlickrClient(apiKey string, apiSecret string) *FlickrClient {
	return &FlickrClient{
		ApiKey:     apiKey,
		ApiSecret:  apiSecret,
		HTTPClient: &http.Client{},
		HTTPVerb:   "GET",
		Args:       url.Values{},
	}
}

func (c *FlickrClient) Sign(tokenSecret string) {
	// the "oauth_signature" param should not be included in the signing process
	c.Args.Del("oauth_signature")
	c.Args.Set("oauth_signature", getSignature(c, tokenSecret))
}

func (c *FlickrClient) GetUrl() string {
	return fmt.Sprintf("%s?%s", c.EndpointUrl, c.Args.Encode())
}

func (c *FlickrClient) ClearArgs() {
	c.Args = url.Values{}
}

func (c *FlickrClient) SetDefaultArgs() {
	c.Args = getDefaultArgs()
}

type FlickrResponse struct {
	XMLName xml.Name `xml:"rsp"`
	Status  string   `xml:"stat,attr"`
}

type RequestToken struct {
	OauthCallbackConfirmed bool
	OauthToken             string
	OauthTokenSecret       string
}

func (rt *RequestToken) Parse(response string) error {
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return err
	}

	confirmed, _ := strconv.ParseBool(val.Get("oauth_callback_confirmed"))
	rt.OauthCallbackConfirmed = confirmed
	rt.OauthToken = val.Get("oauth_token")
	rt.OauthTokenSecret = val.Get("oauth_token_secret")

	return nil
}

type OAuthToken struct {
	OAuthToken       string
	OAuthTokenSecret string
	UserNsid         string
	Username         string
	Fullname         string
}

func (ot *OAuthToken) Parse(response string) error {
	val, err := url.ParseQuery(strings.TrimSpace(response))
	if err != nil {
		return err
	}

	ot.OAuthToken = val.Get("oauth_token")
	ot.OAuthTokenSecret = val.Get("oauth_token_secret")
	ot.Fullname = val.Get("fullname")
	ot.UserNsid = val.Get("user_nsid")
	ot.Username = val.Get("username")

	return nil
}

func getSigningBaseString(client *FlickrClient) string {
	request_url := url.QueryEscape(client.EndpointUrl)
	query := url.QueryEscape(client.Args.Encode())

	return fmt.Sprintf("%s&%s&%s", client.HTTPVerb, request_url, query)
}

func getSignature(client *FlickrClient, token_secret string) string {
	key := fmt.Sprintf("%s&%s", url.QueryEscape(client.ApiSecret), url.QueryEscape(token_secret))
	base_string := getSigningBaseString(client)

	mac := hmac.New(sha1.New, []byte(key))
	mac.Write([]byte(base_string))

	ret := base64.StdEncoding.EncodeToString(mac.Sum(nil))

	return ret
}

func generateNonce() string {
	rand.Seed(time.Now().UTC().UnixNano())
	var letters = []rune("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
	b := make([]rune, 8)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func getDefaultArgs() url.Values {
	args := url.Values{}
	args.Add("oauth_version", "1.0")
	args.Add("oauth_signature_method", "HMAC-SHA1")
	args.Add("oauth_nonce", generateNonce())
	args.Add("oauth_timestamp", fmt.Sprintf("%d", time.Now().Unix()))

	return args
}

func GetRequestToken(client *FlickrClient) (*RequestToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/request_token"
	client.Args = getDefaultArgs()
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_callback", "oob")

	// we don't have token secret at this stage, pass an empty string
	client.Sign("")

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

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

	token := RequestToken{}
	token.Parse(string(body))

	return &token, nil
}

func GetAuthorizeUrl(client *FlickrClient, reqToken *RequestToken) (string, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/authorize"
	client.Args = url.Values{}
	client.Args.Set("oauth_token", reqToken.OauthToken)
	client.Args.Set("perms", "delete")

	return client.GetUrl(), nil
}

func GetAccessToken(client *FlickrClient, reqToken *RequestToken, oauthVerifier string) (*OAuthToken, error) {
	client.EndpointUrl = "https://www.flickr.com/services/oauth/access_token"
	client.Args = getDefaultArgs()
	client.Args.Set("oauth_verifier", oauthVerifier)
	client.Args.Set("oauth_consumer_key", client.ApiKey)
	client.Args.Set("oauth_token", reqToken.OauthToken)
	client.Sign(reqToken.OauthTokenSecret)

	res, err := client.HTTPClient.Get(client.GetUrl())
	if err != nil {
		return nil, err
	}

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

	tok := &OAuthToken{}
	err = tok.Parse(string(body))

	return tok, err
}
<|endoftext|>


<commit_before>package couchbase

import (
	"io"
	"testing"

	"github.com/dustin/gomemcached"
	"github.com/dustin/gomemcached/client"
)

type testT struct{}

func (t testT) Read([]byte) (int, error) {
	return 0, io.EOF
}

func (t testT) Write([]byte) (int, error) {
	return 0, io.EOF
}

func (t testT) Close() error {
	return nil
}

func testMkConn(h string, ah AuthHandler) (*memcached.Client, error) {
	return memcached.Wrap(testT{})
}

func TestConnPool(t *testing.T) {
	cp := newConnectionPool("h", &basicAuth{}, 3, 6)
	cp.mkConn = testMkConn

	seenClients := map[*memcached.Client]bool{}

	// build some connections

	for i := 0; i < 5; i++ {
		sc, err := cp.Get()
		if err != nil {
			t.Fatalf("Error getting connection from pool: %v", err)
		}
		seenClients[sc] = true
	}

	if len(cp.connections) != 0 {
		t.Errorf("Expected 0 connections after gets, got %v",
			len(cp.connections))
	}

	// return them
	for k := range seenClients {
		cp.Return(k)
	}

	if len(cp.connections) != 3 {
		t.Errorf("Expected 3 connections after returning them, got %v",
			len(cp.connections))
	}

	// Try again.
	matched := 0
	grabbed := []*memcached.Client{}
	for i := 0; i < 5; i++ {
		sc, err := cp.Get()
		if err != nil {
			t.Fatalf("Error getting connection from pool: %v", err)
		}
		if seenClients[sc] {
			matched++
		}
		grabbed = append(grabbed, sc)
	}

	if matched != 3 {
		t.Errorf("Expected to match 3 conns, matched %v", matched)
	}

	for _, c := range grabbed {
		cp.Return(c)
	}

	// Connect write error.
	sc, err := cp.Get()
	if err != nil {
		t.Fatalf("Error getting a connection: %v", err)
	}
	err = sc.Transmit(&gomemcached.MCRequest{})
	if err == nil {
		t.Fatalf("Expected error sending a request")
	}
	if sc.IsHealthy() {
		t.Fatalf("Expected unhealthy connection")
	}
	cp.Return(sc)

	if len(cp.connections) != 2 {
		t.Errorf("Expected to have 2 conns, have %v", len(cp.connections))
	}

	err = cp.Close()
	if err != nil {
		t.Errorf("Expected clean close, got %v", err)
	}

	err = cp.Close()
	if err == nil {
		t.Errorf("Expected error on second pool close")
	}
}

func TestConnPoolNil(t *testing.T) {
	var cp *connectionPool
	c, err := cp.Get()
	if err == nil {
		t.Errorf("Expected an error getting from nil, got %v", c)
	}

	// This just shouldn't error.
	cp.Return(c)
}
<commit_msg>Test returning a connection to a closed pool<commit_after>package couchbase

import (
	"io"
	"testing"

	"github.com/dustin/gomemcached"
	"github.com/dustin/gomemcached/client"
)

type testT struct{}

func (t testT) Read([]byte) (int, error) {
	return 0, io.EOF
}

func (t testT) Write([]byte) (int, error) {
	return 0, io.EOF
}

func (t testT) Close() error {
	return nil
}

func testMkConn(h string, ah AuthHandler) (*memcached.Client, error) {
	return memcached.Wrap(testT{})
}

func TestConnPool(t *testing.T) {
	cp := newConnectionPool("h", &basicAuth{}, 3, 6)
	cp.mkConn = testMkConn

	seenClients := map[*memcached.Client]bool{}

	// build some connections

	for i := 0; i < 5; i++ {
		sc, err := cp.Get()
		if err != nil {
			t.Fatalf("Error getting connection from pool: %v", err)
		}
		seenClients[sc] = true
	}

	if len(cp.connections) != 0 {
		t.Errorf("Expected 0 connections after gets, got %v",
			len(cp.connections))
	}

	// return them
	for k := range seenClients {
		cp.Return(k)
	}

	if len(cp.connections) != 3 {
		t.Errorf("Expected 3 connections after returning them, got %v",
			len(cp.connections))
	}

	// Try again.
	matched := 0
	grabbed := []*memcached.Client{}
	for i := 0; i < 5; i++ {
		sc, err := cp.Get()
		if err != nil {
			t.Fatalf("Error getting connection from pool: %v", err)
		}
		if seenClients[sc] {
			matched++
		}
		grabbed = append(grabbed, sc)
	}

	if matched != 3 {
		t.Errorf("Expected to match 3 conns, matched %v", matched)
	}

	for _, c := range grabbed {
		cp.Return(c)
	}

	// Connect write error.
	sc, err := cp.Get()
	if err != nil {
		t.Fatalf("Error getting a connection: %v", err)
	}
	err = sc.Transmit(&gomemcached.MCRequest{})
	if err == nil {
		t.Fatalf("Expected error sending a request")
	}
	if sc.IsHealthy() {
		t.Fatalf("Expected unhealthy connection")
	}
	cp.Return(sc)

	if len(cp.connections) != 2 {
		t.Errorf("Expected to have 2 conns, have %v", len(cp.connections))
	}

	err = cp.Close()
	if err != nil {
		t.Errorf("Expected clean close, got %v", err)
	}

	err = cp.Close()
	if err == nil {
		t.Errorf("Expected error on second pool close")
	}
}

func TestConnPoolNil(t *testing.T) {
	var cp *connectionPool
	c, err := cp.Get()
	if err == nil {
		t.Errorf("Expected an error getting from nil, got %v", c)
	}

	// This just shouldn't error.
	cp.Return(c)
}

func TestConnPoolClosed(t *testing.T) {
	cp := newConnectionPool("h", &basicAuth{}, 3, 6)
	cp.mkConn = testMkConn
	c, err := cp.Get()
	if err != nil {
		t.Fatal(err)
	}
	cp.Close()

	// This just shouldn't error.
	cp.Return(c)
}
<|endoftext|>


<commit_before>package shared

import (
    "net"
)

func GetIPAddress() string {

  ipaddress := ""
  addrs, _ := net.InterfaceAddrs()

  for _, a := range addrs {
    if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
      if ipnet.IP.To4() != nil {
        ipaddress = ipnet.IP.String()
      }
    }
  }

  return ipaddress

}
<commit_msg>added environment functions<commit_after>package shared

import (
    "net"
)

func GetIPAddress() string {

  ipaddress := ""
  addrs, _ := net.InterfaceAddrs()

  for _, a := range addrs {
    if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
      if ipnet.IP.To4() != nil {
        ipaddress = ipnet.IP.String()
      }
    }
  }

  return ipaddress

}

func GetDBUrl() string {
  return os.Getenv("APP_DBURL")
}

func IsDevEnvironment() bool {
  return os.Getenv("APP_ENV") == "dev"
}
<|endoftext|>


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

package docker

import (
	"encoding/json"
	"github.com/dotcloud/docker"
	"net/http"
	"net/url"
	"reflect"
	"testing"
)

func TestAPIClientListContainers(t *testing.T) {
	jsonContainers := `[
     {
             "Id": "8dfafdbc3a40",
             "Image": "base:latest",
             "Command": "echo 1",
             "Created": 1367854155,
             "Status": "Exit 0"
     },
     {
             "Id": "9cd87474be90",
             "Image": "base:latest",
             "Command": "echo 222222",
             "Created": 1367854155,
             "Status": "Exit 0"
     },
     {
             "Id": "3176a2479c92",
             "Image": "base:latest",
             "Command": "echo 3333333333333333",
             "Created": 1367854154,
             "Status": "Exit 0"
     },
     {
             "Id": "4cb07b47f9fb",
             "Image": "base:latest",
             "Command": "echo 444444444444444444444444444444444",
             "Created": 1367854152,
             "Status": "Exit 0"
     }
]`
	var expected []docker.ApiContainer
	err := json.Unmarshal([]byte(jsonContainers), &expected)
	if err != nil {
		t.Fatal(err)
	}
	client := Client{
		endpoint: "http://localhost:4243",
		client: &http.Client{
			Transport: &FakeRoundTripper{message: jsonContainers, status: http.StatusOK},
		},
	}
	containers, err := client.ListContainers(nil)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(containers, expected) {
		t.Errorf("ListContainers: Expected %#v. Got %#v.", expected, containers)
	}
}

func TestAPIClientListContainersParams(t *testing.T) {
	var tests = []struct {
		input  *ListContainersOptions
		params map[string][]string
	}{
		{nil, map[string][]string{}},
		{&ListContainersOptions{All: true}, map[string][]string{"all": {"1"}}},
		{&ListContainersOptions{All: true, Limit: 10}, map[string][]string{"all": {"1"}, "limit": {"10"}}},
		{
			&ListContainersOptions{All: true, Limit: 10, Since: "adf9983", Before: "abdeef"},
			map[string][]string{"all": {"1"}, "limit": {"10"}, "since": {"adf9983"}, "before": {"abdeef"}},
		},
	}
	fakeRT := FakeRoundTripper{message: "[]", status: http.StatusOK}
	client := Client{
		endpoint: "http://localhost:4243",
		client: &http.Client{
			Transport: &fakeRT,
		},
	}
	u, _ := url.Parse(client.getURL("/containers/ps"))
	for _, tt := range tests {
		client.ListContainers(tt.input)
		got := map[string][]string(fakeRT.requests[0].URL.Query())
		if !reflect.DeepEqual(got, tt.params) {
			t.Errorf("Expected %#v, got %#v.", tt.params, got)
		}
		if path := fakeRT.requests[0].URL.Path; path != u.Path {
			t.Errorf("Wrong path on request. Want %q. Got %q.", u.Path, path)
		}
		if meth := fakeRT.requests[0].Method; meth != "GET" {
			t.Errorf("Wrong HTTP method. Want GET. Got %s.", meth)
		}
		fakeRT.Reset()
	}
}

func TestAPIClientListContainersFailure(t *testing.T) {
	var tests = []struct {
		status  int
		message string
	}{
		{400, "bad parameter"},
		{500, "internal server error"},
	}
	for _, tt := range tests {
		client := Client{
			endpoint: "http://localhost:4243",
			client: &http.Client{
				Transport: &FakeRoundTripper{message: tt.message, status: tt.status},
			},
		}
		expected := apiClientError{status: tt.status, message: tt.message}
		containers, err := client.ListContainers(nil)
		if !reflect.DeepEqual(expected, *err.(*apiClientError)) {
			t.Errorf("Wrong error in ListContainers. Want %#v. Got %#v.", expected, err)
		}
		if len(containers) > 0 {
			t.Errorf("ListContainers failure. Expected empty list. Got %#v.", containers)
		}
	}
}

func TestAPIClientInspectContainer(t *testing.T) {
	jsonContainer := `{
             "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
             "Created": "2013-05-07T14:51:42.087658+02:00",
             "Path": "date",
             "Args": [],
             "Config": {
                     "Hostname": "4fa6e0f0c678",
                     "User": "",
                     "Memory": 0,
                     "MemorySwap": 0,
                     "AttachStdin": false,
                     "AttachStdout": true,
                     "AttachStderr": true,
                     "PortSpecs": null,
                     "Tty": false,
                     "OpenStdin": false,
                     "StdinOnce": false,
                     "Env": null,
                     "Cmd": [
                             "date"
                     ],
                     "Dns": null,
                     "Image": "base",
                     "Volumes": {},
                     "VolumesFrom": ""
             },
             "State": {
                     "Running": false,
                     "Pid": 0,
                     "ExitCode": 0,
                     "StartedAt": "2013-05-07T14:51:42.087658+02:00",
                     "Ghost": false
             },
             "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
             "NetworkSettings": {
                     "IpAddress": "",
                     "IpPrefixLen": 0,
                     "Gateway": "",
                     "Bridge": "",
                     "PortMapping": null
             },
             "SysInitPath": "/home/kitty/go/src/github.com/dotcloud/docker/bin/docker",
             "ResolvConfPath": "/etc/resolv.conf",
             "Volumes": {}
}`
	var expected docker.Container
	err := json.Unmarshal([]byte(jsonContainer), &expected)
	if err != nil {
		t.Fatal(err)
	}
	fakeRT := FakeRoundTripper{message: jsonContainer, status: http.StatusOK}
	client := Client{
		endpoint: "http://localhost:4343",
		client:   &http.Client{Transport: &fakeRT},
	}
	id := "4fa6e0f0c678"
	container, err := client.InspectContainer(id)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(*container, expected) {
		t.Errorf("InspectContainer(%q): Expected %#v. Got %#v.", id, expected, container)
	}
	expectedURL, _ := url.Parse(client.getURL("/containers/4fa6e0f0c678/json"))
	if gotPath := fakeRT.requests[0].URL.Path; gotPath != expectedURL.Path {
		t.Errorf("InspectContainer(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath)
	}
}

func TestInspectContainerFailure(t *testing.T) {
	var tests = []struct {
		status  int
		message string
	}{
		{404, "no such container"},
		{500, "internal server error"},
	}
	for _, tt := range tests {
		client := Client{
			endpoint: "http://localhost:4243",
			client: &http.Client{
				Transport: &FakeRoundTripper{message: tt.message, status: tt.status},
			},
		}
		expected := apiClientError{status: tt.status, message: tt.message}
		container, err := client.InspectContainer("abe033")
		if container != nil {
			t.Errorf("InspectContainer: Expected <nil> container, got %#v", container)
		}
		if !reflect.DeepEqual(expected, *err.(*apiClientError)) {
			t.Errorf("InspectContainer: Wrong error information. Want %#v. Got %#v.", expected, err)
		}
	}
}

func TestCreateContainer(t *testing.T) {
	jsonContainer := `{
             "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
	     "Warnings": []
}`
	var expected docker.Container
	err := json.Unmarshal([]byte(jsonContainer), &expected)
	if err != nil {
		t.Fatal(err)
	}
	fakeRT := FakeRoundTripper{message: jsonContainer, status: http.StatusOK}
	client := Client{
		endpoint: "http://localhost:4343",
		client:   &http.Client{Transport: &fakeRT},
	}
	config := docker.Config{AttachStdout: true, AttachStdin: true}
	container, err := client.CreateContainer(&config)
	if err != nil {
		t.Fatal(err)
	}
	id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
	if container.Id != id {
		t.Errorf("CreateContainer: wrong ID. Want %q. Got %q.", id, container.Id)
	}
	req := fakeRT.requests[0]
	if req.Method != "POST" {
		t.Errorf("CreateContainer: wrong HTTP method. Want %q. Got %q.", "POST", req.Method)
	}
	expectedURL, _ := url.Parse(client.getURL("/containers/create"))
	if gotPath := req.URL.Path; gotPath != expectedURL.Path {
		t.Errorf("CreateContainer: Wrong path in request. Want %q. Got %q.", expectedURL.Path, gotPath)
	}
	var gotBody docker.Config
	err = json.NewDecoder(req.Body).Decode(&gotBody)
	if err != nil {
		t.Fatal(err)
	}
}

func TestKillContainer(t *testing.T) {
	fakeRT := FakeRoundTripper{message: "", status: http.StatusNoContent}
	client := Client{
		endpoint: "http://localhost:4343",
		client:   &http.Client{Transport: &fakeRT},
	}
	id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
	err := client.KillContainer(id)
	if err != nil {
		t.Fatal(err)
	}
	req := fakeRT.requests[0]
	if req.Method != "POST" {
		t.Errorf("KillContainer(%q): wrong HTTP method. Want %q. Got %q.", id, "POST", req.Method)
	}
	expectedURL, _ := url.Parse(client.getURL("/containers/"+id+"/kill"))
	if gotPath := req.URL.Path; gotPath != expectedURL.Path {
		t.Errorf("KillContainer(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath)
	}
}
<commit_msg>container: gofmt -s -w .<commit_after>// Copyright 2013 Francisco Souza. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"encoding/json"
	"github.com/dotcloud/docker"
	"net/http"
	"net/url"
	"reflect"
	"testing"
)

func TestAPIClientListContainers(t *testing.T) {
	jsonContainers := `[
     {
             "Id": "8dfafdbc3a40",
             "Image": "base:latest",
             "Command": "echo 1",
             "Created": 1367854155,
             "Status": "Exit 0"
     },
     {
             "Id": "9cd87474be90",
             "Image": "base:latest",
             "Command": "echo 222222",
             "Created": 1367854155,
             "Status": "Exit 0"
     },
     {
             "Id": "3176a2479c92",
             "Image": "base:latest",
             "Command": "echo 3333333333333333",
             "Created": 1367854154,
             "Status": "Exit 0"
     },
     {
             "Id": "4cb07b47f9fb",
             "Image": "base:latest",
             "Command": "echo 444444444444444444444444444444444",
             "Created": 1367854152,
             "Status": "Exit 0"
     }
]`
	var expected []docker.ApiContainer
	err := json.Unmarshal([]byte(jsonContainers), &expected)
	if err != nil {
		t.Fatal(err)
	}
	client := Client{
		endpoint: "http://localhost:4243",
		client: &http.Client{
			Transport: &FakeRoundTripper{message: jsonContainers, status: http.StatusOK},
		},
	}
	containers, err := client.ListContainers(nil)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(containers, expected) {
		t.Errorf("ListContainers: Expected %#v. Got %#v.", expected, containers)
	}
}

func TestAPIClientListContainersParams(t *testing.T) {
	var tests = []struct {
		input  *ListContainersOptions
		params map[string][]string
	}{
		{nil, map[string][]string{}},
		{&ListContainersOptions{All: true}, map[string][]string{"all": {"1"}}},
		{&ListContainersOptions{All: true, Limit: 10}, map[string][]string{"all": {"1"}, "limit": {"10"}}},
		{
			&ListContainersOptions{All: true, Limit: 10, Since: "adf9983", Before: "abdeef"},
			map[string][]string{"all": {"1"}, "limit": {"10"}, "since": {"adf9983"}, "before": {"abdeef"}},
		},
	}
	fakeRT := FakeRoundTripper{message: "[]", status: http.StatusOK}
	client := Client{
		endpoint: "http://localhost:4243",
		client: &http.Client{
			Transport: &fakeRT,
		},
	}
	u, _ := url.Parse(client.getURL("/containers/ps"))
	for _, tt := range tests {
		client.ListContainers(tt.input)
		got := map[string][]string(fakeRT.requests[0].URL.Query())
		if !reflect.DeepEqual(got, tt.params) {
			t.Errorf("Expected %#v, got %#v.", tt.params, got)
		}
		if path := fakeRT.requests[0].URL.Path; path != u.Path {
			t.Errorf("Wrong path on request. Want %q. Got %q.", u.Path, path)
		}
		if meth := fakeRT.requests[0].Method; meth != "GET" {
			t.Errorf("Wrong HTTP method. Want GET. Got %s.", meth)
		}
		fakeRT.Reset()
	}
}

func TestAPIClientListContainersFailure(t *testing.T) {
	var tests = []struct {
		status  int
		message string
	}{
		{400, "bad parameter"},
		{500, "internal server error"},
	}
	for _, tt := range tests {
		client := Client{
			endpoint: "http://localhost:4243",
			client: &http.Client{
				Transport: &FakeRoundTripper{message: tt.message, status: tt.status},
			},
		}
		expected := apiClientError{status: tt.status, message: tt.message}
		containers, err := client.ListContainers(nil)
		if !reflect.DeepEqual(expected, *err.(*apiClientError)) {
			t.Errorf("Wrong error in ListContainers. Want %#v. Got %#v.", expected, err)
		}
		if len(containers) > 0 {
			t.Errorf("ListContainers failure. Expected empty list. Got %#v.", containers)
		}
	}
}

func TestAPIClientInspectContainer(t *testing.T) {
	jsonContainer := `{
             "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
             "Created": "2013-05-07T14:51:42.087658+02:00",
             "Path": "date",
             "Args": [],
             "Config": {
                     "Hostname": "4fa6e0f0c678",
                     "User": "",
                     "Memory": 0,
                     "MemorySwap": 0,
                     "AttachStdin": false,
                     "AttachStdout": true,
                     "AttachStderr": true,
                     "PortSpecs": null,
                     "Tty": false,
                     "OpenStdin": false,
                     "StdinOnce": false,
                     "Env": null,
                     "Cmd": [
                             "date"
                     ],
                     "Dns": null,
                     "Image": "base",
                     "Volumes": {},
                     "VolumesFrom": ""
             },
             "State": {
                     "Running": false,
                     "Pid": 0,
                     "ExitCode": 0,
                     "StartedAt": "2013-05-07T14:51:42.087658+02:00",
                     "Ghost": false
             },
             "Image": "b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc",
             "NetworkSettings": {
                     "IpAddress": "",
                     "IpPrefixLen": 0,
                     "Gateway": "",
                     "Bridge": "",
                     "PortMapping": null
             },
             "SysInitPath": "/home/kitty/go/src/github.com/dotcloud/docker/bin/docker",
             "ResolvConfPath": "/etc/resolv.conf",
             "Volumes": {}
}`
	var expected docker.Container
	err := json.Unmarshal([]byte(jsonContainer), &expected)
	if err != nil {
		t.Fatal(err)
	}
	fakeRT := FakeRoundTripper{message: jsonContainer, status: http.StatusOK}
	client := Client{
		endpoint: "http://localhost:4343",
		client:   &http.Client{Transport: &fakeRT},
	}
	id := "4fa6e0f0c678"
	container, err := client.InspectContainer(id)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(*container, expected) {
		t.Errorf("InspectContainer(%q): Expected %#v. Got %#v.", id, expected, container)
	}
	expectedURL, _ := url.Parse(client.getURL("/containers/4fa6e0f0c678/json"))
	if gotPath := fakeRT.requests[0].URL.Path; gotPath != expectedURL.Path {
		t.Errorf("InspectContainer(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath)
	}
}

func TestInspectContainerFailure(t *testing.T) {
	var tests = []struct {
		status  int
		message string
	}{
		{404, "no such container"},
		{500, "internal server error"},
	}
	for _, tt := range tests {
		client := Client{
			endpoint: "http://localhost:4243",
			client: &http.Client{
				Transport: &FakeRoundTripper{message: tt.message, status: tt.status},
			},
		}
		expected := apiClientError{status: tt.status, message: tt.message}
		container, err := client.InspectContainer("abe033")
		if container != nil {
			t.Errorf("InspectContainer: Expected <nil> container, got %#v", container)
		}
		if !reflect.DeepEqual(expected, *err.(*apiClientError)) {
			t.Errorf("InspectContainer: Wrong error information. Want %#v. Got %#v.", expected, err)
		}
	}
}

func TestCreateContainer(t *testing.T) {
	jsonContainer := `{
             "Id": "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2",
	     "Warnings": []
}`
	var expected docker.Container
	err := json.Unmarshal([]byte(jsonContainer), &expected)
	if err != nil {
		t.Fatal(err)
	}
	fakeRT := FakeRoundTripper{message: jsonContainer, status: http.StatusOK}
	client := Client{
		endpoint: "http://localhost:4343",
		client:   &http.Client{Transport: &fakeRT},
	}
	config := docker.Config{AttachStdout: true, AttachStdin: true}
	container, err := client.CreateContainer(&config)
	if err != nil {
		t.Fatal(err)
	}
	id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
	if container.Id != id {
		t.Errorf("CreateContainer: wrong ID. Want %q. Got %q.", id, container.Id)
	}
	req := fakeRT.requests[0]
	if req.Method != "POST" {
		t.Errorf("CreateContainer: wrong HTTP method. Want %q. Got %q.", "POST", req.Method)
	}
	expectedURL, _ := url.Parse(client.getURL("/containers/create"))
	if gotPath := req.URL.Path; gotPath != expectedURL.Path {
		t.Errorf("CreateContainer: Wrong path in request. Want %q. Got %q.", expectedURL.Path, gotPath)
	}
	var gotBody docker.Config
	err = json.NewDecoder(req.Body).Decode(&gotBody)
	if err != nil {
		t.Fatal(err)
	}
}

func TestKillContainer(t *testing.T) {
	fakeRT := FakeRoundTripper{message: "", status: http.StatusNoContent}
	client := Client{
		endpoint: "http://localhost:4343",
		client:   &http.Client{Transport: &fakeRT},
	}
	id := "4fa6e0f0c6786287e131c3852c58a2e01cc697a68231826813597e4994f1d6e2"
	err := client.KillContainer(id)
	if err != nil {
		t.Fatal(err)
	}
	req := fakeRT.requests[0]
	if req.Method != "POST" {
		t.Errorf("KillContainer(%q): wrong HTTP method. Want %q. Got %q.", id, "POST", req.Method)
	}
	expectedURL, _ := url.Parse(client.getURL("/containers/" + id + "/kill"))
	if gotPath := req.URL.Path; gotPath != expectedURL.Path {
		t.Errorf("KillContainer(%q): Wrong path in request. Want %q. Got %q.", id, expectedURL.Path, gotPath)
	}
}
<|endoftext|>