<commit_before>// Package prop provides the Properties struct which can be used to implement
// org.freedesktop.DBus.Properties.
package prop

import (
	"github.com/godbus/dbus"
	"github.com/godbus/dbus/introspect"
	"sync"
)

// EmitType controls how org.freedesktop.DBus.Properties.PropertiesChanged is
// emitted for a property. If it is EmitTrue, the signal is emitted. If it is
// EmitInvalidates, the signal is also emitted, but the new value of the property
// is not disclosed.
type EmitType byte

const (
	EmitFalse EmitType = iota
	EmitTrue
	EmitInvalidates
)

// ErrIfaceNotFound is the error returned to peers who try to access properties
// on interfaces that aren't found.
var ErrIfaceNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil)

// ErrPropNotFound is the error returned to peers trying to access properties
// that aren't found.
var ErrPropNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil)

// ErrReadOnly is the error returned to peers trying to set a read-only
// property.
var ErrReadOnly = dbus.NewError("org.freedesktop.DBus.Properties.Error.ReadOnly", nil)

// ErrInvalidArg is returned to peers if the type of the property that is being
// changed and the argument don't match.
var ErrInvalidArg = dbus.NewError("org.freedesktop.DBus.Properties.Error.InvalidArg", nil)

// The introspection data for the org.freedesktop.DBus.Properties interface.
var IntrospectData = introspect.Interface{
	Name: "org.freedesktop.DBus.Properties",
	Methods: []introspect.Method{
		{
			Name: "Get",
			Args: []introspect.Arg{
				{Name: "interface", Type: "s", Direction: "in"},
				{Name: "property", Type: "s", Direction: "in"},
				{Name: "value", Type: "v", Direction: "out"},
			},
		},
		{
			Name: "GetAll",
			Args: []introspect.Arg{
				{Name: "interface", Type: "s", Direction: "in"},
				{Name: "props", Type: "a{sv}", Direction: "out"},
			},
		},
		{
			Name: "Set",
			Args: []introspect.Arg{
				{Name: "interface", Type: "s", Direction: "in"},
				{Name: "property", Type: "s", Direction: "in"},
				{Name: "value", Type: "v", Direction: "in"},
			},
		},
	},
	Signals: []introspect.Signal{
		{
			Name: "PropertiesChanged",
			Args: []introspect.Arg{
				{Name: "interface", Type: "s", Direction: "out"},
				{Name: "changed_properties", Type: "a{sv}", Direction: "out"},
				{Name: "invalidates_properties", Type: "as", Direction: "out"},
			},
		},
	},
}

// The introspection data for the org.freedesktop.DBus.Properties interface, as
// a string.
const IntrospectDataString = `
	<interface name="org.freedesktop.DBus.Properties">
		<method name="Get">
			<arg name="interface" direction="in" type="s"/>
			<arg name="property" direction="in" type="s"/>
			<arg name="value" direction="out" type="v"/>
		</method>
		<method name="GetAll">
			<arg name="interface" direction="in" type="s"/>
			<arg name="props" direction="out" type="a{sv}"/>
		</method>
		<method name="Set">
			<arg name="interface" direction="in" type="s"/>
			<arg name="property" direction="in" type="s"/>
			<arg name="value" direction="in" type="v"/>
		</method>
		<signal name="PropertiesChanged">
			<arg name="interface" type="s"/>
			<arg name="changed_properties" type="a{sv}"/>
			<arg name="invalidates_properties" type="as"/>
		</signal>
	</interface>
`

// Prop represents a single property. It is used for creating a Properties
// value.
type Prop struct {
	// Initial value. Must be a DBus-representable type.
	Value interface{}

	// If true, the value can be modified by calls to Set.
	Writable bool

	// Controls how org.freedesktop.DBus.Properties.PropertiesChanged is
	// emitted if this property changes.
	Emit EmitType

	// If not nil, anytime this property is changed by Set, this function is
	// called with an appropiate Change as its argument. If the returned error
	// is not nil, it is sent back to the caller of Set and the property is not
	// changed.
	Callback func(*Change) *dbus.Error
}

// Change represents a change of a property by a call to Set.
type Change struct {
	Props *Properties
	Iface string
	Name  string
	Value interface{}
}

// Properties is a set of values that can be made available to the message bus
// using the org.freedesktop.DBus.Properties interface. It is safe for
// concurrent use by multiple goroutines.
type Properties struct {
	m    map[string]map[string]*Prop
	mut  sync.RWMutex
	conn *dbus.Conn
	path dbus.ObjectPath
}

// New returns a new Properties structure that manages the given properties.
// The key for the first-level map of props is the name of the interface; the
// second-level key is the name of the property. The returned structure will be
// exported as org.freedesktop.DBus.Properties on path.
func New(conn *dbus.Conn, path dbus.ObjectPath, props map[string]map[string]*Prop) *Properties {
	p := &Properties{m: props, conn: conn, path: path}
	conn.Export(p, path, "org.freedesktop.DBus.Properties")
	return p
}

// Get implements org.freedesktop.DBus.Properties.Get.
func (p *Properties) Get(iface, property string) (dbus.Variant, *dbus.Error) {
	p.mut.RLock()
	defer p.mut.RUnlock()
	m, ok := p.m[iface]
	if !ok {
		return dbus.Variant{}, ErrIfaceNotFound
	}
	prop, ok := m[property]
	if !ok {
		return dbus.Variant{}, ErrPropNotFound
	}
	return dbus.MakeVariant(prop.Value), nil
}

// GetAll implements org.freedesktop.DBus.Properties.GetAll.
func (p *Properties) GetAll(iface string) (map[string]dbus.Variant, *dbus.Error) {
	p.mut.RLock()
	defer p.mut.RUnlock()
	m, ok := p.m[iface]
	if !ok {
		return nil, ErrIfaceNotFound
	}
	rm := make(map[string]dbus.Variant, len(m))
	for k, v := range m {
		rm[k] = dbus.MakeVariant(v.Value)
	}
	return rm, nil
}

// GetMust returns the value of the given property and panics if either the
// interface or the property name are invalid.
func (p *Properties) GetMust(iface, property string) interface{} {
	p.mut.RLock()
	defer p.mut.RUnlock()
	return p.m[iface][property].Value
}

// Introspection returns the introspection data that represents the properties
// of iface.
func (p *Properties) Introspection(iface string) []introspect.Property {
	p.mut.RLock()
	defer p.mut.RUnlock()
	m := p.m[iface]
	s := make([]introspect.Property, 0, len(m))
	for k, v := range m {
		p := introspect.Property{Name: k, Type: dbus.SignatureOf(v.Value).String()}
		if v.Writable {
			p.Access = "readwrite"
		} else {
			p.Access = "read"
		}
		s = append(s, p)
	}
	return s
}

// set sets the given property and emits PropertyChanged if appropiate. p.mut
// must already be locked.
func (p *Properties) set(iface, property string, v interface{}) {
	prop := p.m[iface][property]
	prop.Value = v
	switch prop.Emit {
	case EmitFalse:
		// do nothing
	case EmitInvalidates:
		p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
			iface, map[string]dbus.Variant{}, []string{property})
	case EmitTrue:
		p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
			iface, map[string]dbus.Variant{property: dbus.MakeVariant(v)},
			[]string{})
	default:
		panic("invalid value for EmitType")
	}
}

// Set implements org.freedesktop.Properties.Set.
func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error {
	p.mut.Lock()
	defer p.mut.Unlock()
	m, ok := p.m[iface]
	if !ok {
		return ErrIfaceNotFound
	}
	prop, ok := m[property]
	if !ok {
		return ErrPropNotFound
	}
	if !prop.Writable {
		return ErrReadOnly
	}
	if newv.Signature() != dbus.SignatureOf(prop.Value) {
		return ErrInvalidArg
	}
	if prop.Callback != nil {
		err := prop.Callback(&Change{p, iface, property, newv.Value()})
		if err != nil {
			return err
		}
	}
	p.set(iface, property, newv.Value())
	return nil
}

// SetMust sets the value of the given property and panics if the interface or
// the property name are invalid.
func (p *Properties) SetMust(iface, property string, v interface{}) {
	p.mut.Lock()
	p.set(iface, property, v)
	p.mut.Unlock()
}
<commit_msg>Handle prop errors properly<commit_after>// Package prop provides the Properties struct which can be used to implement
// org.freedesktop.DBus.Properties.
package prop

import (
	"sync"

	"github.com/godbus/dbus"
	"github.com/godbus/dbus/introspect"
)

// EmitType controls how org.freedesktop.DBus.Properties.PropertiesChanged is
// emitted for a property. If it is EmitTrue, the signal is emitted. If it is
// EmitInvalidates, the signal is also emitted, but the new value of the property
// is not disclosed.
type EmitType byte

const (
	EmitFalse EmitType = iota
	EmitTrue
	EmitInvalidates
)

// ErrIfaceNotFound is the error returned to peers who try to access properties
// on interfaces that aren't found.
var ErrIfaceNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil)

// ErrPropNotFound is the error returned to peers trying to access properties
// that aren't found.
var ErrPropNotFound = dbus.NewError("org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil)

// ErrReadOnly is the error returned to peers trying to set a read-only
// property.
var ErrReadOnly = dbus.NewError("org.freedesktop.DBus.Properties.Error.ReadOnly", nil)

// ErrInvalidArg is returned to peers if the type of the property that is being
// changed and the argument don't match.
var ErrInvalidArg = dbus.NewError("org.freedesktop.DBus.Properties.Error.InvalidArg", nil)

// The introspection data for the org.freedesktop.DBus.Properties interface.
var IntrospectData = introspect.Interface{
	Name: "org.freedesktop.DBus.Properties",
	Methods: []introspect.Method{
		{
			Name: "Get",
			Args: []introspect.Arg{
				{Name: "interface", Type: "s", Direction: "in"},
				{Name: "property", Type: "s", Direction: "in"},
				{Name: "value", Type: "v", Direction: "out"},
			},
		},
		{
			Name: "GetAll",
			Args: []introspect.Arg{
				{Name: "interface", Type: "s", Direction: "in"},
				{Name: "props", Type: "a{sv}", Direction: "out"},
			},
		},
		{
			Name: "Set",
			Args: []introspect.Arg{
				{Name: "interface", Type: "s", Direction: "in"},
				{Name: "property", Type: "s", Direction: "in"},
				{Name: "value", Type: "v", Direction: "in"},
			},
		},
	},
	Signals: []introspect.Signal{
		{
			Name: "PropertiesChanged",
			Args: []introspect.Arg{
				{Name: "interface", Type: "s", Direction: "out"},
				{Name: "changed_properties", Type: "a{sv}", Direction: "out"},
				{Name: "invalidates_properties", Type: "as", Direction: "out"},
			},
		},
	},
}

// The introspection data for the org.freedesktop.DBus.Properties interface, as
// a string.
const IntrospectDataString = `
	<interface name="org.freedesktop.DBus.Properties">
		<method name="Get">
			<arg name="interface" direction="in" type="s"/>
			<arg name="property" direction="in" type="s"/>
			<arg name="value" direction="out" type="v"/>
		</method>
		<method name="GetAll">
			<arg name="interface" direction="in" type="s"/>
			<arg name="props" direction="out" type="a{sv}"/>
		</method>
		<method name="Set">
			<arg name="interface" direction="in" type="s"/>
			<arg name="property" direction="in" type="s"/>
			<arg name="value" direction="in" type="v"/>
		</method>
		<signal name="PropertiesChanged">
			<arg name="interface" type="s"/>
			<arg name="changed_properties" type="a{sv}"/>
			<arg name="invalidates_properties" type="as"/>
		</signal>
	</interface>
`

// Prop represents a single property. It is used for creating a Properties
// value.
type Prop struct {
	// Initial value. Must be a DBus-representable type.
	Value interface{}

	// If true, the value can be modified by calls to Set.
	Writable bool

	// Controls how org.freedesktop.DBus.Properties.PropertiesChanged is
	// emitted if this property changes.
	Emit EmitType

	// If not nil, anytime this property is changed by Set, this function is
	// called with an appropiate Change as its argument. If the returned error
	// is not nil, it is sent back to the caller of Set and the property is not
	// changed.
	Callback func(*Change) *dbus.Error
}

// Change represents a change of a property by a call to Set.
type Change struct {
	Props *Properties
	Iface string
	Name  string
	Value interface{}
}

// Properties is a set of values that can be made available to the message bus
// using the org.freedesktop.DBus.Properties interface. It is safe for
// concurrent use by multiple goroutines.
type Properties struct {
	m    map[string]map[string]*Prop
	mut  sync.RWMutex
	conn *dbus.Conn
	path dbus.ObjectPath
}

// New falls back to Export, but it returns nil if properties export fails,
// swallowing the error, shouldn't be used.
//
// Deprecated: use Export instead.
func New(conn *dbus.Conn, path dbus.ObjectPath, props map[string]map[string]*Prop) *Properties {
	p, err := Export(conn, path, props)
	if err != nil {
		return nil
	}
	return p
}

// Export returns a new Properties structure that manages the given properties.
// The key for the first-level map of props is the name of the interface; the
// second-level key is the name of the property. The returned structure will be
// exported as org.freedesktop.DBus.Properties on path.
func Export(
	conn *dbus.Conn, path dbus.ObjectPath, props map[string]map[string]*Prop,
) (*Properties, error) {
	p := &Properties{m: props, conn: conn, path: path}
	if err := conn.Export(p, path, "org.freedesktop.DBus.Properties"); err != nil {
		return nil, err
	}
	return p, nil
}

// Get implements org.freedesktop.DBus.Properties.Get.
func (p *Properties) Get(iface, property string) (dbus.Variant, *dbus.Error) {
	p.mut.RLock()
	defer p.mut.RUnlock()
	m, ok := p.m[iface]
	if !ok {
		return dbus.Variant{}, ErrIfaceNotFound
	}
	prop, ok := m[property]
	if !ok {
		return dbus.Variant{}, ErrPropNotFound
	}
	return dbus.MakeVariant(prop.Value), nil
}

// GetAll implements org.freedesktop.DBus.Properties.GetAll.
func (p *Properties) GetAll(iface string) (map[string]dbus.Variant, *dbus.Error) {
	p.mut.RLock()
	defer p.mut.RUnlock()
	m, ok := p.m[iface]
	if !ok {
		return nil, ErrIfaceNotFound
	}
	rm := make(map[string]dbus.Variant, len(m))
	for k, v := range m {
		rm[k] = dbus.MakeVariant(v.Value)
	}
	return rm, nil
}

// GetMust returns the value of the given property and panics if either the
// interface or the property name are invalid.
func (p *Properties) GetMust(iface, property string) interface{} {
	p.mut.RLock()
	defer p.mut.RUnlock()
	return p.m[iface][property].Value
}

// Introspection returns the introspection data that represents the properties
// of iface.
func (p *Properties) Introspection(iface string) []introspect.Property {
	p.mut.RLock()
	defer p.mut.RUnlock()
	m := p.m[iface]
	s := make([]introspect.Property, 0, len(m))
	for k, v := range m {
		p := introspect.Property{Name: k, Type: dbus.SignatureOf(v.Value).String()}
		if v.Writable {
			p.Access = "readwrite"
		} else {
			p.Access = "read"
		}
		s = append(s, p)
	}
	return s
}

// set sets the given property and emits PropertyChanged if appropiate. p.mut
// must already be locked.
func (p *Properties) set(iface, property string, v interface{}) error {
	prop := p.m[iface][property]
	prop.Value = v
	switch prop.Emit {
	case EmitFalse:
		return nil // do nothing
	case EmitInvalidates:
		return p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
			iface, map[string]dbus.Variant{}, []string{property})
	case EmitTrue:
		return p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
			iface, map[string]dbus.Variant{property: dbus.MakeVariant(v)},
			[]string{})
	default:
		panic("invalid value for EmitType")
	}
}

// Set implements org.freedesktop.Properties.Set.
func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error {
	p.mut.Lock()
	defer p.mut.Unlock()
	m, ok := p.m[iface]
	if !ok {
		return ErrIfaceNotFound
	}
	prop, ok := m[property]
	if !ok {
		return ErrPropNotFound
	}
	if !prop.Writable {
		return ErrReadOnly
	}
	if newv.Signature() != dbus.SignatureOf(prop.Value) {
		return ErrInvalidArg
	}
	if prop.Callback != nil {
		err := prop.Callback(&Change{p, iface, property, newv.Value()})
		if err != nil {
			return err
		}
	}
	if err := p.set(iface, property, newv.Value()); err != nil {
		return dbus.MakeFailedError(err)
	}
	return nil
}

// SetMust sets the value of the given property and panics if the interface or
// the property name are invalid.
func (p *Properties) SetMust(iface, property string, v interface{}) {
	p.mut.Lock()
	defer p.mut.Unlock() // unlock in case of panic
	if err := p.set(iface, property, v); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package raft

import (
	"encoding/json"
	golog "log"
)

type Interface interface {
	Step(m Message)
	Msgs() []Message
}

type tick int

type config struct {
	NodeId  int
	Address string
}

type Node struct {
	// election timeout and heartbeat timeout in tick
	election  tick
	heartbeat tick

	// elapsed ticks after the last reset
	elapsed tick
	sm      *stateMachine
}

func New(id int, heartbeat, election tick) *Node {
	if election < heartbeat*3 {
		panic("election is least three times as heartbeat [election: %d, heartbeat: %d]")
	}

	n := &Node{
		heartbeat: heartbeat,
		election:  election,
		sm:        newStateMachine(id, []int{id}),
	}

	return n
}

func Dictate(n *Node) *Node {
	n.Step(Message{Type: msgHup})
	n.Add(n.Id())
	return n
}

func (n *Node) Id() int { return n.sm.id }

// Propose asynchronously proposes data be applied to the underlying state machine.
func (n *Node) Propose(data []byte) { n.propose(normal, data) }

func (n *Node) propose(t int, data []byte) {
	n.Step(Message{Type: msgProp, Entries: []Entry{{Type: t, Data: data}}})
}

func (n *Node) Add(id int) { n.updateConf(configAdd, &config{NodeId: id}) }

func (n *Node) Remove(id int) { n.updateConf(configRemove, &config{NodeId: id}) }

func (n *Node) Msgs() []Message { return n.sm.Msgs() }

func (n *Node) Step(m Message) {
	l := len(n.sm.msgs)
	n.sm.Step(m)
	for _, m := range n.sm.msgs[l:] {
		// reset elapsed in two cases:
		// msgAppResp -> heard from the leader of the same term
		// msgVoteResp with grant -> heard from the candidate the node voted for
		switch m.Type {
		case msgAppResp:
			n.elapsed = 0
		case msgVoteResp:
			if m.Index >= 0 {
				n.elapsed = 0
			}
		}
	}
}

// Next applies all available committed commands.
func (n *Node) Next() []Entry {
	ents := n.sm.nextEnts()
	for i := range ents {
		switch ents[i].Type {
		case normal:
		case configAdd:
			c := new(config)
			if err := json.Unmarshal(ents[i].Data, c); err != nil {
				golog.Println(err)
				continue
			}
			n.sm.Add(c.NodeId)
		case configRemove:
			c := new(config)
			if err := json.Unmarshal(ents[i].Data, c); err != nil {
				golog.Println(err)
				continue
			}
			n.sm.Remove(c.NodeId)
		default:
			panic("unexpected entry type")
		}
	}
	return ents
}

// Tick triggers the node to do a tick.
// If the current elapsed is greater or equal than the timeout,
// node will send corresponding message to the statemachine.
func (n *Node) Tick() {
	timeout, msgType := n.election, msgHup
	if n.sm.state == stateLeader {
		timeout, msgType = n.heartbeat, msgBeat
	}
	if n.elapsed >= timeout {
		n.Step(Message{Type: msgType})
		n.elapsed = 0
	} else {
		n.elapsed++
	}
}

func (n *Node) updateConf(t int, c *config) {
	data, err := json.Marshal(c)
	if err != nil {
		panic(err)
	}
	n.propose(t, data)
}
<commit_msg>raft: correct comment for n.Next<commit_after>package raft

import (
	"encoding/json"
	golog "log"
)

type Interface interface {
	Step(m Message)
	Msgs() []Message
}

type tick int

type config struct {
	NodeId  int
	Address string
}

type Node struct {
	// election timeout and heartbeat timeout in tick
	election  tick
	heartbeat tick

	// elapsed ticks after the last reset
	elapsed tick
	sm      *stateMachine
}

func New(id int, heartbeat, election tick) *Node {
	if election < heartbeat*3 {
		panic("election is least three times as heartbeat [election: %d, heartbeat: %d]")
	}

	n := &Node{
		heartbeat: heartbeat,
		election:  election,
		sm:        newStateMachine(id, []int{id}),
	}

	return n
}

func Dictate(n *Node) *Node {
	n.Step(Message{Type: msgHup})
	n.Add(n.Id())
	return n
}

func (n *Node) Id() int { return n.sm.id }

// Propose asynchronously proposes data be applied to the underlying state machine.
func (n *Node) Propose(data []byte) { n.propose(normal, data) }

func (n *Node) propose(t int, data []byte) {
	n.Step(Message{Type: msgProp, Entries: []Entry{{Type: t, Data: data}}})
}

func (n *Node) Add(id int) { n.updateConf(configAdd, &config{NodeId: id}) }

func (n *Node) Remove(id int) { n.updateConf(configRemove, &config{NodeId: id}) }

func (n *Node) Msgs() []Message { return n.sm.Msgs() }

func (n *Node) Step(m Message) {
	l := len(n.sm.msgs)
	n.sm.Step(m)
	for _, m := range n.sm.msgs[l:] {
		// reset elapsed in two cases:
		// msgAppResp -> heard from the leader of the same term
		// msgVoteResp with grant -> heard from the candidate the node voted for
		switch m.Type {
		case msgAppResp:
			n.elapsed = 0
		case msgVoteResp:
			if m.Index >= 0 {
				n.elapsed = 0
			}
		}
	}
}

// Next returns all the appliable entries
func (n *Node) Next() []Entry {
	ents := n.sm.nextEnts()
	for i := range ents {
		switch ents[i].Type {
		case normal:
		case configAdd:
			c := new(config)
			if err := json.Unmarshal(ents[i].Data, c); err != nil {
				golog.Println(err)
				continue
			}
			n.sm.Add(c.NodeId)
		case configRemove:
			c := new(config)
			if err := json.Unmarshal(ents[i].Data, c); err != nil {
				golog.Println(err)
				continue
			}
			n.sm.Remove(c.NodeId)
		default:
			panic("unexpected entry type")
		}
	}
	return ents
}

// Tick triggers the node to do a tick.
// If the current elapsed is greater or equal than the timeout,
// node will send corresponding message to the statemachine.
func (n *Node) Tick() {
	timeout, msgType := n.election, msgHup
	if n.sm.state == stateLeader {
		timeout, msgType = n.heartbeat, msgBeat
	}
	if n.elapsed >= timeout {
		n.Step(Message{Type: msgType})
		n.elapsed = 0
	} else {
		n.elapsed++
	}
}

func (n *Node) updateConf(t int, c *config) {
	data, err := json.Marshal(c)
	if err != nil {
		panic(err)
	}
	n.propose(t, data)
}
<|endoftext|>


<commit_before>package dagutils

import (
	"context"
	"fmt"
	"path"

	coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"

	"gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
	dag "gx/ipfs/QmXv5mwmQ74r4aiHcNeQ4GAmfB3aWJuqaE4WyDfDfvkgLM/go-merkledag"
	ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)

// These constants define the changes that can be applied to a DAG.
const (
	Add = iota
	Remove
	Mod
)

// Change represents a change to a DAG and contains a reference to the old and
// new CIDs.
type Change struct {
	Type   coreiface.ChangeType
	Path   string
	Before cid.Cid
	After  cid.Cid
}

// String prints a human-friendly line about a change.
func (c *Change) String() string {
	switch c.Type {
	case Add:
		return fmt.Sprintf("Added %s at %s", c.After.String(), c.Path)
	case Remove:
		return fmt.Sprintf("Removed %s from %s", c.Before.String(), c.Path)
	case Mod:
		return fmt.Sprintf("Changed %s to %s at %s", c.Before.String(), c.After.String(), c.Path)
	default:
		panic("nope")
	}
}

// ApplyChange applies the requested changes to the given node in the given dag.
func ApplyChange(ctx context.Context, ds ipld.DAGService, nd *dag.ProtoNode, cs []*Change) (*dag.ProtoNode, error) {
	e := NewDagEditor(nd, ds)
	for _, c := range cs {
		switch c.Type {
		case Add:
			child, err := ds.Get(ctx, c.After)
			if err != nil {
				return nil, err
			}

			childpb, ok := child.(*dag.ProtoNode)
			if !ok {
				return nil, dag.ErrNotProtobuf
			}

			err = e.InsertNodeAtPath(ctx, c.Path, childpb, nil)
			if err != nil {
				return nil, err
			}

		case Remove:
			err := e.RmLink(ctx, c.Path)
			if err != nil {
				return nil, err
			}

		case Mod:
			err := e.RmLink(ctx, c.Path)
			if err != nil {
				return nil, err
			}
			child, err := ds.Get(ctx, c.After)
			if err != nil {
				return nil, err
			}

			childpb, ok := child.(*dag.ProtoNode)
			if !ok {
				return nil, dag.ErrNotProtobuf
			}

			err = e.InsertNodeAtPath(ctx, c.Path, childpb, nil)
			if err != nil {
				return nil, err
			}
		}
	}

	return e.Finalize(ctx, ds)
}

// Diff returns a set of changes that transform node 'a' into node 'b'
func Diff(ctx context.Context, ds ipld.DAGService, a, b ipld.Node) ([]*Change, error) {
	// Base case where both nodes are leaves, just compare
	// their CIDs.
	if len(a.Links()) == 0 && len(b.Links()) == 0 {
		if a.Cid().Equals(b.Cid()) {
			return []*Change{}, nil
		}
		return []*Change{
			&Change{
				Type:   Mod,
				Before: a.Cid(),
				After:  b.Cid(),
			},
		}, nil
	}

	var out []*Change
	cleanA := a.Copy().(*dag.ProtoNode)
	cleanB := b.Copy().(*dag.ProtoNode)

	// strip out unchanged stuff
	for _, lnk := range a.Links() {
		l, _, err := b.ResolveLink([]string{lnk.Name})
		if err == nil {
			if l.Cid.Equals(lnk.Cid) {
				// no change... ignore it
			} else {
				anode, err := lnk.GetNode(ctx, ds)
				if err != nil {
					return nil, err
				}

				bnode, err := l.GetNode(ctx, ds)
				if err != nil {
					return nil, err
				}

				anodepb, ok := anode.(*dag.ProtoNode)
				if !ok {
					return nil, dag.ErrNotProtobuf
				}

				bnodepb, ok := bnode.(*dag.ProtoNode)
				if !ok {
					return nil, dag.ErrNotProtobuf
				}

				sub, err := Diff(ctx, ds, anodepb, bnodepb)
				if err != nil {
					return nil, err
				}

				for _, subc := range sub {
					subc.Path = path.Join(lnk.Name, subc.Path)
					out = append(out, subc)
				}
			}
			cleanA.RemoveNodeLink(l.Name)
			cleanB.RemoveNodeLink(l.Name)
		}
	}

	for _, lnk := range cleanA.Links() {
		out = append(out, &Change{
			Type:   Remove,
			Path:   lnk.Name,
			Before: lnk.Cid,
		})
	}
	for _, lnk := range cleanB.Links() {
		out = append(out, &Change{
			Type:  Add,
			Path:  lnk.Name,
			After: lnk.Cid,
		})
	}

	return out, nil
}

// Conflict represents two incompatible changes and is returned by MergeDiffs().
type Conflict struct {
	A *Change
	B *Change
}

// MergeDiffs takes two slice of changes and adds them to a single slice.
// When a Change from b happens to the same path of an existing change in a,
// a conflict is created and b is not added to the merged slice.
// A slice of Conflicts is returned and contains pointers to the
// Changes involved (which share the same path).
func MergeDiffs(a, b []*Change) ([]*Change, []Conflict) {
	var out []*Change
	var conflicts []Conflict
	paths := make(map[string]*Change)
	for _, c := range a {
		paths[c.Path] = c
	}

	for _, c := range b {
		if ca, ok := paths[c.Path]; ok {
			conflicts = append(conflicts, Conflict{
				A: ca,
				B: c,
			})
		} else {
			out = append(out, c)
		}
	}
	for _, c := range paths {
		out = append(out, c)
	}
	return out, conflicts
}
<commit_msg>fix(object): add support for raw leaves in object diff<commit_after>package dagutils

import (
	"context"
	"fmt"
	"path"

	coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"

	"gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
	dag "gx/ipfs/QmXv5mwmQ74r4aiHcNeQ4GAmfB3aWJuqaE4WyDfDfvkgLM/go-merkledag"
	ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)

// These constants define the changes that can be applied to a DAG.
const (
	Add = iota
	Remove
	Mod
)

// Change represents a change to a DAG and contains a reference to the old and
// new CIDs.
type Change struct {
	Type   coreiface.ChangeType
	Path   string
	Before cid.Cid
	After  cid.Cid
}

// String prints a human-friendly line about a change.
func (c *Change) String() string {
	switch c.Type {
	case Add:
		return fmt.Sprintf("Added %s at %s", c.After.String(), c.Path)
	case Remove:
		return fmt.Sprintf("Removed %s from %s", c.Before.String(), c.Path)
	case Mod:
		return fmt.Sprintf("Changed %s to %s at %s", c.Before.String(), c.After.String(), c.Path)
	default:
		panic("nope")
	}
}

// ApplyChange applies the requested changes to the given node in the given dag.
func ApplyChange(ctx context.Context, ds ipld.DAGService, nd *dag.ProtoNode, cs []*Change) (*dag.ProtoNode, error) {
	e := NewDagEditor(nd, ds)
	for _, c := range cs {
		switch c.Type {
		case Add:
			child, err := ds.Get(ctx, c.After)
			if err != nil {
				return nil, err
			}

			childpb, ok := child.(*dag.ProtoNode)
			if !ok {
				return nil, dag.ErrNotProtobuf
			}

			err = e.InsertNodeAtPath(ctx, c.Path, childpb, nil)
			if err != nil {
				return nil, err
			}

		case Remove:
			err := e.RmLink(ctx, c.Path)
			if err != nil {
				return nil, err
			}

		case Mod:
			err := e.RmLink(ctx, c.Path)
			if err != nil {
				return nil, err
			}
			child, err := ds.Get(ctx, c.After)
			if err != nil {
				return nil, err
			}

			childpb, ok := child.(*dag.ProtoNode)
			if !ok {
				return nil, dag.ErrNotProtobuf
			}

			err = e.InsertNodeAtPath(ctx, c.Path, childpb, nil)
			if err != nil {
				return nil, err
			}
		}
	}

	return e.Finalize(ctx, ds)
}

// Diff returns a set of changes that transform node 'a' into node 'b'
func Diff(ctx context.Context, ds ipld.DAGService, a, b ipld.Node) ([]*Change, error) {
	// Base case where both nodes are leaves, just compare
	// their CIDs.
	if len(a.Links()) == 0 && len(b.Links()) == 0 {
		if a.Cid().Equals(b.Cid()) {
			return []*Change{}, nil
		}
		return []*Change{
			&Change{
				Type:   Mod,
				Before: a.Cid(),
				After:  b.Cid(),
			},
		}, nil
	}

	var out []*Change
	cleanA := a.Copy()
	cleanB := b.Copy()

	// strip out unchanged stuff
	for _, lnk := range a.Links() {
		l, _, err := b.ResolveLink([]string{lnk.Name})
		if err == nil {
			if l.Cid.Equals(lnk.Cid) {
				// no change... ignore it
			} else {
				anode, err := lnk.GetNode(ctx, ds)
				if err != nil {
					return nil, err
				}

				bnode, err := l.GetNode(ctx, ds)
				if err != nil {
					return nil, err
				}

				sub, err := Diff(ctx, ds, anode, bnode)
				if err != nil {
					return nil, err
				}

				for _, subc := range sub {
					subc.Path = path.Join(lnk.Name, subc.Path)
					out = append(out, subc)
				}
			}
			if cleanA, ok := cleanA.(*dag.ProtoNode); ok {
				cleanA.RemoveNodeLink(l.Name)
			}
			if cleanB, ok := cleanB.(*dag.ProtoNode); ok {
				cleanB.RemoveNodeLink(l.Name)
			}
		}
	}

	for _, lnk := range cleanA.Links() {
		out = append(out, &Change{
			Type:   Remove,
			Path:   lnk.Name,
			Before: lnk.Cid,
		})
	}
	for _, lnk := range cleanB.Links() {
		out = append(out, &Change{
			Type:  Add,
			Path:  lnk.Name,
			After: lnk.Cid,
		})
	}

	return out, nil
}

// Conflict represents two incompatible changes and is returned by MergeDiffs().
type Conflict struct {
	A *Change
	B *Change
}

// MergeDiffs takes two slice of changes and adds them to a single slice.
// When a Change from b happens to the same path of an existing change in a,
// a conflict is created and b is not added to the merged slice.
// A slice of Conflicts is returned and contains pointers to the
// Changes involved (which share the same path).
func MergeDiffs(a, b []*Change) ([]*Change, []Conflict) {
	var out []*Change
	var conflicts []Conflict
	paths := make(map[string]*Change)
	for _, c := range a {
		paths[c.Path] = c
	}

	for _, c := range b {
		if ca, ok := paths[c.Path]; ok {
			conflicts = append(conflicts, Conflict{
				A: ca,
				B: c,
			})
		} else {
			out = append(out, c)
		}
	}
	for _, c := range paths {
		out = append(out, c)
	}
	return out, conflicts
}
<|endoftext|>


<commit_before>// Package raygun4go adds Raygun-based error handling to your golang code.
//
// It basically adds an error-handler that recovers from all panics that
// might occur and sends information about that error to Raygun. The amount
// of data being sent is configurable.
//
// Basic example:
//   raygun, err := raygun4go.New("appName", "apiKey")
//   if err != nil {
//     log.Println("Unable to create Raygun client:", err.Error())
//   }
//   defer raygun.HandleError()
//
// This will send the error message together with a stack trace to Raygun.
//
// However, raygun4go really starts to shine if used in a webserver context.
// By calling
//
//   raygun.Request(*http.Request)
//
// you can set a request to be analyzed in case of an error. If an error
// occurs, this will send the request details to Raygun, including
//
//   * hostname
//   * url
//   * http method
//   * ip adress
//   * url parameters
//   * POSTed form fields
//   * headers
//   * cookies
//
// giving you a lot more leverage on your errors than the plain error message
// could provide you with.
//
// Chainable configuration methods are available (see below) to set the
// affected version, user, tags or custom data.
package raygun4go

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"

	"github.com/pborman/uuid"
	goerrors "github.com/go-errors/errors"
	"github.com/kaeuferportal/stack2struct"
)

// Client is the struct holding your Raygun configuration and context
// information that is needed if an error occurs.
type Client struct {
	appName      string             // the name of the app
	apiKey       string             // the api key for your raygun app
	context      contextInformation // optional context information
	silent       bool               // if true, the error is printed instead of sent to Raygun
	logToStdOut  bool               // if true, the client will print debug messages
	asynchronous bool               // if true, reports are sent to Raygun from a new go routine
}

// contextInformation holds optional information on the context the error
// occured in.
type contextInformation struct {
	Request    *http.Request // the request associated to the error
	Version    string        // the version of the package
	Tags       []string      // tags that you would like to use to filter this error
	CustomData interface{}   // whatever you like Raygun to know about this error
	User       string        // the user that saw the error
	identifier string        // a unique identifier for the running process, automatically set by New()
}

// raygunAPIEndpoint  holds the REST - JSON API Endpoint address
var raygunEndpoint = "https://api.raygun.io"

// Identifier returns the otherwise private identifier property from the
// Client's context. It is set by the New()-method and represents a unique
// identifier for your running program.
func (ci *contextInformation) Identifier() string {
	return ci.identifier
}

// New creates and returns a Client, needing an appName and an apiKey. It also
// creates a unique identifier for your program.
func New(appName, apiKey string) (c *Client, err error) {
	context := contextInformation{identifier: uuid.New()}
	if appName == "" || apiKey == "" {
		return nil, errors.New("appName and apiKey are required")
	}
	c = &Client{appName, apiKey, context, false, false, false}
	return c, nil
}

// Silent sets the silent-property on the Client. If true, errors will not be
// sent to Raygun but printed instead.
func (c *Client) Silent(s bool) *Client {
	c.silent = s
	return c
}

// LogToStdOut sets the logToStdOut-property on the Client.  If true, errors will
// be printed to std out as they are submitted to raygun.  This will also log
// any errors that occur when submiting to raygun to std out
func (c *Client) LogToStdOut(l bool) *Client {
	c.logToStdOut = l
	return c
}

// Sets whether or not this client submits reports to Raygun asynchronously.
// The default is false.
func (c *Client) Asynchronous(a bool) *Client {
	c.asynchronous = a
	return c
}

// Request is a chainable option-setting method to add a request to the context.
func (c *Client) Request(r *http.Request) *Client {
	c.context.Request = r
	return c
}

// Version is a chainable option-setting method to add a version to the context.
func (c *Client) Version(v string) *Client {
	c.context.Version = v
	return c
}

// Tags is a chainable option-setting method to add tags to the context. You
// can use tags to filter errors in Raygun.
func (c *Client) Tags(tags []string) *Client {
	c.context.Tags = tags
	return c
}

// CustomData is a chainable option-setting method to add arbitrary custom data
// to the context. Note that the given type (or at least parts of it)
// must implement the Marshaler-interface for this to work.
func (c *Client) CustomData(data interface{}) *Client {
	c.context.CustomData = data
	return c
}

// User is a chainable option-setting method to add an affected Username to the
// context.
func (c *Client) User(u string) *Client {
	c.context.User = u
	return c
}

// HandleError sets up the error handling code. It needs to be called with
//
//   defer c.HandleError()
//
// to handle all panics inside the calling function and all calls made from it.
// Be sure to call this in your main function or (if it is webserver) in your
// request handler as soon as possible.
func (c *Client) HandleError() error {
	e := recover()
	if e == nil {
		return nil
	}

	err, ok := e.(error)
	if !ok {
		err = errors.New(e.(string))
	}

	if c.logToStdOut {
		log.Println("Recovering from:", err.Error())
	}

	post := c.createPost(err, currentStack())
	err = c.submit(post)

	if c.logToStdOut && err != nil {
		log.Println(err.Error())
	}
	return err
}

// createPost creates the data structure that will be sent to Raygun.
func (c *Client) createPost(err error, stack stackTrace) postData {
	return newPostData(c.context, err, stack)
}

// Manually send a new error with the given message to Raygun. This will use the current execution stacktrace.
func (c *Client) CreateError(message string) error {
	err := errors.New(message)
	post := c.createPost(err, currentStack())

	return c.submit(post)
}

// Manually send the given error to Raygun.
// If the given error is a "github.com/go-errors/errors".Error, then its stacktrace will be used in the Raygun report.
// For other errors, the current execution stacktrace is used in the Raygun report.
func (c *Client) SendError(error error) error {
	err := errors.New(error.Error())

  var st stackTrace = nil
  if goerror, ok := error.(*goerrors.Error); ok {
	  st = make(stackTrace, 0, 0)
	  stack2struct.Parse(goerror.Stack(), &st)
  } else {
  	st = currentStack()
  }

	post := c.createPost(err, st)
	return c.submit(post)
}

// submit takes care of actually sending the error to Raygun unless the silent
// option is set.
func (c *Client) submit(post postData) error {
	if c.silent {
		enc, _ := json.MarshalIndent(post, "", "\t")
		fmt.Println(string(enc))
		return nil
	}

  if c.asynchronous {
  	go c.submitCore(post)
  	return nil
  }

  return c.submitCore(post)
}

func (c *Client) submitCore(post postData) error {
	json, err := json.Marshal(post)
	if err != nil {
		errMsg := fmt.Sprintf("Unable to convert to JSON (%s): %#v", err.Error(), post)
		return errors.New(errMsg)
	}

	r, err := http.NewRequest("POST", raygunEndpoint+"/entries", bytes.NewBuffer(json))
	if err != nil {
		errMsg := fmt.Sprintf("Unable to create request (%s)", err.Error())
		return errors.New(errMsg)
	}
	r.Header.Add("X-ApiKey", c.apiKey)
	httpClient := http.Client{}
	resp, err := httpClient.Do(r)

	defer resp.Body.Close()
	if resp.StatusCode == 202 {
		if c.logToStdOut {
			log.Println("Successfully sent message to Raygun")
		}
		return nil
	}

	errMsg := fmt.Sprintf("Unexpected answer from Raygun %d", resp.StatusCode)
	if err != nil {
		errMsg = fmt.Sprintf("%s: %s", errMsg, err.Error())
	}

	return errors.New(errMsg)
}
<commit_msg>Clone function<commit_after>// Package raygun4go adds Raygun-based error handling to your golang code.
//
// It basically adds an error-handler that recovers from all panics that
// might occur and sends information about that error to Raygun. The amount
// of data being sent is configurable.
//
// Basic example:
//   raygun, err := raygun4go.New("appName", "apiKey")
//   if err != nil {
//     log.Println("Unable to create Raygun client:", err.Error())
//   }
//   defer raygun.HandleError()
//
// This will send the error message together with a stack trace to Raygun.
//
// However, raygun4go really starts to shine if used in a webserver context.
// By calling
//
//   raygun.Request(*http.Request)
//
// you can set a request to be analyzed in case of an error. If an error
// occurs, this will send the request details to Raygun, including
//
//   * hostname
//   * url
//   * http method
//   * ip adress
//   * url parameters
//   * POSTed form fields
//   * headers
//   * cookies
//
// giving you a lot more leverage on your errors than the plain error message
// could provide you with.
//
// Chainable configuration methods are available (see below) to set the
// affected version, user, tags or custom data.
package raygun4go

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"

	"github.com/pborman/uuid"
	goerrors "github.com/go-errors/errors"
	"github.com/kaeuferportal/stack2struct"
)

// Client is the struct holding your Raygun configuration and context
// information that is needed if an error occurs.
type Client struct {
	appName      string             // the name of the app
	apiKey       string             // the api key for your raygun app
	context      contextInformation // optional context information
	silent       bool               // if true, the error is printed instead of sent to Raygun
	logToStdOut  bool               // if true, the client will print debug messages
	asynchronous bool               // if true, reports are sent to Raygun from a new go routine
}

// contextInformation holds optional information on the context the error
// occured in.
type contextInformation struct {
	Request    *http.Request // the request associated to the error
	Version    string        // the version of the package
	Tags       []string      // tags that you would like to use to filter this error
	CustomData interface{}   // whatever you like Raygun to know about this error
	User       string        // the user that saw the error
	identifier string        // a unique identifier for the running process, automatically set by New()
}

// raygunAPIEndpoint  holds the REST - JSON API Endpoint address
var raygunEndpoint = "https://api.raygun.io"

// Identifier returns the otherwise private identifier property from the
// Client's context. It is set by the New()-method and represents a unique
// identifier for your running program.
func (ci *contextInformation) Identifier() string {
	return ci.identifier
}

// New creates and returns a Client, needing an appName and an apiKey. It also
// creates a unique identifier for your program.
func New(appName, apiKey string) (c *Client, err error) {
	context := contextInformation{identifier: uuid.New()}
	if appName == "" || apiKey == "" {
		return nil, errors.New("appName and apiKey are required")
	}
	c = &Client{appName, apiKey, context, false, false, false}
	return c, nil
}

func (c *Client) Clone() *Client {
	contextInfoClone := contextInformation{c.context.Request, c.context.Version, c.context.Tags, c.context.CustomData, c.context.User, c.context.identifier}

	clientClone := &Client{c.appName, c.apiKey, contextInfoClone, c.silent, c.logToStdOut}
	return clientClone
}

// Silent sets the silent-property on the Client. If true, errors will not be
// sent to Raygun but printed instead.
func (c *Client) Silent(s bool) *Client {
	c.silent = s
	return c
}

// LogToStdOut sets the logToStdOut-property on the Client.  If true, errors will
// be printed to std out as they are submitted to raygun.  This will also log
// any errors that occur when submiting to raygun to std out
func (c *Client) LogToStdOut(l bool) *Client {
	c.logToStdOut = l
	return c
}

// Sets whether or not this client submits reports to Raygun asynchronously.
// The default is false.
func (c *Client) Asynchronous(a bool) *Client {
	c.asynchronous = a
	return c
}

// Request is a chainable option-setting method to add a request to the context.
func (c *Client) Request(r *http.Request) *Client {
	c.context.Request = r
	return c
}

// Version is a chainable option-setting method to add a version to the context.
func (c *Client) Version(v string) *Client {
	c.context.Version = v
	return c
}

// Tags is a chainable option-setting method to add tags to the context. You
// can use tags to filter errors in Raygun.
func (c *Client) Tags(tags []string) *Client {
	c.context.Tags = tags
	return c
}

// CustomData is a chainable option-setting method to add arbitrary custom data
// to the context. Note that the given type (or at least parts of it)
// must implement the Marshaler-interface for this to work.
func (c *Client) CustomData(data interface{}) *Client {
	c.context.CustomData = data
	return c
}

// User is a chainable option-setting method to add an affected Username to the
// context.
func (c *Client) User(u string) *Client {
	c.context.User = u
	return c
}

// HandleError sets up the error handling code. It needs to be called with
//
//   defer c.HandleError()
//
// to handle all panics inside the calling function and all calls made from it.
// Be sure to call this in your main function or (if it is webserver) in your
// request handler as soon as possible.
func (c *Client) HandleError() error {
	e := recover()
	if e == nil {
		return nil
	}

	err, ok := e.(error)
	if !ok {
		err = errors.New(e.(string))
	}

	if c.logToStdOut {
		log.Println("Recovering from:", err.Error())
	}

	post := c.createPost(err, currentStack())
	err = c.submit(post)

	if c.logToStdOut && err != nil {
		log.Println(err.Error())
	}
	return err
}

// createPost creates the data structure that will be sent to Raygun.
func (c *Client) createPost(err error, stack stackTrace) postData {
	return newPostData(c.context, err, stack)
}

// Manually send a new error with the given message to Raygun. This will use the current execution stacktrace.
func (c *Client) CreateError(message string) error {
	err := errors.New(message)
	post := c.createPost(err, currentStack())

	return c.submit(post)
}

// Manually send the given error to Raygun.
// If the given error is a "github.com/go-errors/errors".Error, then its stacktrace will be used in the Raygun report.
// For other errors, the current execution stacktrace is used in the Raygun report.
func (c *Client) SendError(error error) error {
	err := errors.New(error.Error())

  var st stackTrace = nil
  if goerror, ok := error.(*goerrors.Error); ok {
	  st = make(stackTrace, 0, 0)
	  stack2struct.Parse(goerror.Stack(), &st)
  } else {
  	st = currentStack()
  }

	post := c.createPost(err, st)
	return c.submit(post)
}

// submit takes care of actually sending the error to Raygun unless the silent
// option is set.
func (c *Client) submit(post postData) error {
	if c.silent {
		enc, _ := json.MarshalIndent(post, "", "\t")
		fmt.Println(string(enc))
		return nil
	}

  if c.asynchronous {
  	go c.submitCore(post)
  	return nil
  }

  return c.submitCore(post)
}

func (c *Client) submitCore(post postData) error {
	json, err := json.Marshal(post)
	if err != nil {
		errMsg := fmt.Sprintf("Unable to convert to JSON (%s): %#v", err.Error(), post)
		return errors.New(errMsg)
	}

	r, err := http.NewRequest("POST", raygunEndpoint+"/entries", bytes.NewBuffer(json))
	if err != nil {
		errMsg := fmt.Sprintf("Unable to create request (%s)", err.Error())
		return errors.New(errMsg)
	}
	r.Header.Add("X-ApiKey", c.apiKey)
	httpClient := http.Client{}
	resp, err := httpClient.Do(r)

	defer resp.Body.Close()
	if resp.StatusCode == 202 {
		if c.logToStdOut {
			log.Println("Successfully sent message to Raygun")
		}
		return nil
	}

	errMsg := fmt.Sprintf("Unexpected answer from Raygun %d", resp.StatusCode)
	if err != nil {
		errMsg = fmt.Sprintf("%s: %s", errMsg, err.Error())
	}

	return errors.New(errMsg)
}
<|endoftext|>


<commit_before>/*
   Copyright (C) 2017 Enrico Bianchi (enrico.bianchi@gmail.com)
   Project       Syncimap
   Description   A rsync like IMAP syncronization tool
   License       Apache License 2.0 (see LICENSE for details)
*/

package imap
<commit_msg>Implemented struct and connection method<commit_after>/*
   Copyright (C) 2017 Enrico Bianchi (enrico.bianchi@gmail.com)
   Project       Syncimap
   Description   A rsync like IMAP syncronization tool
   License       Apache License 2.0 (see LICENSE for details)
*/

package imap

import (
	"errors"
	"github.com/emersion/go-imap/client"
	"net/url"
)

type Connection struct {
	Client *client.Client
}

func (conn *Connection) Dial(uri *url.URL) error {
	var err error

	switch uri.Scheme {
	case "imap":
		port := uri.Port()
		conn.Client, err = client.Dial(uri.Host + ":" + port)
	case "imaps":
		conn.Client, err = client.DialTLS(uri.Host+":"+uri.Port(), nil)
	default:
		return errors.New("Scheme not supported: " + uri.Scheme)
	}

	return err
}
<|endoftext|>


<commit_before>package rules

import (
	"github.com/coreos/etcd/client"
	"github.com/coreos/etcd/clientv3"
	"github.com/uber-go/zap"
)

type baseWorker struct {
	locker   ruleLocker
	api      readAPI
	workerID string
	stopping uint32
	stopped  uint32
}

type worker struct {
	baseWorker
	engine *engine
}

type v3Worker struct {
	baseWorker
	engine *v3Engine
}

func newWorker(workerID string, engine *engine) (worker, error) {
	var api readAPI
	var locker ruleLocker
	c, err := client.New(engine.config)
	if err != nil {
		return worker{}, err
	}
	locker = newLockLocker(c)
	api = &etcdReadAPI{
		keysAPI: client.NewKeysAPI(c),
	}
	w := worker{
		baseWorker: baseWorker{
			api:      api,
			locker:   locker,
			workerID: workerID,
		},
		engine: engine,
	}
	return w, nil
}

func newV3Worker(workerID string, engine *v3Engine) (v3Worker, error) {
	var api readAPI
	var locker ruleLocker

	c, err := clientv3.New(engine.configV3)
	if err != nil {
		return v3Worker{}, err
	}
	locker = newV3Locker(c)
	api = &etcdV3ReadAPI{
		kV: c,
	}
	w := v3Worker{
		baseWorker: baseWorker{
			api:      api,
			locker:   locker,
			workerID: workerID,
		},
		engine: engine,
	}
	return w, nil
}

func (w *worker) run() {
	atomicSet(&w.stopped, false)
	for !is(&w.stopping) {
		w.singleRun()
	}
	atomicSet(&w.stopped, true)
}

func (w *v3Worker) run() {
	atomicSet(&w.stopped, false)
	for !is(&w.stopping) {
		w.singleRun()
	}
	atomicSet(&w.stopped, true)
}

type workCallback func()

func (bw *baseWorker) stop() {
	atomicSet(&bw.stopping, true)
}

func (bw *baseWorker) isStopped() bool {
	return is(&bw.stopped)
}

func (bw *baseWorker) doWork(loggerPtr *zap.Logger,
	rulePtr *staticRule, lockTTL int, callback workCallback,
	lockKey string) {
	logger := *loggerPtr
	rule := *rulePtr
	sat, err1 := rule.satisfied(bw.api)
	if err1 != nil {
		logger.Error("Error checking rule", zap.Error(err1))
		return
	}
	if !sat || is(&bw.stopping) {
		return
	}
	l, err2 := bw.locker.lock(lockKey, lockTTL)
	if err2 != nil {
		logger.Error("Failed to acquire lock", zap.String("lock_key", lockKey), zap.Error(err2))
		return
	}
	defer l.unlock()
	// Check for a second time, since checking and locking
	// are not atomic.
	sat, err1 = rule.satisfied(bw.api)
	if err1 != nil {
		logger.Error("Error checking rule", zap.Error(err1))
		return
	}
	if sat || !is(&bw.stopping) {
		callback()
	}
}

func (bw *baseWorker) addWorkerID(ruleContext map[string]string) {
	ruleContext["rule_worker"] = bw.workerID
}

func (w *worker) singleRun() {
	work := <-w.engine.workChannel
	task := work.ruleTask
	if is(&w.stopping) {
		return
	}
	w.addWorkerID(task.Metadata)
	task.Logger = task.Logger.With(zap.String("worker", w.workerID))
	w.doWork(&task.Logger, &work.rule, w.engine.getLockTTLForRule(work.ruleIndex), func() { work.ruleTaskCallback(&task) }, work.lockKey)
}

func (w *v3Worker) singleRun() {
	work := <-w.engine.workChannel
	task := work.ruleTask
	if is(&w.stopping) {
		return
	}
	w.addWorkerID(task.Metadata)
	task.Logger = task.Logger.With(zap.String("worker", w.workerID))
	w.doWork(&task.Logger, &work.rule, w.engine.getLockTTLForRule(work.ruleIndex), func() { work.ruleTaskCallback(&task) }, work.lockKey)
}
<commit_msg>Fix worker bug<commit_after>package rules

import (
	"github.com/coreos/etcd/client"
	"github.com/coreos/etcd/clientv3"
	"github.com/uber-go/zap"
)

type baseWorker struct {
	locker   ruleLocker
	api      readAPI
	workerID string
	stopping uint32
	stopped  uint32
}

type worker struct {
	baseWorker
	engine *engine
}

type v3Worker struct {
	baseWorker
	engine *v3Engine
}

func newWorker(workerID string, engine *engine) (worker, error) {
	var api readAPI
	var locker ruleLocker
	c, err := client.New(engine.config)
	if err != nil {
		return worker{}, err
	}
	locker = newLockLocker(c)
	api = &etcdReadAPI{
		keysAPI: client.NewKeysAPI(c),
	}
	w := worker{
		baseWorker: baseWorker{
			api:      api,
			locker:   locker,
			workerID: workerID,
		},
		engine: engine,
	}
	return w, nil
}

func newV3Worker(workerID string, engine *v3Engine) (v3Worker, error) {
	var api readAPI
	var locker ruleLocker

	c, err := clientv3.New(engine.configV3)
	if err != nil {
		return v3Worker{}, err
	}
	locker = newV3Locker(c)
	api = &etcdV3ReadAPI{
		kV: c,
	}
	w := v3Worker{
		baseWorker: baseWorker{
			api:      api,
			locker:   locker,
			workerID: workerID,
		},
		engine: engine,
	}
	return w, nil
}

func (w *worker) run() {
	atomicSet(&w.stopped, false)
	for !is(&w.stopping) {
		w.singleRun()
	}
	atomicSet(&w.stopped, true)
}

func (w *v3Worker) run() {
	atomicSet(&w.stopped, false)
	for !is(&w.stopping) {
		w.singleRun()
	}
	atomicSet(&w.stopped, true)
}

type workCallback func()

func (bw *baseWorker) stop() {
	atomicSet(&bw.stopping, true)
}

func (bw *baseWorker) isStopped() bool {
	return is(&bw.stopped)
}

func (bw *baseWorker) doWork(loggerPtr *zap.Logger,
	rulePtr *staticRule, lockTTL int, callback workCallback,
	lockKey string) {
	logger := *loggerPtr
	rule := *rulePtr
	sat, err1 := rule.satisfied(bw.api)
	if err1 != nil {
		logger.Error("Error checking rule", zap.Error(err1))
		return
	}
	logger.Debug("Rule satisfied", zap.Bool("satisfied", sat)
	if !sat || is(&bw.stopping) {
		return
	}
	l, err2 := bw.locker.lock(lockKey, lockTTL)
	if err2 != nil {
		logger.Error("Failed to acquire lock", zap.String("lock_key", lockKey), zap.Error(err2))
		return
	}
	defer l.unlock()
	// Check for a second time, since checking and locking
	// are not atomic.
	sat, err1 = rule.satisfied(bw.api)
	if err1 != nil {
		logger.Error("Error checking rule", zap.Error(err1))
		return
	}
	if sat && !is(&bw.stopping) {
		callback()
	}
}

func (bw *baseWorker) addWorkerID(ruleContext map[string]string) {
	ruleContext["rule_worker"] = bw.workerID
}

func (w *worker) singleRun() {
	work := <-w.engine.workChannel
	task := work.ruleTask
	if is(&w.stopping) {
		return
	}
	w.addWorkerID(task.Metadata)
	task.Logger = task.Logger.With(zap.String("worker", w.workerID))
	w.doWork(&task.Logger, &work.rule, w.engine.getLockTTLForRule(work.ruleIndex), func() { work.ruleTaskCallback(&task) }, work.lockKey)
}

func (w *v3Worker) singleRun() {
	work := <-w.engine.workChannel
	task := work.ruleTask
	if is(&w.stopping) {
		return
	}
	w.addWorkerID(task.Metadata)
	task.Logger = task.Logger.With(zap.String("worker", w.workerID))
	w.doWork(&task.Logger, &work.rule, w.engine.getLockTTLForRule(work.ruleIndex), func() { work.ruleTaskCallback(&task) }, work.lockKey)
}
<|endoftext|>


<commit_before>package rabbit

import (
	"errors"
	"github.com/streadway/amqp"
	"log"
	"time"
)

var publisherConnection = &Connection{}

//Publisher allows you to publish events to RabbitMQ
type Publisher struct {
	_channel          *amqp.Channel
	_notifyPublish    []chan amqp.Confirmation
	_reliableMode     bool
	_reliableModeWait bool
}

// NewPublisher constructs a new Publisher instance.
func NewPublisher() *Publisher {
	return &Publisher{}
}

// GetChannel returns a publisher's channel. It opens a new channel if needed.
func (p *Publisher) GetChannel() *amqp.Channel {
	if p._channel != nil {
		return p._channel
	}
	for {
		if err := p.openChannel(); err == nil {
			break
		} else {
			logError(err, "Can't open a new RabbitMQ channel for publisher")
		}
		time.Sleep(1 * time.Second)
	}
	return p._channel
}

func (p *Publisher) openChannel() error {
	c := publisherConnection.GetConnection()
	p._channel = createChannel(c, false)
	if p._channel == nil {
		log.Printf("Can't create a RabbitMQ channel for publisher")
		return errors.New("Can't create channel for publisher")
	}
	for i := range p._notifyPublish {
		p._channel.NotifyPublish(p._notifyPublish[i])
	}
	if p._reliableMode {
		if err := p._channel.Confirm(p._reliableModeWait); err != nil {
			p.Close()
			log.Printf("Error on enabling RabbitMQ confirmation on reconnecting: %s", err.Error())
			return err
		}
	}

	return nil
}

// Confirm enables reliable mode for the publisher.
func (p *Publisher) Confirm(wait bool) error {
	p._reliableMode = true
	p._reliableModeWait = wait
	channel := p.GetChannel()
	err := channel.Confirm(wait)
	if err != nil {
		log.Printf("Error on enabling RabbitMQ confirmation (will disconnect publisher): %s", err.Error())
		p.Close()
	}
	return err
}

// NotifyPublish registers a listener for reliable publishing.
func (p *Publisher) NotifyPublish(c chan amqp.Confirmation) chan amqp.Confirmation {
	channel := p.GetChannel()
	p._notifyPublish = append(p._notifyPublish, c)
	channel.NotifyPublish(c)
	return c
}

// Publish pushes items on to a RabbitMQ Queue.
func (p *Publisher) Publish(message string, subscriber *Subscriber) error {
	return p.PublishBytes([]byte(message), subscriber)
}

// PublishBytes is the same as Publish but accepts a []byte instead of a string
func (p *Publisher) PublishBytes(message []byte, subscriber *Subscriber) error {
	channel := p.GetChannel()

	return channel.Publish(
		subscriber.Exchange,   // exchange
		subscriber.RoutingKey, // routing key
		false, // mandatoryy
		false, // immediate
		amqp.Publishing{
			ContentType:  "application/json",
			Body:         message,
			DeliveryMode: amqp.Persistent,
		})
}

//Close will close the connection and channel for the Publisher
func (p *Publisher) Close() {
	if p._channel != nil {
		p._channel.Close()
		p._channel = nil
	}
}
<commit_msg>fix spelling in comments<commit_after>package rabbit

import (
	"errors"
	"github.com/streadway/amqp"
	"log"
	"time"
)

var publisherConnection = &Connection{}

//Publisher allows you to publish events to RabbitMQ
type Publisher struct {
	_channel          *amqp.Channel
	_notifyPublish    []chan amqp.Confirmation
	_reliableMode     bool
	_reliableModeWait bool
}

// NewPublisher constructs a new Publisher instance.
func NewPublisher() *Publisher {
	return &Publisher{}
}

// GetChannel returns a publisher's channel. It opens a new channel if needed.
func (p *Publisher) GetChannel() *amqp.Channel {
	if p._channel != nil {
		return p._channel
	}
	for {
		if err := p.openChannel(); err == nil {
			break
		} else {
			logError(err, "Can't open a new RabbitMQ channel for publisher")
		}
		time.Sleep(1 * time.Second)
	}
	return p._channel
}

func (p *Publisher) openChannel() error {
	c := publisherConnection.GetConnection()
	p._channel = createChannel(c, false)
	if p._channel == nil {
		log.Printf("Can't create a RabbitMQ channel for publisher")
		return errors.New("Can't create channel for publisher")
	}
	for i := range p._notifyPublish {
		p._channel.NotifyPublish(p._notifyPublish[i])
	}
	if p._reliableMode {
		if err := p._channel.Confirm(p._reliableModeWait); err != nil {
			p.Close()
			log.Printf("Error on enabling RabbitMQ confirmation on reconnecting: %s", err.Error())
			return err
		}
	}

	return nil
}

// Confirm enables reliable mode for the publisher.
func (p *Publisher) Confirm(wait bool) error {
	p._reliableMode = true
	p._reliableModeWait = wait
	channel := p.GetChannel()
	err := channel.Confirm(wait)
	if err != nil {
		log.Printf("Error on enabling RabbitMQ confirmation (will disconnect publisher): %s", err.Error())
		p.Close()
	}
	return err
}

// NotifyPublish registers a listener for reliable publishing.
func (p *Publisher) NotifyPublish(c chan amqp.Confirmation) chan amqp.Confirmation {
	channel := p.GetChannel()
	p._notifyPublish = append(p._notifyPublish, c)
	channel.NotifyPublish(c)
	return c
}

// Publish pushes items on to a RabbitMQ Queue.
func (p *Publisher) Publish(message string, subscriber *Subscriber) error {
	return p.PublishBytes([]byte(message), subscriber)
}

// PublishBytes is the same as Publish but accepts a []byte instead of a string
func (p *Publisher) PublishBytes(message []byte, subscriber *Subscriber) error {
	channel := p.GetChannel()

	return channel.Publish(
		subscriber.Exchange,   // exchange
		subscriber.RoutingKey, // routing key
		false, // mandatory
		false, // immediate
		amqp.Publishing{
			ContentType:  "application/json",
			Body:         message,
			DeliveryMode: amqp.Persistent,
		})
}

//Close will close the connection and channel for the Publisher
func (p *Publisher) Close() {
	if p._channel != nil {
		p._channel.Close()
		p._channel = nil
	}
}
<|endoftext|>


<commit_before>package xkcd_test

import (
	"encoding/json"
	"github.com/rkoesters/xkcd"
	"io"
	"testing"
)

func TestGet(t *testing.T) {
	comic, err := xkcd.Get(221)
	if err != nil {
		t.Fatal(err)
	}

	expected := &xkcd.Comic{
		Num:       221,
		Title:     "Random Number",
		SafeTitle: "Random Number",
		Img:       "https://imgs.xkcd.com/comics/random_number.png",
		Alt:       "RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.",
		Year:      "2007",
		Month:     "2",
		Day:       "9",
		News:      "",
		Link:      "",
		Transcript: `int getRandomNumber()
{
  return 4;
 chosen by fair dice roll.

 guarenteed to be random.
}
{{title text: RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.}}`,
	}

	t.Log("comic: ", comic)
	t.Log("expected: ", expected)

	if *comic != *expected {
		t.Fail()
	}
}

func TestGetCurrent(t *testing.T) {
	comic1, err := xkcd.GetCurrent()
	if err != nil {
		t.Fatal(err)
	}

	comic2, err := xkcd.Get(comic1.Num)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("comic1: ", comic1)
	t.Log("comic2: ", comic2)

	if *comic1 != *comic2 {
		t.Fatal("comic1 and comic2 don't match")
	}
}

func Test404(t *testing.T) {
	_, err := xkcd.Get(404)
	if err != xkcd.ErrNotFound {
		t.Fatal(err)
	}
}

func TestNew(t *testing.T) {
	comic1, err := xkcd.GetCurrent()
	if err != nil {
		t.Fatal(err)
	}

	r, w := io.Pipe()

	go func() {
		e := json.NewEncoder(w)
		err = e.Encode(comic1)
		if err != nil {
			t.Fatal(err)
		}
	}()

	comic2, err := xkcd.New(r)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("comic1: ", comic1)
	t.Log("comic2: ", comic2)

	if *comic1 != *comic2 {
		t.Fatal("comic1 and comic2 don't match")
	}
}
<commit_msg>Add Test1956 and Test2038.<commit_after>package xkcd_test

import (
	"encoding/json"
	"github.com/rkoesters/xkcd"
	"io"
	"reflect"
	"testing"
)

func TestGet(t *testing.T) {
	comic, err := xkcd.Get(221)
	if err != nil {
		t.Fatal(err)
	}

	expected := &xkcd.Comic{
		Num:       221,
		Title:     "Random Number",
		SafeTitle: "Random Number",
		Img:       "https://imgs.xkcd.com/comics/random_number.png",
		Alt:       "RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.",
		Year:      "2007",
		Month:     "2",
		Day:       "9",
		News:      "",
		Link:      "",
		Transcript: `int getRandomNumber()
{
  return 4;
 chosen by fair dice roll.

 guarenteed to be random.
}
{{title text: RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.}}`,
	}

	t.Log("comic: ", comic)
	t.Log("expected: ", expected)

	if !reflect.DeepEqual(comic, expected) {
		t.Fail()
	}
}

func TestGetCurrent(t *testing.T) {
	comic1, err := xkcd.GetCurrent()
	if err != nil {
		t.Fatal(err)
	}

	comic2, err := xkcd.Get(comic1.Num)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("comic1: ", comic1)
	t.Log("comic2: ", comic2)

	if !reflect.DeepEqual(comic1, comic2) {
		t.Fatal("comic1 and comic2 don't match")
	}
}

func Test404(t *testing.T) {
	_, err := xkcd.Get(404)
	if err != xkcd.ErrNotFound {
		t.Fatal(err)
	}
}

func TestNew(t *testing.T) {
	comic1, err := xkcd.GetCurrent()
	if err != nil {
		t.Fatal(err)
	}

	r, w := io.Pipe()

	go func() {
		e := json.NewEncoder(w)
		err = e.Encode(comic1)
		if err != nil {
			t.Fatal(err)
		}
	}()

	comic2, err := xkcd.New(r)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("comic1: ", comic1)
	t.Log("comic2: ", comic2)

	if !reflect.DeepEqual(comic1, comic2) {
		t.Fatal("comic1 and comic2 don't match")
	}
}

func Test1956(t *testing.T) {
	expect := &xkcd.Comic{
		Num:        1956,
		Title:      "Unification",
		SafeTitle:  "Unification",
		Img:        "https://imgs.xkcd.com/comics/unification.png",
		Alt:        "For a while, some physicists worked on a theory unifying the other forces with both the force of gravity and the film \"Gravity,\" but even after Alfonso Cuarón was held in a deep underground chamber of water for 10^31 years he refused to sell his film to Disney.",
		Year:       "2018",
		Month:      "2",
		Day:        "16",
		News:       "",
		Link:       "",
		Transcript: "",
	}

	actual, err := xkcd.Get(expect.Num)
	if err != nil {
		t.Fatal(err)
	}

	t.Logf("actual=%v", actual)
	t.Logf("expect=%v", expect)

	if !reflect.DeepEqual(actual, expect) {
		t.Fail()
	}
}

func Test2038(t *testing.T) {
	expect := &xkcd.Comic{
		Num:        2038,
		Title:      "Hazard Symbol",
		SafeTitle:  "Hazard Symbol",
		Img:        "https://imgs.xkcd.com/comics/hazard_symbol.png",
		Alt:        "The warning diamond on the Materials Safety Data Sheet for this stuff just has the \"😰\" emoji in all four fields.",
		Year:       "2018",
		Month:      "8",
		Day:        "27",
		News:       "",
		Link:       "",
		Transcript: "",
	}

	actual, err := xkcd.Get(expect.Num)
	if err != nil {
		t.Fatal(err)
	}

	t.Logf("actual=%v", actual)
	t.Logf("expect=%v", expect)

	if !reflect.DeepEqual(actual, expect) {
		t.Fail()
	}
}
<|endoftext|>


<commit_before>// Library for all non-constant variables used by the Yieldbot Infrastructure teams
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package dracky

// Debug  Do we print debug statements or not. This is set in each binary but is placed here
// to avoid the use of global variables
var Debug bool

// JavaApp  This is used to let the process -> pid function know how it will match the process name
var JavaApp bool

var SlackChannels map[string]string
SlackChannels['monitoring-test'] = "C09JY7W0P"
SlackChannels['devops-alerts'] = "C02TLVDQU"
<commit_msg>fix quote issue<commit_after>// Library for all non-constant variables used by the Yieldbot Infrastructure teams
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package dracky

// Debug  Do we print debug statements or not. This is set in each binary but is placed here
// to avoid the use of global variables
var Debug bool

// JavaApp  This is used to let the process -> pid function know how it will match the process name
var JavaApp bool

var SlackChannels map[string]string
SlackChannels["monitoring-test"] = "C09JY7W0P"
SlackChannels["devops-alerts"] = "C02TLVDQU"
<|endoftext|>


<commit_before>package kiwi

/*
Copyright (c) 2016-2019, Alexander I.Grafov <grafov@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of kvlog nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
	"sync"
	"testing"
)

/* All tests consists of three parts:

- arrange structures and initialize objects for use in tests
- act on testing object
- check and assert on results

These parts separated by empty lines in each test function.
*/

// Test logging of string value.
func TestRace_NewFromGlobal_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()

	for i := 0; i < 100; i++ {
		go func(i int) {
			log := New()
			log.Log("k", "The sample string.", "instance", i)
		}(i)
	}
	Log("k", "The sample string.", "instance", 0)

	out.Flush()
}

// Test logging of string value.
func TestRace_ForkFromGlobal_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()

	for i := 0; i < 100; i++ {
		go func(i int) {
			log := Fork()
			log.Log("k", "The sample string.", "instance", i)
		}(i)
	}
	Log("k", "The sample string.", "instance", 0)

	out.Flush()
}

// Test logging of string value.
func TestRace_Fork_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()
	var (
		wg sync.WaitGroup
	)

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func(i int) {
			log := Fork()
			log.Log("k", "The sample string.", "instance", i)
			wg.Done()
		}(i)
	}
	Log("k", "The sample string.", "instance", 0)
	wg.Wait()

	out.Flush()
}

// Test logging of string value.
func TestRace_ForkFork_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()
	var (
		wg sync.WaitGroup
	)

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func(i int) {
			log := Fork().Fork()
			log.Log("k", "The sample string.", "instance", i)
			wg.Done()
		}(i)
	}
	Log("k", "The sample string.", "instance", 0)
	wg.Wait()

	out.Flush()
}

// // Test logging of byte array.
// func TestLogger_LogBytesValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", []byte("The sample string with a lot of spaces."))

//	out.Flush()
//	if strings.TrimSpace(output.String()) != `k="The sample string with a lot of spaces."` {
//		t.Fail()
//	}
// }

// // Test logging of integer value.
// func TestLogger_LogIntValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", 123)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=123" {
//		t.Fail()
//	}
// }

// // Test logging of negative integer value.
// func TestLogger_LogNegativeIntValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", -123)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=-123" {
//		t.Fail()
//	}
// }

// // Test logging of float value in default (scientific) format.
// func TestLogger_LogFloatValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", 3.14159265359)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=3.14159265359e+00" {
//		t.Fail()
//	}
// }

// // Test logging of float value in fixed format.
// func TestLogger_LogFixedFloatValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	FloatFormat = 'f'
//	log.Log("k", 3.14159265359)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=3.14159265359" {
//		t.Fail()
//	}
//	// Turn back to default format.
//	FloatFormat = 'e'
// }

// // Test logging of boolean value.
// func TestLogger_LogBoolValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", true, "k2", false)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=true k2=false" {
//		t.Fail()
//	}
// }

// // Test logging of complex number.
// func TestLogger_LogComplexValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", .12345E+5i, "k2", 1.e+0i)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=(0.000000+12345.000000i) k2=(0.000000+1.000000i)" {
//		t.Fail()
//	}
// }

// // Test logging of time literal.
// func TestLogger_LogTimeValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	value := time.Now()
//	valueString := value.Format(TimeLayout)
//	defer out.Close()

//	log.Log("k", value)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != fmt.Sprintf("k=%s", valueString) {
//		t.Fail()
//	}
// }

// func TestLogger_LogIntKeyInvalid_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log(123, 456)

//	out.Flush()
//	expected := `kiwi-error="non a string type (int) for the key (123)" message=456`
//	if strings.TrimSpace(output.String()) != expected {
//		t.Logf("expected %s got %v", expected, output.String())
//		t.Fail()
//	}
// }

// // The logger accepts string keys. In other cases it complains about
// // the wrong key type. It also assumes that each key followed by the
// // value.
// func TestLogger_LogThreeIntKeysInvalid_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log(123, 456, 789)

//	out.Flush()
//	expected := `kiwi-error="non a string type (int) for the key (123)" message=456 kiwi-error="non a string type (int) for the key (789)"`
//	if strings.TrimSpace(output.String()) != expected {
//		t.Logf("expected %s got %v", expected, output.String())
//		t.Fail()
//	}
// }

// // The logger accepts string keys. In other cases it complains about
// // the wrong key type. It also assumes that each key followed by the
// // value.
// func TestLogger_LogFourIntKeysInvalid_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log(12, 34, 56, 78)

//	out.Flush()
//	expected := `kiwi-error="non a string type (int) for the key (12)" message=34 kiwi-error="non a string type (int) for the key (56)" message=78`
//	if strings.TrimSpace(output.String()) != expected {
//		t.Logf("expected %s got %v", expected, output.String())
//		t.Fail()
//	}
// }

// // Test chaining for Add()
// func TestLogger_AddMixChained_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Add("k", "value2").Add("k2", 123).Add("k3", 3.14159265359).Log()

//	out.Flush()
//	expected := `k="value2" k2=123 k3=3.14159265359e+00`
//	if strings.TrimSpace(output.String()) != expected {
//		t.Logf("expected %s got %v", expected, output.String())
//		t.Fail()
//	}
// }

// // Test log with the context value.
// func TestLogger_WithContextPassed_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.With("key1", "value")
//	log.Log("key2", "value")

//	out.Flush()
//	if strings.TrimSpace(output.String()) != `key1="value" key2="value"` {
//		t.Fail()
//	}
// }

// // Test log with adding then removing the context.
// func TestLogger_WithoutContextPassed_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	// add the context
//	log.With("key1", "value")
//	// add regular pair
//	log.Add("key2", "value")
//	// remove the context and flush the record
//	log.Without("key1").Log()

//	out.Flush()
//	if strings.TrimSpace(output.String()) != `key2="value"` {
//		t.Fail()
//	}
// }

// // Test log with adding then reset the context.
// func TestLogger_ResetContext_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	// add the context
//	log.With("key1", "value")
//	// add regular pair
//	log.Add("key2", "value")
//	// reset the context and flush the record
//	log.ResetContext().Log()

//	out.Flush()
//	if strings.TrimSpace(output.String()) != `key2="value"` {
//		t.Fail()
//	}
// }
<commit_msg>Add another race test<commit_after>package kiwi

/*
Copyright (c) 2016-2019, Alexander I.Grafov <grafov@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of kvlog nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
	"sync"
	"testing"
)

/* All tests consists of three parts:

- arrange structures and initialize objects for use in tests
- act on testing object
- check and assert on results

These parts separated by empty lines in each test function.
*/

// Test logging of string value.
func TestRace_NewFromGlobal_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()

	for i := 0; i < 100; i++ {
		go func(i int) {
			log := New()
			log.Log("k", "The sample string.", "instance", i)
		}(i)
	}
	Log("k", "The sample string.", "instance", 0)

	out.Flush()
}

// Test logging of string value.
func TestRace_ForkFromGlobal_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()

	for i := 0; i < 100; i++ {
		go func(i int) {
			log := Fork()
			log.Log("k", "The sample string.", "instance", i)
		}(i)
	}
	Log("k", "The sample string.", "instance", 0)

	out.Flush()
}

// Test logging of string value.
func TestRace_Fork_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()
	var (
		wg sync.WaitGroup
	)

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func(i int) {
			log := Fork()
			log.Log("k", "The sample string.", "instance", i)
			wg.Done()
		}(i)
	}
	Log("k", "The sample string.", "instance", 0)
	wg.Wait()

	out.Flush()
}

// Test logging of string value.
func TestRace_ForkFork_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()
	var (
		wg sync.WaitGroup
	)

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func(i int) {
			log := Fork().Fork()
			log.Log("k", "The sample string.", "instance", i)
			wg.Done()
		}(i)
	}
	Log("k", "The sample string.", "instance", 0)
	wg.Wait()

	out.Flush()
}

// Test logging of string value.
func TestRace_ForkInside_Logfmt(t *testing.T) {
	output := bytes.NewBufferString("")
	out := SinkTo(output, AsLogfmt()).Start()
	defer out.Close()
	var (
		wg  sync.WaitGroup
		log = Fork()
	)
	log.With("logger", "global")
	log.Log("k", "The sample string.", "instance", 0)

	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func(i int, log *Logger) {
			l := log.Fork().With("logger", i)
			l.Log("k", "The sample string.", "instance", i)
			wg.Done()
		}(i, log)
	}
	log.Log("k", "The sample string.", "instance", 0)
	wg.Wait()

	out.Flush()
}

// // Test logging of byte array.
// func TestLogger_LogBytesValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", []byte("The sample string with a lot of spaces."))

//	out.Flush()
//	if strings.TrimSpace(output.String()) != `k="The sample string with a lot of spaces."` {
//		t.Fail()
//	}
// }

// // Test logging of integer value.
// func TestLogger_LogIntValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", 123)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=123" {
//		t.Fail()
//	}
// }

// // Test logging of negative integer value.
// func TestLogger_LogNegativeIntValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", -123)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=-123" {
//		t.Fail()
//	}
// }

// // Test logging of float value in default (scientific) format.
// func TestLogger_LogFloatValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", 3.14159265359)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=3.14159265359e+00" {
//		t.Fail()
//	}
// }

// // Test logging of float value in fixed format.
// func TestLogger_LogFixedFloatValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	FloatFormat = 'f'
//	log.Log("k", 3.14159265359)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=3.14159265359" {
//		t.Fail()
//	}
//	// Turn back to default format.
//	FloatFormat = 'e'
// }

// // Test logging of boolean value.
// func TestLogger_LogBoolValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", true, "k2", false)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=true k2=false" {
//		t.Fail()
//	}
// }

// // Test logging of complex number.
// func TestLogger_LogComplexValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log("k", .12345E+5i, "k2", 1.e+0i)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != "k=(0.000000+12345.000000i) k2=(0.000000+1.000000i)" {
//		t.Fail()
//	}
// }

// // Test logging of time literal.
// func TestLogger_LogTimeValue_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	value := time.Now()
//	valueString := value.Format(TimeLayout)
//	defer out.Close()

//	log.Log("k", value)

//	out.Flush()
//	if strings.TrimSpace(output.String()) != fmt.Sprintf("k=%s", valueString) {
//		t.Fail()
//	}
// }

// func TestLogger_LogIntKeyInvalid_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log(123, 456)

//	out.Flush()
//	expected := `kiwi-error="non a string type (int) for the key (123)" message=456`
//	if strings.TrimSpace(output.String()) != expected {
//		t.Logf("expected %s got %v", expected, output.String())
//		t.Fail()
//	}
// }

// // The logger accepts string keys. In other cases it complains about
// // the wrong key type. It also assumes that each key followed by the
// // value.
// func TestLogger_LogThreeIntKeysInvalid_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log(123, 456, 789)

//	out.Flush()
//	expected := `kiwi-error="non a string type (int) for the key (123)" message=456 kiwi-error="non a string type (int) for the key (789)"`
//	if strings.TrimSpace(output.String()) != expected {
//		t.Logf("expected %s got %v", expected, output.String())
//		t.Fail()
//	}
// }

// // The logger accepts string keys. In other cases it complains about
// // the wrong key type. It also assumes that each key followed by the
// // value.
// func TestLogger_LogFourIntKeysInvalid_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Log(12, 34, 56, 78)

//	out.Flush()
//	expected := `kiwi-error="non a string type (int) for the key (12)" message=34 kiwi-error="non a string type (int) for the key (56)" message=78`
//	if strings.TrimSpace(output.String()) != expected {
//		t.Logf("expected %s got %v", expected, output.String())
//		t.Fail()
//	}
// }

// // Test chaining for Add()
// func TestLogger_AddMixChained_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.Add("k", "value2").Add("k2", 123).Add("k3", 3.14159265359).Log()

//	out.Flush()
//	expected := `k="value2" k2=123 k3=3.14159265359e+00`
//	if strings.TrimSpace(output.String()) != expected {
//		t.Logf("expected %s got %v", expected, output.String())
//		t.Fail()
//	}
// }

// // Test log with the context value.
// func TestLogger_WithContextPassed_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	log.With("key1", "value")
//	log.Log("key2", "value")

//	out.Flush()
//	if strings.TrimSpace(output.String()) != `key1="value" key2="value"` {
//		t.Fail()
//	}
// }

// // Test log with adding then removing the context.
// func TestLogger_WithoutContextPassed_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	// add the context
//	log.With("key1", "value")
//	// add regular pair
//	log.Add("key2", "value")
//	// remove the context and flush the record
//	log.Without("key1").Log()

//	out.Flush()
//	if strings.TrimSpace(output.String()) != `key2="value"` {
//		t.Fail()
//	}
// }

// // Test log with adding then reset the context.
// func TestLogger_ResetContext_Logfmt(t *testing.T) {
//	output := bytes.NewBufferString("")
//	log := New()
//	out := SinkTo(output, AsLogfmt()).Start()
//	defer out.Close()

//	// add the context
//	log.With("key1", "value")
//	// add regular pair
//	log.Add("key2", "value")
//	// reset the context and flush the record
//	log.ResetContext().Log()

//	out.Flush()
//	if strings.TrimSpace(output.String()) != `key2="value"` {
//		t.Fail()
//	}
// }
<|endoftext|>