<commit_before>package statemachine

import (
	"fmt"
	"sync"
	"time"

	"github.com/lytics/metafora"
)

// StateCode is the actual state key. The State struct adds additional metadata
// related to certain StateCodes.
type StateCode string

const (
	Runnable  StateCode = "runnable"  // Scheduled
	Sleeping  StateCode = "sleeping"  // Scheduled, not running until time has elapsed
	Completed StateCode = "completed" // Terminal, not scheduled
	Killed    StateCode = "killed"    // Terminal, not scheduled
	Failed    StateCode = "failed"    // Terminal, not scheduled
	Fault     StateCode = "fault"     // Scheduled, in error handling / retry logic
	Paused    StateCode = "paused"    // Scheduled, not running
)

// Terminal states will never run and cannot transition to a non-terminal
// state.
func (s StateCode) Terminal() bool {
	switch s {
	case Runnable, Sleeping, Paused, Fault:
		return false
	case Completed, Killed, Failed:
		return true
	default:
		panic("unknown state " + s)
	}
}

// State represents the current state of a stateful handler. See StateCode for
// details. Until and Errors are extra state used by the Sleeping and Fault
// states respectively.
type State struct {
	Code   StateCode  `json:"state"`
	Until  *time.Time `json:"until,omitempty"`
	Errors []Err      `json:"errors,omitempty"`
}

// copy state so mutations to Until and Errors aren't shared.
func (s *State) copy() *State {
	ns := &State{Code: s.Code}
	if s.Until != nil {
		until := *s.Until
		ns.Until = &until
	}
	for i := range s.Errors {
		ns.Errors = append(ns.Errors, s.Errors[i])
	}
	return ns
}

func (s State) String() string {
	switch s.Code {
	case Sleeping:
		return fmt.Sprintf("%s until %s", s.Code, s.Until)
	case Fault:
		return fmt.Sprintf("%s (%d errors)", s.Code, len(s.Errors))
	default:
		return string(s.Code)
	}
}

// Messages are events that cause state transitions. Until and Err are used by
// the Sleep and Error messages respectively.
type Message struct {
	Code MessageCode `json:"message"`

	// Until is when the statemachine should transition from sleeping to runnable
	Until *time.Time `json:"until,omitempty"`

	// Err is the error that caused this Error message
	Err error `json:"error,omitempty"`
}

// Valid returns true if the Message is valid. Invalid messages sent as
// commands are discarded by the state machine.
func (m Message) Valid() bool {
	switch m.Code {
	case Run, Pause, Release, Checkpoint, Complete, Kill:
		return true
	case Sleep:
		return m.Until != nil
	case Error:
		return m.Err != nil
	default:
		return false
	}
}

func (m Message) String() string {
	switch m.Code {
	case Sleep:
		if m.Until != nil {
			return fmt.Sprintf("%s until %s", m.Code, m.Until)
		}
	case Error:
		if m.Err != nil {
			return fmt.Sprintf("%s: %s", m.Code, m.Err.Error())
		}
	}
	return string(m.Code)
}

// MessageCode is the symbolic name of a state transition.
type MessageCode string

const (
	Run        MessageCode = "run"
	Sleep      MessageCode = "sleep"
	Pause      MessageCode = "pause"
	Kill       MessageCode = "kill"
	Error      MessageCode = "error"
	Complete   MessageCode = "complete"
	Checkpoint MessageCode = "checkpoint"

	// Special event which triggers state machine to exit without transitioning
	// between states.
	Release MessageCode = "release"
)

// Transitions represent a state machine transition from one state to another
// given an event message.
type Transition struct {
	Event MessageCode
	From  StateCode
	To    StateCode
}

func (t Transition) String() string {
	return fmt.Sprintf("%v---%v--->%v", t.From, t.Event, t.To)
}

var (
	// Rules is the state transition table.
	Rules = [...]Transition{
		// Runnable can transition to anything
		{Event: Checkpoint, From: Runnable, To: Runnable},
		{Event: Release, From: Runnable, To: Runnable},
		{Event: Sleep, From: Runnable, To: Sleeping},
		{Event: Complete, From: Runnable, To: Completed},
		{Event: Kill, From: Runnable, To: Killed},
		{Event: Error, From: Runnable, To: Fault},
		{Event: Pause, From: Runnable, To: Paused},

		// Sleeping can return to Runnable or be Killed/Paused
		{Event: Checkpoint, From: Sleeping, To: Sleeping},
		{Event: Sleep, From: Sleeping, To: Sleeping},
		{Event: Run, From: Sleeping, To: Runnable},
		{Event: Kill, From: Sleeping, To: Killed},
		{Event: Pause, From: Sleeping, To: Paused},
		{Event: Error, From: Sleeping, To: Fault},

		// The error state transitions to either sleeping, failed, or released (to
		// allow custom error handlers to workaround localitly related errors).
		{Event: Sleep, From: Fault, To: Sleeping},
		{Event: Error, From: Fault, To: Failed},

		// Paused can return to Runnable, be put to Sleep, or Killed
		{Event: Checkpoint, From: Paused, To: Paused},
		{Event: Release, From: Paused, To: Paused},
		{Event: Run, From: Paused, To: Runnable},
		{Event: Sleep, From: Paused, To: Sleeping},
		{Event: Kill, From: Paused, To: Killed},
		{Event: Pause, From: Paused, To: Paused},

		// Completed, Failed, and Killed are terminal states that cannot transition
		// to anything.
	}
)

// StatefulHandler is the function signature that the state machine is able to
// run. Instead of metafora.Handler's Stop method, StatefulHandlers receive
// Messages via the commands chan and return their exit status via a Message.
//
// Normally StatefulHandlers simply return a Message as soon as it's received
// on the commands chan. However, it's also acceptable for a handler to return
// a different Message. For example if it encounters an error during shutdown,
// it may choose to return that error as an Error Message as opposed to the
// original command.
type StatefulHandler func(taskID string, commands <-chan Message) Message

type stateMachine struct {
	taskID     string
	h          StatefulHandler
	ss         StateStore
	cl         CommandListener
	cmds       chan Message
	errHandler ErrHandler

	mu    *sync.RWMutex
	state *State
	ts    time.Time
}

// New handler that creates a state machine and exposes state transitions to
// the given handler by calling its Transition method. It should be created in
// the HandlerFunc you use with metafora's Consumer.
//
// If ErrHandler is nil DefaultErrHandler will be used.
func New(tid string, h StatefulHandler, ss StateStore, cl CommandListener, e ErrHandler) metafora.Handler {
	if e == nil {
		e = DefaultErrHandler
	}
	return &stateMachine{
		taskID:     tid,
		h:          h,
		ss:         ss,
		cl:         cl,
		errHandler: e,
		mu:         &sync.RWMutex{},
		ts:         time.Now(),
	}
}

// State returns the current state the state machine is in and what time it
// entered that state. The State may be nil if Run() has yet to be called.
func (s *stateMachine) State() (*State, time.Time) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.state, s.ts
}

func (s *stateMachine) setState(state *State) {
	s.mu.Lock()
	s.state = state.copy()
	s.ts = time.Now()
	s.mu.Unlock()
}

// Run the state machine enabled handler. Loads the initial state and passes
// control to the internal stateful handler passing commands from the command
// listener into the handler's commands chan.
func (s *stateMachine) Run() (done bool) {
	// Multiplex external (Stop) messages and internal ones
	stopped := make(chan struct{})
	s.cmds = make(chan Message)
	go func() {
		for {
			select {
			case m := <-s.cl.Receive():
				if !m.Valid() {
					metafora.Warnf("Ignoring invalid command: %q", m)
					continue
				}
				select {
				case s.cmds <- m:
				case <-stopped:
					return
				}
			case <-stopped:
				return
			}
		}
	}()

	// Stop the command listener and internal message multiplexer when Run exits
	defer func() {
		s.cl.Stop()
		close(stopped)
	}()

	// Load the initial state
	state, err := s.ss.Load(s.taskID)
	if err != nil {
		// A failure to load the state for a task is *fatal* - the task will be
		// unscheduled and requires operator intervention to reschedule.
		metafora.Errorf("task=%q could not load initial state. Marking done! Error: %v", s.taskID, err)
		return true
	}
	if state.Code.Terminal() {
		metafora.Warnf("task=%q in terminal state %s - exiting.", s.taskID, state.Code)
		return true
	}
	s.setState(state)

	// Main Run loop
	done = false
	for {
		metafora.Debugf("task=%q in state %s", s.taskID, state.Code)
		msg := s.exec(state)

		// Enter State
		// Apply Message
		newstate, ok := apply(state, msg)
		if !ok {
			metafora.Warnf("task=%q Invalid state transition=%q returned by task. Old state=%q", s.taskID, msg.Code, state.Code)
			msg = Message{Code: Error, Err: err}
			if newstate, ok = apply(state, msg); !ok {
				metafora.Errorf("task=%q Unable to transition to error state! Exiting with state=%q", s.taskID, state.Code)
				return state.Code.Terminal()
			}
		}

		metafora.Infof("task=%q transitioning %s --> %s --> %s", s.taskID, state, msg, newstate)

		// Save state
		if err := s.ss.Store(s.taskID, newstate); err != nil {
			metafora.Errorf("task=%q Unable to persist state=%q. Unscheduling.", s.taskID, newstate.Code)
			return true
		}

		// Set next state and loop if non-terminal
		state = newstate

		// Expose the state for introspection
		s.setState(state)

		// Exit and unschedule task on terminal state.
		if state.Code.Terminal() {
			return true
		}

		// Release messages indicate the task should exit but not unschedule.
		if msg.Code == Release {
			return false
		}
	}
}

// execute non-terminal states
func (s *stateMachine) exec(state *State) Message {
	switch state.Code {
	case Runnable:
		// Runnable passes control to the stateful handler
		return run(s.h, s.taskID, s.cmds)
	case Paused:
		// Paused until a message arrives
		return <-s.cmds
	case Sleeping:
		// Sleeping until the specified time (or a message)
		if state.Until == nil {
			metafora.Warnf("task=%q told to sleep without a time. Resuming.", s.taskID)
			return Message{Code: Run}
		}
		dur := state.Until.Sub(time.Now())
		metafora.Infof("task=%q sleeping for %s", s.taskID, dur)
		timer := time.NewTimer(dur)
		select {
		case <-timer.C:
			return Message{Code: Run}
		case msg := <-s.cmds:
			timer.Stop()
			// Checkpoint is a special case that shouldn't affect sleep time, so
			// maintain it across the state transition
			if msg.Code == Checkpoint {
				msg.Until = state.Until
			}
			return msg
		}
	case Fault:
		// Special case where we potentially trim the current state to keep
		// errors from growing without bound.
		var msg Message
		msg, state.Errors = s.errHandler(s.taskID, state.Errors)
		return msg
	default:
		panic("invalid state: " + state.String())
	}
}

func run(f StatefulHandler, tid string, cmd <-chan Message) (m Message) {
	defer func() {
		if r := recover(); r != nil {
			metafora.Errorf("task=%q Run method panic()d! Applying Error message. Panic: %v", tid, r)
			m = Message{Code: Error, Err: fmt.Errorf("panic: %v", r)}
		}
	}()
	m = f(tid, cmd)
	return m
}

// Stop sends a Release message to the state machine through the command chan.
func (s *stateMachine) Stop() {
	s.cmds <- Message{Code: Release}
}

// apply a message to cause a state transition. Returns false if the state
// transition is invalid.
func apply(cur *State, m Message) (*State, bool) {
	//XXX Is a linear scan of all rules really the best option here?
	for _, trans := range Rules {
		if trans.Event == m.Code && trans.From == cur.Code {
			metafora.Debugf("Transitioned %s", trans)
			return &State{Code: trans.To, Until: m.Until}, true
		}
	}
	return cur, false
}
<commit_msg>Fix bug where handlers could never exit<commit_after>package statemachine

import (
	"fmt"
	"sync"
	"time"

	"github.com/lytics/metafora"
)

// StateCode is the actual state key. The State struct adds additional metadata
// related to certain StateCodes.
type StateCode string

const (
	Runnable  StateCode = "runnable"  // Scheduled
	Sleeping  StateCode = "sleeping"  // Scheduled, not running until time has elapsed
	Completed StateCode = "completed" // Terminal, not scheduled
	Killed    StateCode = "killed"    // Terminal, not scheduled
	Failed    StateCode = "failed"    // Terminal, not scheduled
	Fault     StateCode = "fault"     // Scheduled, in error handling / retry logic
	Paused    StateCode = "paused"    // Scheduled, not running
)

// Terminal states will never run and cannot transition to a non-terminal
// state.
func (s StateCode) Terminal() bool {
	switch s {
	case Runnable, Sleeping, Paused, Fault:
		return false
	case Completed, Killed, Failed:
		return true
	default:
		panic("unknown state " + s)
	}
}

// State represents the current state of a stateful handler. See StateCode for
// details. Until and Errors are extra state used by the Sleeping and Fault
// states respectively.
type State struct {
	Code   StateCode  `json:"state"`
	Until  *time.Time `json:"until,omitempty"`
	Errors []Err      `json:"errors,omitempty"`
}

// copy state so mutations to Until and Errors aren't shared.
func (s *State) copy() *State {
	ns := &State{Code: s.Code}
	if s.Until != nil {
		until := *s.Until
		ns.Until = &until
	}
	for i := range s.Errors {
		ns.Errors = append(ns.Errors, s.Errors[i])
	}
	return ns
}

func (s State) String() string {
	switch s.Code {
	case Sleeping:
		return fmt.Sprintf("%s until %s", s.Code, s.Until)
	case Fault:
		return fmt.Sprintf("%s (%d errors)", s.Code, len(s.Errors))
	default:
		return string(s.Code)
	}
}

// Messages are events that cause state transitions. Until and Err are used by
// the Sleep and Error messages respectively.
type Message struct {
	Code MessageCode `json:"message"`

	// Until is when the statemachine should transition from sleeping to runnable
	Until *time.Time `json:"until,omitempty"`

	// Err is the error that caused this Error message
	Err error `json:"error,omitempty"`
}

// Valid returns true if the Message is valid. Invalid messages sent as
// commands are discarded by the state machine.
func (m Message) Valid() bool {
	switch m.Code {
	case Run, Pause, Release, Checkpoint, Complete, Kill:
		return true
	case Sleep:
		return m.Until != nil
	case Error:
		return m.Err != nil
	default:
		return false
	}
}

func (m Message) String() string {
	switch m.Code {
	case Sleep:
		if m.Until != nil {
			return fmt.Sprintf("%s until %s", m.Code, m.Until)
		}
	case Error:
		if m.Err != nil {
			return fmt.Sprintf("%s: %s", m.Code, m.Err.Error())
		}
	}
	return string(m.Code)
}

// MessageCode is the symbolic name of a state transition.
type MessageCode string

const (
	Run        MessageCode = "run"
	Sleep      MessageCode = "sleep"
	Pause      MessageCode = "pause"
	Kill       MessageCode = "kill"
	Error      MessageCode = "error"
	Complete   MessageCode = "complete"
	Checkpoint MessageCode = "checkpoint"

	// Special event which triggers state machine to exit without transitioning
	// between states.
	Release MessageCode = "release"
)

// Transitions represent a state machine transition from one state to another
// given an event message.
type Transition struct {
	Event MessageCode
	From  StateCode
	To    StateCode
}

func (t Transition) String() string {
	return fmt.Sprintf("%v---%v--->%v", t.From, t.Event, t.To)
}

var (
	// Rules is the state transition table.
	Rules = [...]Transition{
		// Runnable can transition to anything
		{Event: Checkpoint, From: Runnable, To: Runnable},
		{Event: Release, From: Runnable, To: Runnable},
		{Event: Sleep, From: Runnable, To: Sleeping},
		{Event: Complete, From: Runnable, To: Completed},
		{Event: Kill, From: Runnable, To: Killed},
		{Event: Error, From: Runnable, To: Fault},
		{Event: Pause, From: Runnable, To: Paused},

		// Sleeping can return to Runnable or be Killed/Paused
		{Event: Checkpoint, From: Sleeping, To: Sleeping},
		{Event: Sleep, From: Sleeping, To: Sleeping},
		{Event: Run, From: Sleeping, To: Runnable},
		{Event: Kill, From: Sleeping, To: Killed},
		{Event: Pause, From: Sleeping, To: Paused},
		{Event: Error, From: Sleeping, To: Fault},

		// The error state transitions to either sleeping, failed, or released (to
		// allow custom error handlers to workaround localitly related errors).
		{Event: Sleep, From: Fault, To: Sleeping},
		{Event: Error, From: Fault, To: Failed},

		// Paused can return to Runnable, be put to Sleep, or Killed
		{Event: Checkpoint, From: Paused, To: Paused},
		{Event: Release, From: Paused, To: Paused},
		{Event: Run, From: Paused, To: Runnable},
		{Event: Sleep, From: Paused, To: Sleeping},
		{Event: Kill, From: Paused, To: Killed},
		{Event: Pause, From: Paused, To: Paused},

		// Completed, Failed, and Killed are terminal states that cannot transition
		// to anything.
	}
)

// StatefulHandler is the function signature that the state machine is able to
// run. Instead of metafora.Handler's Stop method, StatefulHandlers receive
// Messages via the commands chan and return their exit status via a Message.
//
// Normally StatefulHandlers simply return a Message as soon as it's received
// on the commands chan. However, it's also acceptable for a handler to return
// a different Message. For example if it encounters an error during shutdown,
// it may choose to return that error as an Error Message as opposed to the
// original command.
type StatefulHandler func(taskID string, commands <-chan Message) Message

type stateMachine struct {
	taskID     string
	h          StatefulHandler
	ss         StateStore
	cl         CommandListener
	cmds       chan Message
	errHandler ErrHandler

	mu    *sync.RWMutex
	state *State
	ts    time.Time

	stopL   *sync.Mutex
	stopped chan bool
}

// New handler that creates a state machine and exposes state transitions to
// the given handler by calling its Transition method. It should be created in
// the HandlerFunc you use with metafora's Consumer.
//
// If ErrHandler is nil DefaultErrHandler will be used.
func New(tid string, h StatefulHandler, ss StateStore, cl CommandListener, e ErrHandler) metafora.Handler {
	if e == nil {
		e = DefaultErrHandler
	}
	return &stateMachine{
		taskID:     tid,
		h:          h,
		ss:         ss,
		cl:         cl,
		errHandler: e,
		mu:         &sync.RWMutex{},
		ts:         time.Now(),
		stopL:      &sync.Mutex{},
		stopped:    make(chan bool),
	}
}

// State returns the current state the state machine is in and what time it
// entered that state. The State may be nil if Run() has yet to be called.
func (s *stateMachine) State() (*State, time.Time) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.state, s.ts
}

func (s *stateMachine) setState(state *State) {
	s.mu.Lock()
	s.state = state.copy()
	s.ts = time.Now()
	s.mu.Unlock()
}

// Run the state machine enabled handler. Loads the initial state and passes
// control to the internal stateful handler passing commands from the command
// listener into the handler's commands chan.
func (s *stateMachine) Run() (done bool) {
	// Multiplex external (Stop) messages and internal ones
	s.cmds = make(chan Message)
	go func() {
		for {
			select {
			case m := <-s.cl.Receive():
				if !m.Valid() {
					metafora.Warnf("Ignoring invalid command: %q", m)
					continue
				}
				select {
				case s.cmds <- m:
				case <-s.stopped:
					return
				}
			case <-s.stopped:
				return
			}
		}
	}()

	// Stop the command listener and internal message multiplexer when Run exits
	defer func() {
		s.cl.Stop()
		s.stop()
	}()

	// Load the initial state
	state, err := s.ss.Load(s.taskID)
	if err != nil {
		// A failure to load the state for a task is *fatal* - the task will be
		// unscheduled and requires operator intervention to reschedule.
		metafora.Errorf("task=%q could not load initial state. Marking done! Error: %v", s.taskID, err)
		return true
	}
	if state.Code.Terminal() {
		metafora.Warnf("task=%q in terminal state %s - exiting.", s.taskID, state.Code)
		return true
	}
	s.setState(state)

	// Main Statemachine Loop
	done = false
	for {
		// Enter State
		metafora.Debugf("task=%q in state %s", s.taskID, state.Code)
		msg := s.exec(state)

		// Apply Message
		newstate, ok := apply(state, msg)
		if !ok {
			metafora.Warnf("task=%q Invalid state transition=%q returned by task. Old state=%q", s.taskID, msg.Code, state.Code)
			msg = Message{Code: Error, Err: err}
			if newstate, ok = apply(state, msg); !ok {
				metafora.Errorf("task=%q Unable to transition to error state! Exiting with state=%q", s.taskID, state.Code)
				return state.Code.Terminal()
			}
		}

		metafora.Infof("task=%q transitioning %s --> %s --> %s", s.taskID, state, msg, newstate)

		// Save state
		if err := s.ss.Store(s.taskID, newstate); err != nil {
			metafora.Errorf("task=%q Unable to persist state=%q. Unscheduling.", s.taskID, newstate.Code)
			return true
		}

		// Set next state and loop if non-terminal
		state = newstate

		// Expose the state for introspection
		s.setState(state)

		// Exit and unschedule task on terminal state.
		if state.Code.Terminal() {
			return true
		}

		// Release messages indicate the task should exit but not unschedule.
		if msg.Code == Release {
			return false
		}

		// Alternatively Stop() may have been called but the handler may not have
		// returned the Release message. Always exit if we've been told to Stop()
		// even if the handler has returned a different Message.
		select {
		case <-s.stopped:
			return false
		default:
		}
	}
}

// execute non-terminal states
func (s *stateMachine) exec(state *State) Message {
	switch state.Code {
	case Runnable:
		// Runnable passes control to the stateful handler
		return run(s.h, s.taskID, s.cmds)
	case Paused:
		// Paused until a message arrives
		return <-s.cmds
	case Sleeping:
		// Sleeping until the specified time (or a message)
		if state.Until == nil {
			metafora.Warnf("task=%q told to sleep without a time. Resuming.", s.taskID)
			return Message{Code: Run}
		}
		dur := state.Until.Sub(time.Now())
		metafora.Infof("task=%q sleeping for %s", s.taskID, dur)
		timer := time.NewTimer(dur)
		select {
		case <-timer.C:
			return Message{Code: Run}
		case msg := <-s.cmds:
			timer.Stop()
			// Checkpoint is a special case that shouldn't affect sleep time, so
			// maintain it across the state transition
			if msg.Code == Checkpoint {
				msg.Until = state.Until
			}
			return msg
		}
	case Fault:
		// Special case where we potentially trim the current state to keep
		// errors from growing without bound.
		var msg Message
		msg, state.Errors = s.errHandler(s.taskID, state.Errors)
		return msg
	default:
		panic("invalid state: " + state.String())
	}
}

func run(f StatefulHandler, tid string, cmd <-chan Message) (m Message) {
	defer func() {
		if r := recover(); r != nil {
			metafora.Errorf("task=%q Run method panic()d! Applying Error message. Panic: %v", tid, r)
			m = Message{Code: Error, Err: fmt.Errorf("panic: %v", r)}
		}
	}()
	m = f(tid, cmd)
	return m
}

// Stop sends a Release message to the state machine through the command chan.
func (s *stateMachine) Stop() {
	s.cmds <- Message{Code: Release}

	// Also inform the state machine it should exit since the internal handler
	// may override the release message causing the task to be unreleaseable.
	s.stop()
}

func (s *stateMachine) stop() {
	s.stopL.Lock()
	defer s.stopL.Unlock()
	select {
	case <-s.stopped:
		return
	default:
		close(s.stopped)
	}
}

// apply a message to cause a state transition. Returns false if the state
// transition is invalid.
func apply(cur *State, m Message) (*State, bool) {
	//XXX Is a linear scan of all rules really the best option here?
	for _, trans := range Rules {
		if trans.Event == m.Code && trans.From == cur.Code {
			metafora.Debugf("Transitioned %s", trans)
			return &State{Code: trans.To, Until: m.Until}, true
		}
	}
	return cur, false
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package openstack_test

import (
	"flag"
	"testing"

	gc "launchpad.net/gocheck"
	"launchpad.net/goose/identity"
	"launchpad.net/goose/nova"

	"github.com/juju/juju/provider/openstack"
)

var live = flag.Bool("live", false, "Include live OpenStack tests")

func Test(t *testing.T) {
	if *live {
		cred, err := identity.CompleteCredentialsFromEnv()
		if err != nil {
			t.Fatalf("Error setting up test suite: %s", err.Error())
		}
		registerLiveTests(cred)
	}
	registerLocalTests()
	gc.TestingT(t)
}

// localTests contains tests which do not require a live service or test double to run.
type localTests struct{}

var _ = gc.Suite(&localTests{})

// ported from lp:juju/juju/providers/openstack/tests/test_machine.py
var addressTests = []struct {
	summary  string
	private  []nova.IPAddress
	public   []nova.IPAddress
	networks []string
	expected string
	failure  error
}{
	{
		summary:  "missing",
		expected: "",
	},
	{
		summary:  "empty",
		private:  []nova.IPAddress{},
		networks: []string{"private"},
		expected: "",
	},
	{
		summary:  "private only",
		private:  []nova.IPAddress{{4, "192.168.0.1"}},
		networks: []string{"private"},
		expected: "192.168.0.1",
	},
	{
		summary:  "private plus (HP cloud)",
		private:  []nova.IPAddress{{4, "10.0.0.1"}, {4, "8.8.4.4"}},
		networks: []string{"private"},
		expected: "8.8.4.4",
	},
	{
		summary:  "public only",
		public:   []nova.IPAddress{{4, "8.8.8.8"}},
		networks: []string{"", "public"},
		expected: "8.8.8.8",
	},
	{
		summary:  "public and private",
		private:  []nova.IPAddress{{4, "10.0.0.4"}},
		public:   []nova.IPAddress{{4, "8.8.4.4"}},
		networks: []string{"private", "public"},
		expected: "8.8.4.4",
	},
	{
		summary:  "public private plus",
		private:  []nova.IPAddress{{4, "127.0.0.4"}, {4, "192.168.0.1"}},
		public:   []nova.IPAddress{{4, "8.8.8.8"}},
		networks: []string{"private", "public"},
		expected: "8.8.8.8",
	},
	{
		summary:  "custom only",
		private:  []nova.IPAddress{{4, "192.168.0.1"}},
		networks: []string{"special"},
		expected: "192.168.0.1",
	},
	{
		summary:  "custom and public",
		private:  []nova.IPAddress{{4, "172.16.0.1"}},
		public:   []nova.IPAddress{{4, "8.8.8.8"}},
		networks: []string{"special", "public"},
		expected: "8.8.8.8",
	},
	{
		summary:  "non-IPv4",
		private:  []nova.IPAddress{{6, "::dead:beef:f00d"}},
		networks: []string{"private"},
		expected: "",
	},
}, {
summary:    "floating and public, same address",
floatingIP: "8.8.8.8",
public:     []nova.IPAddress{{4, "8.8.8.8"}},
networks:   []string{"", "public"},
expected:   "8.8.8.8",
}, {
summary:    "floating and public, different address",
floatingIP: "8.8.4.4",
public:     []nova.IPAddress{{4, "8.8.8.8"}},
networks:   []string{"", "public"},
expected:   "8.8.4.4",
}, {
summary:    "floating and private",
floatingIP: "8.8.4.4",
private:    []nova.IPAddress{{4, "10.0.0.1"}},
networks:   []string{"private"},
expected:   "8.8.4.4",
}, {
summary:    "floating, custom and public",
floatingIP: "8.8.4.4",
private:    []nova.IPAddress{{4, "172.16.0.1"}},
public:     []nova.IPAddress{{4, "8.8.8.8"}},
networks:   []string{"special", "public"},
expected:   "8.8.4.4",
}}
}

func (t *localTests) TestGetServerAddresses(c *gc.C) {
	for i, t := range addressTests {
		c.Logf("#%d. %s -> %s (%v)", i, t.summary, t.expected, t.failure)
		addresses := make(map[string][]nova.IPAddress)
		if t.private != nil {
			if len(t.networks) < 1 {
				addresses["private"] = t.private
			} else {
				addresses[t.networks[0]] = t.private
			}
		}
		if t.public != nil {
			if len(t.networks) < 2 {
				addresses["public"] = t.public
			} else {
				addresses[t.networks[1]] = t.public
			}
		}
		addr := openstack.InstanceAddress(t.floatingIP, addresses)
		c.Assert(addr, gc.Equals, t.expected)
	}
}
<commit_msg>Tweak formatting<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package openstack_test

import (
	"flag"
	"testing"

	gc "launchpad.net/gocheck"
	"launchpad.net/goose/identity"
	"launchpad.net/goose/nova"

	"github.com/juju/juju/provider/openstack"
)

var live = flag.Bool("live", false, "Include live OpenStack tests")

func Test(t *testing.T) {
	if *live {
		cred, err := identity.CompleteCredentialsFromEnv()
		if err != nil {
			t.Fatalf("Error setting up test suite: %s", err.Error())
		}
		registerLiveTests(cred)
	}
	registerLocalTests()
	gc.TestingT(t)
}

// localTests contains tests which do not require a live service or test double to run.
type localTests struct{}

var _ = gc.Suite(&localTests{})

// ported from lp:juju/juju/providers/openstack/tests/test_machine.py
var addressTests = []struct {
	summary    string
	floatingIP string
	private    []nova.IPAddress
	public     []nova.IPAddress
	networks   []string
	expected   string
	failure    error
}{
	{
		summary:  "missing",
		expected: "",
	},
	{
		summary:  "empty",
		private:  []nova.IPAddress{},
		networks: []string{"private"},
		expected: "",
	},
	{
		summary:  "private only",
		private:  []nova.IPAddress{{4, "192.168.0.1"}},
		networks: []string{"private"},
		expected: "192.168.0.1",
	},
	{
		summary:  "private plus (HP cloud)",
		private:  []nova.IPAddress{{4, "10.0.0.1"}, {4, "8.8.4.4"}},
		networks: []string{"private"},
		expected: "8.8.4.4",
	},
	{
		summary:  "public only",
		public:   []nova.IPAddress{{4, "8.8.8.8"}},
		networks: []string{"", "public"},
		expected: "8.8.8.8",
	},
	{
		summary:  "public and private",
		private:  []nova.IPAddress{{4, "10.0.0.4"}},
		public:   []nova.IPAddress{{4, "8.8.4.4"}},
		networks: []string{"private", "public"},
		expected: "8.8.4.4",
	},
	{
		summary:  "public private plus",
		private:  []nova.IPAddress{{4, "127.0.0.4"}, {4, "192.168.0.1"}},
		public:   []nova.IPAddress{{4, "8.8.8.8"}},
		networks: []string{"private", "public"},
		expected: "8.8.8.8",
	},
	{
		summary:  "custom only",
		private:  []nova.IPAddress{{4, "192.168.0.1"}},
		networks: []string{"special"},
		expected: "192.168.0.1",
	},
	{
		summary:  "custom and public",
		private:  []nova.IPAddress{{4, "172.16.0.1"}},
		public:   []nova.IPAddress{{4, "8.8.8.8"}},
		networks: []string{"special", "public"},
		expected: "8.8.8.8",
	},
	{
		summary:  "non-IPv4",
		private:  []nova.IPAddress{{6, "::dead:beef:f00d"}},
		networks: []string{"private"},
		expected: "",
	},
	{
		summary:    "floating and public, same address",
		floatingIP: "8.8.8.8",
		public:     []nova.IPAddress{{4, "8.8.8.8"}},
		networks:   []string{"", "public"},
		expected:   "8.8.8.8",
	},
	{
		summary:    "floating and public, different address",
		floatingIP: "8.8.4.4",
		public:     []nova.IPAddress{{4, "8.8.8.8"}},
		networks:   []string{"", "public"},
		expected:   "8.8.4.4",
	},
	{
		summary:    "floating and private",
		floatingIP: "8.8.4.4",
		private:    []nova.IPAddress{{4, "10.0.0.1"}},
		networks:   []string{"private"},
		expected:   "8.8.4.4",
	},
	{
		summary:    "floating, custom and public",
		floatingIP: "8.8.4.4",
		private:    []nova.IPAddress{{4, "172.16.0.1"}},
		public:     []nova.IPAddress{{4, "8.8.8.8"}},
		networks:   []string{"special", "public"},
		expected:   "8.8.4.4",
	},
}

func (t *localTests) TestGetServerAddresses(c *gc.C) {
	for i, t := range addressTests {
		c.Logf("#%d. %s -> %s (%v)", i, t.summary, t.expected, t.failure)
		addresses := make(map[string][]nova.IPAddress)
		if t.private != nil {
			if len(t.networks) < 1 {
				addresses["private"] = t.private
			} else {
				addresses[t.networks[0]] = t.private
			}
		}
		if t.public != nil {
			if len(t.networks) < 2 {
				addresses["public"] = t.public
			} else {
				addresses[t.networks[1]] = t.public
			}
		}
		addr := openstack.InstanceAddress(t.floatingIP, addresses)
		c.Assert(addr, gc.Equals, t.expected)
	}
}
<|endoftext|>


<commit_before>package statemachine

import (
	"fmt"
	"sync"
	"time"

	"github.com/lytics/metafora"
)

// StateCode is the actual state key. The State struct adds additional metadata
// related to certain StateCodes.
type StateCode string

const (
	Runnable  StateCode = "runnable"  // Scheduled
	Sleeping  StateCode = "sleeping"  // Scheduled, not running until time has elapsed
	Completed StateCode = "completed" // Terminal, not scheduled
	Killed    StateCode = "killed"    // Terminal, not scheduled
	Failed    StateCode = "failed"    // Terminal, not scheduled
	Fault     StateCode = "fault"     // Scheduled, in error handling / retry logic
	Paused    StateCode = "paused"    // Scheduled, not running
)

// Terminal states will never run and cannot transition to a non-terminal
// state.
func (s StateCode) Terminal() bool {
	switch s {
	case Runnable, Sleeping, Paused, Fault:
		return false
	case Completed, Killed, Failed:
		return true
	default:
		panic("unknown state " + s)
	}
}

// State represents the current state of a stateful handler. See StateCode for
// details. Until and Errors are extra state used by the Sleeping and Fault
// states respectively.
type State struct {
	Code   StateCode  `json:"state"`
	Until  *time.Time `json:"until,omitempty"`
	Errors []Err      `json:"errors,omitempty"`
}

// copy state so mutations to Until and Errors aren't shared.
func (s *State) copy() *State {
	ns := &State{Code: s.Code}
	if s.Until != nil {
		until := *s.Until
		ns.Until = &until
	}
	for i := range s.Errors {
		ns.Errors = append(ns.Errors, s.Errors[i])
	}
	return ns
}

func (s State) String() string {
	switch s.Code {
	case Sleeping:
		return fmt.Sprintf("%s until %s", s.Code, s.Until)
	case Fault:
		return fmt.Sprintf("%s (%d errors)", s.Code, len(s.Errors))
	default:
		return string(s.Code)
	}
}

// Messages are events that cause state transitions. Until and Err are used by
// the Sleep and Error messages respectively.
type Message struct {
	Code MessageCode `json:"message"`

	// Until is when the statemachine should transition from sleeping to runnable
	Until *time.Time `json:"until,omitempty"`

	// Err is the error that caused this Error message
	Err error `json:"error,omitempty"`
}

// Valid returns true if the Message is valid. Invalid messages sent as
// commands are discarded by the state machine.
func (m Message) Valid() bool {
	switch m.Code {
	case Run, Pause, Release, Checkpoint, Complete, Kill:
		return true
	case Sleep:
		return m.Until != nil
	case Error:
		return m.Err != nil
	default:
		return false
	}
}

func (m Message) String() string {
	switch m.Code {
	case Sleep:
		if m.Until != nil {
			return fmt.Sprintf("%s until %s", m.Code, m.Until)
		}
	case Error:
		if m.Err != nil {
			return fmt.Sprintf("%s: %s", m.Code, m.Err.Error())
		}
	}
	return string(m.Code)
}

// MessageCode is the symbolic name of a state transition.
type MessageCode string

const (
	Run        MessageCode = "run"
	Sleep      MessageCode = "sleep"
	Pause      MessageCode = "pause"
	Kill       MessageCode = "kill"
	Error      MessageCode = "error"
	Complete   MessageCode = "complete"
	Checkpoint MessageCode = "checkpoint"

	// Special event which triggers state machine to exit without transitioning
	// between states.
	Release MessageCode = "release"
)

// Transitions represent a state machine transition from one state to another
// given an event message.
type Transition struct {
	Event MessageCode
	From  StateCode
	To    StateCode
}

func (t Transition) String() string {
	return fmt.Sprintf("%v---%v--->%v", t.From, t.Event, t.To)
}

var (
	// Rules is the state transition table.
	Rules = [...]Transition{
		// Runnable can transition to anything
		{Event: Checkpoint, From: Runnable, To: Runnable},
		{Event: Release, From: Runnable, To: Runnable},
		{Event: Sleep, From: Runnable, To: Sleeping},
		{Event: Complete, From: Runnable, To: Completed},
		{Event: Kill, From: Runnable, To: Killed},
		{Event: Error, From: Runnable, To: Fault},
		{Event: Pause, From: Runnable, To: Paused},

		// Sleeping can return to Runnable or be Killed/Paused
		{Event: Checkpoint, From: Sleeping, To: Sleeping},
		{Event: Release, From: Sleeping, To: Sleeping},
		{Event: Sleep, From: Sleeping, To: Sleeping},
		{Event: Run, From: Sleeping, To: Runnable},
		{Event: Kill, From: Sleeping, To: Killed},
		{Event: Pause, From: Sleeping, To: Paused},
		{Event: Error, From: Sleeping, To: Fault},

		// The error state transitions to either sleeping, failed, or released (to
		// allow custom error handlers to workaround localitly related errors).
		{Event: Sleep, From: Fault, To: Sleeping},
		{Event: Error, From: Fault, To: Failed},

		// Paused can return to Runnable, be put to Sleep, or Killed
		{Event: Checkpoint, From: Paused, To: Paused},
		{Event: Release, From: Paused, To: Paused},
		{Event: Run, From: Paused, To: Runnable},
		{Event: Sleep, From: Paused, To: Sleeping},
		{Event: Kill, From: Paused, To: Killed},
		{Event: Pause, From: Paused, To: Paused},

		// Completed, Failed, and Killed are terminal states that cannot transition
		// to anything.
	}
)

// StatefulHandler is the function signature that the state machine is able to
// run. Instead of metafora.Handler's Stop method, StatefulHandlers receive
// Messages via the commands chan and return their exit status via a Message.
//
// Normally StatefulHandlers simply return a Message as soon as it's received
// on the commands chan. However, it's also acceptable for a handler to return
// a different Message. For example if it encounters an error during shutdown,
// it may choose to return that error as an Error Message as opposed to the
// original command.
type StatefulHandler func(taskID string, commands <-chan Message) Message

type stateMachine struct {
	taskID     string
	h          StatefulHandler
	ss         StateStore
	cl         CommandListener
	cmds       chan Message
	errHandler ErrHandler

	mu    *sync.RWMutex
	state *State
	ts    time.Time

	stopL   *sync.Mutex
	stopped chan bool
}

// New handler that creates a state machine and exposes state transitions to
// the given handler by calling its Transition method. It should be created in
// the HandlerFunc you use with metafora's Consumer.
//
// If ErrHandler is nil DefaultErrHandler will be used.
func New(tid string, h StatefulHandler, ss StateStore, cl CommandListener, e ErrHandler) metafora.Handler {
	if e == nil {
		e = DefaultErrHandler
	}
	return &stateMachine{
		taskID:     tid,
		h:          h,
		ss:         ss,
		cl:         cl,
		errHandler: e,
		mu:         &sync.RWMutex{},
		ts:         time.Now(),
		stopL:      &sync.Mutex{},
		stopped:    make(chan bool),
	}
}

// State returns the current state the state machine is in and what time it
// entered that state. The State may be nil if Run() has yet to be called.
func (s *stateMachine) State() (*State, time.Time) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.state, s.ts
}

func (s *stateMachine) setState(state *State) {
	s.mu.Lock()
	s.state = state.copy()
	s.ts = time.Now()
	s.mu.Unlock()
}

// Run the state machine enabled handler. Loads the initial state and passes
// control to the internal stateful handler passing commands from the command
// listener into the handler's commands chan.
func (s *stateMachine) Run() (done bool) {
	// Multiplex external (Stop) messages and internal ones
	s.cmds = make(chan Message)
	go func() {
		for {
			select {
			case m := <-s.cl.Receive():
				if !m.Valid() {
					metafora.Warnf("Ignoring invalid command: %q", m)
					continue
				}
				select {
				case s.cmds <- m:
				case <-s.stopped:
					return
				}
			case <-s.stopped:
				return
			}
		}
	}()

	// Stop the command listener and internal message multiplexer when Run exits
	defer func() {
		s.cl.Stop()
		s.stop()
	}()

	// Load the initial state
	state, err := s.ss.Load(s.taskID)
	if err != nil {
		// A failure to load the state for a task is *fatal* - the task will be
		// unscheduled and requires operator intervention to reschedule.
		metafora.Errorf("task=%q could not load initial state. Marking done! Error: %v", s.taskID, err)
		return true
	}
	if state.Code.Terminal() {
		metafora.Warnf("task=%q in terminal state %s - exiting.", s.taskID, state.Code)
		return true
	}
	s.setState(state)

	// Main Statemachine Loop
	done = false
	for {
		// Enter State
		metafora.Debugf("task=%q in state %s", s.taskID, state.Code)
		msg := s.exec(state)

		// Apply Message
		newstate, ok := apply(state, msg)
		if !ok {
			metafora.Warnf("task=%q Invalid state transition=%q returned by task. Old state=%q", s.taskID, msg.Code, state.Code)
			msg = Message{Code: Error, Err: err}
			if newstate, ok = apply(state, msg); !ok {
				metafora.Errorf("task=%q Unable to transition to error state! Exiting with state=%q", s.taskID, state.Code)
				return state.Code.Terminal()
			}
		}

		metafora.Infof("task=%q transitioning %s --> %s --> %s", s.taskID, state, msg, newstate)

		// Save state
		if err := s.ss.Store(s.taskID, newstate); err != nil {
			metafora.Errorf("task=%q Unable to persist state=%q. Unscheduling.", s.taskID, newstate.Code)
			return true
		}

		// Set next state and loop if non-terminal
		state = newstate

		// Expose the state for introspection
		s.setState(state)

		// Exit and unschedule task on terminal state.
		if state.Code.Terminal() {
			return true
		}

		// Release messages indicate the task should exit but not unschedule.
		if msg.Code == Release {
			return false
		}

		// Alternatively Stop() may have been called but the handler may not have
		// returned the Release message. Always exit if we've been told to Stop()
		// even if the handler has returned a different Message.
		select {
		case <-s.stopped:
			return false
		default:
		}
	}
}

// execute non-terminal states
func (s *stateMachine) exec(state *State) Message {
	switch state.Code {
	case Runnable:
		// Runnable passes control to the stateful handler
		return run(s.h, s.taskID, s.cmds)
	case Paused:
		// Paused until a message arrives
		return <-s.cmds
	case Sleeping:
		// Sleeping until the specified time (or a message)
		if state.Until == nil {
			metafora.Warnf("task=%q told to sleep without a time. Resuming.", s.taskID)
			return Message{Code: Run}
		}
		dur := state.Until.Sub(time.Now())
		metafora.Infof("task=%q sleeping for %s", s.taskID, dur)
		timer := time.NewTimer(dur)
		select {
		case <-timer.C:
			return Message{Code: Run}
		case msg := <-s.cmds:
			timer.Stop()
			// Checkpoint & Release are special cases that shouldn't affect sleep
			// time, so maintain it across the state transition
			if msg.Code == Checkpoint || msg.Code == Release {
				msg.Until = state.Until
			}
			return msg
		}
	case Fault:
		// Special case where we potentially trim the current state to keep
		// errors from growing without bound.
		var msg Message
		msg, state.Errors = s.errHandler(s.taskID, state.Errors)
		return msg
	default:
		panic("invalid state: " + state.String())
	}
}

func run(f StatefulHandler, tid string, cmd <-chan Message) (m Message) {
	defer func() {
		if r := recover(); r != nil {
			metafora.Errorf("task=%q Run method panic()d! Applying Error message. Panic: %v", tid, r)
			m = Message{Code: Error, Err: fmt.Errorf("panic: %v", r)}
		}
	}()
	m = f(tid, cmd)
	return m
}

// Stop sends a Release message to the state machine through the command chan.
func (s *stateMachine) Stop() {
	s.cmds <- Message{Code: Release}

	// Also inform the state machine it should exit since the internal handler
	// may override the release message causing the task to be unreleaseable.
	s.stop()
}

func (s *stateMachine) stop() {
	s.stopL.Lock()
	defer s.stopL.Unlock()
	select {
	case <-s.stopped:
		return
	default:
		close(s.stopped)
	}
}

// apply a message to cause a state transition. Returns false if the state
// transition is invalid.
func apply(cur *State, m Message) (*State, bool) {
	//XXX Is a linear scan of all rules really the best option here?
	for _, trans := range Rules {
		if trans.Event == m.Code && trans.From == cur.Code {
			metafora.Debugf("Transitioned %s", trans)
			if m.Err != nil {
				// Append errors from message
				cur.Errors = append(cur.Errors, Err{Time: time.Now(), Err: m.Err.Error()})
			}

			// New State + Message's Until + Combined Errors
			return &State{Code: trans.To, Until: m.Until, Errors: cur.Errors}, true
		}
	}
	return cur, false
}
<commit_msg>Make stateful handler command chan very defensive<commit_after>package statemachine

import (
	"fmt"
	"sync"
	"time"

	"github.com/lytics/metafora"
)

// StateCode is the actual state key. The State struct adds additional metadata
// related to certain StateCodes.
type StateCode string

const (
	Runnable  StateCode = "runnable"  // Scheduled
	Sleeping  StateCode = "sleeping"  // Scheduled, not running until time has elapsed
	Completed StateCode = "completed" // Terminal, not scheduled
	Killed    StateCode = "killed"    // Terminal, not scheduled
	Failed    StateCode = "failed"    // Terminal, not scheduled
	Fault     StateCode = "fault"     // Scheduled, in error handling / retry logic
	Paused    StateCode = "paused"    // Scheduled, not running
)

// Terminal states will never run and cannot transition to a non-terminal
// state.
func (s StateCode) Terminal() bool {
	switch s {
	case Runnable, Sleeping, Paused, Fault:
		return false
	case Completed, Killed, Failed:
		return true
	default:
		panic("unknown state " + s)
	}
}

// State represents the current state of a stateful handler. See StateCode for
// details. Until and Errors are extra state used by the Sleeping and Fault
// states respectively.
type State struct {
	Code   StateCode  `json:"state"`
	Until  *time.Time `json:"until,omitempty"`
	Errors []Err      `json:"errors,omitempty"`
}

// copy state so mutations to Until and Errors aren't shared.
func (s *State) copy() *State {
	ns := &State{Code: s.Code}
	if s.Until != nil {
		until := *s.Until
		ns.Until = &until
	}
	for i := range s.Errors {
		ns.Errors = append(ns.Errors, s.Errors[i])
	}
	return ns
}

func (s State) String() string {
	switch s.Code {
	case Sleeping:
		return fmt.Sprintf("%s until %s", s.Code, s.Until)
	case Fault:
		return fmt.Sprintf("%s (%d errors)", s.Code, len(s.Errors))
	default:
		return string(s.Code)
	}
}

// Messages are events that cause state transitions. Until and Err are used by
// the Sleep and Error messages respectively.
type Message struct {
	Code MessageCode `json:"message"`

	// Until is when the statemachine should transition from sleeping to runnable
	Until *time.Time `json:"until,omitempty"`

	// Err is the error that caused this Error message
	Err error `json:"error,omitempty"`
}

// Valid returns true if the Message is valid. Invalid messages sent as
// commands are discarded by the state machine.
func (m Message) Valid() bool {
	switch m.Code {
	case Run, Pause, Release, Checkpoint, Complete, Kill:
		return true
	case Sleep:
		return m.Until != nil
	case Error:
		return m.Err != nil
	default:
		return false
	}
}

func (m Message) String() string {
	switch m.Code {
	case Sleep:
		if m.Until != nil {
			return fmt.Sprintf("%s until %s", m.Code, m.Until)
		}
	case Error:
		if m.Err != nil {
			return fmt.Sprintf("%s: %s", m.Code, m.Err.Error())
		}
	}
	return string(m.Code)
}

// MessageCode is the symbolic name of a state transition.
type MessageCode string

const (
	Run        MessageCode = "run"
	Sleep      MessageCode = "sleep"
	Pause      MessageCode = "pause"
	Kill       MessageCode = "kill"
	Error      MessageCode = "error"
	Complete   MessageCode = "complete"
	Checkpoint MessageCode = "checkpoint"

	// Special event which triggers state machine to exit without transitioning
	// between states.
	Release MessageCode = "release"
)

// Transitions represent a state machine transition from one state to another
// given an event message.
type Transition struct {
	Event MessageCode
	From  StateCode
	To    StateCode
}

func (t Transition) String() string {
	return fmt.Sprintf("%v---%v--->%v", t.From, t.Event, t.To)
}

var (
	// Rules is the state transition table.
	Rules = [...]Transition{
		// Runnable can transition to anything
		{Event: Checkpoint, From: Runnable, To: Runnable},
		{Event: Release, From: Runnable, To: Runnable},
		{Event: Sleep, From: Runnable, To: Sleeping},
		{Event: Complete, From: Runnable, To: Completed},
		{Event: Kill, From: Runnable, To: Killed},
		{Event: Error, From: Runnable, To: Fault},
		{Event: Pause, From: Runnable, To: Paused},

		// Sleeping can return to Runnable or be Killed/Paused
		{Event: Checkpoint, From: Sleeping, To: Sleeping},
		{Event: Release, From: Sleeping, To: Sleeping},
		{Event: Sleep, From: Sleeping, To: Sleeping},
		{Event: Run, From: Sleeping, To: Runnable},
		{Event: Kill, From: Sleeping, To: Killed},
		{Event: Pause, From: Sleeping, To: Paused},
		{Event: Error, From: Sleeping, To: Fault},

		// The error state transitions to either sleeping, failed, or released (to
		// allow custom error handlers to workaround localitly related errors).
		{Event: Sleep, From: Fault, To: Sleeping},
		{Event: Error, From: Fault, To: Failed},

		// Paused can return to Runnable, be put to Sleep, or Killed
		{Event: Checkpoint, From: Paused, To: Paused},
		{Event: Release, From: Paused, To: Paused},
		{Event: Run, From: Paused, To: Runnable},
		{Event: Sleep, From: Paused, To: Sleeping},
		{Event: Kill, From: Paused, To: Killed},
		{Event: Pause, From: Paused, To: Paused},

		// Completed, Failed, and Killed are terminal states that cannot transition
		// to anything.
	}
)

// StatefulHandler is the function signature that the state machine is able to
// run. Instead of metafora.Handler's Stop method, StatefulHandlers receive
// Messages via the commands chan and return their exit status via a Message.
//
// Normally StatefulHandlers simply return a Message as soon as it's received
// on the commands chan. However, it's also acceptable for a handler to return
// a different Message. For example if it encounters an error during shutdown,
// it may choose to return that error as an Error Message as opposed to the
// original command.
type StatefulHandler func(taskID string, commands <-chan Message) Message

type stateMachine struct {
	taskID     string
	h          StatefulHandler
	ss         StateStore
	cl         CommandListener
	cmds       chan Message
	errHandler ErrHandler

	mu    *sync.RWMutex
	state *State
	ts    time.Time

	stopL   *sync.Mutex
	stopped chan bool
}

// New handler that creates a state machine and exposes state transitions to
// the given handler by calling its Transition method. It should be created in
// the HandlerFunc you use with metafora's Consumer.
//
// If ErrHandler is nil DefaultErrHandler will be used.
func New(tid string, h StatefulHandler, ss StateStore, cl CommandListener, e ErrHandler) metafora.Handler {
	if e == nil {
		e = DefaultErrHandler
	}
	return &stateMachine{
		taskID:     tid,
		h:          h,
		ss:         ss,
		cl:         cl,
		errHandler: e,
		mu:         &sync.RWMutex{},
		ts:         time.Now(),
		stopL:      &sync.Mutex{},
		stopped:    make(chan bool),
	}
}

// State returns the current state the state machine is in and what time it
// entered that state. The State may be nil if Run() has yet to be called.
func (s *stateMachine) State() (*State, time.Time) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.state, s.ts
}

func (s *stateMachine) setState(state *State) {
	s.mu.Lock()
	s.state = state.copy()
	s.ts = time.Now()
	s.mu.Unlock()
}

// Run the state machine enabled handler. Loads the initial state and passes
// control to the internal stateful handler passing commands from the command
// listener into the handler's commands chan.
func (s *stateMachine) Run() (done bool) {
	// Multiplex external (Stop) messages and internal ones
	s.cmds = make(chan Message)
	go func() {
		for {
			select {
			case m := <-s.cl.Receive():
				if !m.Valid() {
					metafora.Warnf("Ignoring invalid command: %q", m)
					continue
				}
				select {
				case s.cmds <- m:
				case <-s.stopped:
					return
				}
			case <-s.stopped:
				return
			}
		}
	}()

	// Stop the command listener and internal message multiplexer when Run exits
	defer func() {
		s.cl.Stop()
		s.stop()
	}()

	// Load the initial state
	state, err := s.ss.Load(s.taskID)
	if err != nil {
		// A failure to load the state for a task is *fatal* - the task will be
		// unscheduled and requires operator intervention to reschedule.
		metafora.Errorf("task=%q could not load initial state. Marking done! Error: %v", s.taskID, err)
		return true
	}
	if state.Code.Terminal() {
		metafora.Warnf("task=%q in terminal state %s - exiting.", s.taskID, state.Code)
		return true
	}
	s.setState(state)

	// Main Statemachine Loop
	done = false
	for {
		// Enter State
		metafora.Debugf("task=%q in state %s", s.taskID, state.Code)
		msg := s.exec(state)

		// Apply Message
		newstate, ok := apply(state, msg)
		if !ok {
			metafora.Warnf("task=%q Invalid state transition=%q returned by task. Old state=%q", s.taskID, msg.Code, state.Code)
			msg = Message{Code: Error, Err: err}
			if newstate, ok = apply(state, msg); !ok {
				metafora.Errorf("task=%q Unable to transition to error state! Exiting with state=%q", s.taskID, state.Code)
				return state.Code.Terminal()
			}
		}

		metafora.Infof("task=%q transitioning %s --> %s --> %s", s.taskID, state, msg, newstate)

		// Save state
		if err := s.ss.Store(s.taskID, newstate); err != nil {
			metafora.Errorf("task=%q Unable to persist state=%q. Unscheduling.", s.taskID, newstate.Code)
			return true
		}

		// Set next state and loop if non-terminal
		state = newstate

		// Expose the state for introspection
		s.setState(state)

		// Exit and unschedule task on terminal state.
		if state.Code.Terminal() {
			return true
		}

		// Release messages indicate the task should exit but not unschedule.
		if msg.Code == Release {
			return false
		}

		// Alternatively Stop() may have been called but the handler may not have
		// returned the Release message. Always exit if we've been told to Stop()
		// even if the handler has returned a different Message.
		select {
		case <-s.stopped:
			return false
		default:
		}
	}
}

// execute non-terminal states
func (s *stateMachine) exec(state *State) Message {
	switch state.Code {
	case Runnable:
		// Runnable passes control to the stateful handler
		return run(s.h, s.taskID, s.cmds)
	case Paused:
		// Paused until a message arrives
		return <-s.cmds
	case Sleeping:
		// Sleeping until the specified time (or a message)
		if state.Until == nil {
			metafora.Warnf("task=%q told to sleep without a time. Resuming.", s.taskID)
			return Message{Code: Run}
		}
		dur := state.Until.Sub(time.Now())
		metafora.Infof("task=%q sleeping for %s", s.taskID, dur)
		timer := time.NewTimer(dur)
		select {
		case <-timer.C:
			return Message{Code: Run}
		case msg := <-s.cmds:
			timer.Stop()
			// Checkpoint & Release are special cases that shouldn't affect sleep
			// time, so maintain it across the state transition
			if msg.Code == Checkpoint || msg.Code == Release {
				msg.Until = state.Until
			}
			return msg
		}
	case Fault:
		// Special case where we potentially trim the current state to keep
		// errors from growing without bound.
		var msg Message
		msg, state.Errors = s.errHandler(s.taskID, state.Errors)
		return msg
	default:
		panic("invalid state: " + state.String())
	}
}

func run(f StatefulHandler, tid string, cmd <-chan Message) (m Message) {
	defer func() {
		if r := recover(); r != nil {
			metafora.Errorf("task=%q Run method panic()d! Applying Error message. Panic: %v", tid, r)
			m = Message{Code: Error, Err: fmt.Errorf("panic: %v", r)}
		}
	}()

	// Defensive code to give handlers a *copy* of the command chan. That way if
	// a handler keeps receiving on the command chan in a goroutine past the
	// handler's lifetime it doesn't intercept commands intended for the
	// statemachine.
	internalcmd := make(chan Message)
	stopped := make(chan struct{})
	go func() {
		for {
			select {
			case c := <-cmd:
				internalcmd <- c
			case <-stopped:
				return
			}
		}
	}()
	defer close(stopped)

	m = f(tid, internalcmd)
	return m
}

// Stop sends a Release message to the state machine through the command chan.
func (s *stateMachine) Stop() {
	s.cmds <- Message{Code: Release}

	// Also inform the state machine it should exit since the internal handler
	// may override the release message causing the task to be unreleaseable.
	s.stop()
}

func (s *stateMachine) stop() {
	s.stopL.Lock()
	defer s.stopL.Unlock()
	select {
	case <-s.stopped:
		return
	default:
		close(s.stopped)
	}
}

// apply a message to cause a state transition. Returns false if the state
// transition is invalid.
func apply(cur *State, m Message) (*State, bool) {
	//XXX Is a linear scan of all rules really the best option here?
	for _, trans := range Rules {
		if trans.Event == m.Code && trans.From == cur.Code {
			metafora.Debugf("Transitioned %s", trans)
			if m.Err != nil {
				// Append errors from message
				cur.Errors = append(cur.Errors, Err{Time: time.Now(), Err: m.Err.Error()})
			}

			// New State + Message's Until + Combined Errors
			return &State{Code: trans.To, Until: m.Until, Errors: cur.Errors}, true
		}
	}
	return cur, false
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package json

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestNewWithInaccessibleFilename(t *testing.T) {
	p := string("/this_should_not_exist/badplacetolog.log")
	collector, err := New(p)
	assert.NotEqual(t, err, error(nil))
	assert.Equal(t, collector, (*Collector)(nil))
}

func TestNewWithFileName(t *testing.T) {
	p := string("/tmp/okplacetolog.log")
	collector, err := New(p)
	assert.Equal(t, err, error(nil))
	assert.NotEqual(t, collector, (*Collector)(nil))
}

func TestNewWithLocalFilename1(t *testing.T) {
	p := string("./okplacetolog.log")
	collector, err := New(p)
	assert.Equal(t, err, error(nil))
	assert.NotEqual(t, collector, (*Collector)(nil))
}

func TestNewWithLocalFilename2(t *testing.T) {
	p := string("okplacetolog.log")
	collector, err := New(p)
	assert.Equal(t, err, error(nil))
	assert.NotEqual(t, collector, (*Collector)(nil))
}
<commit_msg>[test/fix] Delete temp files created by stats/json<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package json

import (
	"github.com/stretchr/testify/assert"
	"os"
	"testing"
)

func TestNewWithInaccessibleFilename(t *testing.T) {
	p := string("/this_should_not_exist/badplacetolog.log")
	collector, err := New(p)
	assert.NotEqual(t, err, error(nil))
	assert.Equal(t, collector, (*Collector)(nil))
}

func TestNewWithFileName(t *testing.T) {
	p := string("/tmp/okplacetolog.log")
	defer func() { _ = os.Remove(p) }()
	collector, err := New(p)
	assert.Equal(t, err, error(nil))
	assert.NotEqual(t, collector, (*Collector)(nil))
}

func TestNewWithLocalFilename1(t *testing.T) {
	p := string("./okplacetolog.log")
	defer func() { _ = os.Remove(p) }()
	collector, err := New(p)
	assert.Equal(t, err, error(nil))
	assert.NotEqual(t, collector, (*Collector)(nil))
}

func TestNewWithLocalFilename2(t *testing.T) {
	p := string("okplacetolog.log")
	defer func() { _ = os.Remove(p) }()
	collector, err := New(p)
	assert.Equal(t, err, error(nil))
	assert.NotEqual(t, collector, (*Collector)(nil))
}
<|endoftext|>


<commit_before>package worker

import (
	"testing"
	"time"

	gocontext "golang.org/x/net/context"

	"github.com/mitchellh/multistep"
	"github.com/stretchr/testify/assert"
	"github.com/travis-ci/worker/backend"
	"github.com/travis-ci/worker/config"
)

func setupStepOpenLogWriter() (*stepOpenLogWriter, multistep.StateBag) {
	s := &stepOpenLogWriter{logTimeout: time.Second, maxLogLength: 4}

	bp, _ := backend.NewBackendProvider("fake",
		config.ProviderConfigFromMap(map[string]string{
			"STARTUP_DURATION": "42.17s",
		}))

	ctx := gocontext.TODO()
	instance, _ := bp.Start(ctx, nil)

	job := &fakeJob{
		payload: &JobPayload{
			Type: "job:test",
			Job: JobJobPayload{
				ID:     2,
				Number: "3.1",
			},
			Build: BuildPayload{
				ID:     1,
				Number: "3",
			},
			Repository: RepositoryPayload{
				ID:   4,
				Slug: "green-eggs/ham",
			},
			UUID:     "foo-bar",
			Config:   map[string]interface{}{},
			Timeouts: TimeoutsPayload{},
		},
	}

	state := &multistep.BasicStateBag{}
	state.Put("ctx", ctx)
	state.Put("buildJob", job)

	return s, state
}

func TestStepOpenLogWriter_Run(t *testing.T) {
	s, state := setupStepOpenLogWriter()
	action := s.Run(state)
	assert.Equal(t, multistep.ActionContinue, action)
	assert.NotNil(t, state.Get("logWriter"))
}
<commit_msg>step_open_log_writer: remove unused vars<commit_after>package worker

import (
	"testing"
	"time"

	gocontext "golang.org/x/net/context"

	"github.com/mitchellh/multistep"
	"github.com/stretchr/testify/assert"
)

func setupStepOpenLogWriter() (*stepOpenLogWriter, multistep.StateBag) {
	s := &stepOpenLogWriter{logTimeout: time.Second, maxLogLength: 4}

	ctx := gocontext.TODO()

	job := &fakeJob{
		payload: &JobPayload{
			Type: "job:test",
			Job: JobJobPayload{
				ID:     2,
				Number: "3.1",
			},
			Build: BuildPayload{
				ID:     1,
				Number: "3",
			},
			Repository: RepositoryPayload{
				ID:   4,
				Slug: "green-eggs/ham",
			},
			UUID:     "foo-bar",
			Config:   map[string]interface{}{},
			Timeouts: TimeoutsPayload{},
		},
	}

	state := &multistep.BasicStateBag{}
	state.Put("ctx", ctx)
	state.Put("buildJob", job)

	return s, state
}

func TestStepOpenLogWriter_Run(t *testing.T) {
	s, state := setupStepOpenLogWriter()
	action := s.Run(state)
	assert.Equal(t, multistep.ActionContinue, action)
	assert.NotNil(t, state.Get("logWriter"))
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 The ivi developers. All rights reserved.
// Project site: https://github.com/gotmc/ivi
// Use of this source code is governed by a MIT-style license that
// can be found in the LICENSE.txt file for the project.

package main

import (
	"log"

	"github.com/gotmc/ivi"
	"github.com/gotmc/ivi/fgen/agilent33220"
	_ "github.com/gotmc/usbtmc/driver/truveris"
	"github.com/gotmc/visa"
	_ "github.com/gotmc/visa/driver/usbtmc"
)

func main() {

	address := "usb0::2391::1031::MY44035849::INSTR"
	res, err := visa.NewResource(address)
	if err != nil {
		log.Fatalf("VISA resource %s: %s", address, err)
	}
	defer res.Close()
	fgen, err := agilent33220.New(res)
	if err != nil {
		log.Fatalf("IVI instrument error: %s", err)
	}
	defer fgen.Close()
	ch := fgen.Channels[0]
	ch.SetStandardWaveform(ivi.Triangle)
	ch.SetFrequency(1000)
	ch.SetAmplitude(0.24)
	wave, err := ch.StandardWaveform()
	if err != nil {
		log.Fatalf("Error determining standard waveform: %s", err)
	}
	log.Printf("Waveform = %s", wave)
}
<commit_msg>Update example<commit_after>// Copyright (c) 2017 The ivi developers. All rights reserved.
// Project site: https://github.com/gotmc/ivi
// Use of this source code is governed by a MIT-style license that
// can be found in the LICENSE.txt file for the project.

package main

import (
	"log"

	"github.com/gotmc/ivi"
	"github.com/gotmc/ivi/fgen/agilent33220"
	_ "github.com/gotmc/usbtmc/driver/truveris"
	"github.com/gotmc/visa"
	_ "github.com/gotmc/visa/driver/usbtmc"
)

func main() {

	address := "usb0::2391::1031::MY44035849::INSTR"
	res, err := visa.NewResource(address)
	if err != nil {
		log.Fatalf("VISA resource %s: %s", address, err)
	}
	defer res.Close()
	fgen, err := agilent33220.New(res)
	if err != nil {
		log.Fatalf("IVI instrument error: %s", err)
	}
	defer fgen.Close()
	ch := fgen.Channels[0]
	ch.DisableOutput()
	ch.SetStandardWaveform(ivi.Triangle)
	ch.SetFrequency(1000)
	ch.SetAmplitude(0.25)
	ch.SetDCOffset(0.1)
	ch.EnableOutput()
	wave, err := ch.StandardWaveform()
	if err != nil {
		log.Fatalf("Error determining standard waveform: %s", err)
	}
	log.Printf("Waveform = %s", wave)
}
<|endoftext|>


<commit_before>package lib127

import (
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net"
	"os"
	"testing"

	"github.com/lende/127/internal/hostsfile"
)

func TestRandomIP(t *testing.T) {
	defer removeFile(tmpHosts(t))
	hosts, err := hostsfile.Open(HostsFile)
	if err != nil {
		t.Errorf("hostsfile.Open(HostsFile):\nUnexpected error:\n\t%v", err)
	}
	tests := []struct{ block, err string }{
		{"127.0.0.0/33", "invalid CIDR address: 127.0.0.0/33"},
		{"127.0.0.0/32", "address block too small: 127.0.0.0/32"},
		{"127.0.0.0/31", "address block too small: 127.0.0.0/31"},
		{"127.0.0.0/30", "no unnasigned IPs in address block: 127.0.0.0/30"},
		{"127.0.0.0/29", "<nil>"},
		{"127.0.0.0/8", "<nil>"},
	}
	for _, test := range tests {
		_, err := randomIP(hosts, test.block)
		if fmt.Sprint(err) != test.err {
			if test.err == "<nil>" {
				t.Errorf("RandomIP():\nUnexpected error:\n\t%v", err)
			} else {
				t.Errorf("RandomIP():\nExpected error:\n\t%v\ngot:\n\t%v", test.err, err)
			}
		}
	}
}

func TestOperations(t *testing.T) {
	defer removeFile(tmpHosts(t))
	// Seed the random number generator with a fixed value so randomIP produce
	// predictable results.
	rand.Seed(1)
	steps := []struct {
		fn                    func(hostname string) (ip string, err error)
		op, hostname, ip, err string
	}{
		{GetIP, "GetIP", "example.test", "127.75.38.138", "<nil>"},
		{Set, "Set", "example.test", "127.75.38.138", "<nil>"},
		{Remove, "Remove", "example.test", "127.75.38.138", "<nil>"},
		{Remove, "Remove", "example.test", "", "<nil>"},
		{GetIP, "GetIP", "example.test", "", "<nil>"},
		{Set, "Set", "Hello世界", "127.134.24.251", "<nil>"},
		{GetIP, "GetIP", "Hello世界", "127.134.24.251", "<nil>"},
		{GetIP, "GetIP", "xn--hello-ck1hg65u", "127.134.24.251", "<nil>"},
		{Remove, "Remove", "xn--hello-ck1hg65u", "127.134.24.251", "<nil>"},
		{GetIP, "GetIP", "Hello世界", "", "<nil>"},
		{Set, "Set", "foo bar", "", "invalid hostname: foo bar"},
		{Set, "Set", "192.168.0.1", "", "invalid hostname: 192.168.0.1"},
		{Set, "Set", "foo_bar", "", "invalid hostname: foo_bar"},
	}
	for _, test := range steps {
		if ip, err := test.fn(test.hostname); fmt.Sprint(err) != test.err {
			if test.err == "<nil>" {
				t.Errorf("%v(%#v):\nUnexpected error:\n\t%v", test.op, test.hostname, err)
			} else {
				t.Errorf("%v(%#v):\nExpected error:\n\t%v\ngot:\n\t%v", test.op, test.hostname, test.err, err)
			}
		} else if ip != test.ip {
			t.Errorf("%v(%#v):\nWant return value:\n\t%#v,\nhave:\n\t%#v", test.op, test.hostname, test.ip, ip)
		}
	}
}

func TestBlockRange(t *testing.T) {
	tests := []struct{ block, minIP, maxIP string }{
		{"127.0.0.0/8", "127.0.0.1", "127.255.255.254"},
		{"127.0.0.0/24", "127.0.0.1", "127.0.0.254"},
		{"127.0.0.0/4", "112.0.0.1", "127.255.255.254"},
		{"127.0.0.24/8", "127.0.0.1", "127.255.255.254"},
		{"203.0.113.16/28", "203.0.113.17", "203.0.113.30"},
	}
	minIP, maxIP := make(net.IP, 4), make(net.IP, 4)
	for _, test := range tests {
		_, ipnet, err := net.ParseCIDR(test.block)
		if err != nil {
			t.Errorf("Unexpected error:\n\t%v", err)
		}
		minU32, maxU32 := ipSpan(ipnet)
		binary.BigEndian.PutUint32(minIP, minU32)
		binary.BigEndian.PutUint32(maxIP, maxU32)
		if test.minIP != minIP.String() || test.maxIP != maxIP.String() {
			t.Errorf("Host address range in block %v:\nwant:\n\t%v - %v,\nhave:\n\t%v - %v",
				test.block, test.minIP, test.maxIP, minIP.String(), maxIP.String())
		}
	}
}

func tmpHosts(t *testing.T) *os.File {
	var hosts = `127.0.0.1 localhost localhost.localdomain
127.0.0.2 localhost2
127.75.38.138 example.test
`
	tmp, err := ioutil.TempFile("", "hosts.127-test")
	if err != nil {
		t.Errorf("Unexpected error:\n\t%v", err)
	}
	if err := ioutil.WriteFile(tmp.Name(), []byte(hosts), 0644); err != nil {
		t.Errorf("Unexpected error:\n\t%v", err)
	}
	HostsFile = tmp.Name()
	return tmp
}

func removeFile(f *os.File) {
	f.Close()
	os.Remove(f.Name())
}
<commit_msg>Write temporary files to T.TempDir() in tests<commit_after>package lib127

import (
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net"
	"path/filepath"
	"testing"

	"github.com/lende/127/internal/hostsfile"
)

func TestRandomIP(t *testing.T) {
	setupTestHostfile(t)

	hosts, err := hostsfile.Open(HostsFile)
	if err != nil {
		t.Errorf("hostsfile.Open(HostsFile):\nUnexpected error:\n\t%v", err)
	}
	tests := []struct{ block, err string }{
		{"127.0.0.0/33", "invalid CIDR address: 127.0.0.0/33"},
		{"127.0.0.0/32", "address block too small: 127.0.0.0/32"},
		{"127.0.0.0/31", "address block too small: 127.0.0.0/31"},
		{"127.0.0.0/30", "no unnasigned IPs in address block: 127.0.0.0/30"},
		{"127.0.0.0/29", "<nil>"},
		{"127.0.0.0/8", "<nil>"},
	}
	for _, test := range tests {
		_, err := randomIP(hosts, test.block)
		if fmt.Sprint(err) != test.err {
			if test.err == "<nil>" {
				t.Errorf("RandomIP():\nUnexpected error:\n\t%v", err)
			} else {
				t.Errorf("RandomIP():\nExpected error:\n\t%v\ngot:\n\t%v", test.err, err)
			}
		}
	}
}

func TestOperations(t *testing.T) {
	setupTestHostfile(t)

	// Seed the random number generator with a fixed value so randomIP produce
	// predictable results.
	rand.Seed(1)
	steps := []struct {
		fn                    func(hostname string) (ip string, err error)
		op, hostname, ip, err string
	}{
		{GetIP, "GetIP", "example.test", "127.75.38.138", "<nil>"},
		{Set, "Set", "example.test", "127.75.38.138", "<nil>"},
		{Remove, "Remove", "example.test", "127.75.38.138", "<nil>"},
		{Remove, "Remove", "example.test", "", "<nil>"},
		{GetIP, "GetIP", "example.test", "", "<nil>"},
		{Set, "Set", "Hello世界", "127.134.24.251", "<nil>"},
		{GetIP, "GetIP", "Hello世界", "127.134.24.251", "<nil>"},
		{GetIP, "GetIP", "xn--hello-ck1hg65u", "127.134.24.251", "<nil>"},
		{Remove, "Remove", "xn--hello-ck1hg65u", "127.134.24.251", "<nil>"},
		{GetIP, "GetIP", "Hello世界", "", "<nil>"},
		{Set, "Set", "foo bar", "", "invalid hostname: foo bar"},
		{Set, "Set", "192.168.0.1", "", "invalid hostname: 192.168.0.1"},
		{Set, "Set", "foo_bar", "", "invalid hostname: foo_bar"},
	}
	for _, test := range steps {
		if ip, err := test.fn(test.hostname); fmt.Sprint(err) != test.err {
			if test.err == "<nil>" {
				t.Errorf("%v(%#v):\nUnexpected error:\n\t%v", test.op, test.hostname, err)
			} else {
				t.Errorf("%v(%#v):\nExpected error:\n\t%v\ngot:\n\t%v", test.op, test.hostname, test.err, err)
			}
		} else if ip != test.ip {
			t.Errorf("%v(%#v):\nWant return value:\n\t%#v,\nhave:\n\t%#v", test.op, test.hostname, test.ip, ip)
		}
	}
}

func TestBlockRange(t *testing.T) {
	tests := []struct{ block, minIP, maxIP string }{
		{"127.0.0.0/8", "127.0.0.1", "127.255.255.254"},
		{"127.0.0.0/24", "127.0.0.1", "127.0.0.254"},
		{"127.0.0.0/4", "112.0.0.1", "127.255.255.254"},
		{"127.0.0.24/8", "127.0.0.1", "127.255.255.254"},
		{"203.0.113.16/28", "203.0.113.17", "203.0.113.30"},
	}
	minIP, maxIP := make(net.IP, 4), make(net.IP, 4)
	for _, test := range tests {
		_, ipnet, err := net.ParseCIDR(test.block)
		if err != nil {
			t.Errorf("Unexpected error:\n\t%v", err)
		}
		minU32, maxU32 := ipSpan(ipnet)
		binary.BigEndian.PutUint32(minIP, minU32)
		binary.BigEndian.PutUint32(maxIP, maxU32)
		if test.minIP != minIP.String() || test.maxIP != maxIP.String() {
			t.Errorf("Host address range in block %v:\nwant:\n\t%v - %v,\nhave:\n\t%v - %v",
				test.block, test.minIP, test.maxIP, minIP.String(), maxIP.String())
		}
	}
}

func setupTestHostfile(t *testing.T) {
	data := `127.0.0.1 localhost localhost.localdomain
127.0.0.2 localhost2
127.75.38.138 example.test
`
	HostsFile = filepath.Join(t.TempDir(), "hosts")

	if err := ioutil.WriteFile(HostsFile, []byte(data), 0600); err != nil {
		t.Errorf("Unexpected error:\n\t%v", err)
	}
}
<|endoftext|>


<commit_before>package lightswarm

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestFrameAddress(t *testing.T) {
	tt := []struct {
		address uint16
		b1      byte
		b2      byte
	}{
		{
			1,
			0,
			1,
		},
		{
			690,
			2,
			178,
		},
		{
			65535,
			255,
			255,
		},
	}
	for i, tc := range tt {
		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
			f := Frame{Addr: tc.address}
			b1, b2 := f.address()
			assert.Equal(t, tc.b1, b1)
			assert.Equal(t, tc.b2, b2)
		})
	}
}
<commit_msg>Checksum test case<commit_after>package lightswarm

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestFrameAddress(t *testing.T) {
	tt := []struct {
		address uint16
		b1      byte
		b2      byte
	}{
		{
			1,
			0,
			1,
		},
		{
			690,
			2,
			178,
		},
		{
			65535,
			255,
			255,
		},
	}
	for i, tc := range tt {
		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
			f := Frame{Addr: tc.address}
			b1, b2 := f.address()
			assert.Equal(t, tc.b1, b1)
			assert.Equal(t, tc.b2, b2)
		})
	}
}

func TestFrameChecksum(t *testing.T) {
	tt := []struct {
		bs       []byte
		expected byte
	}{
		{
			[]byte{0, 1, 2, 3, 4},
			4,
		},
		{
			[]byte{2, 178, ON},
			144,
		},
	}
	for i, tc := range tt {
		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
			f := Frame{}
			checksum := f.checksum(tc.bs)
			assert.Equal(t, tc.expected, checksum)
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"testing"
	"io/ioutil"
	. "github.com/onsi/gomega"
	"os"
	"fmt"
)

var testDirectory = "/tmp/hoverfly-cli-tests"

func setup() {
	os.Mkdir(testDirectory, 0777)
}

func teardown() {
	os.RemoveAll(testDirectory)
}

func Test_LocalCache_WriteSimulation(t *testing.T) {
	RegisterTestingT(t)
	setup()

	ioutil.WriteFile("/tmp/vendor.name.v1.hfile", []byte("this is a test file"), 0644)

	localCache := LocalCache{Uri: "/tmp"}

	data, err := localCache.ReadSimulation(Hoverfile{Vendor: "vendor", Name: "name", Version: "v1"})

	Expect(err).To(BeNil())
	Expect(data).To(Equal([]byte("this is a test file")))

	teardown()
}

func Test_LocalCache_WriteSimulation_ErrorsWhenFileIsMissing(t *testing.T) {
	RegisterTestingT(t)
	setup()

	localCache := LocalCache{Uri: "/tmp"}

	data, err := localCache.ReadSimulation(Hoverfile{Vendor: "vendor", Name: "name", Version: "v1"})
	fmt.Println(string(data))
	Expect(err).ToNot(BeNil())
	Expect(err.Error()).To(Equal("Simulation not found"))
	Expect(data).To(BeNil())

	teardown()
}<commit_msg>Tests were inacurately named<commit_after>package main

import (
	"testing"
	"io/ioutil"
	. "github.com/onsi/gomega"
	"os"
)

var testDirectory = "/tmp/hoverfly-cli-tests"

func setup() {
	os.Mkdir(testDirectory, 0777)
}

func teardown() {
	os.RemoveAll(testDirectory)
}

func Test_LocalCache_ReadSimulation(t *testing.T) {
	RegisterTestingT(t)
	setup()

	ioutil.WriteFile("/tmp/vendor.name.v1.hfile", []byte("this is a test file"), 0644)

	localCache := LocalCache{Uri: "/tmp"}

	data, err := localCache.ReadSimulation(Hoverfile{Vendor: "vendor", Name: "name", Version: "v1"})

	Expect(err).To(BeNil())
	Expect(data).To(Equal([]byte("this is a test file")))

	teardown()
}

func Test_LocalCache_ReadSimulation_ErrorsWhenFileIsMissing(t *testing.T) {
	RegisterTestingT(t)
	setup()

	localCache := LocalCache{Uri: "/tmp"}

	data, err := localCache.ReadSimulation(Hoverfile{Vendor: "vendor", Name: "name", Version: "v1"})

	Expect(err).ToNot(BeNil())
	Expect(err.Error()).To(Equal("Simulation not found"))
	Expect(data).To(BeNil())

	teardown()
}<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/graph"
	"github.com/docker/docker/pkg/archive"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/pkg/parsers"
	"github.com/docker/docker/registry"
)

var (
	insecureRegistries = []string{"0.0.0.0/16"}
	timeout            = true
	debug              = len(os.Getenv("DEBUG")) > 0
	outputStream       = "-"
	rOptions           = &registry.Options{}
)

func init() {
	log.SetFormatter(&log.JSONFormatter{})

	// Output to stderr instead of stdout, could also be a file.
	log.SetOutput(os.Stderr)

	// Only log the warning severity or above.
	log.SetLevel(log.WarnLevel)

	// XXX print a warning that this tool is not stable yet
	fmt.Fprintln(os.Stderr, "WARNING: this tool is not stable yet, and should only be used for testing!")

	flag.BoolVar(&timeout, []string{"t", "-timeout"}, timeout, "allow timeout on the registry session")
	flag.BoolVar(&debug, []string{"D", "-debug"}, debug, "debugging output")
	flag.StringVar(&outputStream, []string{"o", "-output"}, outputStream, "output to file (default stdout)")

	rOptions.InstallFlags()
}

// TODO rewrite this whole PoC
func main() {
	flag.Usage = func() {
		flag.PrintDefaults()
	}
	flag.Parse()
	if debug {
		log.SetLevel(log.DebugLevel)
	}

	var (
		sessions     map[string]*registry.Session
		repositories = map[string]graph.Repository{}
	)

	// make tempDir
	tempDir, err := ioutil.TempDir("", "docker-fetch-")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	defer os.RemoveAll(tempDir)

	sc := registry.NewServiceConfig(rOptions)

	for _, arg := range flag.Args() {
		remote, tagName := parsers.ParseRepositoryTag(arg)
		if tagName == "" {
			tagName = "latest"
		}

		repInfo, err := sc.NewRepositoryInfo(remote)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		fmt.Fprintf(os.Stderr, "%#v %q\n", repInfo, tagName)

		idx, err := repInfo.GetEndpoint()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		fmt.Fprintf(os.Stderr, "Pulling %s:%s from %s\n", repInfo.RemoteName, tagName, idx)

		var session *registry.Session
		if s, ok := sessions[idx.String()]; ok {
			session = s
		} else {
			// TODO(vbatts) obviously the auth and http factory shouldn't be nil here
			session, err = registry.NewSession(nil, nil, idx, timeout)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
		}

		rd, err := session.GetRepositoryData(repInfo.RemoteName)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		log.Debugf("rd: %#v", rd)

		// produce the "repositories" file for the archive
		if _, ok := repositories[repInfo.RemoteName]; !ok {
			repositories[repInfo.RemoteName] = graph.Repository{}
		}
		log.Debugf("repositories: %#v", repositories)

		if len(rd.Endpoints) == 0 {
			log.Fatalf("expected registry endpoints, but received none from the index")
		}

		tags, err := session.GetRemoteTags(rd.Endpoints, repInfo.RemoteName, rd.Tokens)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		if hash, ok := tags[tagName]; ok {
			repositories[repInfo.RemoteName][tagName] = hash
		}
		log.Debugf("repositories: %#v", repositories)

		imgList, err := session.GetRemoteHistory(repositories[repInfo.RemoteName][tagName], rd.Endpoints[0], rd.Tokens)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		log.Debugf("imgList: %#v", imgList)

		for _, imgID := range imgList {
			// pull layers and jsons
			buf, _, err := session.GetRemoteImageJSON(imgID, rd.Endpoints[0], rd.Tokens)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			if err = os.MkdirAll(filepath.Join(tempDir, imgID), 0755); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			fh, err := os.Create(filepath.Join(tempDir, imgID, "json"))
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			if _, err = fh.Write(buf); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			fh.Close()
			log.Debugf("%s", fh.Name())

			tarRdr, err := session.GetRemoteImageLayer(imgID, rd.Endpoints[0], rd.Tokens, 0)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			fh, err = os.Create(filepath.Join(tempDir, imgID, "layer.tar"))
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			// the body is usually compressed
			gzRdr, err := gzip.NewReader(tarRdr)
			if err != nil {
				log.Debugf("image layer for %q is not gzipped", imgID)
				// the archive may not be gzipped, so just copy the stream
				if _, err = io.Copy(fh, tarRdr); err != nil {
					fmt.Fprintln(os.Stderr, err)
					os.Exit(1)
				}
			} else {
				// no error, so gzip decompress the stream
				if _, err = io.Copy(fh, gzRdr); err != nil {
					fmt.Fprintln(os.Stderr, err)
					os.Exit(1)
				}
				if err = gzRdr.Close(); err != nil {
					fmt.Fprintln(os.Stderr, err)
					os.Exit(1)
				}
			}
			if err = tarRdr.Close(); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			if err = fh.Close(); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			log.Debugf("%s", fh.Name())
		}
	}

	// marshal the "repositories" file for writing out
	log.Debugf("repositories: %q", repositories)
	buf, err := json.Marshal(repositories)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fh, err := os.Create(filepath.Join(tempDir, "repositories"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	if _, err = fh.Write(buf); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fh.Close()
	log.Debugf("%s", fh.Name())

	var output io.WriteCloser
	if outputStream == "-" {
		output = os.Stdout
	} else {
		output, err = os.Create(outputStream)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}
	defer output.Close()

	if err = os.Chdir(tempDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	tarStream, err := archive.Tar(".", archive.Uncompressed)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	if _, err = io.Copy(output, tarStream); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<commit_msg>docker-fetch: fix debug output<commit_after>package main

import (
	"compress/gzip"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/graph"
	"github.com/docker/docker/pkg/archive"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/docker/docker/pkg/parsers"
	"github.com/docker/docker/registry"
)

var (
	insecureRegistries = []string{"0.0.0.0/16"}
	timeout            = true
	debug              = len(os.Getenv("DEBUG")) > 0
	outputStream       = "-"
	rOptions           = &registry.Options{}
)

func init() {
	log.SetFormatter(&log.JSONFormatter{})

	// Output to stderr instead of stdout, could also be a file.
	log.SetOutput(os.Stderr)

	// Only log the warning severity or above.
	log.SetLevel(log.WarnLevel)

	// XXX print a warning that this tool is not stable yet
	fmt.Fprintln(os.Stderr, "WARNING: this tool is not stable yet, and should only be used for testing!")

	flag.BoolVar(&timeout, []string{"t", "-timeout"}, timeout, "allow timeout on the registry session")
	flag.BoolVar(&debug, []string{"D", "-debug"}, debug, "debugging output")
	flag.StringVar(&outputStream, []string{"o", "-output"}, outputStream, "output to file (default stdout)")

	rOptions.InstallFlags()
}

// TODO rewrite this whole PoC
func main() {
	flag.Usage = func() {
		flag.PrintDefaults()
	}
	flag.Parse()
	if debug {
		os.Setenv("DEBUG", "1")
		log.SetLevel(log.DebugLevel)
	}

	var (
		sessions     map[string]*registry.Session
		repositories = map[string]graph.Repository{}
	)

	// make tempDir
	tempDir, err := ioutil.TempDir("", "docker-fetch-")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	defer os.RemoveAll(tempDir)

	sc := registry.NewServiceConfig(rOptions)

	for _, arg := range flag.Args() {
		remote, tagName := parsers.ParseRepositoryTag(arg)
		if tagName == "" {
			tagName = "latest"
		}

		repInfo, err := sc.NewRepositoryInfo(remote)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		log.Debugf("%#v %q\n", repInfo, tagName)

		idx, err := repInfo.GetEndpoint()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		fmt.Fprintf(os.Stderr, "Pulling %s:%s from %s\n", repInfo.RemoteName, tagName, idx)

		var session *registry.Session
		if s, ok := sessions[idx.String()]; ok {
			session = s
		} else {
			// TODO(vbatts) obviously the auth and http factory shouldn't be nil here
			session, err = registry.NewSession(nil, nil, idx, timeout)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
		}

		rd, err := session.GetRepositoryData(repInfo.RemoteName)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		log.Debugf("rd: %#v", rd)

		// produce the "repositories" file for the archive
		if _, ok := repositories[repInfo.RemoteName]; !ok {
			repositories[repInfo.RemoteName] = graph.Repository{}
		}
		log.Debugf("repositories: %#v", repositories)

		if len(rd.Endpoints) == 0 {
			log.Fatalf("expected registry endpoints, but received none from the index")
		}

		tags, err := session.GetRemoteTags(rd.Endpoints, repInfo.RemoteName, rd.Tokens)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		if hash, ok := tags[tagName]; ok {
			repositories[repInfo.RemoteName][tagName] = hash
		}
		log.Debugf("repositories: %#v", repositories)

		imgList, err := session.GetRemoteHistory(repositories[repInfo.RemoteName][tagName], rd.Endpoints[0], rd.Tokens)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		log.Debugf("imgList: %#v", imgList)

		for _, imgID := range imgList {
			// pull layers and jsons
			buf, _, err := session.GetRemoteImageJSON(imgID, rd.Endpoints[0], rd.Tokens)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			if err = os.MkdirAll(filepath.Join(tempDir, imgID), 0755); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			fh, err := os.Create(filepath.Join(tempDir, imgID, "json"))
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			if _, err = fh.Write(buf); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			fh.Close()
			log.Debugf("%s", fh.Name())

			tarRdr, err := session.GetRemoteImageLayer(imgID, rd.Endpoints[0], rd.Tokens, 0)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			fh, err = os.Create(filepath.Join(tempDir, imgID, "layer.tar"))
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			// the body is usually compressed
			gzRdr, err := gzip.NewReader(tarRdr)
			if err != nil {
				log.Debugf("image layer for %q is not gzipped", imgID)
				// the archive may not be gzipped, so just copy the stream
				if _, err = io.Copy(fh, tarRdr); err != nil {
					fmt.Fprintln(os.Stderr, err)
					os.Exit(1)
				}
			} else {
				// no error, so gzip decompress the stream
				if _, err = io.Copy(fh, gzRdr); err != nil {
					fmt.Fprintln(os.Stderr, err)
					os.Exit(1)
				}
				if err = gzRdr.Close(); err != nil {
					fmt.Fprintln(os.Stderr, err)
					os.Exit(1)
				}
			}
			if err = tarRdr.Close(); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			if err = fh.Close(); err != nil {
				fmt.Fprintln(os.Stderr, err)
				os.Exit(1)
			}
			log.Debugf("%s", fh.Name())
		}
	}

	// marshal the "repositories" file for writing out
	log.Debugf("repositories: %q", repositories)
	buf, err := json.Marshal(repositories)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fh, err := os.Create(filepath.Join(tempDir, "repositories"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	if _, err = fh.Write(buf); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	fh.Close()
	log.Debugf("%s", fh.Name())

	var output io.WriteCloser
	if outputStream == "-" {
		output = os.Stdout
	} else {
		output, err = os.Create(outputStream)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}
	defer output.Close()

	if err = os.Chdir(tempDir); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	tarStream, err := archive.Tar(".", archive.Uncompressed)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	if _, err = io.Copy(output, tarStream); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"io/ioutil"
	"testing"
)

func TestHelp(t *testing.T) {

	options := getDefaultOptions()

	options.HELP = true

	options.fixUp()
	output, errOutput := getOutput(options)
	expectations := getExpectations("help")

	if output != "" {
		t.Error("For help message, expected empty stdout, got", output)
	}

	if errOutput != expectations {
		t.Error("For help message, got\n", errOutput, "\nwanted\n", expectations)
	}
}

//Callers should call fixUpOptions after receiving this.
func getDefaultOptions() *appOptions {
	options := &appOptions{
		flagSet: flag.NewFlagSet("main", flag.ExitOnError),
	}
	defineFlags(options)
	options.flagSet.Parse([]string{})
	return options
}

func getOutput(options *appOptions) (outputResult string, errorResult string) {

	output := &bytes.Buffer{}
	errOutput := &bytes.Buffer{}

	process(options, output, errOutput)

	outputReaderBytes, _ := ioutil.ReadAll(output)
	errorReaderBytes, _ := ioutil.ReadAll(errOutput)

	return string(outputReaderBytes), string(errorReaderBytes)
}

func getExpectations(name string) string {
	bytes, _ := ioutil.ReadFile("test_expectations/" + name + ".txt")
	return string(bytes)
}
<commit_msg>Add a test for Generating a single puzzle<commit_after>package main

import (
	"bytes"
	"flag"
	"github.com/jkomoros/sudoku"
	"io/ioutil"
	"testing"
)

func TestHelp(t *testing.T) {

	options := getDefaultOptions()

	options.HELP = true

	options.fixUp()
	output, errOutput := getOutput(options)
	expectations := getExpectations("help")

	if output != "" {
		t.Error("For help message, expected empty stdout, got", output)
	}

	if errOutput != expectations {
		t.Error("For help message, got\n", errOutput, "\nwanted\n", expectations)
	}
}

func TestSingleGenerate(t *testing.T) {
	options := getDefaultOptions()

	options.GENERATE = true
	options.NUM = 1
	options.NO_CACHE = true

	options.fixUp()

	output, errOutput := getOutput(options)

	if errOutput != "" {
		t.Error("Generating a puzzle expected empty stderr, but got", errOutput)
	}

	grid := sudoku.NewGrid()
	grid.Load(output)

	if grid.Invalid() || grid.Empty() {
		t.Error("Output for single generate was not a valid puzzle", output)
	}

}

//Callers should call fixUpOptions after receiving this.
func getDefaultOptions() *appOptions {
	options := &appOptions{
		flagSet: flag.NewFlagSet("main", flag.ExitOnError),
	}
	defineFlags(options)
	options.flagSet.Parse([]string{})
	return options
}

func getOutput(options *appOptions) (outputResult string, errorResult string) {

	output := &bytes.Buffer{}
	errOutput := &bytes.Buffer{}

	process(options, output, errOutput)

	outputReaderBytes, _ := ioutil.ReadAll(output)
	errorReaderBytes, _ := ioutil.ReadAll(errOutput)

	return string(outputReaderBytes), string(errorReaderBytes)
}

func getExpectations(name string) string {
	bytes, _ := ioutil.ReadFile("test_expectations/" + name + ".txt")
	return string(bytes)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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

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

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

package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/knative/eventing-sources/pkg/githubsource"
	"gopkg.in/go-playground/webhooks.v3"
	gh "gopkg.in/go-playground/webhooks.v3/github"
)

const (
	// Environment variable containing the HTTP port
	envPort = "PORT"

	// Environment variable containing GitHub secret token
	envSecret = "GITHUB_SECRET_TOKEN"
)

func main() {
	sink := flag.String("sink", "", "uri to send events to")

	flag.Parse()

	if sink == nil || *sink == "" {
		log.Fatalf("No sink given")
	}

	port := os.Getenv(envPort)
	if port == "" {
		port = "8080"
	}

	secretToken := os.Getenv(envSecret)
	if secretToken == "" {
		log.Fatalf("No secret token given")
	}

	log.Printf("Sink is: %q", sink)

	ra := &githubsource.GitHubReceiveAdapter{
		Sink: *sink,
	}

	hook := gh.New(&gh.Config{Secret: secretToken})
	hook.RegisterEvents(ra.HandleEvent,
		gh.CommitCommentEvent,
		gh.CreateEvent,
		gh.DeleteEvent,
		gh.DeploymentEvent,
		gh.DeploymentStatusEvent,
		gh.ForkEvent,
		gh.GollumEvent,
		gh.InstallationEvent,
		gh.IntegrationInstallationEvent,
		gh.IssueCommentEvent,
		gh.IssuesEvent,
		gh.LabelEvent,
		gh.MemberEvent,
		gh.MembershipEvent,
		gh.MilestoneEvent,
		gh.OrganizationEvent,
		gh.OrgBlockEvent,
		gh.PageBuildEvent,
		gh.PingEvent,
		gh.ProjectCardEvent,
		gh.ProjectColumnEvent,
		gh.ProjectEvent,
		gh.PublicEvent,
		gh.PullRequestEvent,
		gh.PullRequestReviewEvent,
		gh.PullRequestReviewCommentEvent,
		gh.PushEvent,
		gh.ReleaseEvent,
		gh.RepositoryEvent,
		gh.StatusEvent,
		gh.TeamEvent,
		gh.TeamAddEvent,
		gh.WatchEvent)

	addr := fmt.Sprintf(":%s", port)
	err := webhooks.Run(hook, addr, "/")
	if err != nil {
		log.Fatalf("Failed to run the webhook")
	}
}
<commit_msg>Print the string instead of the pointer (#99)<commit_after>/*
Copyright 2018 The Knative Authors

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

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

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

package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	"github.com/knative/eventing-sources/pkg/githubsource"
	"gopkg.in/go-playground/webhooks.v3"
	gh "gopkg.in/go-playground/webhooks.v3/github"
)

const (
	// Environment variable containing the HTTP port
	envPort = "PORT"

	// Environment variable containing GitHub secret token
	envSecret = "GITHUB_SECRET_TOKEN"
)

func main() {
	sink := flag.String("sink", "", "uri to send events to")

	flag.Parse()

	if sink == nil || *sink == "" {
		log.Fatalf("No sink given")
	}

	port := os.Getenv(envPort)
	if port == "" {
		port = "8080"
	}

	secretToken := os.Getenv(envSecret)
	if secretToken == "" {
		log.Fatalf("No secret token given")
	}

	log.Printf("Sink is: %q", *sink)

	ra := &githubsource.GitHubReceiveAdapter{
		Sink: *sink,
	}

	hook := gh.New(&gh.Config{Secret: secretToken})
	hook.RegisterEvents(ra.HandleEvent,
		gh.CommitCommentEvent,
		gh.CreateEvent,
		gh.DeleteEvent,
		gh.DeploymentEvent,
		gh.DeploymentStatusEvent,
		gh.ForkEvent,
		gh.GollumEvent,
		gh.InstallationEvent,
		gh.IntegrationInstallationEvent,
		gh.IssueCommentEvent,
		gh.IssuesEvent,
		gh.LabelEvent,
		gh.MemberEvent,
		gh.MembershipEvent,
		gh.MilestoneEvent,
		gh.OrganizationEvent,
		gh.OrgBlockEvent,
		gh.PageBuildEvent,
		gh.PingEvent,
		gh.ProjectCardEvent,
		gh.ProjectColumnEvent,
		gh.ProjectEvent,
		gh.PublicEvent,
		gh.PullRequestEvent,
		gh.PullRequestReviewEvent,
		gh.PullRequestReviewCommentEvent,
		gh.PushEvent,
		gh.ReleaseEvent,
		gh.RepositoryEvent,
		gh.StatusEvent,
		gh.TeamEvent,
		gh.TeamAddEvent,
		gh.WatchEvent)

	addr := fmt.Sprintf(":%s", port)
	err := webhooks.Run(hook, addr, "/")
	if err != nil {
		log.Fatalf("Failed to run the webhook")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/cloud9-tools/go-sstable"
)

var output = flag.String("output", "", "SSTable file to generate")

func main() {
	flag.Parse()
	if *output == "" {
		flag.Usage()
		fmt.Fprintln(os.Stderr, "error: missing required flag -output=")
		os.Exit(1)
	}
	if flag.NArg() != 0 {
		flag.Usage()
		fmt.Fprintf(os.Stderr, "error: %d unexpected positional argument(s)\n", flag.NArg())
		os.Exit(1)
	}

	inbytes, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}

	inmap := make(map[string][]byte)
	err = json.Unmarshal(inbytes, &inmap)
	if err != nil {
		panic(err)
	}

	outfile, err := os.OpenFile(*output, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		panic(err)
	}
	defer outfile.Close()

	var input []sstable.Pair
	for k, v := range inmap {
		input = append(input, sstable.Pair{k, []byte(v)})
	}
	err = sstable.Build(outfile, input)
	if err != nil {
		panic(err)
	}
}
<commit_msg>Remove leftover []byte cast.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/cloud9-tools/go-sstable"
)

var output = flag.String("output", "", "SSTable file to generate")

func main() {
	flag.Parse()
	if *output == "" {
		flag.Usage()
		fmt.Fprintln(os.Stderr, "error: missing required flag -output=")
		os.Exit(1)
	}
	if flag.NArg() != 0 {
		flag.Usage()
		fmt.Fprintf(os.Stderr, "error: %d unexpected positional argument(s)\n", flag.NArg())
		os.Exit(1)
	}

	inbytes, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}

	inmap := make(map[string][]byte)
	err = json.Unmarshal(inbytes, &inmap)
	if err != nil {
		panic(err)
	}

	outfile, err := os.OpenFile(*output, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666)
	if err != nil {
		panic(err)
	}
	defer outfile.Close()

	var input []sstable.Pair
	for k, v := range inmap {
		input = append(input, sstable.Pair{k, v})
	}
	err = sstable.Build(outfile, input)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>