<commit_before>// level game server
// https://github.com/heynemann/level
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Bernardo Heynemann <heynemann@gmail.com>

package service

import (
	"fmt"
	"os"

	"github.com/heynemann/level/extensions/serviceRegistry"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/uber-go/zap"
)

var logLevels = map[string]int{
	"debug": int(zap.DebugLevel),
	"info":  int(zap.InfoLevel),
	"warn":  int(zap.WarnLevel),
	"error": int(zap.ErrorLevel),
	"panic": int(zap.PanicLevel),
	"fatal": int(zap.FatalLevel),
}

//Service describes a server interface
type Service interface {
	SetServerFlags(cmd *cobra.Command)
	SetDefaultConfigurations(*viper.Viper)
}

//Server identifies a service Server
type Server struct {
	Logger          zap.Logger
	ConfigPath      string
	Config          *viper.Viper
	ServiceRegistry *registry.ServiceRegistry
	Service         registry.Service
	ServerService   Service
	LogLevel        string
	Quit            chan bool
}

//NewServer creates an configures a new server instance
func NewServer(serv registry.Service, logger zap.Logger, configPath string) (*Server, error) {
	var service Service
	var ok bool
	if service, ok = serv.(Service); !ok {
		return nil, fmt.Errorf(
			"Service %s does not implement interface Service. Please refer to the docs.",
			serv.GetServiceDetails().Name,
		)
	}

	s := &Server{Service: serv, ServerService: service, Logger: logger, ConfigPath: configPath}
	err := s.Configure()
	if err != nil {
		return nil, err
	}

	return s, nil
}

func (s *Server) initializeServiceRegistry() error {
	natsURL := s.Config.GetString("services.nats.URL")
	l := s.Logger.With(
		zap.String("operation", "initializeServiceRegistry"),
		zap.String("natsURL", natsURL),
	)

	l.Debug("Initializing registry...")
	sr, err := registry.NewServiceRegistry(
		natsURL,
		s.Logger,
	)
	if err != nil {
		l.Error("Error initializing service registry.", zap.Error(err))
		return err
	}

	l.Info("Service registry initialized successfully.")
	s.ServiceRegistry = sr

	l.Debug("Registering service...")
	s.ServiceRegistry.Register(s.Service)
	l.Info("Service registered successfully.")

	return nil
}

//Configure the server
func (s *Server) Configure() error {
	s.Config = viper.New()
	s.SetDefaultConfiguration()
	s.ServerService.SetDefaultConfigurations(s.Config)

	s.LoadConfiguration(s.ConfigPath)
	err := s.initializeServiceRegistry()
	return err
}

//SetDefaultConfiguration options
func (s *Server) SetDefaultConfiguration() {
	s.Logger.Debug("Setting default configuration")
	s.Config.SetDefault("services.nats.url", "nats://localhost:4222")

	s.Config.SetDefault("services.redis.host", "localhost")
	s.Config.SetDefault("services.redis.port", 4444)
}

//LoadConfiguration from filesystem
func (s *Server) LoadConfiguration(configPath string) {
	if configPath == "" {
		s.Logger.Panic("Could not load configuration due to empty config path.")
		os.Exit(-1)
	}

	s.Config.SetConfigFile(configPath)
	s.Config.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := s.Config.ReadInConfig(); err == nil {
		s.Logger.Info("Loaded configuration file.", zap.String("configPath", s.Config.ConfigFileUsed()))
	}
}

//Listen to incoming messages
func (s *Server) Listen() {
	s.Logger.Info("Service listening for messages...")
	s.Quit = make(chan bool)

	for {
		select {
		case <-s.Quit:
			return
		}
	}
}

//Close the server running
func (s *Server) Close() {
	s.Quit <- true
}

func (s *Server) setServerFlags(cmd *cobra.Command) {
	cmd.PersistentFlags().StringVarP(&s.ConfigPath, "config", "c", "./config/local.yaml", "configuration file to initialize this server with")
	cmd.PersistentFlags().StringVarP(&s.LogLevel, "loglevel", "l", "warn", "default log level for this backend server")
}

func getCommandFor(s *Server) *cobra.Command {
	details := s.Service.GetServiceDetails()

	return &cobra.Command{
		Use:   details.Name,
		Short: details.Description,
		Long:  details.Description,

		Run: func(cmd *cobra.Command, args []string) {
			s.Logger = s.Logger.With(
				zap.String("serverName", details.Name),
				zap.String("serverDescription", details.Description),
				zap.String("serverVersion", details.Version),
				zap.String("serverID", details.ServiceID),
			)

			s.setServerFlags(cmd)
			s.ServerService.SetServerFlags(cmd)

			s.Logger.Debug("Running backend server")
			s.Listen()
		},
	}
}

//RunMultipleServices in a single server
func RunMultipleServices(logger zap.Logger, configPath string, services ...registry.Service) error {
	if len(services) == 0 {
		return fmt.Errorf("Can't configure server with no services.")
	}
	serv := services[0]

	s, err := NewServer(serv, logger, configPath)
	if err != nil {
		logger.Error("Backend server finalized with error!", zap.Error(err))
		os.Exit(-1)
	}

	for i := 1; i < len(services); i++ {
		s.ServiceRegistry.Register(services[i])
	}

	cmd := getCommandFor(s)
	if err = cmd.Execute(); err != nil {
		s.Logger.Error("Backend server finalized with error!", zap.Error(err))
		os.Exit(-1)
	}

	return nil
}

//Run a new Service
func Run(serv registry.Service, logger zap.Logger, configPath string) error {
	return RunMultipleServices(logger, configPath, serv)
}
<commit_msg>Service reorder<commit_after>// level game server
// https://github.com/heynemann/level
//
// Licensed under the MIT license:
// http://www.opensource.org/licenses/mit-license
// Copyright © 2016 Bernardo Heynemann <heynemann@gmail.com>

package service

import (
	"fmt"
	"os"

	"github.com/heynemann/level/extensions/serviceRegistry"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"github.com/uber-go/zap"
)

var logLevels = map[string]int{
	"debug": int(zap.DebugLevel),
	"info":  int(zap.InfoLevel),
	"warn":  int(zap.WarnLevel),
	"error": int(zap.ErrorLevel),
	"panic": int(zap.PanicLevel),
	"fatal": int(zap.FatalLevel),
}

//Service describes a server interface
type Service interface {
	SetServerFlags(cmd *cobra.Command)
	SetDefaultConfigurations(*viper.Viper)
}

//Server identifies a service Server
type Server struct {
	Logger          zap.Logger
	ConfigPath      string
	Config          *viper.Viper
	ServiceRegistry *registry.ServiceRegistry
	Service         registry.Service
	ServerService   Service
	LogLevel        string
	Quit            chan bool
}

//NewServer creates an configures a new server instance
func NewServer(serv registry.Service, logger zap.Logger, configPath string) (*Server, error) {
	var service Service
	var ok bool
	if service, ok = serv.(Service); !ok {
		return nil, fmt.Errorf(
			"Service %s does not implement interface Service. Please refer to the docs.",
			serv.GetServiceDetails().Name,
		)
	}

	s := &Server{Service: serv, ServerService: service, Logger: logger, ConfigPath: configPath}
	err := s.Configure()
	if err != nil {
		return nil, err
	}

	return s, nil
}

//Configure the server
func (s *Server) Configure() error {
	s.Config = viper.New()
	s.SetDefaultConfiguration()
	s.ServerService.SetDefaultConfigurations(s.Config)

	s.LoadConfiguration(s.ConfigPath)
	err := s.initializeServiceRegistry()
	return err
}

//SetDefaultConfiguration options
func (s *Server) SetDefaultConfiguration() {
	s.Logger.Debug("Setting default configuration")
	s.Config.SetDefault("services.nats.url", "nats://localhost:4222")

	s.Config.SetDefault("services.redis.host", "localhost")
	s.Config.SetDefault("services.redis.port", 4444)
}

//LoadConfiguration from filesystem
func (s *Server) LoadConfiguration(configPath string) {
	if configPath == "" {
		s.Logger.Panic("Could not load configuration due to empty config path.")
		os.Exit(-1)
	}

	s.Config.SetConfigFile(configPath)
	s.Config.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := s.Config.ReadInConfig(); err == nil {
		s.Logger.Info("Loaded configuration file.", zap.String("configPath", s.Config.ConfigFileUsed()))
	}
}

func (s *Server) initializeServiceRegistry() error {
	natsURL := s.Config.GetString("services.nats.URL")
	l := s.Logger.With(
		zap.String("operation", "initializeServiceRegistry"),
		zap.String("natsURL", natsURL),
	)

	l.Debug("Initializing registry...")
	sr, err := registry.NewServiceRegistry(
		natsURL,
		s.Logger,
	)
	if err != nil {
		l.Error("Error initializing service registry.", zap.Error(err))
		return err
	}

	l.Info("Service registry initialized successfully.")
	s.ServiceRegistry = sr

	l.Debug("Registering service...")
	s.ServiceRegistry.Register(s.Service)
	l.Info("Service registered successfully.")

	return nil
}

//Listen to incoming messages
func (s *Server) Listen() {
	s.Logger.Info("Service listening for messages...")
	s.Quit = make(chan bool)

	for {
		select {
		case <-s.Quit:
			return
		}
	}
}

//Close the server running
func (s *Server) Close() {
	s.Quit <- true
}

func (s *Server) setServerFlags(cmd *cobra.Command) {
	cmd.PersistentFlags().StringVarP(&s.ConfigPath, "config", "c", "./config/local.yaml", "configuration file to initialize this server with")
	cmd.PersistentFlags().StringVarP(&s.LogLevel, "loglevel", "l", "warn", "default log level for this backend server")
}

func getCommandFor(s *Server) *cobra.Command {
	details := s.Service.GetServiceDetails()

	return &cobra.Command{
		Use:   details.Name,
		Short: details.Description,
		Long:  details.Description,

		Run: func(cmd *cobra.Command, args []string) {
			s.Logger = s.Logger.With(
				zap.String("serverName", details.Name),
				zap.String("serverDescription", details.Description),
				zap.String("serverVersion", details.Version),
				zap.String("serverID", details.ServiceID),
			)

			s.setServerFlags(cmd)
			s.ServerService.SetServerFlags(cmd)

			s.Logger.Debug("Running backend server")
			s.Listen()
		},
	}
}

//RunMultipleServices in a single server
func RunMultipleServices(logger zap.Logger, configPath string, services ...registry.Service) error {
	if len(services) == 0 {
		return fmt.Errorf("Can't configure server with no services.")
	}
	serv := services[0]

	s, err := NewServer(serv, logger, configPath)
	if err != nil {
		logger.Error("Backend server finalized with error!", zap.Error(err))
		os.Exit(-1)
	}

	for i := 1; i < len(services); i++ {
		s.ServiceRegistry.Register(services[i])
	}

	cmd := getCommandFor(s)
	if err = cmd.Execute(); err != nil {
		s.Logger.Error("Backend server finalized with error!", zap.Error(err))
		os.Exit(-1)
	}

	return nil
}

//Run a new Service
func Run(serv registry.Service, logger zap.Logger, configPath string) error {
	return RunMultipleServices(logger, configPath, serv)
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016 Fabian Wenzelmann

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package set_test

import (
	"fmt"
	"github.com/FabianWe/gocontainer/set"
)

// Iterate over a set of ints and compute the sum of its elements.
func ExampleIter() {
	s := set.EmptySet()
	for i := 1; i < 6; i++ {
		s.Add(i)
	}
	sum := 0
	for v := range s.Iter() {
		val := v.(int)
		sum += val
	}
	fmt.Println(sum)
	// Output: 15
}

// Iterate over a set using the Apply function, checks if there is an element
// that is even.
func ExampleApply() {
	s := set.EmptySet()
	for i := 1; i < 20; i += 2 {
		s.Add(i)
	}
	s.Add(2)
	even := false
	f := func(v set.SetValue) bool {
		val := v.(int)
		if val%2 == 0 {
			even = true
			return false
		}
		return true
	}
	s.Apply(f)
	fmt.Println(even)
	// Output: true
}
<commit_msg>renamed set example function<commit_after>// The MIT License (MIT)

// Copyright (c) 2016 Fabian Wenzelmann

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package set_test

import (
	"fmt"
	"github.com/FabianWe/gocontainer/set"
)

// Iterate over a set of ints and compute the sum of its elements.
func Example() {
	s := set.EmptySet()
	for i := 1; i < 6; i++ {
		s.Add(i)
	}
	sum := 0
	for v := range s.Iter() {
		val := v.(int)
		sum += val
	}
	fmt.Println(sum)
	// Output: 15
}

// Iterate over a set using the Apply function, checks if there is an element
// that is even.
func ExampleApply() {
	s := set.EmptySet()
	for i := 1; i < 20; i += 2 {
		s.Add(i)
	}
	s.Add(2)
	even := false
	f := func(v set.SetValue) bool {
		val := v.(int)
		if val%2 == 0 {
			even = true
			return false
		}
		return true
	}
	s.Apply(f)
	fmt.Println(even)
	// Output: true
}
<|endoftext|>


<commit_before>package task

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"reflect"

	"github.com/avabot/ava/shared/datatypes"
)

type Task struct {
	Done bool
	Err  error

	typ      string
	resultID sql.NullInt64
	ctx      *dt.Ctx
	resp     *dt.Resp
	respMsg  *dt.RespMsg
}

func New(ctx *dt.Ctx, resp *dt.Resp, respMsg *dt.RespMsg) (*Task, error) {
	if resp.State == nil {
		return &Task{}, errors.New("state nil in *dt.Resp")
	}
	return &Task{
		ctx:     ctx,
		resp:    resp,
		respMsg: respMsg,
	}, nil
}

func (t *Task) getState() float64 {
	tmp := t.resp.State[t.key()]
	if tmp == nil {
		return addressStateNone
	}
	switch tmp.(type) {
	case float64:
		return tmp.(float64)
	case uint64:
		return float64(tmp.(uint64))
	}
	log.Println("err: state was type", reflect.TypeOf(tmp))
	return 0.0
}

func (t *Task) setState(s float64) {
	t.resp.State[t.key()] = s
}

func (t *Task) ResetState() {
	t.resp.State[t.key()] = 0.0
}

func (t *Task) setInterimID(id uint64) {
	t.resp.State[t.key()] = id
}

func (t *Task) key() string {
	return fmt.Sprintf("__task%s_UserID_%d", t.typ, t.ctx.Msg.User.ID)
}

// getInterimID is useful when you've saved an object, but haven't finished
// modifying it, yet. For example, addresses are saved, but named after the
// fact. If we save the resultID into the task table, the task will cede control
// back to its calling package. As a result, we save the interimID in the resp
// state to keep task control.
func (t *Task) getInterimID() uint64 {
	if len(t.typ) == 0 {
		log.Println("warn: t.typ should be set but was \"\"")
	}
	switch t.resp.State[t.key()].(type) {
	case uint64:
		return t.resp.State[t.key()].(uint64)
	case float64:
		return uint64(t.resp.State[t.key()].(float64))
	default:
		log.Println("warn: couldn't get interim ID: invalid type",
			reflect.TypeOf(t.resp.State[t.key()]))
	}
	return uint64(0)
}
<commit_msg>Add tmp panic to invalid state for debug<commit_after>package task

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"reflect"

	"github.com/avabot/ava/shared/datatypes"
)

type Task struct {
	Done bool
	Err  error

	typ      string
	resultID sql.NullInt64
	ctx      *dt.Ctx
	resp     *dt.Resp
	respMsg  *dt.RespMsg
}

func New(ctx *dt.Ctx, resp *dt.Resp, respMsg *dt.RespMsg) (*Task, error) {
	if resp.State == nil {
		return &Task{}, errors.New("state nil in *dt.Resp")
	}
	return &Task{
		ctx:     ctx,
		resp:    resp,
		respMsg: respMsg,
	}, nil
}

func (t *Task) getState() float64 {
	tmp := t.resp.State[t.key()]
	if tmp == nil {
		return addressStateNone
	}
	switch tmp.(type) {
	case float64:
		return tmp.(float64)
	case uint64:
		return float64(tmp.(uint64))
	}
	log.Println("err: state was type", reflect.TypeOf(tmp))
	return 0.0
}

func (t *Task) setState(s float64) {
	if s > 3 {
		panic("task state too high")
	}
	t.resp.State[t.key()] = s
}

func (t *Task) ResetState() {
	t.resp.State[t.key()] = 0.0
}

func (t *Task) setInterimID(id uint64) {
	t.resp.State[t.key()] = id
}

func (t *Task) key() string {
	return fmt.Sprintf("__task%s_UserID_%d", t.typ, t.ctx.Msg.User.ID)
}

// getInterimID is useful when you've saved an object, but haven't finished
// modifying it, yet. For example, addresses are saved, but named after the
// fact. If we save the resultID into the task table, the task will cede control
// back to its calling package. As a result, we save the interimID in the resp
// state to keep task control.
func (t *Task) getInterimID() uint64 {
	if len(t.typ) == 0 {
		log.Println("warn: t.typ should be set but was \"\"")
	}
	switch t.resp.State[t.key()].(type) {
	case uint64:
		return t.resp.State[t.key()].(uint64)
	case float64:
		return uint64(t.resp.State[t.key()].(float64))
	default:
		log.Println("warn: couldn't get interim ID: invalid type",
			reflect.TypeOf(t.resp.State[t.key()]))
	}
	return uint64(0)
}
<|endoftext|>


<commit_before>package sigmon

import (
	"sync"
	"syscall"
	"testing"
	"time"
)

var (
	sigs = []syscall.Signal{
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGUSR1,
		syscall.SIGUSR2,
	}
)

type checkable struct {
	sync.Mutex
	id  int
	val int
	ct  int
}

func (c *checkable) handler(sm *SignalMonitor) {
	c.Lock()
	defer c.Unlock()

	c.val = c.id
	c.ct++
}

func (c *checkable) info() (id, val, ct int) {
	c.Lock()
	defer c.Unlock()

	return c.id, c.val, c.ct
}

func TestUnitSignalJunctionConnect(t *testing.T) {
	j := newSignalJunction()
	j.connect()

	for _, s := range sigs {
		if err := callOSSignal(s); err != nil {
			t.Errorf("unexpected error when calling %s: %s", s, err)
		}
	}

	if !receiveOnAll(j) {
		t.Fatal("should not wait forever")
	}
}

func TestUnitSignalJunctionDisconnect(t *testing.T) {
	j := newSignalJunction()
	j.connect()
	j.disconnect()

	if receiveOnAll(j) {
		t.Fatal("should wait forever")
	}
}

func TestUnitSignalHandlerRegister(t *testing.T) {
	c1 := &checkable{id: 123}
	c2 := &checkable{id: 234}

	h := newSignalHandler(nil)
	h.register(c1.handler)
	h.register(c2.handler)

	select {
	case fn := <-h.registry:
		if fn == nil {
			t.Error("want function, got nil")
		}

		fn(&SignalMonitor{})
	case <-time.After(time.Millisecond):
		t.Error("should not wait forever")
	}

	_, c1Val, _ := c1.info()
	if 0 != c1Val {
		t.Errorf("want %d, got %d", 0, c1Val)
	}
	c2ID, c2Val, _ := c2.info()
	if c2ID != c2Val {
		t.Errorf("want %d, got %d", c2ID, c2Val)
	}
}

func TestUnitSignalHandlerSet(t *testing.T) {
	c := &checkable{id: 123}
	h := newSignalHandler(nil)
	h.set(c.handler)

	h.handler(&SignalMonitor{})

	id, val, _ := c.info()
	if id != val {
		t.Errorf("want %d, got %d", id, val)
	}
}

func TestUnitSignalHandlerHandle(t *testing.T) {
	c := &checkable{id: 123}
	h := newSignalHandler(c.handler)

	h.handle(&SignalMonitor{})

	id, val, _ := c.info()
	if id != val {
		t.Errorf("want %d, got %d", id, val)
	}
}

func TestUnitSignalMonitorSet(t *testing.T) {
	c := &checkable{id: 123}
	m := New(nil)
	m.Set(c.handler)

	select {
	case fn := <-m.handler.registry:
		if fn == nil {
			t.Error("want function, got nil")
		}
	case <-time.After(time.Millisecond):
		t.Error("should not wait forever")
	}
}

func TestUnitSignalMonitorScan(t *testing.T) {
	m := New(nil)
	ret := make(chan bool, 1)

	go func() {
		m.off <- struct{}{}
		m.handler.registry <- func(sm *SignalMonitor) {}
		m.junction.sighup <- syscall.SIGHUP
		m.junction.sigint <- syscall.SIGINT
		m.junction.sigterm <- syscall.SIGTERM
		m.junction.sigusr1 <- syscall.SIGUSR1
		m.junction.sigusr2 <- syscall.SIGUSR2
	}()

	for i := 0; i < 7; i++ {
		ret <- m.scan()
		select {
		case r := <-ret:
			want, got := i > 0, r
			if want != got {
				t.Errorf("want %t, got %t", want, got)
			}
		default:
			t.Error("did not receive msg")
		}
	}
}

func TestUnitSignalMonitorBiasedScan(t *testing.T) {
	m := New(nil)
	wg := sync.WaitGroup{}

	wg.Add(1)
	go func() {
		wg.Wait()
		m.junction.sighup <- syscall.SIGHUP
	}()
	go func() {
		wg.Wait()
		m.off <- struct{}{}
	}()
	go func() {
		wg.Wait()
		m.handler.registry <- func(sm *SignalMonitor) {}
	}()

	wg.Done()
	for i := 1 << 21; i > 0; i-- {
	}

	m.biasedScan()
	m.biasedScan()

	select {
	case <-m.junction.sighup:
	default:
		t.Error("bias may be wrong")
	}
}

func TestUnitSignalMonitorRun(t *testing.T) {
	c := &checkable{id: 123}
	m := New(c.handler)
	if m.on {
		t.Errorf("want %t, got %t", false, m.on)
	}

	m.Run()
	m.Run()
	if !m.on {
		t.Errorf("want %t, got %t", true, m.on)
	}

	s := syscall.SIGHUP
	if err := callOSSignal(s); err != nil {
		t.Errorf("unexpected error when calling %s: %s", s, err)
	}

	id, val, ct := c.info()
	if id != val {
		t.Errorf("want %d, got %d", id, val)
	}
	if ct > 1 {
		t.Error("signal possibly connected multiple times")
	}
}

func receiveOnAll(j *signalJunction) bool {
	for i := 0; i < 5; i++ {
		select {
		case <-j.sighup:
		case <-j.sigint:
		case <-j.sigterm:
		case <-j.sigusr1:
		case <-j.sigusr2:
		case <-time.After(time.Microsecond * 100):
			return false
		}
	}

	return true
}

func callOSSignal(s syscall.Signal) error {
	if err := syscall.Kill(syscall.Getpid(), s); err != nil {
		return err
	}

	// delay for requested signal propagation
	for i := 1 << 13; i > 0; i-- {
		syscall.Getpid()
	}

	return nil
}
<commit_msg>Add signal monitor sig unit test.<commit_after>package sigmon

import (
	"sync"
	"syscall"
	"testing"
	"time"
)

var (
	sigs = []syscall.Signal{
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGUSR1,
		syscall.SIGUSR2,
	}
)

type checkable struct {
	sync.Mutex
	id  int
	val int
	ct  int
}

func (c *checkable) handler(sm *SignalMonitor) {
	c.Lock()
	defer c.Unlock()

	c.val = c.id
	c.ct++
}

func (c *checkable) info() (id, val, ct int) {
	c.Lock()
	defer c.Unlock()

	return c.id, c.val, c.ct
}

func TestUnitSignalJunctionConnect(t *testing.T) {
	j := newSignalJunction()
	j.connect()

	for _, s := range sigs {
		if err := callOSSignal(s); err != nil {
			t.Errorf("unexpected error when calling %s: %s", s, err)
		}
	}

	if !receiveOnAll(j) {
		t.Fatal("should not wait forever")
	}
}

func TestUnitSignalJunctionDisconnect(t *testing.T) {
	j := newSignalJunction()
	j.connect()
	j.disconnect()

	if receiveOnAll(j) {
		t.Fatal("should wait forever")
	}
}

func TestUnitSignalHandlerRegister(t *testing.T) {
	c1 := &checkable{id: 123}
	c2 := &checkable{id: 234}

	h := newSignalHandler(nil)
	h.register(c1.handler)
	h.register(c2.handler)

	select {
	case fn := <-h.registry:
		if fn == nil {
			t.Error("want function, got nil")
		}

		fn(&SignalMonitor{})
	case <-time.After(time.Millisecond):
		t.Error("should not wait forever")
	}

	_, c1Val, _ := c1.info()
	if 0 != c1Val {
		t.Errorf("want %d, got %d", 0, c1Val)
	}
	c2ID, c2Val, _ := c2.info()
	if c2ID != c2Val {
		t.Errorf("want %d, got %d", c2ID, c2Val)
	}
}

func TestUnitSignalHandlerSet(t *testing.T) {
	c := &checkable{id: 123}
	h := newSignalHandler(nil)
	h.set(c.handler)

	h.handler(&SignalMonitor{})

	id, val, _ := c.info()
	if id != val {
		t.Errorf("want %d, got %d", id, val)
	}
}

func TestUnitSignalHandlerHandle(t *testing.T) {
	c := &checkable{id: 123}
	h := newSignalHandler(c.handler)

	h.handle(&SignalMonitor{})

	id, val, _ := c.info()
	if id != val {
		t.Errorf("want %d, got %d", id, val)
	}
}

func TestUnitSignalMonitorSet(t *testing.T) {
	c := &checkable{id: 123}
	m := New(nil)
	m.Set(c.handler)

	select {
	case fn := <-m.handler.registry:
		if fn == nil {
			t.Error("want function, got nil")
		}
	case <-time.After(time.Millisecond):
		t.Error("should not wait forever")
	}
}

func TestUnitSignalMonitorScan(t *testing.T) {
	m := New(nil)
	ret := make(chan bool, 1)

	go func() {
		m.off <- struct{}{}
		m.handler.registry <- func(sm *SignalMonitor) {}
		m.junction.sighup <- syscall.SIGHUP
		m.junction.sigint <- syscall.SIGINT
		m.junction.sigterm <- syscall.SIGTERM
		m.junction.sigusr1 <- syscall.SIGUSR1
		m.junction.sigusr2 <- syscall.SIGUSR2
	}()

	for i := 0; i < 7; i++ {
		ret <- m.scan()
		select {
		case r := <-ret:
			want, got := i > 0, r
			if want != got {
				t.Errorf("want %t, got %t", want, got)
			}
		default:
			t.Error("did not receive msg")
		}
	}
}

func TestUnitSignalMonitorBiasedScan(t *testing.T) {
	m := New(nil)
	wg := sync.WaitGroup{}

	wg.Add(1)
	go func() {
		wg.Wait()
		m.junction.sighup <- syscall.SIGHUP
	}()
	go func() {
		wg.Wait()
		m.off <- struct{}{}
	}()
	go func() {
		wg.Wait()
		m.handler.registry <- func(sm *SignalMonitor) {}
	}()

	wg.Done()
	for i := 1 << 21; i > 0; i-- {
	}

	m.biasedScan()
	m.biasedScan()

	select {
	case <-m.junction.sighup:
	default:
		t.Error("bias may be wrong")
	}
}

func TestUnitSignalMonitorRun(t *testing.T) {
	c := &checkable{id: 123}
	m := New(c.handler)
	if m.on {
		t.Errorf("want %t, got %t", false, m.on)
	}

	m.Run()
	m.Run()
	if !m.on {
		t.Errorf("want %t, got %t", true, m.on)
	}

	s := syscall.SIGHUP
	if err := callOSSignal(s); err != nil {
		t.Errorf("unexpected error when calling %s: %s", s, err)
	}

	id, val, ct := c.info()
	if id != val {
		t.Errorf("want %d, got %d", id, val)
	}
	if ct > 1 {
		t.Error("signal possibly connected multiple times")
	}
}

func TestUnitSignalMonitorSig(t *testing.T) {
	m := New(nil)
	m.sig = SIGHUP

	want, got := SIGHUP, m.Sig()
	if want != got {
		t.Errorf("want %s, got %s", want, got)
	}

}

func receiveOnAll(j *signalJunction) bool {
	for i := 0; i < 5; i++ {
		select {
		case <-j.sighup:
		case <-j.sigint:
		case <-j.sigterm:
		case <-j.sigusr1:
		case <-j.sigusr2:
		case <-time.After(time.Microsecond * 100):
			return false
		}
	}

	return true
}

func callOSSignal(s syscall.Signal) error {
	if err := syscall.Kill(syscall.Getpid(), s); err != nil {
		return err
	}

	// delay for requested signal propagation
	for i := 1 << 13; i > 0; i-- {
		syscall.Getpid()
	}

	return nil
}
<|endoftext|>


<commit_before>package sink

import (
	"code.cloudfoundry.org/lager"

	"github.com/cloudfoundry-community/splunk-firehose-nozzle/splunk"

	"os"
	"net"
)

type SplunkSink struct {
	name         string
	index        string
	host         string
	splunkClient splunk.SplunkClient
}

func NewSplunkSink(name string, index string, host string, splunkClient splunk.SplunkClient) *SplunkSink {

	if host == "" {
		hostname, err := os.Hostname()

		if err != nil {
			panic(err)
		}
		host = hostname
	}

	return &SplunkSink{
		name:         name,
		index:        index,
		host:         host,
		splunkClient: splunkClient,
	}
}

func (s *SplunkSink) Log(message lager.LogFormat) {

	host_ip_address, err := net.LookupIP(s.host)

	if err != nil {
		// what to do here?
		panic(err)
	}

	event := map[string]interface{}{
		"job_index":     s.index,
		"job":           s.name,
		"ip":            host_ip_address[0].String(),
		"origin":        "splunk_nozzle",
		"logger_source": message.Source,
		"message":       message.Message,
		"log_level":     int(message.LogLevel),
	}
	if message.Data != nil && len(message.Data) > 0 {
		data := map[string]interface{}{}
		for key, value := range message.Data {
			data[key] = value
		}
		event["data"] = data
	}

	events := []map[string]interface{}{
		map[string]interface{}{
			"time":       message.Timestamp,
			"host":       s.host,
			"source":     s.name,
			"sourcetype": "cf:splunknozzle",
			"event":      event,
		},
	}

	s.splunkClient.Post(events)
}
<commit_msg> cleaned up white space<commit_after>package sink

import (
	"code.cloudfoundry.org/lager"
	"github.com/cloudfoundry-community/splunk-firehose-nozzle/splunk"
	"os"
	"net"
)

type SplunkSink struct {
	name         string
	index        string
	host         string
	splunkClient splunk.SplunkClient
}

func NewSplunkSink(name string, index string, host string, splunkClient splunk.SplunkClient) *SplunkSink {

	if host == "" {
		hostname, err := os.Hostname()
		if err != nil {
			panic(err)
		}
		host = hostname
	}
	return &SplunkSink{
		name:         name,
		index:        index,
		host:         host,
		splunkClient: splunkClient,
	}
}

func (s *SplunkSink) Log(message lager.LogFormat) {

	host_ip_address, err := net.LookupIP(s.host)
	if err != nil {
		// what to do here?
		panic(err)
	}
	event := map[string]interface{}{
		"job_index":     s.index,
		"job":           s.name,
		"ip":            host_ip_address[0].String(),
		"origin":        "splunk_nozzle",
		"logger_source": message.Source,
		"message":       message.Message,
		"log_level":     int(message.LogLevel),
	}
	if message.Data != nil && len(message.Data) > 0 {
		data := map[string]interface{}{}
		for key, value := range message.Data {
			data[key] = value
		}
		event["data"] = data
	}

	events := []map[string]interface{}{
		map[string]interface{}{
			"time":       message.Timestamp,
			"host":       s.host,
			"source":     s.name,
			"sourcetype": "cf:splunknozzle",
			"event":      event,
		},
	}

	s.splunkClient.Post(events)
}
<|endoftext|>


<commit_before>package layer

import (
	"net/http"
	"testing"

	"github.com/nbio/st"
	"gopkg.in/vinxi/utils.v0"
)

type plugin struct {
	middleware interface{}
}

func (p *plugin) Register(mw Middleware) {
	mw.Use(RequestPhase, p.middleware)
}

func newPlugin(f interface{}) *plugin {
	return &plugin{middleware: f}
}

func TestMiddleware(t *testing.T) {
	mw := New()

	mw.Use(RequestPhase, func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "bar")
			h.ServeHTTP(w, r)
		})
	})

	st.Expect(t, mw.Pool["request"].Len(), 1)

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Header().Get("foo"), "bar")
}

func TestNoHandlerRegistered(t *testing.T) {
	mw := New()

	st.Expect(t, mw.Pool["request"], (*Stack)(nil))

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Code, 502)
	st.Expect(t, string(w.Body), "Bad Gateway")
}

func TestFinalErrorHandling(t *testing.T) {
	mw := New()

	mw.Use("request", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			panic("something went wrong")
		})
	})

	st.Expect(t, mw.Pool["request"].Len(), 1)

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Code, 500)
	st.Expect(t, string(w.Body), "Proxy Error")
}

func TestUseFinalHandler(t *testing.T) {
	mw := New()

	mw.UseFinalHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(503)
		w.Write([]byte("vinxi: service unavailable"))
	}))

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Code, 503)
	st.Expect(t, string(w.Body), "vinxi: service unavailable")
}

func TestRegisterPlugin(t *testing.T) {
	mw := New()

	p := newPlugin(func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "bar")
			h.ServeHTTP(w, r)
		})
	})
	mw.Use(RequestPhase, p)

	st.Expect(t, mw.Pool["request"].Len(), 1)

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Header().Get("foo"), "bar")
}

func TestRegisterUnsupportedInterface(t *testing.T) {
	defer func() {
		r := recover()
		st.Expect(t, r, "vinxi: unsupported middleware interface")
	}()

	mw := New()

	mw.Use(RequestPhase, func() {})
}

func TestUsePriority(t *testing.T) {
	mw := New()

	mw.UseFinalHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(503)
		w.Write([]byte("vinxi: service unavailable"))
	}))

	array := []int{}

	buildAppendingMiddleware := func(before, after int) interface{} {
		return func(h http.Handler) http.Handler {
			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				array = append(array, before)
				h.ServeHTTP(w, r)
				array = append(array, after)
			})
		}
	}
	mw.UsePriority("request", Normal, buildAppendingMiddleware(3, 10))
	mw.UsePriority("request", Tail, buildAppendingMiddleware(5, 8))
	mw.UsePriority("request", Head, buildAppendingMiddleware(1, 12))
	mw.UsePriority("request", Tail, buildAppendingMiddleware(6, 7))
	mw.UsePriority("request", Head, buildAppendingMiddleware(2, 11))
	mw.UsePriority("request", Normal, buildAppendingMiddleware(4, 9))

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, array, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})
}

func TestSimpleMiddlewareCallChain(t *testing.T) {
	mw := New()

	calls := 0
	fn := func(w http.ResponseWriter, r *http.Request, h http.Handler) {
		calls++
		h.ServeHTTP(w, r)
	}
	final := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		calls++
	})

	mw.Use(RequestPhase, fn)
	mw.Use(RequestPhase, fn)
	mw.Use(RequestPhase, fn)

	wrt := utils.NewWriterStub()
	req := &http.Request{}

	mw.Run("request", wrt, req, final)
	st.Expect(t, calls, 4)
}

func TestFlush(t *testing.T) {
	mw := New()

	mw.Use("request", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			h.ServeHTTP(w, r)
		})
	})
	mw.Flush()
	st.Expect(t, mw.Pool, Pool{})
}

func TestParentLayer(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("bar", "bar")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(200)
			w.Write([]byte("hello world"))
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 200)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, w.Header().Get("bar"), "bar")
	st.Expect(t, string(w.Body), "hello world")
}

func TestParentLayerStopChain(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(200)
			w.Write([]byte("hello world"))
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(500)
			w.Write([]byte("oops"))
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 200)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, string(w.Body), "hello world")
}

func TestParentLayerPanic(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	parent.Use("error", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(502)
			w.Write([]byte("error"))
		})
	})

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			panic("oops")
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 502)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, string(w.Body), "error")
}

func TestParentLayerPanicFinalHandler(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	parent.Use("error", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("error", "foo")
			h.ServeHTTP(w, r)
		})
	})

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			panic("oops")
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 500)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, w.Header().Get("error"), "foo")
	st.Expect(t, string(w.Body), "Proxy Error")
}

func TestParentLayerChildPanicHandler(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	// Just discovered that this won't be called since seems like
	// Go only triggers the top panic recover handler.
	mw.Use("error", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("error", "child")
			h.ServeHTTP(w, r)
		})
	})

	parent.Use("error", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("error", "parent")
			h.ServeHTTP(w, r)
		})
	})

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			panic("oops")
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 500)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, w.Header().Get("error"), "parent")
	st.Expect(t, string(w.Body), "Proxy Error")
}

func BenchmarkLayerRun(b *testing.B) {
	w := utils.NewWriterStub()
	req := &http.Request{}

	mw := New()
	for i := 0; i < 100; i++ {
		mw.Use(RequestPhase, func(h http.Handler) http.Handler {
			return http.HandlerFunc(h.ServeHTTP)
		})
	}

	for n := 0; n < b.N; n++ {
		mw.Run(RequestPhase, w, req, http.HandlerFunc(nil))
	}
}

func BenchmarkStackLayers(b *testing.B) {
	w := utils.NewWriterStub()
	req := &http.Request{}

	handler := func(h http.Handler) http.Handler {
		return http.HandlerFunc(h.ServeHTTP)
	}

	mw := New()
	for i := 0; i < 100; i++ {
		mw.UsePriority(RequestPhase, Head, handler)
		mw.UsePriority(RequestPhase, Normal, handler)
		mw.UsePriority(RequestPhase, Tail, handler)
	}

	for n := 0; n < b.N; n++ {
		mw.Run(RequestPhase, w, req, http.HandlerFunc(nil))
	}
}
<commit_msg>feat(tests): add concurrency test<commit_after>package layer

import (
	"net/http"
	"sync"
	"testing"

	"github.com/nbio/st"
	"gopkg.in/vinxi/utils.v0"
)

type plugin struct {
	middleware interface{}
}

func (p *plugin) Register(mw Middleware) {
	mw.Use(RequestPhase, p.middleware)
}

func newPlugin(f interface{}) *plugin {
	return &plugin{middleware: f}
}

func TestMiddleware(t *testing.T) {
	mw := New()

	mw.Use(RequestPhase, func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "bar")
			h.ServeHTTP(w, r)
		})
	})

	st.Expect(t, mw.Pool["request"].Len(), 1)

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Header().Get("foo"), "bar")
}

func TestNoHandlerRegistered(t *testing.T) {
	mw := New()

	st.Expect(t, mw.Pool["request"], (*Stack)(nil))

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Code, 502)
	st.Expect(t, string(w.Body), "Bad Gateway")
}

func TestFinalErrorHandling(t *testing.T) {
	mw := New()

	mw.Use("request", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			panic("something went wrong")
		})
	})

	st.Expect(t, mw.Pool["request"].Len(), 1)

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Code, 500)
	st.Expect(t, string(w.Body), "Proxy Error")
}

func TestUseFinalHandler(t *testing.T) {
	mw := New()

	mw.UseFinalHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(503)
		w.Write([]byte("vinxi: service unavailable"))
	}))

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Code, 503)
	st.Expect(t, string(w.Body), "vinxi: service unavailable")
}

func TestRegisterPlugin(t *testing.T) {
	mw := New()

	p := newPlugin(func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "bar")
			h.ServeHTTP(w, r)
		})
	})
	mw.Use(RequestPhase, p)

	st.Expect(t, mw.Pool["request"].Len(), 1)

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, w.Header().Get("foo"), "bar")
}

func TestRegisterUnsupportedInterface(t *testing.T) {
	defer func() {
		r := recover()
		st.Expect(t, r, "vinxi: unsupported middleware interface")
	}()

	mw := New()

	mw.Use(RequestPhase, func() {})
}

func TestUsePriority(t *testing.T) {
	mw := New()

	mw.UseFinalHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(503)
		w.Write([]byte("vinxi: service unavailable"))
	}))

	array := []int{}

	buildAppendingMiddleware := func(before, after int) interface{} {
		return func(h http.Handler) http.Handler {
			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				array = append(array, before)
				h.ServeHTTP(w, r)
				array = append(array, after)
			})
		}
	}
	mw.UsePriority("request", Normal, buildAppendingMiddleware(3, 10))
	mw.UsePriority("request", Tail, buildAppendingMiddleware(5, 8))
	mw.UsePriority("request", Head, buildAppendingMiddleware(1, 12))
	mw.UsePriority("request", Tail, buildAppendingMiddleware(6, 7))
	mw.UsePriority("request", Head, buildAppendingMiddleware(2, 11))
	mw.UsePriority("request", Normal, buildAppendingMiddleware(4, 9))

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("request", w, req, nil)

	st.Expect(t, array, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})
}

func TestSimpleMiddlewareCallChain(t *testing.T) {
	mw := New()

	calls := 0
	fn := func(w http.ResponseWriter, r *http.Request, h http.Handler) {
		calls++
		h.ServeHTTP(w, r)
	}
	final := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		calls++
	})

	mw.Use(RequestPhase, fn)
	mw.Use(RequestPhase, fn)
	mw.Use(RequestPhase, fn)

	wrt := utils.NewWriterStub()
	req := &http.Request{}

	mw.Run("request", wrt, req, final)
	st.Expect(t, calls, 4)
}

func TestConcurrentRegistration(t *testing.T) {
	var wg sync.WaitGroup
	mw := New()

	fn := func(w http.ResponseWriter, r *http.Request, h http.Handler) {
		w.Header().Set("foo", w.Header().Get("foo")+"bar")
		h.ServeHTTP(w, r)
	}

	var called bool
	final := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		called = true
	})

	max := 10
	wg.Add(max)

	for i := 0; i < max; i += 1 {
		go (func() {
			mw.Use(RequestPhase, fn)
			wg.Done()
		})()
	}
	wg.Wait()

	wrt := utils.NewWriterStub()
	mw.Run("request", wrt, &http.Request{}, final)

	st.Expect(t, wrt.Header().Get("foo"), "barbarbarbarbarbarbarbarbarbar")
	st.Expect(t, called, true)
}

func TestFlush(t *testing.T) {
	mw := New()

	mw.Use("request", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			h.ServeHTTP(w, r)
		})
	})
	mw.Flush()
	st.Expect(t, mw.Pool, Pool{})
}

func TestParentLayer(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("bar", "bar")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(200)
			w.Write([]byte("hello world"))
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 200)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, w.Header().Get("bar"), "bar")
	st.Expect(t, string(w.Body), "hello world")
}

func TestParentLayerStopChain(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(200)
			w.Write([]byte("hello world"))
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(500)
			w.Write([]byte("oops"))
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 200)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, string(w.Body), "hello world")
}

func TestParentLayerPanic(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	parent.Use("error", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(502)
			w.Write([]byte("error"))
		})
	})

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			panic("oops")
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 502)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, string(w.Body), "error")
}

func TestParentLayerPanicFinalHandler(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	parent.Use("error", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("error", "foo")
			h.ServeHTTP(w, r)
		})
	})

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			panic("oops")
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 500)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, w.Header().Get("error"), "foo")
	st.Expect(t, string(w.Body), "Proxy Error")
}

func TestParentLayerChildPanicHandler(t *testing.T) {
	parent := New()
	mw := New()
	mw.SetParent(parent)

	// Just discovered that this won't be called since seems like
	// Go only triggers the top panic recover handler.
	mw.Use("error", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("error", "child")
			h.ServeHTTP(w, r)
		})
	})

	parent.Use("error", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("error", "parent")
			h.ServeHTTP(w, r)
		})
	})

	parent.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("foo", "foo")
			h.ServeHTTP(w, r)
		})
	})

	mw.Use("foo", func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			panic("oops")
		})
	})

	w := utils.NewWriterStub()
	req := &http.Request{}
	mw.Run("foo", w, req, nil)

	st.Expect(t, w.Code, 500)
	st.Expect(t, w.Header().Get("foo"), "foo")
	st.Expect(t, w.Header().Get("error"), "parent")
	st.Expect(t, string(w.Body), "Proxy Error")
}

func BenchmarkLayerRun(b *testing.B) {
	w := utils.NewWriterStub()
	req := &http.Request{}

	mw := New()
	for i := 0; i < 100; i++ {
		mw.Use(RequestPhase, func(h http.Handler) http.Handler {
			return http.HandlerFunc(h.ServeHTTP)
		})
	}

	for n := 0; n < b.N; n++ {
		mw.Run(RequestPhase, w, req, http.HandlerFunc(nil))
	}
}

func BenchmarkStackLayers(b *testing.B) {
	w := utils.NewWriterStub()
	req := &http.Request{}

	handler := func(h http.Handler) http.Handler {
		return http.HandlerFunc(h.ServeHTTP)
	}

	mw := New()
	for i := 0; i < 100; i++ {
		mw.UsePriority(RequestPhase, Head, handler)
		mw.UsePriority(RequestPhase, Normal, handler)
		mw.UsePriority(RequestPhase, Tail, handler)
	}

	for n := 0; n < b.N; n++ {
		mw.Run(RequestPhase, w, req, http.HandlerFunc(nil))
	}
}
<|endoftext|>


<commit_before>package slackboard

const (
	Version = "0.6.6"
)
<commit_msg>bumped version to 0.6.7.<commit_after>package slackboard

const (
	Version = "0.6.7"
)
<|endoftext|>


<commit_before>package oddb

import (
	"errors"
	"io"
)

// ErrRecordNotFound is returned from Get and Delete when Database
// cannot find the Record by the specified key
var ErrRecordNotFound = errors.New("oddb: Record not found for the specified key")

// EmptyRows is a convenient variable that acts as an empty Rows.
// Useful for oddb implementators and testing.
var EmptyRows = NewRows(emptyRowsIter(0))

type emptyRowsIter int

func (rs emptyRowsIter) Close() error {
	return nil
}

func (rs emptyRowsIter) Next(record *Record) error {
	return io.EOF
}

// Database represents a collection of record (either public or private)
// in a container.
//
// TODO: We might need to define standard errors for common failures
// of database operations like ErrRecordNotFound
type Database interface {

	// Conn returns the parent Conn of the Database
	Conn() Conn

	// ID returns the identifier of the Database.
	ID() string

	// Get fetches the Record identified by the supplied key and
	// writes it onto the supplied Record.
	//
	// Get returns an ErrRecordNotFound if Record identified by
	// the supplied key does not exist in the Database.
	// It also returns error if the underlying implementation
	// failed to read the Record.
	Get(id RecordID, record *Record) error

	// Save updates the supplied Record in the Database if Record with
	// the same key exists, else such Record is created.
	//
	// Save returns an error if the underlying implemention failed to
	// create / modify the Record.
	Save(record *Record) error

	// Delete removes the Record identified by the key in the Database.
	//
	// Delete returns an ErrRecordNotFound if the Record identified by
	// the supplied key does not exist in the Database.
	// It also returns an error if the underlying implementation
	// failed to remove the Record.
	Delete(id RecordID) error

	// Query executes the supplied query against the Database and returns
	// an Rows to iterate the results.
	Query(query *Query) (*Rows, error)

	// Extend extends the Database record schema such that a record
	// arrived subsequently with that schema can be saved
	//
	// Extend returns an error if the specified schema conflicts with
	// existing schem in the Database
	Extend(recordType string, schema RecordSchema) error

	GetSubscription(key string, deviceID string, subscription *Subscription) error
	SaveSubscription(subscription *Subscription) error
	DeleteSubscription(key string, deviceID string) error
	GetSubscriptionsByDeviceID(deviceID string) []Subscription
	GetMatchingSubscriptions(record *Record) []Subscription
}

// Rows implements a scanner-like interface for easy iteration on a
// result set returned from a query
type Rows struct {
	iter    RowsIter
	lasterr error
	closed  bool
	record  Record
	nexted  bool
}

// NewRows creates a new Rows.
//
// Driver implementators are expected to call this method with
// their implementation of RowsIter to return a Rows from Database.Query.
func NewRows(iter RowsIter) *Rows {
	return &Rows{
		iter: iter,
	}
}

// Close closes the Rows and prevents futher enumerations on the instance.
func (r *Rows) Close() error {
	if r.closed {
		return nil
	}

	r.closed = true
	return r.iter.Close()
}

// Scan tries to prepare the next record and returns whether such record
// is ready to be read.
func (r *Rows) Scan() bool {
	if r.closed {
		return false
	}

	r.lasterr = r.iter.Next(&r.record)
	if r.lasterr != nil {
		r.Close()
		return false
	}

	return true
}

// Record returns the current record in Rows.
//
// It must be called after calling Scan and Scan returned true.
// If Scan is not called or previous Scan return false, the behaviour
// of Record is unspecified.
func (r *Rows) Record() Record {
	return r.record
}

// Err returns the last error encountered during Scan.
//
// NOTE: It is not an error if the underlying result set is exhausted.
func (r *Rows) Err() error {
	if r.lasterr == io.EOF {
		return nil
	}

	return r.lasterr
}

// RowsIter is an iterator on results returned by execution of a query.
type RowsIter interface {
	// Close closes the rows iterator
	Close() error

	// Next populates the next Record in the current rows iterator into
	// the provided record.
	//
	// Next should return io.EOF when there are no more rows
	Next(record *Record) error
}

// MemoryRows is a native implementation of RowIter.
// Can be used in test or simple back-end(fs) not support cursor.
type MemoryRows struct {
	CurrentRowIndex int
	Records         []Record
}

func NewMemoryRows(records []Record) *MemoryRows {
	return &MemoryRows{0, records}
}

func (rs *MemoryRows) Close() error {
	return nil
}

func (rs *MemoryRows) Next(record *Record) error {
	if rs.CurrentRowIndex >= len(rs.Records) {
		return io.EOF
	}

	*record = rs.Records[rs.CurrentRowIndex]
	rs.CurrentRowIndex = rs.CurrentRowIndex + 1
	return nil
}
<commit_msg>oddb: add TxDatabase interface<commit_after>package oddb

import (
	"errors"
	"io"
)

// ErrRecordNotFound is returned from Get and Delete when Database
// cannot find the Record by the specified key
var ErrRecordNotFound = errors.New("oddb: Record not found for the specified key")

// EmptyRows is a convenient variable that acts as an empty Rows.
// Useful for oddb implementators and testing.
var EmptyRows = NewRows(emptyRowsIter(0))

type emptyRowsIter int

func (rs emptyRowsIter) Close() error {
	return nil
}

func (rs emptyRowsIter) Next(record *Record) error {
	return io.EOF
}

var ErrDatabaseTxDidBegin = errors.New("oddb: a transaction has already begun")
var ErrDatabaseTxDidNotBegin = errors.New("oddb: a transaction has not begun")
var ErrDatabaseTxDone = errors.New("oddb: Database's transaction has already commited or rolled back")

// Database represents a collection of record (either public or private)
// in a container.
type Database interface {

	// Conn returns the parent Conn of the Database
	Conn() Conn

	// ID returns the identifier of the Database.
	ID() string

	// Get fetches the Record identified by the supplied key and
	// writes it onto the supplied Record.
	//
	// Get returns an ErrRecordNotFound if Record identified by
	// the supplied key does not exist in the Database.
	// It also returns error if the underlying implementation
	// failed to read the Record.
	Get(id RecordID, record *Record) error

	// Save updates the supplied Record in the Database if Record with
	// the same key exists, else such Record is created.
	//
	// Save returns an error if the underlying implemention failed to
	// create / modify the Record.
	Save(record *Record) error

	// Delete removes the Record identified by the key in the Database.
	//
	// Delete returns an ErrRecordNotFound if the Record identified by
	// the supplied key does not exist in the Database.
	// It also returns an error if the underlying implementation
	// failed to remove the Record.
	Delete(id RecordID) error

	// Query executes the supplied query against the Database and returns
	// an Rows to iterate the results.
	Query(query *Query) (*Rows, error)

	// Extend extends the Database record schema such that a record
	// arrived subsequently with that schema can be saved
	//
	// Extend returns an error if the specified schema conflicts with
	// existing schem in the Database
	Extend(recordType string, schema RecordSchema) error

	GetSubscription(key string, deviceID string, subscription *Subscription) error
	SaveSubscription(subscription *Subscription) error
	DeleteSubscription(key string, deviceID string) error
	GetSubscriptionsByDeviceID(deviceID string) []Subscription
	GetMatchingSubscriptions(record *Record) []Subscription
}

// TxDatabase defines the methods for a Database that supports
// transaction.
//
// A Begin'ed transaction must end with a call to Commit or Rollback. After
// that, all opertions on Database will return ErrDatabaseTxDone.
//
// NOTE(limouren): The interface is not Database specific, but currently only
// Database supports it.
type TxDatabase interface {
	// Begin opens a transaction for the current Database.
	//
	// Calling Begin on an already Begin'ed Database returns ErrDatabaseTxDidBegin.
	Begin() error

	// Commit saves all the changes made to Database after Begin atomically.
	Commit() error

	// Rollbacks discards all the changes made to Database after Begin.
	Rollback() error
}

// Rows implements a scanner-like interface for easy iteration on a
// result set returned from a query
type Rows struct {
	iter    RowsIter
	lasterr error
	closed  bool
	record  Record
	nexted  bool
}

// NewRows creates a new Rows.
//
// Driver implementators are expected to call this method with
// their implementation of RowsIter to return a Rows from Database.Query.
func NewRows(iter RowsIter) *Rows {
	return &Rows{
		iter: iter,
	}
}

// Close closes the Rows and prevents futher enumerations on the instance.
func (r *Rows) Close() error {
	if r.closed {
		return nil
	}

	r.closed = true
	return r.iter.Close()
}

// Scan tries to prepare the next record and returns whether such record
// is ready to be read.
func (r *Rows) Scan() bool {
	if r.closed {
		return false
	}

	r.lasterr = r.iter.Next(&r.record)
	if r.lasterr != nil {
		r.Close()
		return false
	}

	return true
}

// Record returns the current record in Rows.
//
// It must be called after calling Scan and Scan returned true.
// If Scan is not called or previous Scan return false, the behaviour
// of Record is unspecified.
func (r *Rows) Record() Record {
	return r.record
}

// Err returns the last error encountered during Scan.
//
// NOTE: It is not an error if the underlying result set is exhausted.
func (r *Rows) Err() error {
	if r.lasterr == io.EOF {
		return nil
	}

	return r.lasterr
}

// RowsIter is an iterator on results returned by execution of a query.
type RowsIter interface {
	// Close closes the rows iterator
	Close() error

	// Next populates the next Record in the current rows iterator into
	// the provided record.
	//
	// Next should return io.EOF when there are no more rows
	Next(record *Record) error
}

// MemoryRows is a native implementation of RowIter.
// Can be used in test or simple back-end(fs) not support cursor.
type MemoryRows struct {
	CurrentRowIndex int
	Records         []Record
}

func NewMemoryRows(records []Record) *MemoryRows {
	return &MemoryRows{0, records}
}

func (rs *MemoryRows) Close() error {
	return nil
}

func (rs *MemoryRows) Next(record *Record) error {
	if rs.CurrentRowIndex >= len(rs.Records) {
		return io.EOF
	}

	*record = rs.Records[rs.CurrentRowIndex]
	rs.CurrentRowIndex = rs.CurrentRowIndex + 1
	return nil
}
<|endoftext|>


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

package output

import (
	"errors"
	"fmt"
	"os"
	"time"

	"github.com/caixw/apidoc/doc"
)

// 支持的渲染方式
var renderTypes = []string{
	"html",
}

type Options struct {
	Elapsed time.Duration `json:"-"`       // 编译用时
	Version string        `json:"version"` // 文档的版本号
	Dir     string        `json:"dir"`     // 文档的保存目录
	Title   string        `json:"title"`   // 文档的标题
	BaseURL string        `json:"baseURL"` // api 文档中 url 的前缀
	Type    string        `json:"type"`    // 渲染方式，默认为 html

	// Language string // 产生的ui界面语言
	//Groups     []string `json:"groups"`     // 需要打印的分组内容。
	//Timezone   string   `json:"timezone"`   // 时区
}

// 对 Options 作一些初始化操作。
func (o *Options) Init() error {
	if len(o.Dir) == 0 {
		return errors.New("未指定 Dir")
	}
	o.Dir += string(os.PathSeparator)

	if len(o.Title) == 0 {
		o.Title = "APIDOC"
	}

	if !isSuppertedType(o.Type) {
		return fmt.Errorf("不支持的渲染类型：[%v]", o.Type)
	}

	return nil
}

// 渲染 docs 的内容，具体的渲染参数由 o 指定。
func Render(docs *doc.Doc, o *Options) error {
	switch o.Type {
	case "html":
		return html(docs, o)
	default:
		return fmt.Errorf("不支持的渲染方式:[%v]", o.Type)
	}
}

func isSuppertedType(typ string) bool {
	for _, k := range renderTypes {
		if k == typ {
			return true
		}
	}

	return false
}
<commit_msg>output.Options.Title 现在不允许为空<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package output

import (
	"errors"
	"fmt"
	"os"
	"time"

	"github.com/caixw/apidoc/doc"
)

// 支持的渲染方式
var renderTypes = []string{
	"html",
}

type Options struct {
	Elapsed time.Duration `json:"-"`       // 编译用时
	Version string        `json:"version"` // 文档的版本号
	Dir     string        `json:"dir"`     // 文档的保存目录
	Title   string        `json:"title"`   // 文档的标题
	BaseURL string        `json:"baseURL"` // api 文档中 url 的前缀
	Type    string        `json:"type"`    // 渲染方式，默认为 html

	// Language string // 产生的ui界面语言
	//Groups     []string `json:"groups"`     // 需要打印的分组内容。
	//Timezone   string   `json:"timezone"`   // 时区
}

// 对 Options 作一些初始化操作。
func (o *Options) Init() error {
	if len(o.Dir) == 0 {
		return errors.New("未指定 Dir")
	}
	o.Dir += string(os.PathSeparator)

	if len(o.Title) == 0 {
		return errors.New("未指定 Title")
	}

	if !isSuppertedType(o.Type) {
		return fmt.Errorf("不支持的渲染类型：[%v]", o.Type)
	}

	return nil
}

// 渲染 docs 的内容，具体的渲染参数由 o 指定。
func Render(docs *doc.Doc, o *Options) error {
	switch o.Type {
	case "html":
		return html(docs, o)
	default:
		return fmt.Errorf("不支持的渲染方式:[%v]", o.Type)
	}
}

func isSuppertedType(typ string) bool {
	for _, k := range renderTypes {
		if k == typ {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package metrics

import (
	"fmt"
	"strings"
	"time"

	"github.com/fweikert/continuous-integration/metrics/clients"
	"github.com/fweikert/continuous-integration/metrics/data"
)

type WorkerAvailability struct {
	client  *clients.BuildkiteClient
	orgs    []string
	columns []Column
}

func (wa *WorkerAvailability) Name() string {
	return "worker_availability"
}

func (wa *WorkerAvailability) Columns() []Column {
	return wa.columns
}

func (wa *WorkerAvailability) Collect() (data.DataSet, error) {
	ts := time.Now().Unix()
	result := data.CreateDataSet(GetColumnNames(wa.columns))
	for _, org := range wa.orgs {
		allPlatforms, err := wa.getIdleAndBusyCountsPerPlatform(org)
		if err != nil {
			return nil, err
		}
		for platform, counts := range allPlatforms {
			err = result.AddRow(ts, platform, counts[0], counts[1])
			if err != nil {
				return nil, err
			}
		}
	}
	return result, nil
}

func (wa *WorkerAvailability) getIdleAndBusyCountsPerPlatform(org string) (map[string]*[2]int, error) {
	agents, err := wa.client.GetAgents(org)
	if err != nil {
		return nil, fmt.Errorf("Cannot retrieve agents from Buildkite: %v", err)
	}

	allPlatforms := make(map[string]*[2]int)
	for _, a := range agents {
		platform, err := getPlatformForHost(*a.Hostname)
		if err != nil {
			return nil, err
		}
		if _, ok := allPlatforms[platform]; !ok {
			allPlatforms[platform] = &[2]int{0, 0}
		}
		var index int
		if a.Job != nil {
			index = 1
		}
		allPlatforms[platform][index] += 1
	}
	return allPlatforms, nil
}

func getPlatformForHost(hostName string) (string, error) {
	pos := strings.LastIndex(hostName, "-")
	if pos < 0 {
		return "", fmt.Errorf("Unknown host name '%s' cannot be resolved to a platform.", hostName)
	}
	return hostName[:pos], nil
}

// CREATE TABLE worker_availability (timestamp BIGINT, org VARCHAR(255), platform VARCHAR(255), idle_count INT, busy_count INT, PRIMARY KEY(timestamp, org, platform));
func CreateWorkerAvailability(client *clients.BuildkiteClient, orgs ...string) *WorkerAvailability {
	columns := []Column{Column{"timestamp", true}, Column{"org", true}, Column{"platform", true}, Column{"idle_count", false}, Column{"busy_count", false}}
	return &WorkerAvailability{client: client, orgs: orgs, columns: columns}
}
<commit_msg>Properly store 'org' value for worker_availability metric<commit_after>package metrics

import (
	"fmt"
	"strings"
	"time"

	"github.com/fweikert/continuous-integration/metrics/clients"
	"github.com/fweikert/continuous-integration/metrics/data"
)

type WorkerAvailability struct {
	client  *clients.BuildkiteClient
	orgs    []string
	columns []Column
}

func (wa *WorkerAvailability) Name() string {
	return "worker_availability"
}

func (wa *WorkerAvailability) Columns() []Column {
	return wa.columns
}

func (wa *WorkerAvailability) Collect() (data.DataSet, error) {
	ts := time.Now().Unix()
	result := data.CreateDataSet(GetColumnNames(wa.columns))
	for _, org := range wa.orgs {
		allPlatforms, err := wa.getIdleAndBusyCountsPerPlatform(org)
		if err != nil {
			return nil, err
		}
		for platform, counts := range allPlatforms {
			err = result.AddRow(ts, org, platform, counts[0], counts[1])
			if err != nil {
				return nil, err
			}
		}
	}
	return result, nil
}

func (wa *WorkerAvailability) getIdleAndBusyCountsPerPlatform(org string) (map[string]*[2]int, error) {
	agents, err := wa.client.GetAgents(org)
	if err != nil {
		return nil, fmt.Errorf("Cannot retrieve agents from Buildkite: %v", err)
	}

	allPlatforms := make(map[string]*[2]int)
	for _, a := range agents {
		platform, err := getPlatformForHost(*a.Hostname)
		if err != nil {
			return nil, err
		}
		if _, ok := allPlatforms[platform]; !ok {
			allPlatforms[platform] = &[2]int{0, 0}
		}
		var index int
		if a.Job != nil {
			index = 1
		}
		allPlatforms[platform][index] += 1
	}
	return allPlatforms, nil
}

func getPlatformForHost(hostName string) (string, error) {
	pos := strings.LastIndex(hostName, "-")
	if pos < 0 {
		return "", fmt.Errorf("Unknown host name '%s' cannot be resolved to a platform.", hostName)
	}
	return hostName[:pos], nil
}

// CREATE TABLE worker_availability (timestamp BIGINT, org VARCHAR(255), platform VARCHAR(255), idle_count INT, busy_count INT, PRIMARY KEY(timestamp, org, platform));
func CreateWorkerAvailability(client *clients.BuildkiteClient, orgs ...string) *WorkerAvailability {
	columns := []Column{Column{"timestamp", true}, Column{"org", true}, Column{"platform", true}, Column{"idle_count", false}, Column{"busy_count", false}}
	return &WorkerAvailability{client: client, orgs: orgs, columns: columns}
}
<|endoftext|>


<commit_before>package parse

import "unicode/utf8"

type rawtextlexer struct {
	str      string
	pos      int
	lastpos  int
	lastpos2 int
}

func (l *rawtextlexer) eof() bool {
	return l.pos >= len(l.str)
}
func (l *rawtextlexer) next() rune {
	l.lastpos2 = l.lastpos
	l.lastpos = l.pos
	var r, width = utf8.DecodeRuneInString(l.str[l.pos:])
	l.pos += width
	return r
}
func (l *rawtextlexer) backup() {
	l.pos = l.lastpos
	l.lastpos = l.lastpos2
	l.lastpos2 = 0
}
func (l *rawtextlexer) emitRune(result []byte) []byte {
	return append(result, []byte(l.str[l.lastpos:l.pos])...)
}

// rawtext processes the raw text found in templates:
// - trim leading/trailing whitespace if either:
//  a. the whitespace includes a newline, or
//  b. the caller tells us the surrounding content is a tight joiner  by start/endTightJoin
// - trim leading and trailing whitespace on each internal line
// - join lines with no space if '<' or '>' are on either side, else with 1 space.
func rawtext(s string, trimBefore, trimAfter bool) []byte {
	var lex = rawtextlexer{s, 0, 0, 0}
	var (
		spaces         = 0
		seenNewline    = trimBefore
		lastChar       rune
		charBeforeTrim rune
		result         = make([]byte, 0, len(s))
	)
	if trimBefore {
		spaces = 1
	}

	for {
		if lex.eof() {
			// if we haven't seen a newline, add all the space we've been trimming.
			if !seenNewline && spaces > 0 && !trimAfter {
				result = append(result, s[lex.pos-spaces:lex.pos]...)
			}
			return result
		}
		var r = lex.next()

		// join lines
		if spaces > 0 {
			// more space, keep going
			if isSpace(r) {
				spaces++
				continue
			}
			if isEndOfLine(r) {
				spaces++
				seenNewline = true
				continue
			}

			// done with scanning a set of space.  actions:
			// - add the run of space to the result if we haven't seen a newline.
			// - add one space if the character before and after the newline are not tight joiners.
			// - else, ignore the space.
			switch {
			case !seenNewline:
				result = append(result, s[lex.lastpos-spaces:lex.lastpos]...)
			case seenNewline && !isTightJoiner(charBeforeTrim) && !isTightJoiner(r):
				result = append(result, ' ')
			default:
				// ignore the space
			}
			spaces = 0
			seenNewline = false
		}

		// begin to trim
		seenNewline = isEndOfLine(r)
		if isSpace(r) || seenNewline {
			spaces = 1
			charBeforeTrim = lastChar
			continue
		}

		// non-space characters are added verbatim.
		result = lex.emitRune(result)
		lastChar = r
	}
	return result
}

func isTightJoiner(r rune) bool {
	switch r {
	case 0, '<', '>':
		return true
	}
	return false
}
<commit_msg>Parse optimization - remove use of append() when processing raw text.<commit_after>package parse

import "unicode/utf8"

type rawtextlexer struct {
	str      string
	pos      int
	lastpos  int
	lastpos2 int
}

func (l *rawtextlexer) eof() bool {
	return l.pos >= len(l.str)
}
func (l *rawtextlexer) next() rune {
	l.lastpos2 = l.lastpos
	l.lastpos = l.pos
	var r, width = utf8.DecodeRuneInString(l.str[l.pos:])
	l.pos += width
	return r
}
func (l *rawtextlexer) backup() {
	l.pos = l.lastpos
	l.lastpos = l.lastpos2
	l.lastpos2 = 0
}

// rawtext processes the raw text found in templates:
// - trim leading/trailing whitespace if either:
//  a. the whitespace includes a newline, or
//  b. the caller tells us the surrounding content is a tight joiner by trimBefore/After
// - trim leading and trailing whitespace on each internal line
// - join lines with no space if '<' or '>' are on either side, else with 1 space.
func rawtext(s string, trimBefore, trimAfter bool) []byte {
	var lex = rawtextlexer{s, 0, 0, 0}
	var (
		spaces         = 0
		seenNewline    = trimBefore
		lastChar       rune
		charBeforeTrim rune
		result         = make([]byte, len(s))
		resultLen      = 0
	)
	if trimBefore {
		spaces = 1
	}

	for {
		if lex.eof() {
			// if we haven't seen a newline, add all the space we've been trimming.
			if !seenNewline && spaces > 0 && !trimAfter {
				for i := lex.pos - spaces; i < lex.pos; i++ {
					result[resultLen] = s[i]
					resultLen++
				}
			}
			return result[:resultLen]
		}
		var r = lex.next()

		// join lines
		if spaces > 0 {
			// more space, keep going
			if isSpace(r) {
				spaces++
				continue
			}
			if isEndOfLine(r) {
				spaces++
				seenNewline = true
				continue
			}

			// done with scanning a set of space.  actions:
			// - add the run of space to the result if we haven't seen a newline.
			// - add one space if the character before and after the newline are not tight joiners.
			// - else, ignore the space.
			switch {
			case !seenNewline:
				for i := lex.lastpos - spaces; i < lex.lastpos; i++ {
					result[resultLen] = s[i]
					resultLen++
				}
			case seenNewline && !isTightJoiner(charBeforeTrim) && !isTightJoiner(r):
				result[resultLen] = ' '
				resultLen++
			default:
				// ignore the space
			}
			spaces = 0
			seenNewline = false
		}

		// begin to trim
		seenNewline = isEndOfLine(r)
		if isSpace(r) || seenNewline {
			spaces = 1
			charBeforeTrim = lastChar
			continue
		}

		// non-space characters are added verbatim.
		for i := lex.lastpos; i < lex.pos; i++ {
			result[resultLen] = lex.str[i]
			resultLen++
		}
		lastChar = r
	}
	return result[:resultLen]
}

func isTightJoiner(r rune) bool {
	switch r {
	case 0, '<', '>':
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package packver

func Version() string {
	return "v0.2.3"
}
<commit_msg>Create later version of packver to make sure tests work<commit_after>package packver

func Version() string {
	// This file's purpose is to be pinned to a specific tag (by one of the
	// tests) and if that happens correctly, the below line will be instead
	// "v0.2.3", which it's obviously not if you're reading this comment.
	return "this version should not be returned"
}
<|endoftext|>


<commit_before>package borg

import (
  "testing"
)

func TestConst(t *testing.T) {
  exp, got := 7, Foo()
  if got != exp {
      t.Errorf("expected %d, got %#v\n", exp, got)
  }
}
<commit_msg>remove defunct test<commit_after><|endoftext|>


<commit_before>package policy

import (
	"encoding/json"
	"time"

	"github.com/scjalliance/resourceful/environment"
)

// Policy describes the matching conditions and rules for handling a particular
// resource.
//
// A policy is applied only if all of its conditions are matched.
type Policy struct {
	Criteria Criteria      `json:"criteria"`
	Limit    uint          `json:"limit"`
	Duration time.Duration `json:"duration"` // Time between scheduled re-evaluations of the policy condition
	// FIXME: JSON duration codec
}

// New returns a new policy with the given limit, duration and criteria.
func New(limit uint, duration time.Duration, criteria Criteria) Policy {
	return Policy{
		Criteria: criteria,
		Limit:    limit,
		Duration: duration,
	}
}

// MarshalJSON will encode the policy as JSON.
func (p *Policy) MarshalJSON() ([]byte, error) {
	type jsonPolicy Policy
	return json.Marshal(&struct {
		*jsonPolicy
		Duration string `json:"duration"`
	}{
		jsonPolicy: (*jsonPolicy)(p),
		Duration:   p.Duration.String(),
	})
}

// UnmarshalJSON will decode JSON policy data.
func (p *Policy) UnmarshalJSON(data []byte) error {
	type jsonPolicy Policy
	aux := &struct {
		*jsonPolicy
		Duration string `json:"duration"`
	}{
		jsonPolicy: (*jsonPolicy)(p),
	}
	var err error
	if err = json.Unmarshal(data, aux); err != nil {
		return err
	}
	if aux.Duration != "" {
		if p.Duration, err = time.ParseDuration(aux.Duration); err != nil {
			return err
		}
	}
	return nil
}

// Match returns true if the policy applies to the given resource, consumer and
// environment.
//
// All of the policy's conditions must match for the policy to be applied.
func (pol *Policy) Match(resource, consumer string, env environment.Environment) bool {
	return pol.Criteria.Match(resource, consumer, env)
}
<commit_msg>Made policy receivers consistent<commit_after>package policy

import (
	"encoding/json"
	"time"

	"github.com/scjalliance/resourceful/environment"
)

// Policy describes the matching conditions and rules for handling a particular
// resource.
//
// A policy is applied only if all of its conditions are matched.
type Policy struct {
	Criteria Criteria      `json:"criteria"`
	Limit    uint          `json:"limit"`
	Duration time.Duration `json:"duration"` // Time between scheduled re-evaluations of the policy condition
	// FIXME: JSON duration codec
}

// New returns a new policy with the given limit, duration and criteria.
func New(limit uint, duration time.Duration, criteria Criteria) Policy {
	return Policy{
		Criteria: criteria,
		Limit:    limit,
		Duration: duration,
	}
}

// MarshalJSON will encode the policy as JSON.
func (p *Policy) MarshalJSON() ([]byte, error) {
	type jsonPolicy Policy
	return json.Marshal(&struct {
		*jsonPolicy
		Duration string `json:"duration"`
	}{
		jsonPolicy: (*jsonPolicy)(p),
		Duration:   p.Duration.String(),
	})
}

// UnmarshalJSON will decode JSON policy data.
func (p *Policy) UnmarshalJSON(data []byte) error {
	type jsonPolicy Policy
	aux := &struct {
		*jsonPolicy
		Duration string `json:"duration"`
	}{
		jsonPolicy: (*jsonPolicy)(p),
	}
	var err error
	if err = json.Unmarshal(data, aux); err != nil {
		return err
	}
	if aux.Duration != "" {
		if p.Duration, err = time.ParseDuration(aux.Duration); err != nil {
			return err
		}
	}
	return nil
}

// Match returns true if the policy applies to the given resource, consumer and
// environment.
//
// All of the policy's conditions must match for the policy to be applied.
func (p *Policy) Match(resource, consumer string, env environment.Environment) bool {
	return p.Criteria.Match(resource, consumer, env)
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"
	"runtime"
	"strings"
)

var cmdEnv = &Command{
	Run:       runEnv,
	UsageLine: "env [var ...]",
	Short:     "print Go environment information",
	Long: `
Env prints Go environment information.

By default env prints information as a shell script
(on Windows, a batch file).  If one or more variable
names is given as arguments,  env prints the value of
each named variable on its own line.
	`,
}

type envVar struct {
	name, value string
}

func mkEnv() []envVar {
	var b builder
	b.init()

	env := []envVar{
		{"GOARCH", goarch},
		{"GOBIN", gobin},
		{"GOCHAR", archChar},
		{"GOEXE", exeSuffix},
		{"GOHOSTARCH", runtime.GOARCH},
		{"GOHOSTOS", runtime.GOOS},
		{"GOOS", goos},
		{"GOPATH", os.Getenv("GOPATH")},
		{"GORACE", os.Getenv("GORACE")},
		{"GOROOT", goroot},
		{"GOTOOLDIR", toolDir},

		// disable escape codes in clang errors
		{"TERM", "dumb"},
	}

	if goos != "plan9" {
		cmd := b.gccCmd(".")
		env = append(env, envVar{"CC", cmd[0]})
		env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
		cmd = b.gxxCmd(".")
		env = append(env, envVar{"CXX", cmd[0]})
	}

	if buildContext.CgoEnabled {
		env = append(env, envVar{"CGO_ENABLED", "1"})
	} else {
		env = append(env, envVar{"CGO_ENABLED", "0"})
	}

	return env
}

func findEnv(env []envVar, name string) string {
	for _, e := range env {
		if e.name == name {
			return e.value
		}
	}
	return ""
}

func runEnv(cmd *Command, args []string) {
	env := mkEnv()
	if len(args) > 0 {
		for _, name := range args {
			fmt.Printf("%s\n", findEnv(env, name))
		}
		return
	}

	for _, e := range env {
		if e.name != "TERM" {
			switch runtime.GOOS {
			default:
				fmt.Printf("%s=\"%s\"\n", e.name, e.value)
			case "plan9":
				fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
			case "windows":
				fmt.Printf("set %s=%s\n", e.name, e.value)
			}
		}
	}
}
<commit_msg>cmd/go: Plan 9 compatible "env" output<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"os"
	"runtime"
	"strings"
)

var cmdEnv = &Command{
	Run:       runEnv,
	UsageLine: "env [var ...]",
	Short:     "print Go environment information",
	Long: `
Env prints Go environment information.

By default env prints information as a shell script
(on Windows, a batch file).  If one or more variable
names is given as arguments,  env prints the value of
each named variable on its own line.
	`,
}

type envVar struct {
	name, value string
}

func mkEnv() []envVar {
	var b builder
	b.init()

	env := []envVar{
		{"GOARCH", goarch},
		{"GOBIN", gobin},
		{"GOCHAR", archChar},
		{"GOEXE", exeSuffix},
		{"GOHOSTARCH", runtime.GOARCH},
		{"GOHOSTOS", runtime.GOOS},
		{"GOOS", goos},
		{"GOPATH", os.Getenv("GOPATH")},
		{"GORACE", os.Getenv("GORACE")},
		{"GOROOT", goroot},
		{"GOTOOLDIR", toolDir},

		// disable escape codes in clang errors
		{"TERM", "dumb"},
	}

	if goos != "plan9" {
		cmd := b.gccCmd(".")
		env = append(env, envVar{"CC", cmd[0]})
		env = append(env, envVar{"GOGCCFLAGS", strings.Join(cmd[3:], " ")})
		cmd = b.gxxCmd(".")
		env = append(env, envVar{"CXX", cmd[0]})
	}

	if buildContext.CgoEnabled {
		env = append(env, envVar{"CGO_ENABLED", "1"})
	} else {
		env = append(env, envVar{"CGO_ENABLED", "0"})
	}

	return env
}

func findEnv(env []envVar, name string) string {
	for _, e := range env {
		if e.name == name {
			return e.value
		}
	}
	return ""
}

func runEnv(cmd *Command, args []string) {
	env := mkEnv()
	if len(args) > 0 {
		for _, name := range args {
			fmt.Printf("%s\n", findEnv(env, name))
		}
		return
	}

	for _, e := range env {
		if e.name != "TERM" {
			switch runtime.GOOS {
			default:
				fmt.Printf("%s=\"%s\"\n", e.name, e.value)
			case "plan9":
				if strings.IndexByte(e.value, '\x00') < 0 {
					fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
				} else {
					v := strings.Split(e.value, "\x00")
					fmt.Printf("%s=(", e.name)
					for x, s := range v {
						if x > 0 {
							fmt.Printf(" ")
						}
						fmt.Printf("%s", s)
					}
					fmt.Printf(")\n")
				}
			case "windows":
				fmt.Printf("set %s=%s\n", e.name, e.value)
			}
		}
	}
}
<|endoftext|>


<commit_before>package goose

import (
	"database/sql"
	"fmt"
	"os"
	"path/filepath"

	"github.com/kylelemons/go-gypsy/yaml"
	"github.com/lib/pq"
)

// DBDriver encapsulates the info needed to work with
// a specific database driver
type DBDriver struct {
	Name    string
	OpenStr string
	Import  string
	Dialect SqlDialect
}

type DBConf struct {
	MigrationsDir string
	Env           string
	Driver        DBDriver
	PgSchema      string
}

// extract configuration details from the given file
func NewDBConf(p, env string, pgschema string) (*DBConf, error) {
	cfgFile := filepath.Join(p, "dbconf.yml")

	f, err := yaml.ReadFile(cfgFile)
	if err != nil {
		return nil, err
	}

	drv, err := f.Get(fmt.Sprintf("%s.driver", env))
	if err != nil {
		return nil, err
	}
	drv = os.ExpandEnv(drv)

	open, err := f.Get(fmt.Sprintf("%s.open", env))
	if err != nil {
		return nil, err
	}
	open = os.ExpandEnv(open)

	// Automatically parse postgres urls
	if drv == "postgres" {
		// Assumption: If we can parse the URL, we should
		if parsedURL, err := pq.ParseURL(open); err == nil && parsedURL != "" {
			open = parsedURL
		}
	}

	d := newDBDriver(drv, open)

	// allow the configuration to override the Import for this driver
	if imprt, err := f.Get(fmt.Sprintf("%s.import", env)); err == nil {
		d.Import = imprt
	}

	// allow the configuration to override the Dialect for this driver
	if dialect, err := f.Get(fmt.Sprintf("%s.dialect", env)); err == nil {
		d.Dialect = dialectByName(dialect)
	}

	if !d.IsValid() {
		return nil, fmt.Errorf("goose: invalid driver configuration: %v", d)
	}

	return &DBConf{
		MigrationsDir: filepath.Join(p, "migrations"),
		Env:           env,
		Driver:        d,
		PgSchema:      pgschema,
	}, nil
}

// Create a new DBDriver and populate driver specific
// fields for drivers that we know about.
// Further customization may be done in NewDBConf
func newDBDriver(name, open string) DBDriver {

	d := DBDriver{
		Name:    name,
		OpenStr: open,
	}

	switch name {
	case "postgres":
		d.Import = "github.com/kevinburke/goose/Godeps/_workspace/src/github.com/lib/pq"
		d.Dialect = &PostgresDialect{}

	case "mymysql":
		d.Import = "github.com/kevinburke/goose/Godeps/_workspace/src/github.com/ziutek/mymysql/godrv"
		d.Dialect = &MySqlDialect{}

	case "mysql":
		d.Import = "github.com/kevinburke/goose/Godeps/_workspace/src/github.com/go-sql-driver/mysql"
		d.Dialect = &MySqlDialect{}

	case "sqlite3":
		d.Import = "github.com/kevinburke/goose/Godeps/_workspace/src/github.com/mattn/go-sqlite3"
		d.Dialect = &Sqlite3Dialect{}
	}

	return d
}

// ensure we have enough info about this driver
func (drv *DBDriver) IsValid() bool {
	return len(drv.Import) > 0 && drv.Dialect != nil
}

// OpenDBFromDBConf wraps database/sql.DB.Open() and configures
// the newly opened DB based on the given DBConf.
//
// Callers must Close() the returned DB.
func OpenDBFromDBConf(conf *DBConf) (*sql.DB, error) {
	db, err := sql.Open(conf.Driver.Name, conf.Driver.OpenStr)
	if err != nil {
		return nil, err
	}

	// if a postgres schema has been specified, apply it
	if conf.Driver.Name == "postgres" && conf.PgSchema != "" {
		if _, err := db.Exec("SET search_path TO " + conf.PgSchema); err != nil {
			return nil, err
		}
	}

	return db, nil
}
<commit_msg>lib/goose: update Import statements<commit_after>package goose

import (
	"database/sql"
	"fmt"
	"os"
	"path/filepath"

	"github.com/kylelemons/go-gypsy/yaml"
	"github.com/lib/pq"
)

// DBDriver encapsulates the info needed to work with
// a specific database driver
type DBDriver struct {
	Name    string
	OpenStr string
	Import  string
	Dialect SqlDialect
}

type DBConf struct {
	MigrationsDir string
	Env           string
	Driver        DBDriver
	PgSchema      string
}

// extract configuration details from the given file
func NewDBConf(p, env string, pgschema string) (*DBConf, error) {
	cfgFile := filepath.Join(p, "dbconf.yml")

	f, err := yaml.ReadFile(cfgFile)
	if err != nil {
		return nil, err
	}

	drv, err := f.Get(fmt.Sprintf("%s.driver", env))
	if err != nil {
		return nil, err
	}
	drv = os.ExpandEnv(drv)

	open, err := f.Get(fmt.Sprintf("%s.open", env))
	if err != nil {
		return nil, err
	}
	open = os.ExpandEnv(open)

	// Automatically parse postgres urls
	if drv == "postgres" {
		// Assumption: If we can parse the URL, we should
		if parsedURL, err := pq.ParseURL(open); err == nil && parsedURL != "" {
			open = parsedURL
		}
	}

	d := newDBDriver(drv, open)

	// allow the configuration to override the Import for this driver
	if imprt, err := f.Get(fmt.Sprintf("%s.import", env)); err == nil {
		d.Import = imprt
	}

	// allow the configuration to override the Dialect for this driver
	if dialect, err := f.Get(fmt.Sprintf("%s.dialect", env)); err == nil {
		d.Dialect = dialectByName(dialect)
	}

	if !d.IsValid() {
		return nil, fmt.Errorf("goose: invalid driver configuration: %v", d)
	}

	return &DBConf{
		MigrationsDir: filepath.Join(p, "migrations"),
		Env:           env,
		Driver:        d,
		PgSchema:      pgschema,
	}, nil
}

// Create a new DBDriver and populate driver specific
// fields for drivers that we know about.
// Further customization may be done in NewDBConf
func newDBDriver(name, open string) DBDriver {

	d := DBDriver{
		Name:    name,
		OpenStr: open,
	}

	switch name {
	case "postgres":
		d.Import = "github.com/kevinburke/goose/vendor/github.com/lib/pq"
		d.Dialect = &PostgresDialect{}

	case "mymysql":
		d.Import = "github.com/kevinburke/goose/vendor/github.com/ziutek/mymysql/godrv"
		d.Dialect = &MySqlDialect{}

	case "mysql":
		d.Import = "github.com/kevinburke/goose/vendor/github.com/go-sql-driver/mysql"
		d.Dialect = &MySqlDialect{}

	case "sqlite3":
		d.Import = "github.com/kevinburke/goose/vendor/github.com/mattn/go-sqlite3"
		d.Dialect = &Sqlite3Dialect{}
	}

	return d
}

// ensure we have enough info about this driver
func (drv *DBDriver) IsValid() bool {
	return len(drv.Import) > 0 && drv.Dialect != nil
}

// OpenDBFromDBConf wraps database/sql.DB.Open() and configures
// the newly opened DB based on the given DBConf.
//
// Callers must Close() the returned DB.
func OpenDBFromDBConf(conf *DBConf) (*sql.DB, error) {
	db, err := sql.Open(conf.Driver.Name, conf.Driver.OpenStr)
	if err != nil {
		return nil, err
	}

	// if a postgres schema has been specified, apply it
	if conf.Driver.Name == "postgres" && conf.PgSchema != "" {
		if _, err := db.Exec("SET search_path TO " + conf.PgSchema); err != nil {
			return nil, err
		}
	}

	return db, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package ticketbuyer

import (
	"sync"

	"github.com/decred/dcrwallet/wallet"
)

// PurchaseManager is the main handler of websocket notifications to
// pass to the purchaser and internal quit notifications.
type PurchaseManager struct {
	w          *wallet.Wallet
	purchaser  *TicketPurchaser
	ntfnChan   <-chan *wallet.MainTipChangedNotification
	passphrase []byte
	wg         sync.WaitGroup
	quitMtx    sync.Mutex
	quit       chan struct{}
}

// NewPurchaseManager creates a new PurchaseManager.
func NewPurchaseManager(w *wallet.Wallet, purchaser *TicketPurchaser,
	ntfnChan <-chan *wallet.MainTipChangedNotification, passphrase []byte) *PurchaseManager {
	return &PurchaseManager{
		w:          w,
		purchaser:  purchaser,
		ntfnChan:   ntfnChan,
		passphrase: passphrase,
		quit:       make(chan struct{}),
	}
}

// purchase purchases the tickets for the given block height.
func (p *PurchaseManager) purchase(height int64) {
	err := p.w.Unlock(p.passphrase, nil)
	if err != nil {
		log.Errorf("Failed to purchase tickets this round: %v", err)
		return
	}
	purchaseInfo, err := p.purchaser.Purchase(height)
	if err != nil {
		log.Errorf("Failed to purchase tickets this round: %v", err)
		return
	}
	// Since we don't know if the wallet had been unlocked before we unlocked
	// it, avoid locking it here, even though we don't need it to remain
	// unlocked.
	log.Debugf("Purchased %v tickets this round", purchaseInfo.Purchased)
}

// Purchaser returns the ticket buyer instance associated with the purchase
// manager.
func (p *PurchaseManager) Purchaser() *TicketPurchaser {
	return p.purchaser
}

// NotificationHandler handles notifications, which trigger ticket purchases.
func (p *PurchaseManager) NotificationHandler() {
	p.quitMtx.Lock()
	quit := p.quit
	p.quitMtx.Unlock()

	s1, s2 := make(chan struct{}), make(chan struct{})
	close(s1) // unblock first worker
out:
	for {
		select {
		case v, ok := <-p.ntfnChan:
			if !ok {
				break out
			}
			p.wg.Add(1)
			go func(s1, s2 chan struct{}) {
				defer p.wg.Done()
				select {
				case <-s1: // wait for previous worker to finish
				case <-quit:
					return
				}
				// Purchase tickets for each attached block, not just for the
				// update to the main chain.  This is probably not optimal but
				// it matches how dcrticketbuyer worked.
				for h := v.NewHeight - int32(len(v.AttachedBlocks)) + 1; h <= v.NewHeight; h++ {
					p.purchase(int64(h))
				}

				close(s2) // unblock next worker
			}(s1, s2)
			s1, s2 = s2, make(chan struct{})
		case <-quit:
			break out
		}
	}
	p.wg.Done()
}

// Start starts the purchase manager goroutines.
func (p *PurchaseManager) Start() {
	p.wg.Add(1)
	go p.NotificationHandler()

	log.Infof("Starting ticket buyer")
}

// WaitForShutdown blocks until all purchase manager goroutines have finished executing.
func (p *PurchaseManager) WaitForShutdown() {
	p.wg.Wait()
}

// Stop signals all purchase manager goroutines to shutdown.
func (p *PurchaseManager) Stop() {
	p.quitMtx.Lock()
	quit := p.quit

	log.Infof("Stopping ticket buyer")

	select {
	case <-quit:
	default:
		close(quit)
	}
	p.quitMtx.Unlock()
}
<commit_msg>ticketbuyer: mitigate older blocks on reconnect/resync. (#949)<commit_after>// Copyright (c) 2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package ticketbuyer

import (
	"sync"
	"time"

	"github.com/decred/dcrwallet/wallet"
)

// PurchaseManager is the main handler of websocket notifications to
// pass to the purchaser and internal quit notifications.
type PurchaseManager struct {
	w          *wallet.Wallet
	purchaser  *TicketPurchaser
	ntfnChan   <-chan *wallet.MainTipChangedNotification
	passphrase []byte
	wg         sync.WaitGroup
	quitMtx    sync.Mutex
	quit       chan struct{}
}

// NewPurchaseManager creates a new PurchaseManager.
func NewPurchaseManager(w *wallet.Wallet, purchaser *TicketPurchaser,
	ntfnChan <-chan *wallet.MainTipChangedNotification, passphrase []byte) *PurchaseManager {
	return &PurchaseManager{
		w:          w,
		purchaser:  purchaser,
		ntfnChan:   ntfnChan,
		passphrase: passphrase,
		quit:       make(chan struct{}),
	}
}

// purchase purchases the tickets for the given block height.
func (p *PurchaseManager) purchase(height int64) {
	err := p.w.Unlock(p.passphrase, nil)
	if err != nil {
		log.Errorf("Failed to purchase tickets this round: %v", err)
		return
	}
	purchaseInfo, err := p.purchaser.Purchase(height)
	if err != nil {
		log.Errorf("Failed to purchase tickets this round: %v", err)
		return
	}
	// Since we don't know if the wallet had been unlocked before we unlocked
	// it, avoid locking it here, even though we don't need it to remain
	// unlocked.
	log.Debugf("Purchased %v tickets this round", purchaseInfo.Purchased)
}

// Purchaser returns the ticket buyer instance associated with the purchase
// manager.
func (p *PurchaseManager) Purchaser() *TicketPurchaser {
	return p.purchaser
}

// NotificationHandler handles notifications, which trigger ticket purchases.
func (p *PurchaseManager) NotificationHandler() {
	p.quitMtx.Lock()
	quit := p.quit
	p.quitMtx.Unlock()

	s1, s2 := make(chan struct{}), make(chan struct{})
	close(s1) // unblock first worker
out:
	for {
		select {
		case v, ok := <-p.ntfnChan:
			if !ok {
				break out
			}
			p.wg.Add(1)
			go func(s1, s2 chan struct{}) {
				defer p.wg.Done()
				select {
				case <-s1: // wait for previous worker to finish
				case <-quit:
					return
				}

				defer close(s2) // defer unblocking next worker
				blockHash := v.AttachedBlocks[len(v.AttachedBlocks)-1]
				blockInfo, err := p.w.BlockInfo(wallet.NewBlockIdentifierFromHash(blockHash))
				if err != nil {
					log.Errorf("failed to get block info using block hash %s", blockHash.String())
					return
				}

				// only try buying tickets on blocks 5 minutes old or less
				if time.Now().Unix()-blockInfo.Timestamp <= int64(p.w.ChainParams().TargetTimePerBlock.Seconds()) {
					p.purchase(int64(v.NewHeight))
				}
			}(s1, s2)
			s1, s2 = s2, make(chan struct{})
		case <-quit:
			break out
		}
	}
	p.wg.Done()
}

// Start starts the purchase manager goroutines.
func (p *PurchaseManager) Start() {
	p.wg.Add(1)
	go p.NotificationHandler()

	log.Infof("Starting ticket buyer")
}

// WaitForShutdown blocks until all purchase manager goroutines have finished executing.
func (p *PurchaseManager) WaitForShutdown() {
	p.wg.Wait()
}

// Stop signals all purchase manager goroutines to shutdown.
func (p *PurchaseManager) Stop() {
	p.quitMtx.Lock()
	quit := p.quit

	log.Infof("Stopping ticket buyer")

	select {
	case <-quit:
	default:
		close(quit)
	}
	p.quitMtx.Unlock()
}
<|endoftext|>


<commit_before>// Copyright 2016 The Linux Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package specs

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 1
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-rc3"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>version: bump master back to -dev<commit_after>// Copyright 2016 The Linux Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package specs

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 1
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 0
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 0

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-rc3-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>