<commit_before>package htlcswitch

import (
	"errors"
	"sync"

	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/lnwire"
)

var (
	// ErrAlreadyPaid signals we have already paid this payment hash.
	ErrAlreadyPaid = errors.New("invoice is already paid")

	// ErrPaymentInFlight signals that payment for this payment hash is
	// already "in flight" on the network.
	ErrPaymentInFlight = errors.New("payment is in transition")

	// ErrPaymentNotInitiated is returned  if payment wasn't initiated in
	// switch.
	ErrPaymentNotInitiated = errors.New("payment isn't initiated")

	// ErrPaymentAlreadyCompleted is returned in the event we attempt to
	// recomplete a completed payment.
	ErrPaymentAlreadyCompleted = errors.New("payment is already completed")

	// ErrUnknownPaymentStatus is returned when we do not recognize the
	// existing state of a payment.
	ErrUnknownPaymentStatus = errors.New("unknown payment status")
)

// ControlTower tracks all outgoing payments made by the switch, whose primary
// purpose is to prevent duplicate payments to the same payment hash. In
// production, a persistent implementation is preferred so that tracking can
// survive across restarts. Payments are transition through various payment
// states, and the ControlTower interface provides access to driving the state
// transitions.
type ControlTower interface {
	// ClearForTakeoff atomically checks that no inflight or completed
	// payments exist for this payment hash. If none are found, this method
	// atomically transitions the status for this payment hash as InFlight.
	ClearForTakeoff(htlc *lnwire.UpdateAddHTLC) error

	// Success transitions an InFlight payment into a Completed payment.
	// After invoking this method, ClearForTakeoff should always return an
	// error to prevent us from making duplicate payments to the same
	// payment hash.
	Success(paymentHash [32]byte) error

	// Fail transitions an InFlight payment into a Grounded Payment. After
	// invoking this method, ClearForTakeoff should return nil on its next
	// call for this payment hash, allowing the switch to make a subsequent
	// payment.
	Fail(paymentHash [32]byte) error
}

// paymentControl is persistent implementation of ControlTower to restrict
// double payment sending.
type paymentControl struct {
	strict bool

	mx sync.Mutex
	db *channeldb.DB
}

// NewPaymentControl creates a new instance of the paymentControl.
func NewPaymentControl(strict bool, db *channeldb.DB) ControlTower {
	return &paymentControl{
		strict: strict,
		db:     db,
	}
}

// ClearForTakeoff checks that we don't already have an InFlight or Completed
// payment identified by the same payment hash.
func (p *paymentControl) ClearForTakeoff(htlc *lnwire.UpdateAddHTLC) error {
	p.mx.Lock()
	defer p.mx.Unlock()

	// Retrieve current status of payment from local database.
	paymentStatus, err := p.db.FetchPaymentStatus(htlc.PaymentHash)
	if err != nil {
		return err
	}

	switch paymentStatus {

	case channeldb.StatusGrounded:
		// It is safe to reattempt a payment if we know that we haven't
		// left one in flight. Since this one is grounded, Transition
		// the payment status to InFlight to prevent others.
		return p.db.UpdatePaymentStatus(htlc.PaymentHash, channeldb.StatusInFlight)

	case channeldb.StatusInFlight:
		// We already have an InFlight payment on the network. We will
		// disallow any more payment until a response is received.
		return ErrPaymentInFlight

	case channeldb.StatusCompleted:
		// We've already completed a payment to this payment hash,
		// forbid the switch from sending another.
		return ErrAlreadyPaid

	default:
		return ErrUnknownPaymentStatus
	}
}

// Success transitions an InFlight payment to Completed, otherwise it returns an
// error. After calling Success, ClearForTakeoff should prevent any further
// attempts for the same payment hash.
func (p *paymentControl) Success(paymentHash [32]byte) error {
	p.mx.Lock()
	defer p.mx.Unlock()

	paymentStatus, err := p.db.FetchPaymentStatus(paymentHash)
	if err != nil {
		return err
	}

	switch {

	case paymentStatus == channeldb.StatusGrounded && p.strict:
		// Our records show the payment as still being grounded, meaning
		// it never should have left the switch.
		return ErrPaymentNotInitiated

	case paymentStatus == channeldb.StatusGrounded && !p.strict:
		// Our records show the payment as still being grounded, meaning
		// it never should have left the switch.
		fallthrough

	case paymentStatus == channeldb.StatusInFlight:
		// A successful response was received for an InFlight payment,
		// mark it as completed to prevent sending to this payment hash
		// again.
		return p.db.UpdatePaymentStatus(paymentHash, channeldb.StatusCompleted)

	case paymentStatus == channeldb.StatusCompleted:
		// The payment was completed previously, alert the caller that
		// this may be a duplicate call.
		return ErrPaymentAlreadyCompleted

	default:
		return ErrUnknownPaymentStatus
	}
}

// Fail transitions an InFlight payment to Grounded, otherwise it returns an
// error. After calling Fail, ClearForTakeoff should fail any further attempts
// for the same payment hash.
func (p *paymentControl) Fail(paymentHash [32]byte) error {
	p.mx.Lock()
	defer p.mx.Unlock()

	paymentStatus, err := p.db.FetchPaymentStatus(paymentHash)
	if err != nil {
		return err
	}

	switch {

	case paymentStatus == channeldb.StatusGrounded && p.strict:
		// Our records show the payment as still being grounded, meaning
		// it never should have left the switch.
		return ErrPaymentNotInitiated

	case paymentStatus == channeldb.StatusGrounded && !p.strict:
		// Our records show the payment as still being grounded, meaning
		// it never should have left the switch.
		fallthrough

	case paymentStatus == channeldb.StatusInFlight:
		// A failed response was received for an InFlight payment, mark
		// it as Grounded again to allow subsequent attempts.
		return p.db.UpdatePaymentStatus(paymentHash, channeldb.StatusGrounded)

	case paymentStatus == channeldb.StatusCompleted:
		// The payment was completed previously, and we are now
		// reporting that it has failed. Leave the status as completed,
		// but alert the user that something is wrong.
		return ErrPaymentAlreadyCompleted

	default:
		return ErrUnknownPaymentStatus
	}
}
<commit_msg>htlcswitch/control_tower: use one db txn for transitions<commit_after>package htlcswitch

import (
	"errors"

	"github.com/coreos/bbolt"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/lnwire"
)

var (
	// ErrAlreadyPaid signals we have already paid this payment hash.
	ErrAlreadyPaid = errors.New("invoice is already paid")

	// ErrPaymentInFlight signals that payment for this payment hash is
	// already "in flight" on the network.
	ErrPaymentInFlight = errors.New("payment is in transition")

	// ErrPaymentNotInitiated is returned  if payment wasn't initiated in
	// switch.
	ErrPaymentNotInitiated = errors.New("payment isn't initiated")

	// ErrPaymentAlreadyCompleted is returned in the event we attempt to
	// recomplete a completed payment.
	ErrPaymentAlreadyCompleted = errors.New("payment is already completed")

	// ErrUnknownPaymentStatus is returned when we do not recognize the
	// existing state of a payment.
	ErrUnknownPaymentStatus = errors.New("unknown payment status")
)

// ControlTower tracks all outgoing payments made by the switch, whose primary
// purpose is to prevent duplicate payments to the same payment hash. In
// production, a persistent implementation is preferred so that tracking can
// survive across restarts. Payments are transition through various payment
// states, and the ControlTower interface provides access to driving the state
// transitions.
type ControlTower interface {
	// ClearForTakeoff atomically checks that no inflight or completed
	// payments exist for this payment hash. If none are found, this method
	// atomically transitions the status for this payment hash as InFlight.
	ClearForTakeoff(htlc *lnwire.UpdateAddHTLC) error

	// Success transitions an InFlight payment into a Completed payment.
	// After invoking this method, ClearForTakeoff should always return an
	// error to prevent us from making duplicate payments to the same
	// payment hash.
	Success(paymentHash [32]byte) error

	// Fail transitions an InFlight payment into a Grounded Payment. After
	// invoking this method, ClearForTakeoff should return nil on its next
	// call for this payment hash, allowing the switch to make a subsequent
	// payment.
	Fail(paymentHash [32]byte) error
}

// paymentControl is persistent implementation of ControlTower to restrict
// double payment sending.
type paymentControl struct {
	strict bool

	db *channeldb.DB
}

// NewPaymentControl creates a new instance of the paymentControl. The strict
// flag indicates whether the controller should require "strict" state
// transitions, which would be otherwise intolerant to older databases that may
// already have duplicate payments to the same payment hash. It should be
// enabled only after sufficient checks have been made to ensure the db does not
// contain such payments. In the meantime, non-strict mode enforces a superset
// of the state transitions that prevent additional payments to a given payment
// hash from being added.
func NewPaymentControl(strict bool, db *channeldb.DB) ControlTower {
	return &paymentControl{
		strict: strict,
		db:     db,
	}
}

// ClearForTakeoff checks that we don't already have an InFlight or Completed
// payment identified by the same payment hash.
func (p *paymentControl) ClearForTakeoff(htlc *lnwire.UpdateAddHTLC) error {
	var takeoffErr error
	err := p.db.Batch(func(tx *bolt.Tx) error {
		// Retrieve current status of payment from local database.
		paymentStatus, err := channeldb.FetchPaymentStatusTx(
			tx, htlc.PaymentHash,
		)
		if err != nil {
			return err
		}

		// Reset the takeoff error, to avoid carrying over an error
		// from a previous execution of the batched db transaction.
		takeoffErr = nil

		switch paymentStatus {

		case channeldb.StatusGrounded:
			// It is safe to reattempt a payment if we know that we
			// haven't left one in flight. Since this one is
			// grounded, Transition the payment status to InFlight
			// to prevent others.
			return channeldb.UpdatePaymentStatusTx(
				tx, htlc.PaymentHash, channeldb.StatusInFlight,
			)

		case channeldb.StatusInFlight:
			// We already have an InFlight payment on the network. We will
			// disallow any more payment until a response is received.
			takeoffErr = ErrPaymentInFlight

		case channeldb.StatusCompleted:
			// We've already completed a payment to this payment hash,
			// forbid the switch from sending another.
			takeoffErr = ErrAlreadyPaid

		default:
			takeoffErr = ErrUnknownPaymentStatus
		}

		return nil
	})
	if err != nil {
		return err
	}

	return takeoffErr
}

// Success transitions an InFlight payment to Completed, otherwise it returns an
// error. After calling Success, ClearForTakeoff should prevent any further
// attempts for the same payment hash.
func (p *paymentControl) Success(paymentHash [32]byte) error {
	var updateErr error
	err := p.db.Batch(func(tx *bolt.Tx) error {
		paymentStatus, err := channeldb.FetchPaymentStatusTx(
			tx, paymentHash,
		)
		if err != nil {
			return err
		}

		// Reset the update error, to avoid carrying over an error
		// from a previous execution of the batched db transaction.
		updateErr = nil

		switch {

		case paymentStatus == channeldb.StatusGrounded && p.strict:
			// Our records show the payment as still being grounded,
			// meaning it never should have left the switch.
			updateErr = ErrPaymentNotInitiated

		case paymentStatus == channeldb.StatusGrounded && !p.strict:
			// Though our records show the payment as still being
			// grounded, meaning it never should have left the
			// switch, we permit this transition in non-strict mode
			// to handle inconsistent db states.
			fallthrough

		case paymentStatus == channeldb.StatusInFlight:
			// A successful response was received for an InFlight
			// payment, mark it as completed to prevent sending to
			// this payment hash again.
			return channeldb.UpdatePaymentStatusTx(
				tx, paymentHash, channeldb.StatusCompleted,
			)

		case paymentStatus == channeldb.StatusCompleted:
			// The payment was completed previously, alert the
			// caller that this may be a duplicate call.
			updateErr = ErrPaymentAlreadyCompleted

		default:
			updateErr = ErrUnknownPaymentStatus
		}

		return nil
	})
	if err != nil {
		return err
	}

	return updateErr
}

// Fail transitions an InFlight payment to Grounded, otherwise it returns an
// error. After calling Fail, ClearForTakeoff should fail any further attempts
// for the same payment hash.
func (p *paymentControl) Fail(paymentHash [32]byte) error {
	var updateErr error
	err := p.db.Batch(func(tx *bolt.Tx) error {
		paymentStatus, err := channeldb.FetchPaymentStatusTx(
			tx, paymentHash,
		)
		if err != nil {
			return err
		}

		// Reset the update error, to avoid carrying over an error
		// from a previous execution of the batched db transaction.
		updateErr = nil

		switch {

		case paymentStatus == channeldb.StatusGrounded && p.strict:
			// Our records show the payment as still being grounded,
			// meaning it never should have left the switch.
			updateErr = ErrPaymentNotInitiated

		case paymentStatus == channeldb.StatusGrounded && !p.strict:
			// Though our records show the payment as still being
			// grounded, meaning it never should have left the
			// switch, we permit this transition in non-strict mode
			// to handle inconsistent db states.
			fallthrough

		case paymentStatus == channeldb.StatusInFlight:
			// A failed response was received for an InFlight
			// payment, mark it as Grounded again to allow
			// subsequent attempts.
			return channeldb.UpdatePaymentStatusTx(
				tx, paymentHash, channeldb.StatusGrounded,
			)

		case paymentStatus == channeldb.StatusCompleted:
			// The payment was completed previously, and we are now
			// reporting that it has failed. Leave the status as
			// completed, but alert the user that something is
			// wrong.
			updateErr = ErrPaymentAlreadyCompleted

		default:
			updateErr = ErrUnknownPaymentStatus
		}

		return nil
	})
	if err != nil {
		return err
	}

	return updateErr
}
<|endoftext|>


<commit_before>package completer

import (
	"reflect"
	"sort"
	"testing"
)

func TestCompleterAddAndLookup(t *testing.T) {
	for _, tc := range []struct {
		add          []string
		wantLookup   map[string]string
		wantComplete map[string][]string
	}{
		{
			add: []string{
				"foo",
			},
			wantComplete: map[string][]string{
				"f":   []string{"foo"},
				"fo":  []string{"foo"},
				"foo": []string{"foo"},
			},
			wantLookup: map[string]string{
				"":    "",
				"f":   "foo",
				"fo":  "foo",
				"foo": "foo",
			},
		},
		{
			add: []string{
				"bar",
				"foo",
			},
			wantComplete: map[string][]string{
				"b":   []string{"bar"},
				"ba":  []string{"bar"},
				"bar": []string{"bar"},
				"f":   []string{"foo"},
				"fo":  []string{"foo"},
				"foo": []string{"foo"},
			},
			wantLookup: map[string]string{
				"":    "",
				"b":   "bar",
				"ba":  "bar",
				"bar": "bar",
				"f":   "foo",
				"fo":  "foo",
				"foo": "foo",
			},
		},
		{
			add: []string{
				"bar",
				"baz",
				"foo",
			},
			wantComplete: map[string][]string{
				"b":   []string{"bar", "baz"},
				"ba":  []string{"bar", "baz"},
				"bar": []string{"bar"},
				"baz": []string{"baz"},
				"f":   []string{"foo"},
				"fo":  []string{"foo"},
				"foo": []string{"foo"},
			},
			wantLookup: map[string]string{
				"":    "",
				"b":   "",
				"ba":  "",
				"bar": "bar",
				"baz": "baz",
				"f":   "foo",
				"fo":  "foo",
				"foo": "foo",
			},
		},
		{
			add: []string{
				"bar",
				"baz",
				"foo",
				"fux",
			},
			wantComplete: map[string][]string{
				"b":   []string{"bar", "baz"},
				"ba":  []string{"bar", "baz"},
				"bar": []string{"bar"},
				"baz": []string{"baz"},
				"f":   []string{"foo", "fux"},
				"fo":  []string{"foo"},
				"foo": []string{"foo"},
				"fu":  []string{"fux"},
				"fux": []string{"fux"},
			},
			wantLookup: map[string]string{
				"":    "",
				"b":   "",
				"ba":  "",
				"bar": "bar",
				"baz": "baz",
				"f":   "",
				"fo":  "foo",
				"foo": "foo",
				"fu":  "fux",
				"fux": "fux",
			},
		},
		{
			add: []string{
				"foo",
				"foobar",
			},
			wantComplete: map[string][]string{
				"f":      []string{"foo", "foobar"},
				"fo":     []string{"foo", "foobar"},
				"foo":    []string{"foo", "foobar"},
				"foob":   []string{"foobar"},
				"fooba":  []string{"foobar"},
				"foobar": []string{"foobar"},
			},
			wantLookup: map[string]string{
				"":       "",
				"f":      "",
				"fo":     "",
				"foo":    "foo",
				"foob":   "foobar",
				"fooba":  "foobar",
				"foobar": "foobar",
			},
		},
		{
			add: []string{
				"foo",
				"foobar",
				"foobaz",
			},
			wantComplete: map[string][]string{
				"f":      []string{"foo", "foobar", "foobaz"},
				"fo":     []string{"foo", "foobar", "foobaz"},
				"foo":    []string{"foo", "foobar", "foobaz"},
				"foob":   []string{"foobar", "foobaz"},
				"fooba":  []string{"foobar", "foobaz"},
				"foobar": []string{"foobar"},
			},
			wantLookup: map[string]string{
				"":       "",
				"f":      "",
				"fo":     "",
				"foo":    "foo",
				"foob":   "",
				"fooba":  "",
				"foobar": "foobar",
				"foobaz": "foobaz",
			},
		},
	} {
		c := NewCompleter()
		for _, s := range tc.add {
			if err := c.Add(s); err != nil {
				t.Errorf("%+v.Add(%q) == %s, want <nil>", c, s)
			}
		}
		for prefix, wantLookup := range tc.wantLookup {
			if got, ok := c.Lookup(prefix); got != wantLookup || (got == "" && ok) {
				t.Errorf("%+v.Lookup(%q) == %q, %t, want %q", c, prefix, got, ok, wantLookup)
			}
		}
		for prefix, wantComplete := range tc.wantComplete {
			gotComplete := c.Complete(prefix)
			sort.Strings(gotComplete)
			if !reflect.DeepEqual(gotComplete, wantComplete) {
				t.Errorf("%+v.Complete(%q) == %v, want %v", c, prefix, gotComplete, wantComplete)
			}
		}
	}
}

func TestCompleterSubstringLookup(t *testing.T) {
	c := NewCompleter()
	c.Add("foo")
	if err := c.Add("fo"); err != nil {
		t.Errorf("%+v.Add(\"fo\") == %v, want <nil>", c, err)
	}
	prefix := "f"
	if got, ok := c.Lookup(prefix); ok {
		t.Errorf("%+v.Lookup(%q) == %q, %t, want \"\", false", c, prefix, got, ok)
	}
}

func TestCompleterAddDuplicate(t *testing.T) {
	c := NewCompleter()
	c.Add("foo")
	if err := c.Add("foo"); err == nil {
		t.Errorf("%+v.Add(\"foo\") == <nil>, want !<nil>", c)
	}
}
<commit_msg>Add missing argument<commit_after>package completer

import (
	"reflect"
	"sort"
	"testing"
)

func TestCompleterAddAndLookup(t *testing.T) {
	for _, tc := range []struct {
		add          []string
		wantLookup   map[string]string
		wantComplete map[string][]string
	}{
		{
			add: []string{
				"foo",
			},
			wantComplete: map[string][]string{
				"f":   []string{"foo"},
				"fo":  []string{"foo"},
				"foo": []string{"foo"},
			},
			wantLookup: map[string]string{
				"":    "",
				"f":   "foo",
				"fo":  "foo",
				"foo": "foo",
			},
		},
		{
			add: []string{
				"bar",
				"foo",
			},
			wantComplete: map[string][]string{
				"b":   []string{"bar"},
				"ba":  []string{"bar"},
				"bar": []string{"bar"},
				"f":   []string{"foo"},
				"fo":  []string{"foo"},
				"foo": []string{"foo"},
			},
			wantLookup: map[string]string{
				"":    "",
				"b":   "bar",
				"ba":  "bar",
				"bar": "bar",
				"f":   "foo",
				"fo":  "foo",
				"foo": "foo",
			},
		},
		{
			add: []string{
				"bar",
				"baz",
				"foo",
			},
			wantComplete: map[string][]string{
				"b":   []string{"bar", "baz"},
				"ba":  []string{"bar", "baz"},
				"bar": []string{"bar"},
				"baz": []string{"baz"},
				"f":   []string{"foo"},
				"fo":  []string{"foo"},
				"foo": []string{"foo"},
			},
			wantLookup: map[string]string{
				"":    "",
				"b":   "",
				"ba":  "",
				"bar": "bar",
				"baz": "baz",
				"f":   "foo",
				"fo":  "foo",
				"foo": "foo",
			},
		},
		{
			add: []string{
				"bar",
				"baz",
				"foo",
				"fux",
			},
			wantComplete: map[string][]string{
				"b":   []string{"bar", "baz"},
				"ba":  []string{"bar", "baz"},
				"bar": []string{"bar"},
				"baz": []string{"baz"},
				"f":   []string{"foo", "fux"},
				"fo":  []string{"foo"},
				"foo": []string{"foo"},
				"fu":  []string{"fux"},
				"fux": []string{"fux"},
			},
			wantLookup: map[string]string{
				"":    "",
				"b":   "",
				"ba":  "",
				"bar": "bar",
				"baz": "baz",
				"f":   "",
				"fo":  "foo",
				"foo": "foo",
				"fu":  "fux",
				"fux": "fux",
			},
		},
		{
			add: []string{
				"foo",
				"foobar",
			},
			wantComplete: map[string][]string{
				"f":      []string{"foo", "foobar"},
				"fo":     []string{"foo", "foobar"},
				"foo":    []string{"foo", "foobar"},
				"foob":   []string{"foobar"},
				"fooba":  []string{"foobar"},
				"foobar": []string{"foobar"},
			},
			wantLookup: map[string]string{
				"":       "",
				"f":      "",
				"fo":     "",
				"foo":    "foo",
				"foob":   "foobar",
				"fooba":  "foobar",
				"foobar": "foobar",
			},
		},
		{
			add: []string{
				"foo",
				"foobar",
				"foobaz",
			},
			wantComplete: map[string][]string{
				"f":      []string{"foo", "foobar", "foobaz"},
				"fo":     []string{"foo", "foobar", "foobaz"},
				"foo":    []string{"foo", "foobar", "foobaz"},
				"foob":   []string{"foobar", "foobaz"},
				"fooba":  []string{"foobar", "foobaz"},
				"foobar": []string{"foobar"},
			},
			wantLookup: map[string]string{
				"":       "",
				"f":      "",
				"fo":     "",
				"foo":    "foo",
				"foob":   "",
				"fooba":  "",
				"foobar": "foobar",
				"foobaz": "foobaz",
			},
		},
	} {
		c := NewCompleter()
		for _, s := range tc.add {
			if err := c.Add(s); err != nil {
				t.Errorf("%+v.Add(%q) == %s, want <nil>", c, s, err)
			}
		}
		for prefix, wantLookup := range tc.wantLookup {
			if got, ok := c.Lookup(prefix); got != wantLookup || (got == "" && ok) {
				t.Errorf("%+v.Lookup(%q) == %q, %t, want %q", c, prefix, got, ok, wantLookup)
			}
		}
		for prefix, wantComplete := range tc.wantComplete {
			gotComplete := c.Complete(prefix)
			sort.Strings(gotComplete)
			if !reflect.DeepEqual(gotComplete, wantComplete) {
				t.Errorf("%+v.Complete(%q) == %v, want %v", c, prefix, gotComplete, wantComplete)
			}
		}
	}
}

func TestCompleterSubstringLookup(t *testing.T) {
	c := NewCompleter()
	c.Add("foo")
	if err := c.Add("fo"); err != nil {
		t.Errorf("%+v.Add(\"fo\") == %v, want <nil>", c, err)
	}
	prefix := "f"
	if got, ok := c.Lookup(prefix); ok {
		t.Errorf("%+v.Lookup(%q) == %q, %t, want \"\", false", c, prefix, got, ok)
	}
}

func TestCompleterAddDuplicate(t *testing.T) {
	c := NewCompleter()
	c.Add("foo")
	if err := c.Add("foo"); err == nil {
		t.Errorf("%+v.Add(\"foo\") == <nil>, want !<nil>", c)
	}
}
<|endoftext|>


<commit_before>package metricz_test

import (
	"encoding/json"
	"io/ioutil"
	"net"
	"net/http"
	"runtime"

	"time"

	. "github.com/cloudfoundry-incubator/metricz"
	"github.com/cloudfoundry-incubator/metricz/instrumentation"
	"github.com/cloudfoundry/loggregatorlib/loggertesthelper"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Component", func() {
	var uniquePortForTest uint
	BeforeEach(func() {
		uniquePortForTest = uint(CurrentGinkgoTestDescription().LineNumber + 10000)
	})
	It("component URL", func() {

		component, err := NewComponent(loggertesthelper.Logger(), "loggregator", uniquePortForTest, GoodHealthMonitor{}, 0, nil, nil)
		Ω(err).ShouldNot(HaveOccurred())

		url := component.URL()

		host, port, err := net.SplitHostPort(url.Host)
		Ω(err).ShouldNot(HaveOccurred())

		Ω(url.Scheme).Should(Equal("http"))

		Ω(host).ShouldNot(Equal("0.0.0.0"))
		Ω(host).ShouldNot(Equal("127.0.0.1"))

		Ω(port).ShouldNot(Equal("0"))
	})
	It("status credentials nil", func() {

		component, err := NewComponent(loggertesthelper.Logger(), "loggregator", uniquePortForTest, GoodHealthMonitor{}, 0, nil, nil)
		Ω(err).ShouldNot(HaveOccurred())

		url := component.URL()

		Ω(url.User.Username()).ShouldNot(BeEmpty())

		_, passwordPresent := url.User.Password()
		Ω(passwordPresent).Should(BeTrue())
	})
	It("status credentials default", func() {

		component, err := NewComponent(loggertesthelper.Logger(), "loggregator", uniquePortForTest, GoodHealthMonitor{}, 0, []string{"", ""}, nil)
		Ω(err).ShouldNot(HaveOccurred())

		url := component.URL()

		Ω(url.User.Username()).ShouldNot(BeEmpty())

		_, passwordPresent := url.User.Password()
		Ω(passwordPresent).Should(BeTrue())
	})
	It("good healthz endpoint", func() {
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go component.StartMonitoringEndpoints()

		req, err := http.NewRequest("GET", component.URL().String()+"/healthz", nil)
		resp, err := http.DefaultClient.Do(req)
		Ω(err).ShouldNot(HaveOccurred())

		Ω(resp.StatusCode, 200)
		Ω(resp.Header.Get("Content-Type"), "text/plain")
		body, err := ioutil.ReadAll(resp.Body)
		Ω(err).ShouldNot(HaveOccurred())
		Ω(string(body)).Should(Equal("ok"))
	})
	It("bad healthz endpoint", func() {

		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			BadHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go component.StartMonitoringEndpoints()

		req, err := http.NewRequest("GET", component.URL().String()+"/healthz", nil)
		resp, err := http.DefaultClient.Do(req)
		Ω(err).ShouldNot(HaveOccurred())

		Ω(resp.StatusCode).Should(Equal(200))
		body, err := ioutil.ReadAll(resp.Body)
		Ω(err).ShouldNot(HaveOccurred())
		Ω(string(body)).Should(Equal("bad"))
	})
	It("panic when failing to monitor endpoints", func() {

		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{},
		)
		Ω(err).ShouldNot(HaveOccurred())

		finishChan := make(chan bool)

		go func() {
			defer GinkgoRecover()
			err := component.StartMonitoringEndpoints()
			Ω(err).ShouldNot(HaveOccurred())
		}()
		time.Sleep(50 * time.Millisecond)

		go func() {
			defer GinkgoRecover()

			err := component.StartMonitoringEndpoints()
			Ω(err).Should(HaveOccurred())
			finishChan <- true
		}()

		<-finishChan
	})
	It("stopping server", func() {

		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go func() {
			defer GinkgoRecover()
			err := component.StartMonitoringEndpoints()
			Ω(err).ShouldNot(HaveOccurred())
		}()

		time.Sleep(50 * time.Millisecond)

		component.StopMonitoringEndpoints()

		go func() {
			defer GinkgoRecover()
			err := component.StartMonitoringEndpoints()
			Ω(err).ShouldNot(HaveOccurred())
		}()
	})
	It("varz requires basic auth", func() {

		tags := map[string]interface{}{"tagName1": "tagValue1", "tagName2": "tagValue2"}
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{
				testInstrumentable{
					"agentListener",
					[]instrumentation.Metric{
						instrumentation.Metric{Name: "messagesReceived", Value: 2004},
						instrumentation.Metric{Name: "queueLength", Value: 5, Tags: tags},
					},
				},
				testInstrumentable{
					"cfSinkServer",
					[]instrumentation.Metric{
						instrumentation.Metric{Name: "activeSinkCount", Value: 3},
					},
				},
			},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go component.StartMonitoringEndpoints()

		unauthenticatedURL := component.URL()
		unauthenticatedURL.User = nil
		unauthenticatedURL.Path = "/varz"

		req, err := http.NewRequest("GET", unauthenticatedURL.String(), nil)
		Ω(err).ShouldNot(HaveOccurred())
		resp, err := http.DefaultClient.Do(req)
		Ω(err).ShouldNot(HaveOccurred())
		Ω(resp.StatusCode).Should(Equal(401))
	})
	It("varz endpoint", func() {

		tags := map[string]interface{}{"tagName1": "tagValue1", "tagName2": "tagValue2"}
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{
				testInstrumentable{
					"agentListener",
					[]instrumentation.Metric{
						instrumentation.Metric{Name: "messagesReceived", Value: 2004},
						instrumentation.Metric{Name: "queueLength", Value: 5, Tags: tags},
					},
				},
				testInstrumentable{
					"cfSinkServer",
					[]instrumentation.Metric{
						instrumentation.Metric{Name: "activeSinkCount", Value: 3},
					},
				},
			},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go component.StartMonitoringEndpoints()

		req, err := http.NewRequest("GET", component.URL().String()+"/varz", nil)
		resp, err := http.DefaultClient.Do(req)
		Ω(err).ShouldNot(HaveOccurred())

		memStats := new(runtime.MemStats)
		runtime.ReadMemStats(memStats)

		Ω(resp.StatusCode).Should(Equal(200))
		Ω(resp.Header.Get("Content-Type")).Should(Equal("application/json"))
		body, err := ioutil.ReadAll(resp.Body)
		Ω(err).ShouldNot(HaveOccurred())

		expected := map[string]interface{}{
			"name":          "loggregator",
			"numCPUS":       runtime.NumCPU(),
			"numGoRoutines": runtime.NumGoroutine(),
			"memoryStats": map[string]interface{}{
				"numBytesAllocatedHeap":  int(memStats.HeapAlloc),
				"numBytesAllocatedStack": int(memStats.StackInuse),
				"numBytesAllocated":      int(memStats.Alloc),
				"numMallocs":             int(memStats.Mallocs),
				"numFrees":               int(memStats.Frees),
				"lastGCPauseTimeNS":      int(memStats.PauseNs[(memStats.NumGC+255)%256]),
			},
			"tags": map[string]string{
				"ip": "something",
			},
			"contexts": []interface{}{
				map[string]interface{}{
					"name": "agentListener",
					"metrics": []interface{}{
						map[string]interface{}{
							"name":  "messagesReceived",
							"value": float64(2004),
						},
						map[string]interface{}{
							"name":  "queueLength",
							"value": float64(5),
							"tags": map[string]interface{}{
								"tagName1": "tagValue1",
								"tagName2": "tagValue2",
							},
						},
					},
				},
				map[string]interface{}{
					"name": "cfSinkServer",
					"metrics": []interface{}{
						map[string]interface{}{
							"name":  "activeSinkCount",
							"value": float64(3),
						},
					},
				},
			},
		}

		var actualMap map[string]interface{}
		json.Unmarshal(body, &actualMap)
		Ω(actualMap["tags"]).ShouldNot(BeNil())
		Ω(expected["contexts"]).Should(Equal(actualMap["contexts"]))
		Ω(expected["name"]).Should(Equal(actualMap["name"]))
		Ω(expected["numCPUS"]).Should(BeNumerically("==", actualMap["numCPUS"]))
		Ω(expected["numGoRoutines"]).Should(BeNumerically("==", actualMap["numGoRoutines"]))
		Ω(actualMap["memoryStats"]).ShouldNot(BeNil())
		Ω(actualMap["memoryStats"]).ShouldNot(BeEmpty())
	})
})

type GoodHealthMonitor struct{}

func (hm GoodHealthMonitor) Ok() bool {
	return true
}

type BadHealthMonitor struct{}

func (hm BadHealthMonitor) Ok() bool {
	return false
}

type testInstrumentable struct {
	name    string
	metrics []instrumentation.Metric
}

func (t testInstrumentable) Emit() instrumentation.Context {
	return instrumentation.Context{Name: t.name, Metrics: t.metrics}
}
<commit_msg>Fix vertical space<commit_after>package metricz_test

import (
	"encoding/json"
	"io/ioutil"
	"net"
	"net/http"
	"runtime"

	"time"

	. "github.com/cloudfoundry-incubator/metricz"
	"github.com/cloudfoundry-incubator/metricz/instrumentation"
	"github.com/cloudfoundry/loggregatorlib/loggertesthelper"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Component", func() {
	var uniquePortForTest uint

	BeforeEach(func() {
		uniquePortForTest = uint(CurrentGinkgoTestDescription().LineNumber + 10000)
	})

	It("component URL", func() {
		component, err := NewComponent(loggertesthelper.Logger(), "loggregator", uniquePortForTest, GoodHealthMonitor{}, 0, nil, nil)
		Ω(err).ShouldNot(HaveOccurred())

		url := component.URL()

		host, port, err := net.SplitHostPort(url.Host)
		Ω(err).ShouldNot(HaveOccurred())

		Ω(url.Scheme).Should(Equal("http"))

		Ω(host).ShouldNot(Equal("0.0.0.0"))
		Ω(host).ShouldNot(Equal("127.0.0.1"))

		Ω(port).ShouldNot(Equal("0"))
	})

	It("status credentials nil", func() {
		component, err := NewComponent(loggertesthelper.Logger(), "loggregator", uniquePortForTest, GoodHealthMonitor{}, 0, nil, nil)
		Ω(err).ShouldNot(HaveOccurred())

		url := component.URL()

		Ω(url.User.Username()).ShouldNot(BeEmpty())

		_, passwordPresent := url.User.Password()
		Ω(passwordPresent).Should(BeTrue())
	})

	It("status credentials default", func() {
		component, err := NewComponent(loggertesthelper.Logger(), "loggregator", uniquePortForTest, GoodHealthMonitor{}, 0, []string{"", ""}, nil)
		Ω(err).ShouldNot(HaveOccurred())

		url := component.URL()

		Ω(url.User.Username()).ShouldNot(BeEmpty())

		_, passwordPresent := url.User.Password()
		Ω(passwordPresent).Should(BeTrue())
	})

	It("good healthz endpoint", func() {
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go component.StartMonitoringEndpoints()

		req, err := http.NewRequest("GET", component.URL().String()+"/healthz", nil)
		resp, err := http.DefaultClient.Do(req)
		Ω(err).ShouldNot(HaveOccurred())

		Ω(resp.StatusCode, 200)
		Ω(resp.Header.Get("Content-Type"), "text/plain")
		body, err := ioutil.ReadAll(resp.Body)
		Ω(err).ShouldNot(HaveOccurred())
		Ω(string(body)).Should(Equal("ok"))
	})

	It("bad healthz endpoint", func() {
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			BadHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go component.StartMonitoringEndpoints()

		req, err := http.NewRequest("GET", component.URL().String()+"/healthz", nil)
		resp, err := http.DefaultClient.Do(req)
		Ω(err).ShouldNot(HaveOccurred())

		Ω(resp.StatusCode).Should(Equal(200))
		body, err := ioutil.ReadAll(resp.Body)
		Ω(err).ShouldNot(HaveOccurred())
		Ω(string(body)).Should(Equal("bad"))
	})

	It("panic when failing to monitor endpoints", func() {
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{},
		)
		Ω(err).ShouldNot(HaveOccurred())

		finishChan := make(chan bool)

		go func() {
			defer GinkgoRecover()
			err := component.StartMonitoringEndpoints()
			Ω(err).ShouldNot(HaveOccurred())
		}()
		time.Sleep(50 * time.Millisecond)

		go func() {
			defer GinkgoRecover()

			err := component.StartMonitoringEndpoints()
			Ω(err).Should(HaveOccurred())
			finishChan <- true
		}()

		<-finishChan
	})

	It("stopping server", func() {
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go func() {
			defer GinkgoRecover()
			err := component.StartMonitoringEndpoints()
			Ω(err).ShouldNot(HaveOccurred())
		}()

		time.Sleep(50 * time.Millisecond)

		component.StopMonitoringEndpoints()

		go func() {
			defer GinkgoRecover()
			err := component.StartMonitoringEndpoints()
			Ω(err).ShouldNot(HaveOccurred())
		}()
	})

	It("varz requires basic auth", func() {
		tags := map[string]interface{}{"tagName1": "tagValue1", "tagName2": "tagValue2"}
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{
				testInstrumentable{
					"agentListener",
					[]instrumentation.Metric{
						instrumentation.Metric{Name: "messagesReceived", Value: 2004},
						instrumentation.Metric{Name: "queueLength", Value: 5, Tags: tags},
					},
				},
				testInstrumentable{
					"cfSinkServer",
					[]instrumentation.Metric{
						instrumentation.Metric{Name: "activeSinkCount", Value: 3},
					},
				},
			},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go component.StartMonitoringEndpoints()

		unauthenticatedURL := component.URL()
		unauthenticatedURL.User = nil
		unauthenticatedURL.Path = "/varz"

		req, err := http.NewRequest("GET", unauthenticatedURL.String(), nil)
		Ω(err).ShouldNot(HaveOccurred())
		resp, err := http.DefaultClient.Do(req)
		Ω(err).ShouldNot(HaveOccurred())
		Ω(resp.StatusCode).Should(Equal(401))
	})

	It("varz endpoint", func() {
		tags := map[string]interface{}{"tagName1": "tagValue1", "tagName2": "tagValue2"}
		component, err := NewComponent(
			loggertesthelper.Logger(),
			"loggregator",
			uniquePortForTest,
			GoodHealthMonitor{},
			0,
			[]string{"user", "pass"},
			[]instrumentation.Instrumentable{
				testInstrumentable{
					"agentListener",
					[]instrumentation.Metric{
						instrumentation.Metric{Name: "messagesReceived", Value: 2004},
						instrumentation.Metric{Name: "queueLength", Value: 5, Tags: tags},
					},
				},
				testInstrumentable{
					"cfSinkServer",
					[]instrumentation.Metric{
						instrumentation.Metric{Name: "activeSinkCount", Value: 3},
					},
				},
			},
		)
		Ω(err).ShouldNot(HaveOccurred())

		go component.StartMonitoringEndpoints()

		req, err := http.NewRequest("GET", component.URL().String()+"/varz", nil)
		resp, err := http.DefaultClient.Do(req)
		Ω(err).ShouldNot(HaveOccurred())

		memStats := new(runtime.MemStats)
		runtime.ReadMemStats(memStats)

		Ω(resp.StatusCode).Should(Equal(200))
		Ω(resp.Header.Get("Content-Type")).Should(Equal("application/json"))
		body, err := ioutil.ReadAll(resp.Body)
		Ω(err).ShouldNot(HaveOccurred())

		expected := map[string]interface{}{
			"name":          "loggregator",
			"numCPUS":       runtime.NumCPU(),
			"numGoRoutines": runtime.NumGoroutine(),
			"memoryStats": map[string]interface{}{
				"numBytesAllocatedHeap":  int(memStats.HeapAlloc),
				"numBytesAllocatedStack": int(memStats.StackInuse),
				"numBytesAllocated":      int(memStats.Alloc),
				"numMallocs":             int(memStats.Mallocs),
				"numFrees":               int(memStats.Frees),
				"lastGCPauseTimeNS":      int(memStats.PauseNs[(memStats.NumGC+255)%256]),
			},
			"tags": map[string]string{
				"ip": "something",
			},
			"contexts": []interface{}{
				map[string]interface{}{
					"name": "agentListener",
					"metrics": []interface{}{
						map[string]interface{}{
							"name":  "messagesReceived",
							"value": float64(2004),
						},
						map[string]interface{}{
							"name":  "queueLength",
							"value": float64(5),
							"tags": map[string]interface{}{
								"tagName1": "tagValue1",
								"tagName2": "tagValue2",
							},
						},
					},
				},
				map[string]interface{}{
					"name": "cfSinkServer",
					"metrics": []interface{}{
						map[string]interface{}{
							"name":  "activeSinkCount",
							"value": float64(3),
						},
					},
				},
			},
		}

		var actualMap map[string]interface{}
		json.Unmarshal(body, &actualMap)
		Ω(actualMap["tags"]).ShouldNot(BeNil())
		Ω(expected["contexts"]).Should(Equal(actualMap["contexts"]))
		Ω(expected["name"]).Should(Equal(actualMap["name"]))
		Ω(expected["numCPUS"]).Should(BeNumerically("==", actualMap["numCPUS"]))
		Ω(expected["numGoRoutines"]).Should(BeNumerically("==", actualMap["numGoRoutines"]))
		Ω(actualMap["memoryStats"]).ShouldNot(BeNil())
		Ω(actualMap["memoryStats"]).ShouldNot(BeEmpty())
	})
})

type GoodHealthMonitor struct{}

func (hm GoodHealthMonitor) Ok() bool {
	return true
}

type BadHealthMonitor struct{}

func (hm BadHealthMonitor) Ok() bool {
	return false
}

type testInstrumentable struct {
	name    string
	metrics []instrumentation.Metric
}

func (t testInstrumentable) Emit() instrumentation.Context {
	return instrumentation.Context{Name: t.name, Metrics: t.metrics}
}
<|endoftext|>


<commit_before>package terraform

// ResourceProvider is an interface that must be implemented by any
// resource provider: the thing that creates and manages the resources in
// a Terraform configuration.
//
// Important implementation note: All returned pointers, such as
// *ResourceConfig, *InstanceState, *InstanceDiff, etc. must not point to
// shared data. Terraform is highly parallel and assumes that this data is safe
// to read/write in parallel so it must be unique references. Note that it is
// safe to return arguments as results, however.
type ResourceProvider interface {
	/*********************************************************************
	* Functions related to the provider
	*********************************************************************/

	// Input is called to ask the provider to ask the user for input
	// for completing the configuration if necesarry.
	//
	// This may or may not be called, so resource provider writers shouldn't
	// rely on this being available to set some default values for validate
	// later. Example of a situation where this wouldn't be called is if
	// the user is not using a TTY.
	Input(UIInput, *ResourceConfig) (*ResourceConfig, error)

	// Validate is called once at the beginning with the raw configuration
	// (no interpolation done) and can return a list of warnings and/or
	// errors.
	//
	// This is called once with the provider configuration only. It may not
	// be called at all if no provider configuration is given.
	//
	// This should not assume that any values of the configurations are valid.
	// The primary use case of this call is to check that required keys are
	// set.
	Validate(*ResourceConfig) ([]string, []error)

	// Configure configures the provider itself with the configuration
	// given. This is useful for setting things like access keys.
	//
	// This won't be called at all if no provider configuration is given.
	//
	// Configure returns an error if it occurred.
	Configure(*ResourceConfig) error

	// Resources returns all the available resource types that this provider
	// knows how to manage.
	Resources() []ResourceType

	/*********************************************************************
	* Functions related to individual resources
	*********************************************************************/

	// ValidateResource is called once at the beginning with the raw
	// configuration (no interpolation done) and can return a list of warnings
	// and/or errors.
	//
	// This is called once per resource.
	//
	// This should not assume any of the values in the resource configuration
	// are valid since it is possible they have to be interpolated still.
	// The primary use case of this call is to check that the required keys
	// are set and that the general structure is correct.
	ValidateResource(string, *ResourceConfig) ([]string, []error)

	// Apply applies a diff to a specific resource and returns the new
	// resource state along with an error.
	//
	// If the resource state given has an empty ID, then a new resource
	// is expected to be created.
	Apply(
		*InstanceInfo,
		*InstanceState,
		*InstanceDiff) (*InstanceState, error)

	// Diff diffs a resource versus a desired state and returns
	// a diff.
	Diff(
		*InstanceInfo,
		*InstanceState,
		*ResourceConfig) (*InstanceDiff, error)

	// Refresh refreshes a resource and updates all of its attributes
	// with the latest information.
	Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error)

	/*********************************************************************
	* Functions related to importing
	*********************************************************************/

	// ImportState requests that the given resource be imported.
	//
	// The returned InstanceState only requires ID be set. Importing
	// will always call Refresh after the state to complete it.
	//
	// IMPORTANT: InstanceState doesn't have the resource type attached
	// to it. A type must be specified on the state via the Ephemeral
	// field on the state.
	//
	// This function can return multiple states. Normally, an import
	// will map 1:1 to a physical resource. However, some resources map
	// to multiple. For example, an AWS security group may contain many rules.
	// Each rule is represented by a separate resource in Terraform,
	// therefore multiple states are returned.
	ImportState(*InstanceInfo, string) ([]*InstanceState, error)

	/*********************************************************************
	* Functions related to data resources
	*********************************************************************/

	// ValidateDataSource is called once at the beginning with the raw
	// configuration (no interpolation done) and can return a list of warnings
	// and/or errors.
	//
	// This is called once per data source instance.
	//
	// This should not assume any of the values in the resource configuration
	// are valid since it is possible they have to be interpolated still.
	// The primary use case of this call is to check that the required keys
	// are set and that the general structure is correct.
	ValidateDataSource(string, *ResourceConfig) ([]string, []error)

	// DataSources returns all of the available data sources that this
	// provider implements.
	DataSources() []DataSource

	// ReadDataDiff produces a diff that represents the state that will
	// be produced when the given data source is read using a later call
	// to ReadDataApply.
	ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)

	// ReadDataApply initializes a data instance using the configuration
	// in a diff produced by ReadDataDiff.
	ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
}

// ResourceProviderCloser is an interface that providers that can close
// connections that aren't needed anymore must implement.
type ResourceProviderCloser interface {
	Close() error
}

// ResourceType is a type of resource that a resource provider can manage.
type ResourceType struct {
	Name       string // Name of the resource, example "instance" (no provider prefix)
	Importable bool   // Whether this resource supports importing
}

// DataSource is a data source that a resource provider implements.
type DataSource struct {
	Name string
}

// ResourceProviderFactory is a function type that creates a new instance
// of a resource provider.
type ResourceProviderFactory func() (ResourceProvider, error)

// ResourceProviderFactoryFixed is a helper that creates a
// ResourceProviderFactory that just returns some fixed provider.
func ResourceProviderFactoryFixed(p ResourceProvider) ResourceProviderFactory {
	return func() (ResourceProvider, error) {
		return p, nil
	}
}

func ProviderHasResource(p ResourceProvider, n string) bool {
	for _, rt := range p.Resources() {
		if rt.Name == n {
			return true
		}
	}

	return false
}

func ProviderHasDataSource(p ResourceProvider, n string) bool {
	for _, rt := range p.DataSources() {
		if rt.Name == n {
			return true
		}
	}

	return false
}
<commit_msg>terraform: Stop API added to ResourceProvider<commit_after>package terraform

// ResourceProvider is an interface that must be implemented by any
// resource provider: the thing that creates and manages the resources in
// a Terraform configuration.
//
// Important implementation note: All returned pointers, such as
// *ResourceConfig, *InstanceState, *InstanceDiff, etc. must not point to
// shared data. Terraform is highly parallel and assumes that this data is safe
// to read/write in parallel so it must be unique references. Note that it is
// safe to return arguments as results, however.
type ResourceProvider interface {
	/*********************************************************************
	* Functions related to the provider
	*********************************************************************/

	// Input is called to ask the provider to ask the user for input
	// for completing the configuration if necesarry.
	//
	// This may or may not be called, so resource provider writers shouldn't
	// rely on this being available to set some default values for validate
	// later. Example of a situation where this wouldn't be called is if
	// the user is not using a TTY.
	Input(UIInput, *ResourceConfig) (*ResourceConfig, error)

	// Validate is called once at the beginning with the raw configuration
	// (no interpolation done) and can return a list of warnings and/or
	// errors.
	//
	// This is called once with the provider configuration only. It may not
	// be called at all if no provider configuration is given.
	//
	// This should not assume that any values of the configurations are valid.
	// The primary use case of this call is to check that required keys are
	// set.
	Validate(*ResourceConfig) ([]string, []error)

	// Configure configures the provider itself with the configuration
	// given. This is useful for setting things like access keys.
	//
	// This won't be called at all if no provider configuration is given.
	//
	// Configure returns an error if it occurred.
	Configure(*ResourceConfig) error

	// Resources returns all the available resource types that this provider
	// knows how to manage.
	Resources() []ResourceType

	// Stop is called when the provider should halt any in-flight actions.
	//
	// This can be used to make a nicer Ctrl-C experience for Terraform.
	// Even if this isn't implemented to do anything (just returns nil),
	// Terraform will still cleanly stop after the currently executing
	// graph node is complete. However, this API can be used to make more
	// efficient halts.
	//
	// Stop doesn't have to and shouldn't block waiting for in-flight actions
	// to complete. It should take any action it wants and return immediately
	// acknowledging it has received the stop request. Terraform core will
	// automatically not make any further API calls to the provider soon
	// after Stop is called (technically exactly once the currently executing
	// graph nodes are complete).
	//
	// The error returned, if non-nil, is assumed to mean that signaling the
	// stop somehow failed and that the user should expect potentially waiting
	// a longer period of time.
	Stop() error

	/*********************************************************************
	* Functions related to individual resources
	*********************************************************************/

	// ValidateResource is called once at the beginning with the raw
	// configuration (no interpolation done) and can return a list of warnings
	// and/or errors.
	//
	// This is called once per resource.
	//
	// This should not assume any of the values in the resource configuration
	// are valid since it is possible they have to be interpolated still.
	// The primary use case of this call is to check that the required keys
	// are set and that the general structure is correct.
	ValidateResource(string, *ResourceConfig) ([]string, []error)

	// Apply applies a diff to a specific resource and returns the new
	// resource state along with an error.
	//
	// If the resource state given has an empty ID, then a new resource
	// is expected to be created.
	Apply(
		*InstanceInfo,
		*InstanceState,
		*InstanceDiff) (*InstanceState, error)

	// Diff diffs a resource versus a desired state and returns
	// a diff.
	Diff(
		*InstanceInfo,
		*InstanceState,
		*ResourceConfig) (*InstanceDiff, error)

	// Refresh refreshes a resource and updates all of its attributes
	// with the latest information.
	Refresh(*InstanceInfo, *InstanceState) (*InstanceState, error)

	/*********************************************************************
	* Functions related to importing
	*********************************************************************/

	// ImportState requests that the given resource be imported.
	//
	// The returned InstanceState only requires ID be set. Importing
	// will always call Refresh after the state to complete it.
	//
	// IMPORTANT: InstanceState doesn't have the resource type attached
	// to it. A type must be specified on the state via the Ephemeral
	// field on the state.
	//
	// This function can return multiple states. Normally, an import
	// will map 1:1 to a physical resource. However, some resources map
	// to multiple. For example, an AWS security group may contain many rules.
	// Each rule is represented by a separate resource in Terraform,
	// therefore multiple states are returned.
	ImportState(*InstanceInfo, string) ([]*InstanceState, error)

	/*********************************************************************
	* Functions related to data resources
	*********************************************************************/

	// ValidateDataSource is called once at the beginning with the raw
	// configuration (no interpolation done) and can return a list of warnings
	// and/or errors.
	//
	// This is called once per data source instance.
	//
	// This should not assume any of the values in the resource configuration
	// are valid since it is possible they have to be interpolated still.
	// The primary use case of this call is to check that the required keys
	// are set and that the general structure is correct.
	ValidateDataSource(string, *ResourceConfig) ([]string, []error)

	// DataSources returns all of the available data sources that this
	// provider implements.
	DataSources() []DataSource

	// ReadDataDiff produces a diff that represents the state that will
	// be produced when the given data source is read using a later call
	// to ReadDataApply.
	ReadDataDiff(*InstanceInfo, *ResourceConfig) (*InstanceDiff, error)

	// ReadDataApply initializes a data instance using the configuration
	// in a diff produced by ReadDataDiff.
	ReadDataApply(*InstanceInfo, *InstanceDiff) (*InstanceState, error)
}

// ResourceProviderCloser is an interface that providers that can close
// connections that aren't needed anymore must implement.
type ResourceProviderCloser interface {
	Close() error
}

// ResourceType is a type of resource that a resource provider can manage.
type ResourceType struct {
	Name       string // Name of the resource, example "instance" (no provider prefix)
	Importable bool   // Whether this resource supports importing
}

// DataSource is a data source that a resource provider implements.
type DataSource struct {
	Name string
}

// ResourceProviderFactory is a function type that creates a new instance
// of a resource provider.
type ResourceProviderFactory func() (ResourceProvider, error)

// ResourceProviderFactoryFixed is a helper that creates a
// ResourceProviderFactory that just returns some fixed provider.
func ResourceProviderFactoryFixed(p ResourceProvider) ResourceProviderFactory {
	return func() (ResourceProvider, error) {
		return p, nil
	}
}

func ProviderHasResource(p ResourceProvider, n string) bool {
	for _, rt := range p.Resources() {
		if rt.Name == n {
			return true
		}
	}

	return false
}

func ProviderHasDataSource(p ResourceProvider, n string) bool {
	for _, rt := range p.DataSources() {
		if rt.Name == n {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016
	All Rights Reserved

	For Licensing and Usage information, please see LICENSE.md

	vcgencmd.go is a command-line utility to print out all sorts of information
	from a Raspberry Pi using the VCGenCmd interface. For example:

	vcgencmd temp
	vcgencmd clocks
	vcgencmd volts

    etc.
*/
package main

import (
	"flag"
	"fmt"
	"github.com/djthorpe/gopi/rpi"
	"os"
	"path"
	"strings"
)

////////////////////////////////////////////////////////////////////////////

var commandmap = map[string]func(*rpi.State){
	"all":      allCommand,
	"temp":     tempCommand,
	"clocks":   clocksCommand,
	"volts":    voltsCommand,
	"memory":   memoryCommand,
	"codecs":   codecsCommand,
	"otp":      otpCommand,
	"serial":   serialCommand,
	"revision": revisionCommand,
	"model":    modelCommand,
}

////////////////////////////////////////////////////////////////////////////

func allCommand(pi *rpi.State) {
	tempCommand(pi)
	clocksCommand(pi)
	voltsCommand(pi)
	memoryCommand(pi)
	codecsCommand(pi)
	otpCommand(pi)
	serialCommand(pi)
	revisionCommand(pi)
}

func tempCommand(pi *rpi.State) {
	// print out temperature
	coretemp, err := pi.GetCoreTemperatureCelcius()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Printf("Temperature=%vºC\n", coretemp)
}

func clocksCommand(pi *rpi.State) {
	// print out clocks
	clocks, err := pi.GetClockFrequencyHertz()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("Clock Frequency")
	for k, v := range clocks {
		fmt.Printf("  %v=%vMHz\n", k, (float64(v) / 1E6))
	}
}

func voltsCommand(pi *rpi.State) {
	// print out volts
	volts, err := pi.GetVolts()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("Volts")
	for k, v := range volts {
		fmt.Printf("  %v=%vV\n", k, v)
	}
}

func memoryCommand(pi *rpi.State) {
	// print out memory sizes
	memory, err := pi.GetMemoryMegabytes()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("Memory")
	for k, v := range memory {
		fmt.Printf("  %v=%vMB\n", k, v)
	}
}

func codecsCommand(pi *rpi.State) {
	// print out codecs
	codecs, err := pi.GetCodecs()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("Codecs")
	for k, v := range codecs {
		fmt.Printf("  %v=%v\n", k, v)
	}
}

func otpCommand(pi *rpi.State) {
	// print out OTP memory
	otp, err := pi.GetOTP()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("OTP")
	for i, v := range otp {
		fmt.Printf("  %02d=%08X\n", i, v)
	}
}

func serialCommand(pi *rpi.State) {
	// print out Serial number
	serial, err := pi.GetSerial()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Printf("Serial=%016X\n", serial)
}

func revisionCommand(pi *rpi.State) {
	// print out Revision
	revision, err := pi.GetRevision()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Printf("Revision=%08X\n", revision)
}

func modelCommand(pi *rpi.State) {
	// print out Revision
	model, err := pi.GetModel()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Printf("Model=%+v\n", model)
}

////////////////////////////////////////////////////////////////////////////

func main() {

	pi := rpi.New()
	defer pi.Terminate()

	////////////////////////////////////////////////////////////////////////////

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s <command>\n", path.Base(os.Args[0]))

		fmt.Fprintf(os.Stderr, " <command> can be one of the following: ")
		for k, _ := range commandmap {
			fmt.Fprintf(os.Stderr, "%s, ", k)
		}
		vccommands, _ := pi.GetCommands()
		for _, v := range vccommands {
			fmt.Fprintf(os.Stderr, "%s, ", v)
		}
		fmt.Fprintf(os.Stderr, "\n")
		flag.PrintDefaults()
	}
	flag.Parse()

	////////////////////////////////////////////////////////////////////////////

	args := flag.Args()
	if len(args) < 1 {
		flag.Usage()
		os.Exit(1)
	}

	////////////////////////////////////////////////////////////////////////////

	var done bool

	// attempt to run a custom command
	if len(args) == 1 {
		if f := commandmap[args[0]]; f != nil {
			f(pi)
			done = true
		}
	}

	// if custom command not run, use VCGenCmd
	if done == false {
		fmt.Println(rpi.VCGenCmd(strings.Join(args, " ")))
	}

}
<commit_msg>Updates<commit_after>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016
	All Rights Reserved

	For Licensing and Usage information, please see LICENSE.md

	vcgencmd.go is a command-line utility to print out all sorts of information
	from a Raspberry Pi using the VCGenCmd interface. For example:

	vcgencmd temp
	vcgencmd clocks
	vcgencmd volts

    etc.
*/
package main

import (
	"flag"
	"fmt"
	"github.com/djthorpe/gopi/rpi"
	"os"
	"path"
	"strings"
)

////////////////////////////////////////////////////////////////////////////

var commandmap = map[string]func(*rpi.State){
	"all":      allCommand,
	"temp":     tempCommand,
	"clocks":   clocksCommand,
	"volts":    voltsCommand,
	"memory":   memoryCommand,
	"codecs":   codecsCommand,
	"otp":      otpCommand,
	"serial":   serialCommand,
	"revision": revisionCommand,
	"model":    modelCommand,
}

////////////////////////////////////////////////////////////////////////////

func allCommand(pi *rpi.State) {
	tempCommand(pi)
	clocksCommand(pi)
	voltsCommand(pi)
	memoryCommand(pi)
	codecsCommand(pi)
	otpCommand(pi)
	serialCommand(pi)
	revisionCommand(pi)
	modelCommand(pi)
}

func tempCommand(pi *rpi.State) {
	// print out temperature
	coretemp, err := pi.GetCoreTemperatureCelcius()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Printf("Temperature=%vºC\n", coretemp)
}

func clocksCommand(pi *rpi.State) {
	// print out clocks
	clocks, err := pi.GetClockFrequencyHertz()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("Clock Frequency")
	for k, v := range clocks {
		fmt.Printf("  %v=%vMHz\n", k, (float64(v) / 1E6))
	}
}

func voltsCommand(pi *rpi.State) {
	// print out volts
	volts, err := pi.GetVolts()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("Volts")
	for k, v := range volts {
		fmt.Printf("  %v=%vV\n", k, v)
	}
}

func memoryCommand(pi *rpi.State) {
	// print out memory sizes
	memory, err := pi.GetMemoryMegabytes()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("Memory")
	for k, v := range memory {
		fmt.Printf("  %v=%vMB\n", k, v)
	}
}

func codecsCommand(pi *rpi.State) {
	// print out codecs
	codecs, err := pi.GetCodecs()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("Codecs")
	for k, v := range codecs {
		fmt.Printf("  %v=%v\n", k, v)
	}
}

func otpCommand(pi *rpi.State) {
	// print out OTP memory
	otp, err := pi.GetOTP()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Println("OTP")
	for i, v := range otp {
		fmt.Printf("  %02d=%08X\n", i, v)
	}
}

func serialCommand(pi *rpi.State) {
	// print out Serial number
	serial, err := pi.GetSerial()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Printf("Serial=%016X\n", serial)
}

func revisionCommand(pi *rpi.State) {
	// print out Revision
	revision, err := pi.GetRevision()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Printf("Revision=%08X\n", revision)
}

func modelCommand(pi *rpi.State) {
	// print out Revision
	model, err := pi.GetModel()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	fmt.Printf("Model=%+v\n", model)
}

////////////////////////////////////////////////////////////////////////////

func main() {

	pi := rpi.New()
	defer pi.Terminate()

	////////////////////////////////////////////////////////////////////////////

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s <command>\n", path.Base(os.Args[0]))

		fmt.Fprintf(os.Stderr, " <command> can be one of the following: ")
		for k, _ := range commandmap {
			fmt.Fprintf(os.Stderr, "%s, ", k)
		}
		vccommands, _ := pi.GetCommands()
		for _, v := range vccommands {
			fmt.Fprintf(os.Stderr, "%s, ", v)
		}
		fmt.Fprintf(os.Stderr, "\n")
		flag.PrintDefaults()
	}
	flag.Parse()

	////////////////////////////////////////////////////////////////////////////

	args := flag.Args()
	if len(args) < 1 {
		flag.Usage()
		os.Exit(1)
	}

	////////////////////////////////////////////////////////////////////////////

	var done bool

	// attempt to run a custom command
	if len(args) == 1 {
		if f := commandmap[args[0]]; f != nil {
			f(pi)
			done = true
		}
	}

	// if custom command not run, use VCGenCmd
	if done == false {
		fmt.Println(rpi.VCGenCmd(strings.Join(args, " ")))
	}

}
<|endoftext|>


<commit_before>package handler

import (
	"context"
	"fmt"
	"io"

	"github.com/micro/go-micro"
	"github.com/micro/go-micro/errors"
	"github.com/micro/go-micro/network/router"
	pb "github.com/micro/go-micro/network/router/proto"
)

// Router implements router handler
type Router struct {
	Router  router.Router
	Adverts micro.Publisher
}

// Lookup looks up routes in the routing table and returns them
func (r *Router) Lookup(ctx context.Context, req *pb.LookupRequest, resp *pb.LookupResponse) error {
	query := router.NewQuery(
		router.QueryService(req.Query.Service),
	)

	routes, err := r.Router.Lookup(query)
	if err != nil {
		return errors.InternalServerError("go.micro.router", "failed to lookup routes: %v", err)
	}

	var respRoutes []*pb.Route
	for _, route := range routes {
		respRoute := &pb.Route{
			Service: route.Service,
			Address: route.Address,
			Gateway: route.Gateway,
			Network: route.Network,
			Link:    route.Link,
			Metric:  int64(route.Metric),
		}
		respRoutes = append(respRoutes, respRoute)
	}

	resp.Routes = respRoutes

	return nil
}

func (r *Router) Advertise(ctx context.Context, req *pb.AdvertiseRequest, stream pb.Router_AdvertiseStream) error {
	advertChan, err := r.Router.Advertise()
	if err != nil {
		return errors.InternalServerError("go.micro.router", "failed to get adverts: %v", err)
	}

	for advert := range advertChan {
		var events []*pb.Event
		for _, event := range advert.Events {
			route := &pb.Route{
				Service: event.Route.Service,
				Address: event.Route.Address,
				Gateway: event.Route.Gateway,
				Network: event.Route.Network,
				Link:    event.Route.Link,
				Metric:  int64(event.Route.Metric),
			}
			e := &pb.Event{
				Type:      pb.EventType(event.Type),
				Timestamp: event.Timestamp.UnixNano(),
				Route:     route,
			}
			events = append(events, e)
		}

		advert := &pb.Advert{
			Id:        advert.Id,
			Type:      pb.AdvertType(advert.Type),
			Timestamp: advert.Timestamp.UnixNano(),
			Events:    events,
		}

		// send the advert
		err := stream.Send(advert)
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return errors.InternalServerError("go.micro.router", "error sending message %v", err)
		}
	}

	return nil
}

func (r *Router) Process(ctx context.Context, req *pb.Advert, rsp *pb.ProcessResponse) error {
	// publish the advert
	if err := r.Adverts.Publish(context.Background(), req); err != nil {
		return errors.InternalServerError("go.micro.router", "error publishing advert: %v", err)
	}
	return nil
}

func (r *Router) Status(ctx context.Context, req *pb.Request, rsp *pb.StatusResponse) error {
	status := r.Router.Status()

	rsp.Status = &pb.Status{
		Code: status.Code.String(),
	}

	if status.Error != nil {
		rsp.Status.Error = status.Error.Error()
	}

	return nil
}

// Watch streans routing table events
func (r *Router) Watch(ctx context.Context, req *pb.WatchRequest, stream pb.Router_WatchStream) error {
	watcher, err := r.Router.Watch()
	if err != nil {
		return errors.InternalServerError("go.micro.router", "failed creating event watcher: %v", err)
	}

	defer stream.Close()

	for {
		event, err := watcher.Next()
		if err == router.ErrWatcherStopped {
			break
		}

		if err != nil {
			return errors.InternalServerError("go.micro.router", "error watching events: %v", err)
		}

		route := &pb.Route{
			Service: event.Route.Service,
			Address: event.Route.Address,
			Gateway: event.Route.Gateway,
			Network: event.Route.Network,
			Link:    event.Route.Link,
			Metric:  int64(event.Route.Metric),
		}

		tableEvent := &pb.Event{
			Type:      pb.EventType(event.Type),
			Timestamp: event.Timestamp.UnixNano(),
			Route:     route,
		}

		if err := stream.Send(tableEvent); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>remove fmt<commit_after>package handler

import (
	"context"
	"io"

	"github.com/micro/go-micro"
	"github.com/micro/go-micro/errors"
	"github.com/micro/go-micro/network/router"
	pb "github.com/micro/go-micro/network/router/proto"
)

// Router implements router handler
type Router struct {
	Router  router.Router
	Adverts micro.Publisher
}

// Lookup looks up routes in the routing table and returns them
func (r *Router) Lookup(ctx context.Context, req *pb.LookupRequest, resp *pb.LookupResponse) error {
	query := router.NewQuery(
		router.QueryService(req.Query.Service),
	)

	routes, err := r.Router.Lookup(query)
	if err != nil {
		return errors.InternalServerError("go.micro.router", "failed to lookup routes: %v", err)
	}

	var respRoutes []*pb.Route
	for _, route := range routes {
		respRoute := &pb.Route{
			Service: route.Service,
			Address: route.Address,
			Gateway: route.Gateway,
			Network: route.Network,
			Link:    route.Link,
			Metric:  int64(route.Metric),
		}
		respRoutes = append(respRoutes, respRoute)
	}

	resp.Routes = respRoutes

	return nil
}

func (r *Router) Advertise(ctx context.Context, req *pb.AdvertiseRequest, stream pb.Router_AdvertiseStream) error {
	advertChan, err := r.Router.Advertise()
	if err != nil {
		return errors.InternalServerError("go.micro.router", "failed to get adverts: %v", err)
	}

	for advert := range advertChan {
		var events []*pb.Event
		for _, event := range advert.Events {
			route := &pb.Route{
				Service: event.Route.Service,
				Address: event.Route.Address,
				Gateway: event.Route.Gateway,
				Network: event.Route.Network,
				Link:    event.Route.Link,
				Metric:  int64(event.Route.Metric),
			}
			e := &pb.Event{
				Type:      pb.EventType(event.Type),
				Timestamp: event.Timestamp.UnixNano(),
				Route:     route,
			}
			events = append(events, e)
		}

		advert := &pb.Advert{
			Id:        advert.Id,
			Type:      pb.AdvertType(advert.Type),
			Timestamp: advert.Timestamp.UnixNano(),
			Events:    events,
		}

		// send the advert
		err := stream.Send(advert)
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return errors.InternalServerError("go.micro.router", "error sending message %v", err)
		}
	}

	return nil
}

func (r *Router) Process(ctx context.Context, req *pb.Advert, rsp *pb.ProcessResponse) error {
	// publish the advert
	if err := r.Adverts.Publish(context.Background(), req); err != nil {
		return errors.InternalServerError("go.micro.router", "error publishing advert: %v", err)
	}
	return nil
}

func (r *Router) Status(ctx context.Context, req *pb.Request, rsp *pb.StatusResponse) error {
	status := r.Router.Status()

	rsp.Status = &pb.Status{
		Code: status.Code.String(),
	}

	if status.Error != nil {
		rsp.Status.Error = status.Error.Error()
	}

	return nil
}

// Watch streans routing table events
func (r *Router) Watch(ctx context.Context, req *pb.WatchRequest, stream pb.Router_WatchStream) error {
	watcher, err := r.Router.Watch()
	if err != nil {
		return errors.InternalServerError("go.micro.router", "failed creating event watcher: %v", err)
	}

	defer stream.Close()

	for {
		event, err := watcher.Next()
		if err == router.ErrWatcherStopped {
			break
		}

		if err != nil {
			return errors.InternalServerError("go.micro.router", "error watching events: %v", err)
		}

		route := &pb.Route{
			Service: event.Route.Service,
			Address: event.Route.Address,
			Gateway: event.Route.Gateway,
			Network: event.Route.Network,
			Link:    event.Route.Link,
			Metric:  int64(event.Route.Metric),
		}

		tableEvent := &pb.Event{
			Type:      pb.EventType(event.Type),
			Timestamp: event.Timestamp.UnixNano(),
			Route:     route,
		}

		if err := stream.Send(tableEvent); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


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

package testing

import (
	"errors"
	"github.com/globocom/tsuru/router"
	"sync"
)

var Instance = FakeRouter{backends: make(map[string][]string)}

var ErrBackendNotFound = errors.New("Backend not found")

func init() {
	router.Register("fake", &Instance)
}

type FakeRouter struct {
	backends map[string][]string
	mutex    sync.Mutex
}

func (r *FakeRouter) HasBackend(name string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	_, ok := r.backends[name]
	return ok
}

func (r *FakeRouter) HasRoute(name, address string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes, ok := r.backends[name]
	if !ok {
		return false
	}
	for _, route := range routes {
		if route == address {
			return true
		}
	}
	return false
}

func (r *FakeRouter) AddBackend(name string) error {
	if r.HasBackend(name) {
		return errors.New("Backend already exists")
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends[name] = nil
	return nil
}

func (r *FakeRouter) RemoveBackend(name string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	delete(r.backends, name)
	return nil
}

func (r *FakeRouter) AddRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes := r.backends[name]
	routes = append(routes, ip)
	r.backends[name] = routes
	return nil
}

func (r *FakeRouter) RemoveRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	index := -1
	routes := r.backends[name]
	for i := range routes {
		if routes[i] == ip {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Route not found")
	}
	routes[index] = routes[len(routes)-1]
	r.backends[name] = routes[:len(routes)-1]
	return nil
}

func (FakeRouter) AddCNAME(cname, name, address string) error {
	return nil
}

func (FakeRouter) RemoveCNAME(cname, address string) error {
	return nil
}

func (r *FakeRouter) Addr(name string) (string, error) {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	if v, ok := r.backends[name]; ok {
		return v[0], nil
	}
	return "", ErrBackendNotFound
}
<commit_msg>Revert "router/testing: make the registered router public"<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testing

import (
	"errors"
	"github.com/globocom/tsuru/router"
	"sync"
)

var ErrBackendNotFound = errors.New("Backend not found")

func init() {
	router.Register("fake", &FakeRouter{backends: make(map[string][]string)})
}

type FakeRouter struct {
	backends map[string][]string
	mutex    sync.Mutex
}

func (r *FakeRouter) HasBackend(name string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	_, ok := r.backends[name]
	return ok
}

func (r *FakeRouter) HasRoute(name, address string) bool {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes, ok := r.backends[name]
	if !ok {
		return false
	}
	for _, route := range routes {
		if route == address {
			return true
		}
	}
	return false
}

func (r *FakeRouter) AddBackend(name string) error {
	if r.HasBackend(name) {
		return errors.New("Backend already exists")
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.backends[name] = nil
	return nil
}

func (r *FakeRouter) RemoveBackend(name string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	delete(r.backends, name)
	return nil
}

func (r *FakeRouter) AddRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes := r.backends[name]
	routes = append(routes, ip)
	r.backends[name] = routes
	return nil
}

func (r *FakeRouter) RemoveRoute(name, ip string) error {
	if !r.HasBackend(name) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	index := -1
	routes := r.backends[name]
	for i := range routes {
		if routes[i] == ip {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Route not found")
	}
	routes[index] = routes[len(routes)-1]
	r.backends[name] = routes[:len(routes)-1]
	return nil
}

func (FakeRouter) AddCNAME(cname, name, address string) error {
	return nil
}

func (FakeRouter) RemoveCNAME(cname, address string) error {
	return nil
}

func (r *FakeRouter) Addr(name string) (string, error) {
	r.mutex.Lock()
	defer r.mutex.Unlock()
	if v, ok := r.backends[name]; ok {
		return v[0], nil
	}
	return "", ErrBackendNotFound
}
<|endoftext|>


<commit_before>package messagematch

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

func TestArrayFullMatchLengthMismatchMatchLonger(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	match := map[string]interface{}{
		"a": []interface{}{1, 2, 3, 4},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func TestArrayFullMisMatch(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 4},
	}
	match := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func TestArrayFullMatchLengthMismatchMessageLonger(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3, 4},
	}
	match := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestStringMap(t *testing.T) {
	assert := assert.New(t)
	internalMap := map[string]interface{}{
		"other": "side",
	}
	message := map[string]interface{}{
		"a": internalMap,
	}
	match := map[string]interface{}{
		"a": "b",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func SkipTestArrayContainsMisMatchIntString(t *testing.T) {
	//	pretty.Println("TestArrayContainsMisMatchIntString")
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{"z", 2, 3},
	}
	match := map[string]interface{}{
		"a": 2,
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

//ported from https://github.com/dana/perl-Message-Match/blob/master/t/basic.t
//not nested
func TestSimplestPossible(t *testing.T) {
	//	pretty.Println("TestSimplestPossible")
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
	}
	match := map[string]interface{}{
		"a": "b",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestExtraStuff(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"c": "d",
	}
	match := map[string]interface{}{
		"a": "b",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestSimpleMiss(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"c": "d",
	}
	match := map[string]interface{}{
		"e": "f",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func TestSimplestPossibleMultiMatchRequired(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"c": "d",
	}
	match := map[string]interface{}{
		"a": "b",
		"c": "d",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

//nested
func TestSimplestNested(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	match := map[string]interface{}{
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestSimplestNestedWithExtraStuff(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	match := map[string]interface{}{
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestMultipleMatchesRequiredNested(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	match := map[string]interface{}{
		"x": map[string]interface{}{
			"y": "z",
		},
		"a": "b",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

//array in message, scalar in match: checks membership
func TestArrayContains(t *testing.T) {
	//	pretty.Println("TestArrayContains")
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	match := map[string]interface{}{
		"a": 2,
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestArrayDoesNotContain(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	match := map[string]interface{}{
		"a": 5,
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}

//array on both sides: full recursion
func TestArrayFullMatch(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	match := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestNestedArrayFullMatch(t *testing.T) {
	assert := assert.New(t)
	firstSub := map[string]interface{}{
		"a": "b",
	}
	secondSub := map[string]interface{}{
		"a": "b",
	}
	message := map[string]interface{}{
		"a": []interface{}{firstSub, 2, 3},
	}
	match := map[string]interface{}{
		"a": []interface{}{secondSub, 2, 3},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

/* Initial set */
//func Match(message map[string]interface{}, match map[string]interface{}) (bool, error) {
func TestBasicMatchStringAndNumber(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b"},
			},
		},
	}
	match := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

func TestBasicMatchStringAndNotNumber(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b"},
			},
		},
	}
	match := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  7,
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}

func TestBasicNoMessageExist(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b"},
			},
		},
	}
	match := map[string]interface{}{
		"NName": "WWednesday",
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func TestBasicNoMatch(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b"},
			},
		},
	}
	match := map[string]interface{}{
		"Name": "WWednesday",
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}

func TestBasicMatch(t *testing.T) {
	assert := assert.New(t)
	c := map[string]interface{}{
		"x": "y",
	}
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b", c},
			},
		},
	}
	match := map[string]interface{}{
		"Name": "Wednesday",
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
	//pretty.Print("noop")
}
<commit_msg>cleanups<commit_after>package messagematch

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

func TestArrayFullMatchLengthMismatchMatchLonger(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	match := map[string]interface{}{
		"a": []interface{}{1, 2, 3, 4},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func TestArrayFullMisMatch(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 4},
	}
	match := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func TestArrayFullMatchLengthMismatchMessageLonger(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3, 4},
	}
	match := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestStringMap(t *testing.T) {
	assert := assert.New(t)
	internalMap := map[string]interface{}{
		"other": "side",
	}
	message := map[string]interface{}{
		"a": internalMap,
	}
	match := map[string]interface{}{
		"a": "b",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func SkipTestArrayContainsMisMatchIntString(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{"z", 2, 3},
	}
	match := map[string]interface{}{
		"a": 2,
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

//ported from https://github.com/dana/perl-Message-Match/blob/master/t/basic.t
//not nested
func TestSimplestPossible(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
	}
	match := map[string]interface{}{
		"a": "b",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestExtraStuff(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"c": "d",
	}
	match := map[string]interface{}{
		"a": "b",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestSimpleMiss(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"c": "d",
	}
	match := map[string]interface{}{
		"e": "f",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func TestSimplestPossibleMultiMatchRequired(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"c": "d",
	}
	match := map[string]interface{}{
		"a": "b",
		"c": "d",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

//nested
func TestSimplestNested(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	match := map[string]interface{}{
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestSimplestNestedWithExtraStuff(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	match := map[string]interface{}{
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestMultipleMatchesRequiredNested(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": "b",
		"x": map[string]interface{}{
			"y": "z",
		},
	}
	match := map[string]interface{}{
		"x": map[string]interface{}{
			"y": "z",
		},
		"a": "b",
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

//array in message, scalar in match: checks membership
func TestArrayContains(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	match := map[string]interface{}{
		"a": 2,
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestArrayDoesNotContain(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	match := map[string]interface{}{
		"a": 5,
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}

//array on both sides: full recursion
func TestArrayFullMatch(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	match := map[string]interface{}{
		"a": []interface{}{1, 2, 3},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
func TestNestedArrayFullMatch(t *testing.T) {
	assert := assert.New(t)
	firstSub := map[string]interface{}{
		"a": "b",
	}
	secondSub := map[string]interface{}{
		"a": "b",
	}
	message := map[string]interface{}{
		"a": []interface{}{firstSub, 2, 3},
	}
	match := map[string]interface{}{
		"a": []interface{}{secondSub, 2, 3},
	}
	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

/* Initial set */
//func Match(message map[string]interface{}, match map[string]interface{}) (bool, error) {
func TestBasicMatchStringAndNumber(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b"},
			},
		},
	}
	match := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}

func TestBasicMatchStringAndNotNumber(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b"},
			},
		},
	}
	match := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  7,
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}

func TestBasicNoMessageExist(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b"},
			},
		},
	}
	match := map[string]interface{}{
		"NName": "WWednesday",
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}
func TestBasicNoMatch(t *testing.T) {
	assert := assert.New(t)
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b"},
			},
		},
	}
	match := map[string]interface{}{
		"Name": "WWednesday",
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.False(doesMatch)
}

func TestBasicMatch(t *testing.T) {
	assert := assert.New(t)
	c := map[string]interface{}{
		"x": "y",
	}
	message := map[string]interface{}{
		"Name": "Wednesday",
		"Age":  6,
		"Parents": map[string]interface{}{
			"bee": "boo",
			"foo": map[string]interface{}{
				"hi": []interface{}{"a", "b", c},
			},
		},
	}
	match := map[string]interface{}{
		"Name": "Wednesday",
	}

	doesMatch, matchErr := Match(message, match)
	assert.Nil(matchErr)
	assert.True(doesMatch)
}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"net/http"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"

	"github.com/gobricks/facecontrol/classes/credentials"
	"github.com/gobricks/facecontrol/classes/response"
	"github.com/gobricks/facecontrol/config"
)

// Check accepts JWT token string and returns user credentials
func Check(c *gin.Context) {
	tokenString := c.Param("token")

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(config.JWTSecret), nil
	})

	if err != nil {
		c.JSON(400, response.BaseResponse{
			Success: false,
			Error:   err.Error(),
		})
		return
	}

	if token.Valid == false {
		c.JSON(403, response.BaseResponse{
			Success: false,
			Error:   http.StatusText(http.StatusForbidden),
		})
		return
	}

	credentials := c.MustGet("credentials").(*credentials.Credentials)
	uid := token.Claims["uid"].(string)

	user, err := credentials.Get(uid)
	if err != nil {
		c.JSON(404, response.BaseResponse{
			Success: false,
			Error:   err.Error(),
		})
		return
	}

	c.JSON(200, response.UserResponse{
		BaseResponse: response.BaseResponse{
			Success: true,
		},
		User: user.Payload,
	})
}
<commit_msg>constants for HTTP status codes<commit_after>package handlers

import (
	"fmt"
	"net/http"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"

	"github.com/gobricks/facecontrol/classes/credentials"
	"github.com/gobricks/facecontrol/classes/response"
	"github.com/gobricks/facecontrol/config"
)

// Check accepts JWT token string and returns user credentials
func Check(c *gin.Context) {
	tokenString := c.Param("token")

	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(config.JWTSecret), nil
	})

	if err != nil {
		c.JSON(http.StatusBadRequest, response.BaseResponse{
			Success: false,
			Error:   err.Error(),
		})
		return
	}

	if token.Valid == false {
		c.JSON(http.StatusForbidden, response.BaseResponse{
			Success: false,
			Error:   http.StatusText(http.StatusForbidden),
		})
		return
	}

	credentials := c.MustGet("credentials").(*credentials.Credentials)
	uid := token.Claims["uid"].(string)

	user, err := credentials.Get(uid)
	if err != nil {
		c.JSON(http.StatusNotFound, response.BaseResponse{
			Success: false,
			Error:   err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, response.UserResponse{
		BaseResponse: response.BaseResponse{
			Success: true,
		},
		User: user.Payload,
	})
}
<|endoftext|>


<commit_before>package mithril

import "testing"

func TestCreateElement(t *testing.T) {
	el := M("div#id-value.class-name[data1='value1'][data2=\"value2\"][data3]")
	if el == nil {
		t.Fatalf("Expected element to be a VirtualElement object but it was nil")
	}
}

func TestElementTag(t *testing.T) {
	if el := M("li"); el.Tag != "li" {
		t.Fatalf("Expected element tag to be \"li\" but it was %s", el.Tag)
	}
}

func TestElementID(t *testing.T) {
	if el := M("div#id-value"); el.Attrs.ID != "id-value" {
		t.Fatalf("Expected element ID to be id-value but it was %s", el.Attrs.ID)
	}
}

func TestCreateElementChildren(t *testing.T) {
	el := M(
		"div#obj1",
		M("div#obj2"),
	)
	if _, ok := el.Children.(*VirtualElement); !ok {
		t.Fatalf("Expected element.Children to be a VirtualElement")
	}
}

func TestCreateElementWithAttr(t *testing.T) {
	attr := NewAttributes()
	attr.ID = "listview"
	el := M("ul", attr)
	if el.Attrs.ID != "listview" {
		t.Fatalf("Expected element ID to be a listview but it was %s", el.Attrs.ID)
	}
}
<commit_msg>update mithril go test<commit_after>package mithril

import "testing"

func TestCreateElement(t *testing.T) {
	el := M("div#id-value.lol.class-name[data1='value1'][data2=\"value2\"][data3]")
	if el == nil {
		t.Fatalf("Expected element to be a VirtualElement object but it was nil")
	}
}

func TestElementTag(t *testing.T) {
	if el := M("li"); el.Tag != "li" {
		t.Fatalf("Expected element tag to be \"li\" but it was %s", el.Tag)
	}
}

func TestElementID(t *testing.T) {
	if el := M("div#id-value"); el.Attr("id") != "id-value" {
		t.Fatalf("Expected element ID to be id-value but it was %s", el.Attr("id"))
	}
}

func TestCreateElementChildren(t *testing.T) {
	el := M(
		"div#obj1",
		M("div#obj2"),
	)
	if _, ok := el.Children.(*VirtualElement); !ok {
		t.Fatalf("Expected element.Children to be a VirtualElement")
	}
}

func TestCreateElementWithAttr(t *testing.T) {
	el := M("ul", []Attribute{
		NewStringAttr("id", "listview"),
	})
	if el.Attr("id") != "listview" {
		t.Fatalf("Expected element ID to be a listview but it was %s", el.Attr("id"))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"github.com/gokyle/goconfig"
	"io"
	"log"
	"net/http"
	"os"
)

func get(src string, dest string) (int64, error) {
	resp, err := http.Get(src)
	errr(err, "Can't make http request")

	file, err := os.Create(dest)
	errr(err, "Can't create file!")

	defer resp.Body.Close()

	gz, err := gzip.NewReader(resp.Body)
	errr(err, "Can't uncompress file!")

	defer gz.Close()
	defer file.Close()

	n, err := io.Copy(file, gz)
	return n, err
}

func errr(e error, msg string) {
	if e != nil {
		log.Printf("[!]: %s - %s", msg, e)
	}
}

func main() {
	var conf, err = goconfig.ParseFile("config.ini")
	var url = conf["global"]["url"]
	var params string = "?"

	for key, val := range conf["params"] {
		params = params + key + "=" + val + "&"
	}

	errr(err, "Can't parse config file!")
	log.Printf("Getting lists from: %s", url)

	for key, val := range conf["list"] {
		var full_url = url + params + "list=" + val
		var file_name = "/tmp/" + key

		log.Printf("downloading %s", key)
		written, err2 := get(full_url, file_name)
		errr(err2, "Can't write file!")

		log.Printf("%d written to %s", written, file_name)
	}
}
<commit_msg>append/create remove loggin<commit_after>package main

import (
	"compress/gzip"
	"github.com/gokyle/goconfig"
	"io"
	"log"
	"net/http"
	"os"
)

func get(src string, dest string) (int64, error) {
	resp, err := http.Get(src)
	errr(err, "Can't make http request")

	file, err := os.OpenFile(dest, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
	errr(err, "Can't create file!")

	defer resp.Body.Close()

	gz, err := gzip.NewReader(resp.Body)
	errr(err, "Can't uncompress file!")

	defer gz.Close()
	defer file.Close()

	n, err := io.Copy(file, gz)
	return n, err
}

func errr(e error, msg string) {
	if e != nil {
		log.Printf("[!]: %s - %s", msg, e)
	}
}

func main() {
	var conf, err = goconfig.ParseFile("config.ini")
	var url = conf["global"]["url"]
	var params string = "?"

	for key, val := range conf["params"] {
		params = params + key + "=" + val + "&"
	}

	errr(err, "Can't parse config file!")
	log.Printf("Getting lists from: %s", url)

	for key, val := range conf["list"] {
		var full_url = url + params + "list=" + val
		var file_name = conf["global"]["destination"]

		log.Printf("downloading %s", key)
		_, err2 := get(full_url, file_name)
		errr(err2, "Can't write file!")
	}
}
<|endoftext|>