<commit_before>/*
Copyright 2018 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package network

import (
	"context"
	"errors"
	"net"
	"net/http"
	"time"

	"k8s.io/apimachinery/pkg/util/wait"
)

// RoundTripperFunc implementation roundtrips a request.
type RoundTripperFunc func(*http.Request) (*http.Response, error)

// RoundTrip implements http.RoundTripper.
func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
	return rt(r)
}

func newAutoTransport(v1 http.RoundTripper, v2 http.RoundTripper) http.RoundTripper {
	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
		t := v1
		if r.ProtoMajor == 2 {
			t = v2
		}
		return t.RoundTrip(r)
	})
}

const (
	initialTO = float64(50 * time.Millisecond)
	sleepTO   = 30 * time.Millisecond
	factor    = 1.4
	numSteps  = 10
)

var errDialTimeout = errors.New("timed out dialing")

// dialWithBackOff executes `net.Dialer.DialContext()` with exponentially increasing
// dial timeouts. In addition it sleeps with random jitter between tries.
func dialWithBackOff(ctx context.Context, network, address string) (net.Conn, error) {
	return dialBackOffHelper(ctx, network, address, numSteps, initialTO, sleepTO)
}

func dialBackOffHelper(ctx context.Context, network, address string, steps int, initial float64, sleep time.Duration) (net.Conn, error) {
	to := initial
	dialer := &net.Dialer{
		Timeout:   time.Duration(to),
		KeepAlive: 5 * time.Second,
		DualStack: true,
	}
	// TODO(vagababov): use backoff.Step when we use moden k8s client.
	for i := 0; i < steps; i++ {
		c, err := dialer.DialContext(ctx, network, address)
		if err != nil {
			if err, ok := err.(net.Error); ok && err.Timeout() {
				if i == steps-1 {
					break
				}
				to *= factor
				dialer.Timeout = time.Duration(to)
				time.Sleep(wait.Jitter(sleep, 1.0)) // Sleep with jitter.
				continue
			}
			return nil, err
		}
		return c, err
	}
	return nil, errDialTimeout
}

func newHTTPTransport(connTimeout time.Duration) http.RoundTripper {
	return &http.Transport{
		// Those match net/http/transport.go
		Proxy:                 http.ProxyFromEnvironment,
		MaxIdleConns:          100,
		IdleConnTimeout:       5 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,

		// This is bespoke.
		DialContext: dialWithBackOff,
	}
}

// NewAutoTransport creates a RoundTripper that can use appropriate transport
// based on the request's HTTP version.
func NewAutoTransport() http.RoundTripper {
	return newAutoTransport(newHTTPTransport(DefaultConnTimeout), NewH2CTransport())
}

// AutoTransport uses h2c for HTTP2 requests and falls back to `http.DefaultTransport` for all others
var AutoTransport = NewAutoTransport()
<commit_msg>Fix typo in the comment (#4571)<commit_after>/*
Copyright 2018 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package network

import (
	"context"
	"errors"
	"net"
	"net/http"
	"time"

	"k8s.io/apimachinery/pkg/util/wait"
)

// RoundTripperFunc implementation roundtrips a request.
type RoundTripperFunc func(*http.Request) (*http.Response, error)

// RoundTrip implements http.RoundTripper.
func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
	return rt(r)
}

func newAutoTransport(v1 http.RoundTripper, v2 http.RoundTripper) http.RoundTripper {
	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
		t := v1
		if r.ProtoMajor == 2 {
			t = v2
		}
		return t.RoundTrip(r)
	})
}

const (
	initialTO = float64(50 * time.Millisecond)
	sleepTO   = 30 * time.Millisecond
	factor    = 1.4
	numSteps  = 10
)

var errDialTimeout = errors.New("timed out dialing")

// dialWithBackOff executes `net.Dialer.DialContext()` with exponentially increasing
// dial timeouts. In addition it sleeps with random jitter between tries.
func dialWithBackOff(ctx context.Context, network, address string) (net.Conn, error) {
	return dialBackOffHelper(ctx, network, address, numSteps, initialTO, sleepTO)
}

func dialBackOffHelper(ctx context.Context, network, address string, steps int, initial float64, sleep time.Duration) (net.Conn, error) {
	to := initial
	dialer := &net.Dialer{
		Timeout:   time.Duration(to),
		KeepAlive: 5 * time.Second,
		DualStack: true,
	}
	// TODO(vagababov): use backoff.Step when we use modern k8s client.
	for i := 0; i < steps; i++ {
		c, err := dialer.DialContext(ctx, network, address)
		if err != nil {
			if err, ok := err.(net.Error); ok && err.Timeout() {
				if i == steps-1 {
					break
				}
				to *= factor
				dialer.Timeout = time.Duration(to)
				time.Sleep(wait.Jitter(sleep, 1.0)) // Sleep with jitter.
				continue
			}
			return nil, err
		}
		return c, err
	}
	return nil, errDialTimeout
}

func newHTTPTransport(connTimeout time.Duration) http.RoundTripper {
	return &http.Transport{
		// Those match net/http/transport.go
		Proxy:                 http.ProxyFromEnvironment,
		MaxIdleConns:          100,
		IdleConnTimeout:       5 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,

		// This is bespoke.
		DialContext: dialWithBackOff,
	}
}

// NewAutoTransport creates a RoundTripper that can use appropriate transport
// based on the request's HTTP version.
func NewAutoTransport() http.RoundTripper {
	return newAutoTransport(newHTTPTransport(DefaultConnTimeout), NewH2CTransport())
}

// AutoTransport uses h2c for HTTP2 requests and falls back to `http.DefaultTransport` for all others
var AutoTransport = NewAutoTransport()
<|endoftext|>


<commit_before>package paxos

import (
	"junta/assert"
	"junta/store"
	"testing"
)

func selfRefNewManager(extraNodes ...string) (*Manager, *store.Store) {
	p := make(FakePutter, 1)
	st := store.New()
	self := "a"
	st.Apply(uint64(1), mustEncodeSet(membersKey+"/"+self, self+"addr"))
	for i, node := range extraNodes {
		st.Apply(uint64(i+2), mustEncodeSet(membersKey+"/"+node, node+"addr"))
	}
	m := NewManager(self, uint64(len(extraNodes)+1), 1, st, p)
	p[0] = m
	return m, st
}

func TestProposeAndLearn(t *testing.T) {
	exp := "foo"
	m, _ := selfRefNewManager()

	_, ix := m.getInstance(0)
	ix.Propose(exp)
	got := ix.Value()

	assert.Equal(t, exp, got, "")
}

func TestProposeAndRecv(t *testing.T) {
	exp := "foo"
	m, _ := selfRefNewManager()

	_, ix := m.getInstance(0)
	ix.Propose(exp)
	got := ix.Value()
	assert.Equal(t, exp, got, "")

	seqn, v := m.Recv()
	assert.Equal(t, uint64(2), seqn, "")
	assert.Equal(t, exp, v, "")
}

func TestProposeAndRecvAltStart(t *testing.T) {
	exp := "foo"
	m, _ := selfRefNewManager()

	_, ix := m.getInstance(0)
	ix.Propose(exp)
	got := ix.Value()
	assert.Equal(t, exp, got, "")

	seqn, v := m.Recv()
	assert.Equal(t, uint64(2), seqn, "")
	assert.Equal(t, exp, v, "")
}

func TestProposeAndRecvMultiple(t *testing.T) {
	exp := []string{"/foo", "/bar"}
	seqnexp := []uint64{2, 3}
	m, st := selfRefNewManager()

	_, ix := m.getInstance(0)
	ix.Propose(exp[0])
	got0 := ix.Value()
	assert.Equal(t, exp[0], got0, "")

	seqn0, v0 := m.Recv()
	assert.Equal(t, seqnexp[0], seqn0, "seqn 1")
	assert.Equal(t, exp[0], v0, "")

	st.Apply(seqn0, v0)

	_, ix = m.getInstance(0)
	ix.Propose(exp[1])
	got1 := ix.Value()
	assert.Equal(t, exp[1], got1, "")

	seqn1, v1 := m.Recv()
	assert.Equal(t, seqnexp[1], seqn1, "seqn 1")
	assert.Equal(t, exp[1], v1, "")
}

func TestNewInstanceBecauseOfMessage(t *testing.T) {
	exp := "foo"
	m, _ := selfRefNewManager()

	m.Put(newVoteFrom(1, 1, exp))
	seqn, v := m.Recv()
	assert.Equal(t, uint64(1), seqn, "")
	assert.Equal(t, exp, v, "")
}

func TestNewInstanceBecauseOfMessageTriangulate(t *testing.T) {
	exp := "bar"
	m, _ := selfRefNewManager()

	m.Put(newVoteFrom(1, 1, exp))
	seqn, v := m.Recv()
	assert.Equal(t, uint64(1), seqn, "")
	assert.Equal(t, exp, v, "")
}

func TestUnusedSeqn(t *testing.T) {
	exp1, exp2 := "foo", "bar"
	m, _ := selfRefNewManager()

	m.Put(newVoteFrom(1, 1, exp1))
	seqn, v := m.Recv()
	assert.Equal(t, uint64(1), seqn, "")
	assert.Equal(t, exp1, v, "")

	_, ix := m.getInstance(0)
	ix.Propose(exp2)
	got := ix.Value()
	assert.Equal(t, exp2, got, "")
	seqn, v = m.Recv()
	assert.Equal(t, uint64(2), seqn, "")
	assert.Equal(t, exp2, v, "")
}

func TestIgnoreMalformedMsg(t *testing.T) {
	m, _ := selfRefNewManager()

	m.Put(resize(newVoteFrom(1, 1, ""), -1))

	_, ix := m.getInstance(0)
	ix.Propose("y")
	got := ix.Value()
	assert.Equal(t, "y", got, "")

	seqn, v := m.Recv()
	assert.Equal(t, uint64(2), seqn, "")
	assert.Equal(t, "y", v, "")
}

func TestProposeAndStore(t *testing.T) {
	exp := "foo"
	mg, st := selfRefNewManager()

	go func() {
		for {
			st.Apply(mg.Recv())
		}
	}()

	_, got, _ := mg.Propose(exp)
	assert.Equal(t, exp, got, "")
}

func TestProposeBadMutation(t *testing.T) {
	mg, st := selfRefNewManager()

	go func() {
		for {
			st.Apply(mg.Recv())
		}
	}()

	_, _, err := mg.Propose("foo")
	assert.Equal(t, store.BadMutationError, err)
}

func mustEncodeSet(k, v string) string {
	m, err := store.EncodeSet(k, v, store.Clobber)
	if err != nil {
		panic(err)
	}
	return m
}

func TestReadFromStore(t *testing.T) {
	// The cluster initially has 1 node (quorum of 1).
	st := store.New()
	p := make(ChanPutCloser)
	self := "a"
	st.Apply(1, mustEncodeSet(membersDir+self, ""))
	st.Apply(2, mustEncodeSet(slotDir+"0", self))
	m := NewManager(self, 2, 1, st, p)

	// Fire up a new instance with a vote message. This instance should block
	// trying to read the list of members. If it doesn't wait, it'll
	// immediately learn the value `x`.
	in := newVoteFrom(0, 1, "x")
	in.SetSeqn(5)
	m.Put(in)

	// Satisfy the sync read of data members above. After this, there will be
	// 2 nodes in the cluster, making the quorum 2.
	st.Apply(3, mustEncodeSet(membersDir+"b", ""))
	st.Apply(4, mustEncodeSet(slotDir+"1", "b"))

	// Now try to make it learn a new value with 2 votes to meet the new
	// quorum.
	exp := "y"
	in = newVoteFrom(0, 2, exp)
	in.SetSeqn(5)
	m.Put(in)
	in = newVoteFrom(1, 2, exp)
	in.SetSeqn(5)
	m.Put(in)

	seqn, v := m.Recv()
	assert.Equal(t, uint64(5), seqn, "")
	assert.Equal(t, exp, v, "")
}

type putFunc func(Msg)

func (pf putFunc) Put(msg Msg) {
	go pf(msg)
}

func (pf putFunc) Close() {}

func TestManagerPutFrom(t *testing.T) {
	exp := "bar"
	seqnExp := uint64(7)
	fromAddr := "y"
	fromIndex := 1 // [a, b, c].indexof(b) => 1

	st := store.New()
	self := "a"
	st.Apply(uint64(1), mustEncodeSet(membersDir+self, "x"))
	st.Apply(uint64(2), mustEncodeSet(slotDir+"0", self))
	st.Apply(uint64(3), mustEncodeSet(membersDir+"b", "y"))
	st.Apply(uint64(4), mustEncodeSet(slotDir+"1", "b"))
	st.Apply(uint64(5), mustEncodeSet(membersDir+"c", "z"))
	st.Apply(uint64(6), mustEncodeSet(slotDir+"2", "c"))
	p := make(FakePutter, 1)
	m := NewManager(self, 6, 1, st, p)
	p[0] = m

	froms := make(chan int)

	fp := putFunc(func (msg Msg) {
		froms <- msg.From()
	})

	seqn, it := m.getInstance(seqnExp)
	assert.Equal(t, seqnExp, seqn)
	it.cPutter = fp
	it.aPutter = fp
	it.lPutter = fp

	v1 := newVote(1, exp)
	v1.SetSeqn(seqnExp)
	m.PutFrom(fromAddr, v1)

	assert.Equal(t, fromIndex, <-froms, "")
	assert.Equal(t, fromIndex, <-froms, "")
	assert.Equal(t, fromIndex, <-froms, "")
}

func TestManagerAddrsFor(t *testing.T) {
	m, _ := selfRefNewManager()
	msg := newInvite(1)
	msg.SetSeqn(1)
	assert.Equal(t, []string{m.Self+"addr"}, m.AddrsFor(msg))
}

func TestManagerGetInstanceForPropose(t *testing.T) {
	m, _ := selfRefNewManager()
	seqn, _ := m.getInstance(0)
	assert.Equal(t, uint64(2), seqn)
}
<commit_msg>update to new store interface<commit_after>package paxos

import (
	"junta/assert"
	"junta/store"
	"testing"
)

func selfRefNewManager(extraNodes ...string) (*Manager, *store.Store) {
	p := make(FakePutter, 1)
	st := store.New()
	self := "a"
	st.Apply(uint64(1), mustEncodeSet(membersKey+"/"+self, self+"addr"))
	for i, node := range extraNodes {
		st.Apply(uint64(i+2), mustEncodeSet(membersKey+"/"+node, node+"addr"))
	}
	m := NewManager(self, uint64(len(extraNodes)+1), 1, st, p)
	p[0] = m
	return m, st
}

func TestProposeAndLearn(t *testing.T) {
	exp := "foo"
	m, _ := selfRefNewManager()

	_, ix := m.getInstance(0)
	ix.Propose(exp)
	got := ix.Value()

	assert.Equal(t, exp, got, "")
}

func TestProposeAndRecv(t *testing.T) {
	exp := "foo"
	m, _ := selfRefNewManager()

	_, ix := m.getInstance(0)
	ix.Propose(exp)
	got := ix.Value()
	assert.Equal(t, exp, got, "")

	seqn, v := m.Recv()
	assert.Equal(t, uint64(2), seqn, "")
	assert.Equal(t, exp, v, "")
}

func TestProposeAndRecvAltStart(t *testing.T) {
	exp := "foo"
	m, _ := selfRefNewManager()

	_, ix := m.getInstance(0)
	ix.Propose(exp)
	got := ix.Value()
	assert.Equal(t, exp, got, "")

	seqn, v := m.Recv()
	assert.Equal(t, uint64(2), seqn, "")
	assert.Equal(t, exp, v, "")
}

func TestProposeAndRecvMultiple(t *testing.T) {
	exp := []string{"/foo", "/bar"}
	seqnexp := []uint64{2, 3}
	m, st := selfRefNewManager()

	_, ix := m.getInstance(0)
	ix.Propose(exp[0])
	got0 := ix.Value()
	assert.Equal(t, exp[0], got0, "")

	seqn0, v0 := m.Recv()
	assert.Equal(t, seqnexp[0], seqn0, "seqn 1")
	assert.Equal(t, exp[0], v0, "")

	st.Apply(seqn0, v0)

	_, ix = m.getInstance(0)
	ix.Propose(exp[1])
	got1 := ix.Value()
	assert.Equal(t, exp[1], got1, "")

	seqn1, v1 := m.Recv()
	assert.Equal(t, seqnexp[1], seqn1, "seqn 1")
	assert.Equal(t, exp[1], v1, "")
}

func TestNewInstanceBecauseOfMessage(t *testing.T) {
	exp := "foo"
	m, _ := selfRefNewManager()

	m.Put(newVoteFrom(1, 1, exp))
	seqn, v := m.Recv()
	assert.Equal(t, uint64(1), seqn, "")
	assert.Equal(t, exp, v, "")
}

func TestNewInstanceBecauseOfMessageTriangulate(t *testing.T) {
	exp := "bar"
	m, _ := selfRefNewManager()

	m.Put(newVoteFrom(1, 1, exp))
	seqn, v := m.Recv()
	assert.Equal(t, uint64(1), seqn, "")
	assert.Equal(t, exp, v, "")
}

func TestUnusedSeqn(t *testing.T) {
	exp1, exp2 := "foo", "bar"
	m, _ := selfRefNewManager()

	m.Put(newVoteFrom(1, 1, exp1))
	seqn, v := m.Recv()
	assert.Equal(t, uint64(1), seqn, "")
	assert.Equal(t, exp1, v, "")

	_, ix := m.getInstance(0)
	ix.Propose(exp2)
	got := ix.Value()
	assert.Equal(t, exp2, got, "")
	seqn, v = m.Recv()
	assert.Equal(t, uint64(2), seqn, "")
	assert.Equal(t, exp2, v, "")
}

func TestIgnoreMalformedMsg(t *testing.T) {
	m, _ := selfRefNewManager()

	m.Put(resize(newVoteFrom(1, 1, ""), -1))

	_, ix := m.getInstance(0)
	ix.Propose("y")
	got := ix.Value()
	assert.Equal(t, "y", got, "")

	seqn, v := m.Recv()
	assert.Equal(t, uint64(2), seqn, "")
	assert.Equal(t, "y", v, "")
}

func TestProposeAndStore(t *testing.T) {
	exp := "foo"
	mg, st := selfRefNewManager()

	go func() {
		for {
			st.Apply(mg.Recv())
		}
	}()

	_, got, _ := mg.Propose(exp)
	assert.Equal(t, exp, got, "")
}

func TestProposeBadMutation(t *testing.T) {
	mg, st := selfRefNewManager()

	go func() {
		for {
			st.Apply(mg.Recv())
		}
	}()

	_, _, err := mg.Propose("foo")
	assert.Equal(t, store.ErrBadMutation, err)
}

func mustEncodeSet(k, v string) string {
	m, err := store.EncodeSet(k, v, store.Clobber)
	if err != nil {
		panic(err)
	}
	return m
}

func TestReadFromStore(t *testing.T) {
	// The cluster initially has 1 node (quorum of 1).
	st := store.New()
	p := make(ChanPutCloser)
	self := "a"
	st.Apply(1, mustEncodeSet(membersDir+self, ""))
	st.Apply(2, mustEncodeSet(slotDir+"0", self))
	m := NewManager(self, 2, 1, st, p)

	// Fire up a new instance with a vote message. This instance should block
	// trying to read the list of members. If it doesn't wait, it'll
	// immediately learn the value `x`.
	in := newVoteFrom(0, 1, "x")
	in.SetSeqn(5)
	m.Put(in)

	// Satisfy the sync read of data members above. After this, there will be
	// 2 nodes in the cluster, making the quorum 2.
	st.Apply(3, mustEncodeSet(membersDir+"b", ""))
	st.Apply(4, mustEncodeSet(slotDir+"1", "b"))

	// Now try to make it learn a new value with 2 votes to meet the new
	// quorum.
	exp := "y"
	in = newVoteFrom(0, 2, exp)
	in.SetSeqn(5)
	m.Put(in)
	in = newVoteFrom(1, 2, exp)
	in.SetSeqn(5)
	m.Put(in)

	seqn, v := m.Recv()
	assert.Equal(t, uint64(5), seqn, "")
	assert.Equal(t, exp, v, "")
}

type putFunc func(Msg)

func (pf putFunc) Put(msg Msg) {
	go pf(msg)
}

func (pf putFunc) Close() {}

func TestManagerPutFrom(t *testing.T) {
	exp := "bar"
	seqnExp := uint64(7)
	fromAddr := "y"
	fromIndex := 1 // [a, b, c].indexof(b) => 1

	st := store.New()
	self := "a"
	st.Apply(uint64(1), mustEncodeSet(membersDir+self, "x"))
	st.Apply(uint64(2), mustEncodeSet(slotDir+"0", self))
	st.Apply(uint64(3), mustEncodeSet(membersDir+"b", "y"))
	st.Apply(uint64(4), mustEncodeSet(slotDir+"1", "b"))
	st.Apply(uint64(5), mustEncodeSet(membersDir+"c", "z"))
	st.Apply(uint64(6), mustEncodeSet(slotDir+"2", "c"))
	p := make(FakePutter, 1)
	m := NewManager(self, 6, 1, st, p)
	p[0] = m

	froms := make(chan int)

	fp := putFunc(func (msg Msg) {
		froms <- msg.From()
	})

	seqn, it := m.getInstance(seqnExp)
	assert.Equal(t, seqnExp, seqn)
	it.cPutter = fp
	it.aPutter = fp
	it.lPutter = fp

	v1 := newVote(1, exp)
	v1.SetSeqn(seqnExp)
	m.PutFrom(fromAddr, v1)

	assert.Equal(t, fromIndex, <-froms, "")
	assert.Equal(t, fromIndex, <-froms, "")
	assert.Equal(t, fromIndex, <-froms, "")
}

func TestManagerAddrsFor(t *testing.T) {
	m, _ := selfRefNewManager()
	msg := newInvite(1)
	msg.SetSeqn(1)
	assert.Equal(t, []string{m.Self+"addr"}, m.AddrsFor(msg))
}

func TestManagerGetInstanceForPropose(t *testing.T) {
	m, _ := selfRefNewManager()
	seqn, _ := m.getInstance(0)
	assert.Equal(t, uint64(2), seqn)
}
<|endoftext|>


<commit_before>package paxos

import (
	"net"
	"os"
	"testing"
	"testing/quick"

	"junta/assert"
)

// For testing convenience
func newVoteFrom(from int, i uint64, vval string) Msg {
	m := newVote(i, vval)
	m.SetSeqn(1)
	m.SetFrom(from)
	return m
}

// For testing convenience
func newNominateFrom(from int, crnd uint64, v string) Msg {
	m := newNominate(crnd, v)
	m.SetSeqn(1)
	m.SetFrom(from)
	return m
}

// For testing convenience
func newRsvpFrom(from int, i, vrnd uint64, vval string) Msg {
	m := newRsvp(i, vrnd, vval)
	m.SetSeqn(1)
	m.SetFrom(from)
	return m
}

// For testing convenience
func newInviteFrom(from int, rnd uint64) Msg {
	m := newInvite(rnd)
	m.SetSeqn(1)
	m.SetFrom(from)
	return m
}

func TestMessageNewInvite(t *testing.T) {
	m := newInvite(1)
	assert.Equal(t, invite, m.Cmd(), "")
	crnd := inviteParts(m)
	assert.Equal(t, uint64(1), crnd, "")
}

func TestMessageNewInviteAlt(t *testing.T) {
	m := newInvite(2)
	assert.Equal(t, invite, m.Cmd(), "")
	crnd := inviteParts(m)
	assert.Equal(t, uint64(2), crnd, "")
}

func TestMessageNewNominate(t *testing.T) {
	m := newNominate(1, "foo")
	assert.Equal(t, nominate, m.Cmd(), "")
	crnd, v := nominateParts(m)
	assert.Equal(t, uint64(1), crnd, "")
	assert.Equal(t, "foo", v, "")
}

func TestMessageNewNominateAlt(t *testing.T) {
	m := newNominate(2, "bar")
	assert.Equal(t, nominate, m.Cmd(), "")
	crnd, v := nominateParts(m)
	assert.Equal(t, uint64(2), crnd, "")
	assert.Equal(t, "bar", v, "")
}

func TestMessageNewRsvp(t *testing.T) {
	m := newRsvp(1, 0, "")
	assert.Equal(t, rsvp, m.Cmd(), "")
	i, vrnd, vval := rsvpParts(m)
	assert.Equal(t, uint64(1), i, "")
	assert.Equal(t, uint64(0), vrnd, "")
	assert.Equal(t, "", vval, "")
}

func TestMessageNewRsvpAlt(t *testing.T) {
	m := newRsvp(2, 1, "foo")
	assert.Equal(t, rsvp, m.Cmd(), "")
	i, vrnd, vval := rsvpParts(m)
	assert.Equal(t, uint64(2), i, "")
	assert.Equal(t, uint64(1), vrnd, "")
	assert.Equal(t, "foo", vval, "")
}

func TestMessageNewVote(t *testing.T) {
	m := newVote(1, "foo")
	assert.Equal(t, vote, m.Cmd(), "")
	i, vval := voteParts(m)
	assert.Equal(t, uint64(1), i, "")
	assert.Equal(t, "foo", vval, "")
}

func TestMessageNewVoteAlt(t *testing.T) {
	m := newVote(2, "bar")
	assert.Equal(t, vote, m.Cmd(), "")
	i, vval := voteParts(m)
	assert.Equal(t, uint64(2), i, "")
	assert.Equal(t, "bar", vval, "")
}

func TestMessageNewLearn(t *testing.T) {
	f := func(exp string) bool {
		m := newLearn(exp)
		assert.Equal(t, learn, m.Cmd(), "")
		val := learnParts(m)
		assert.Equal(t, exp, val, "")
		return true
	}
	quick.Check(f, nil)
}

func TestMessageNewTick(t *testing.T) {
	m := newTick()
	assert.Equal(t, tick, m.Cmd(), "")
}

func TestMessageNewPropose(t *testing.T) {
	m := newPropose("foo")
	assert.Equal(t, propose, m.Cmd(), "")
	val := proposeParts(m)
	assert.Equal(t, "foo", val, "")
}

func TestMessageSetFrom(t *testing.T) {
	m := newInvite(1)
	m.SetFrom(1)
	assert.Equal(t, 1, m.From(), "")
	m.SetFrom(2)
	assert.Equal(t, 2, m.From(), "")
}

func TestMessageSetSeqn(t *testing.T) {
	m := newInvite(1)
	m.SetSeqn(1)
	assert.Equal(t, uint64(1), m.Seqn(), "")
	m.SetSeqn(2)
	assert.Equal(t, uint64(2), m.Seqn(), "")
}

func resize(m Msg, n int) Msg {
	x := len(m) + n
	if x > cap(m) {
		y := make(Msg, x)
		copy(y, m)
		return y
	}
	return m[0 : len(m)+n]
}

var badMessages = []Msg{
	Msg{0},                         // too short
	Msg{0, 255},                    // bad cmd
	resize(newInvite(0), -1),       // too short for type
	resize(newInvite(0), 1),        // too long for type
	resize(newRsvp(0, 0, ""), -1),  // too short for type
	resize(newNominate(0, ""), -1), // too short for type
	resize(newVote(0, ""), -1),     // too short for type
}

func TestBadMessagesOk(t *testing.T) {
	for _, m := range badMessages {
		if m.Ok() {
			t.Errorf("check failed for bad msg: %#v", m)
		}
	}
}

var goodMessages = []Msg{
	newInvite(1),
	newRsvp(2, 1, "foo"),
	newNominate(1, "foo"),
	newVote(1, "foo"),
}

func TestGoodMessagesOk(t *testing.T) {
	for _, m := range goodMessages {
		if !m.Ok() {
			t.Errorf("check failed for good msg: %#v", m)
		}
	}
}

func TestWireBytes(t *testing.T) {
	m := newInvite(1)
	b := m.WireBytes()
	assert.Equal(t, []byte(m[1:]), b, "")
	b[0] = 2
	assert.Equal(t, byte(2), m[1], "")
}

type fakePacketConn struct {
	a net.Addr
	b []byte
}

func (fpc *fakePacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err os.Error) {
	return copy(b, fpc.b), fpc.a, nil
}

// Tests

func TestReadMsg(t *testing.T) {
	msg := newInvite(2)
	addr := &net.UDPAddr{net.IP{1, 2, 3, 4}, 123}
	fpc := &fakePacketConn{addr, msg.WireBytes()}
	gotMsg, gotAddr, err := ReadMsg(fpc, 3000)
	assert.Equal(t, nil, err, "")
	assert.Equal(t, msg, gotMsg, "")
	assert.Equal(t, addr.String(), gotAddr, "")
}
<commit_msg>remove stale comment<commit_after>package paxos

import (
	"net"
	"os"
	"testing"
	"testing/quick"

	"junta/assert"
)

// For testing convenience
func newVoteFrom(from int, i uint64, vval string) Msg {
	m := newVote(i, vval)
	m.SetSeqn(1)
	m.SetFrom(from)
	return m
}

// For testing convenience
func newNominateFrom(from int, crnd uint64, v string) Msg {
	m := newNominate(crnd, v)
	m.SetSeqn(1)
	m.SetFrom(from)
	return m
}

// For testing convenience
func newRsvpFrom(from int, i, vrnd uint64, vval string) Msg {
	m := newRsvp(i, vrnd, vval)
	m.SetSeqn(1)
	m.SetFrom(from)
	return m
}

// For testing convenience
func newInviteFrom(from int, rnd uint64) Msg {
	m := newInvite(rnd)
	m.SetSeqn(1)
	m.SetFrom(from)
	return m
}

func TestMessageNewInvite(t *testing.T) {
	m := newInvite(1)
	assert.Equal(t, invite, m.Cmd(), "")
	crnd := inviteParts(m)
	assert.Equal(t, uint64(1), crnd, "")
}

func TestMessageNewInviteAlt(t *testing.T) {
	m := newInvite(2)
	assert.Equal(t, invite, m.Cmd(), "")
	crnd := inviteParts(m)
	assert.Equal(t, uint64(2), crnd, "")
}

func TestMessageNewNominate(t *testing.T) {
	m := newNominate(1, "foo")
	assert.Equal(t, nominate, m.Cmd(), "")
	crnd, v := nominateParts(m)
	assert.Equal(t, uint64(1), crnd, "")
	assert.Equal(t, "foo", v, "")
}

func TestMessageNewNominateAlt(t *testing.T) {
	m := newNominate(2, "bar")
	assert.Equal(t, nominate, m.Cmd(), "")
	crnd, v := nominateParts(m)
	assert.Equal(t, uint64(2), crnd, "")
	assert.Equal(t, "bar", v, "")
}

func TestMessageNewRsvp(t *testing.T) {
	m := newRsvp(1, 0, "")
	assert.Equal(t, rsvp, m.Cmd(), "")
	i, vrnd, vval := rsvpParts(m)
	assert.Equal(t, uint64(1), i, "")
	assert.Equal(t, uint64(0), vrnd, "")
	assert.Equal(t, "", vval, "")
}

func TestMessageNewRsvpAlt(t *testing.T) {
	m := newRsvp(2, 1, "foo")
	assert.Equal(t, rsvp, m.Cmd(), "")
	i, vrnd, vval := rsvpParts(m)
	assert.Equal(t, uint64(2), i, "")
	assert.Equal(t, uint64(1), vrnd, "")
	assert.Equal(t, "foo", vval, "")
}

func TestMessageNewVote(t *testing.T) {
	m := newVote(1, "foo")
	assert.Equal(t, vote, m.Cmd(), "")
	i, vval := voteParts(m)
	assert.Equal(t, uint64(1), i, "")
	assert.Equal(t, "foo", vval, "")
}

func TestMessageNewVoteAlt(t *testing.T) {
	m := newVote(2, "bar")
	assert.Equal(t, vote, m.Cmd(), "")
	i, vval := voteParts(m)
	assert.Equal(t, uint64(2), i, "")
	assert.Equal(t, "bar", vval, "")
}

func TestMessageNewLearn(t *testing.T) {
	f := func(exp string) bool {
		m := newLearn(exp)
		assert.Equal(t, learn, m.Cmd(), "")
		val := learnParts(m)
		assert.Equal(t, exp, val, "")
		return true
	}
	quick.Check(f, nil)
}

func TestMessageNewTick(t *testing.T) {
	m := newTick()
	assert.Equal(t, tick, m.Cmd(), "")
}

func TestMessageNewPropose(t *testing.T) {
	m := newPropose("foo")
	assert.Equal(t, propose, m.Cmd(), "")
	val := proposeParts(m)
	assert.Equal(t, "foo", val, "")
}

func TestMessageSetFrom(t *testing.T) {
	m := newInvite(1)
	m.SetFrom(1)
	assert.Equal(t, 1, m.From(), "")
	m.SetFrom(2)
	assert.Equal(t, 2, m.From(), "")
}

func TestMessageSetSeqn(t *testing.T) {
	m := newInvite(1)
	m.SetSeqn(1)
	assert.Equal(t, uint64(1), m.Seqn(), "")
	m.SetSeqn(2)
	assert.Equal(t, uint64(2), m.Seqn(), "")
}

func resize(m Msg, n int) Msg {
	x := len(m) + n
	if x > cap(m) {
		y := make(Msg, x)
		copy(y, m)
		return y
	}
	return m[0 : len(m)+n]
}

var badMessages = []Msg{
	Msg{0},                         // too short
	Msg{0, 255},                    // bad cmd
	resize(newInvite(0), -1),       // too short for type
	resize(newInvite(0), 1),        // too long for type
	resize(newRsvp(0, 0, ""), -1),  // too short for type
	resize(newNominate(0, ""), -1), // too short for type
	resize(newVote(0, ""), -1),     // too short for type
}

func TestBadMessagesOk(t *testing.T) {
	for _, m := range badMessages {
		if m.Ok() {
			t.Errorf("check failed for bad msg: %#v", m)
		}
	}
}

var goodMessages = []Msg{
	newInvite(1),
	newRsvp(2, 1, "foo"),
	newNominate(1, "foo"),
	newVote(1, "foo"),
}

func TestGoodMessagesOk(t *testing.T) {
	for _, m := range goodMessages {
		if !m.Ok() {
			t.Errorf("check failed for good msg: %#v", m)
		}
	}
}

func TestWireBytes(t *testing.T) {
	m := newInvite(1)
	b := m.WireBytes()
	assert.Equal(t, []byte(m[1:]), b, "")
	b[0] = 2
	assert.Equal(t, byte(2), m[1], "")
}

type fakePacketConn struct {
	a net.Addr
	b []byte
}

func (fpc *fakePacketConn) ReadFrom(b []byte) (n int, addr net.Addr, err os.Error) {
	return copy(b, fpc.b), fpc.a, nil
}

func TestReadMsg(t *testing.T) {
	msg := newInvite(2)
	addr := &net.UDPAddr{net.IP{1, 2, 3, 4}, 123}
	fpc := &fakePacketConn{addr, msg.WireBytes()}
	gotMsg, gotAddr, err := ReadMsg(fpc, 3000)
	assert.Equal(t, nil, err, "")
	assert.Equal(t, msg, gotMsg, "")
	assert.Equal(t, addr.String(), gotAddr, "")
}
<|endoftext|>


<commit_before>package ginkgo

import (
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sort"
	"sync"
	"syscall"
	"time"

	"github.com/openshift/origin/pkg/monitor"
)

type testStatus struct {
	out     io.Writer
	timeout time.Duration
	monitor monitor.Interface

	includeSuccessfulOutput bool

	lock     sync.Mutex
	failures int
	index    int
	total    int
}

func newTestStatus(out io.Writer, includeSuccessfulOutput bool, total int, timeout time.Duration, m monitor.Interface) *testStatus {
	return &testStatus{
		out:     out,
		total:   total,
		timeout: timeout,
		monitor: m,

		includeSuccessfulOutput: includeSuccessfulOutput,
	}
}

func (s *testStatus) Failure() {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.failures++
}

func (s *testStatus) Fprintf(format string) {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.index < s.total {
		s.index++
	}
	fmt.Fprintf(s.out, format, s.failures, s.index, s.total)
}

func (s *testStatus) Run(ctx context.Context, test *testCase) {
	defer func() {
		switch {
		case test.success:
			if s.includeSuccessfulOutput {
				s.out.Write(test.out)
				fmt.Fprintln(s.out)
			}
			fmt.Fprintf(s.out, "passed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
		case test.skipped:
			if s.includeSuccessfulOutput {
				s.out.Write(test.out)
				fmt.Fprintln(s.out)
			} else {
				message := lastLinesUntil(string(test.out), 100, "skip [")
				if len(message) > 0 {
					fmt.Fprintln(s.out, message)
					fmt.Fprintln(s.out)
				}
			}
			fmt.Fprintf(s.out, "skipped: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
		case test.failed:
			s.out.Write(test.out)
			fmt.Fprintln(s.out)
			if s.monitor != nil {
				events := s.monitor.Events(test.start, test.end)
				if len(events) > 0 {
					for _, event := range events {
						fmt.Fprintln(s.out, event.String())
					}
					fmt.Fprintln(s.out)
				}
			}
			fmt.Fprintf(s.out, "failed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
			s.Failure()
		}
	}()

	test.start = time.Now()
	c := exec.Command(os.Args[0], "run-test", test.name)
	s.Fprintf(fmt.Sprintf("started: (%s) %q\n\n", "%d/%d/%d", test.name))
	out, err := runWithTimeout(ctx, c, s.timeout)
	test.end = time.Now()

	duration := test.end.Sub(test.start).Round(time.Second / 10)
	if duration > time.Minute {
		duration = duration.Round(time.Second)
	}
	test.duration = duration
	test.out = out
	if err == nil {
		test.success = true
		return
	}
	if exitErr, ok := err.(*exec.ExitError); ok {
		switch exitErr.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() {
		case 1:
			// failed
			test.failed = true
		case 2:
			// timeout (ABRT is an exit code 2)
			test.failed = true
		case 3:
			// skipped
			test.skipped = true
		default:
			test.failed = true
		}
		return
	}
	test.failed = true
}

func summarizeTests(tests []*testCase) (int, int, int, []*testCase) {
	var pass, fail, skip int
	var failingTests []*testCase
	for _, t := range tests {
		switch {
		case t.success:
			pass++
		case t.failed:
			fail++
			failingTests = append(failingTests, t)
		case t.skipped:
			skip++
		}
	}
	return pass, fail, skip, failingTests
}

func sortedTests(tests []*testCase) []*testCase {
	copied := make([]*testCase, len(tests))
	copy(copied, tests)
	sort.Slice(copied, func(i, j int) bool { return copied[i].name < copied[j].name })
	return copied
}
<commit_msg>Suppress monitor output per test when only running a few tests<commit_after>package ginkgo

import (
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sort"
	"sync"
	"syscall"
	"time"

	"github.com/openshift/origin/pkg/monitor"
)

type testStatus struct {
	out     io.Writer
	timeout time.Duration
	monitor monitor.Interface

	includeSuccessfulOutput bool

	lock     sync.Mutex
	failures int
	index    int
	total    int
}

func newTestStatus(out io.Writer, includeSuccessfulOutput bool, total int, timeout time.Duration, m monitor.Interface) *testStatus {
	return &testStatus{
		out:     out,
		total:   total,
		timeout: timeout,
		monitor: m,

		includeSuccessfulOutput: includeSuccessfulOutput,
	}
}

func (s *testStatus) Failure() {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.failures++
}

func (s *testStatus) Fprintf(format string) {
	s.lock.Lock()
	defer s.lock.Unlock()
	if s.index < s.total {
		s.index++
	}
	fmt.Fprintf(s.out, format, s.failures, s.index, s.total)
}

func (s *testStatus) Run(ctx context.Context, test *testCase) {
	defer func() {
		switch {
		case test.success:
			if s.includeSuccessfulOutput {
				s.out.Write(test.out)
				fmt.Fprintln(s.out)
			}
			fmt.Fprintf(s.out, "passed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
		case test.skipped:
			if s.includeSuccessfulOutput {
				s.out.Write(test.out)
				fmt.Fprintln(s.out)
			} else {
				message := lastLinesUntil(string(test.out), 100, "skip [")
				if len(message) > 0 {
					fmt.Fprintln(s.out, message)
					fmt.Fprintln(s.out)
				}
			}
			fmt.Fprintf(s.out, "skipped: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
		case test.failed:
			s.out.Write(test.out)
			fmt.Fprintln(s.out)
			// only write the monitor output for a test if there is more than two tests being run (otherwise it's redundant)
			if s.monitor != nil && s.total > 2 {
				events := s.monitor.Events(test.start, test.end)
				if len(events) > 0 {
					for _, event := range events {
						fmt.Fprintln(s.out, event.String())
					}
					fmt.Fprintln(s.out)
				}
			}
			fmt.Fprintf(s.out, "failed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
			s.Failure()
		}
	}()

	test.start = time.Now()
	c := exec.Command(os.Args[0], "run-test", test.name)
	s.Fprintf(fmt.Sprintf("started: (%s) %q\n\n", "%d/%d/%d", test.name))
	out, err := runWithTimeout(ctx, c, s.timeout)
	test.end = time.Now()

	duration := test.end.Sub(test.start).Round(time.Second / 10)
	if duration > time.Minute {
		duration = duration.Round(time.Second)
	}
	test.duration = duration
	test.out = out
	if err == nil {
		test.success = true
		return
	}
	if exitErr, ok := err.(*exec.ExitError); ok {
		switch exitErr.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() {
		case 1:
			// failed
			test.failed = true
		case 2:
			// timeout (ABRT is an exit code 2)
			test.failed = true
		case 3:
			// skipped
			test.skipped = true
		default:
			test.failed = true
		}
		return
	}
	test.failed = true
}

func summarizeTests(tests []*testCase) (int, int, int, []*testCase) {
	var pass, fail, skip int
	var failingTests []*testCase
	for _, t := range tests {
		switch {
		case t.success:
			pass++
		case t.failed:
			fail++
			failingTests = append(failingTests, t)
		case t.skipped:
			skip++
		}
	}
	return pass, fail, skip, failingTests
}

func sortedTests(tests []*testCase) []*testCase {
	copied := make([]*testCase, len(tests))
	copy(copied, tests)
	sort.Slice(copied, func(i, j int) bool { return copied[i].name < copied[j].name })
	return copied
}
<|endoftext|>


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

package types

import (
	"github.com/coreos/etcd/pkg/testutil"
	"reflect"
	"testing"
)

func TestParseInitialCluster(t *testing.T) {
	c, err := NewURLsMap("mem1=http://10.0.0.1:2379,mem1=http://128.193.4.20:2379,mem2=http://10.0.0.2:2379,default=http://127.0.0.1:2379")
	if err != nil {
		t.Fatalf("unexpected parse error: %v", err)
	}
	wc := URLsMap(map[string]URLs{
		"mem1":    testutil.MustNewURLs(t, []string{"http://10.0.0.1:2379", "http://128.193.4.20:2379"}),
		"mem2":    testutil.MustNewURLs(t, []string{"http://10.0.0.2:2379"}),
		"default": testutil.MustNewURLs(t, []string{"http://127.0.0.1:2379"}),
	})
	if !reflect.DeepEqual(c, wc) {
		t.Errorf("cluster = %+v, want %+v", c, wc)
	}
}

func TestParseInitialClusterBad(t *testing.T) {
	tests := []string{
		// invalid URL
		"%^",
		// no URL defined for member
		"mem1=,mem2=http://128.193.4.20:2379,mem3=http://10.0.0.2:2379",
		"mem1,mem2=http://128.193.4.20:2379,mem3=http://10.0.0.2:2379",
		// bad URL for member
		"default=http://localhost/",
	}
	for i, tt := range tests {
		if _, err := NewURLsMap(tt); err == nil {
			t.Errorf("#%d: unexpected successful parse, want err", i)
		}
	}
}

func TestNameURLPairsString(t *testing.T) {
	cls := URLsMap(map[string]URLs{
		"abc": testutil.MustNewURLs(t, []string{"http://1.1.1.1:1111", "http://0.0.0.0:0000"}),
		"def": testutil.MustNewURLs(t, []string{"http://2.2.2.2:2222"}),
		"ghi": testutil.MustNewURLs(t, []string{"http://3.3.3.3:1234", "http://127.0.0.1:2380"}),
		// no PeerURLs = not included
		"four": testutil.MustNewURLs(t, []string{}),
		"five": testutil.MustNewURLs(t, nil),
	})
	w := "abc=http://0.0.0.0:0000,abc=http://1.1.1.1:1111,def=http://2.2.2.2:2222,ghi=http://127.0.0.1:2380,ghi=http://3.3.3.3:1234"
	if g := cls.String(); g != w {
		t.Fatalf("NameURLPairs.String():\ngot  %#v\nwant %#v", g, w)
	}
}

func TestParse(t *testing.T) {
	tests := []struct {
		s  string
		wm map[string][]string
	}{
		{
			"",
			map[string][]string{},
		},
		{
			"a=b",
			map[string][]string{"a": {"b"}},
		},
		{
			"a=b,a=c",
			map[string][]string{"a": {"b", "c"}},
		},
		{
			"a=b,a1=c",
			map[string][]string{"a": {"b"}, "a1": {"c"}},
		},
	}
	for i, tt := range tests {
		m := parse(tt.s)
		if !reflect.DeepEqual(m, tt.wm) {
			t.Errorf("#%d: m = %+v, want %+v", i, m, tt.wm)
		}
	}
}

// TestNewURLsMapIPV6 is only tested in Go1.5+ because Go1.4 doesn't support literal IPv6 address with zone in
// URI (https://github.com/golang/go/issues/6530).
func TestNewURLsMapIPV6(t *testing.T) {
	c, err := NewURLsMap("mem1=http://[2001:db8::1]:2380,mem1=http://[fe80::6e40:8ff:feb1:58e4%25en0]:2380,mem2=http://[fe80::92e2:baff:fe7c:3224%25ext0]:2380")
	if err != nil {
		t.Fatalf("unexpected parse error: %v", err)
	}
	wc := URLsMap(map[string]URLs{
		"mem1": testutil.MustNewURLs(t, []string{"http://[2001:db8::1]:2380", "http://[fe80::6e40:8ff:feb1:58e4%25en0]:2380"}),
		"mem2": testutil.MustNewURLs(t, []string{"http://[fe80::92e2:baff:fe7c:3224%25ext0]:2380"}),
	})
	if !reflect.DeepEqual(c, wc) {
		t.Errorf("cluster = %#v, want %#v", c, wc)
	}
}
<commit_msg>pkg/types: Add tests for NewURLsMapFromStringMap<commit_after>// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package types

import (
	"github.com/coreos/etcd/pkg/testutil"
	"reflect"
	"testing"
)

func TestParseInitialCluster(t *testing.T) {
	c, err := NewURLsMap("mem1=http://10.0.0.1:2379,mem1=http://128.193.4.20:2379,mem2=http://10.0.0.2:2379,default=http://127.0.0.1:2379")
	if err != nil {
		t.Fatalf("unexpected parse error: %v", err)
	}
	wc := URLsMap(map[string]URLs{
		"mem1":    testutil.MustNewURLs(t, []string{"http://10.0.0.1:2379", "http://128.193.4.20:2379"}),
		"mem2":    testutil.MustNewURLs(t, []string{"http://10.0.0.2:2379"}),
		"default": testutil.MustNewURLs(t, []string{"http://127.0.0.1:2379"}),
	})
	if !reflect.DeepEqual(c, wc) {
		t.Errorf("cluster = %+v, want %+v", c, wc)
	}
}

func TestParseInitialClusterBad(t *testing.T) {
	tests := []string{
		// invalid URL
		"%^",
		// no URL defined for member
		"mem1=,mem2=http://128.193.4.20:2379,mem3=http://10.0.0.2:2379",
		"mem1,mem2=http://128.193.4.20:2379,mem3=http://10.0.0.2:2379",
		// bad URL for member
		"default=http://localhost/",
	}
	for i, tt := range tests {
		if _, err := NewURLsMap(tt); err == nil {
			t.Errorf("#%d: unexpected successful parse, want err", i)
		}
	}
}

func TestNameURLPairsString(t *testing.T) {
	cls := URLsMap(map[string]URLs{
		"abc": testutil.MustNewURLs(t, []string{"http://1.1.1.1:1111", "http://0.0.0.0:0000"}),
		"def": testutil.MustNewURLs(t, []string{"http://2.2.2.2:2222"}),
		"ghi": testutil.MustNewURLs(t, []string{"http://3.3.3.3:1234", "http://127.0.0.1:2380"}),
		// no PeerURLs = not included
		"four": testutil.MustNewURLs(t, []string{}),
		"five": testutil.MustNewURLs(t, nil),
	})
	w := "abc=http://0.0.0.0:0000,abc=http://1.1.1.1:1111,def=http://2.2.2.2:2222,ghi=http://127.0.0.1:2380,ghi=http://3.3.3.3:1234"
	if g := cls.String(); g != w {
		t.Fatalf("NameURLPairs.String():\ngot  %#v\nwant %#v", g, w)
	}
}

func TestParse(t *testing.T) {
	tests := []struct {
		s  string
		wm map[string][]string
	}{
		{
			"",
			map[string][]string{},
		},
		{
			"a=b",
			map[string][]string{"a": {"b"}},
		},
		{
			"a=b,a=c",
			map[string][]string{"a": {"b", "c"}},
		},
		{
			"a=b,a1=c",
			map[string][]string{"a": {"b"}, "a1": {"c"}},
		},
	}
	for i, tt := range tests {
		m := parse(tt.s)
		if !reflect.DeepEqual(m, tt.wm) {
			t.Errorf("#%d: m = %+v, want %+v", i, m, tt.wm)
		}
	}
}

// TestNewURLsMapIPV6 is only tested in Go1.5+ because Go1.4 doesn't support literal IPv6 address with zone in
// URI (https://github.com/golang/go/issues/6530).
func TestNewURLsMapIPV6(t *testing.T) {
	c, err := NewURLsMap("mem1=http://[2001:db8::1]:2380,mem1=http://[fe80::6e40:8ff:feb1:58e4%25en0]:2380,mem2=http://[fe80::92e2:baff:fe7c:3224%25ext0]:2380")
	if err != nil {
		t.Fatalf("unexpected parse error: %v", err)
	}
	wc := URLsMap(map[string]URLs{
		"mem1": testutil.MustNewURLs(t, []string{"http://[2001:db8::1]:2380", "http://[fe80::6e40:8ff:feb1:58e4%25en0]:2380"}),
		"mem2": testutil.MustNewURLs(t, []string{"http://[fe80::92e2:baff:fe7c:3224%25ext0]:2380"}),
	})
	if !reflect.DeepEqual(c, wc) {
		t.Errorf("cluster = %#v, want %#v", c, wc)
	}
}

func TestNewURLsMapFromStringMapEmpty(t *testing.T) {
	mss := make(map[string]string)
	urlsMap, err := NewURLsMapFromStringMap(mss, ",")
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	s := ""
	um, err := NewURLsMap(s)
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}

	if um.String() != urlsMap.String() {
		t.Errorf("Expected:\n%+v\ngot:\n%+v", um, urlsMap)
	}
}

func TestNewURLsMapFromStringMapNormal(t *testing.T) {
	mss := make(map[string]string)
	mss["host0"] = "http://127.0.0.1:2379,http://127.0.0.1:2380"
	mss["host1"] = "http://127.0.0.1:2381,http://127.0.0.1:2382"
	mss["host2"] = "http://127.0.0.1:2383,http://127.0.0.1:2384"
	mss["host3"] = "http://127.0.0.1:2385,http://127.0.0.1:2386"
	urlsMap, err := NewURLsMapFromStringMap(mss, ",")
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}
	s := "host0=http://127.0.0.1:2379,host0=http://127.0.0.1:2380," +
		"host1=http://127.0.0.1:2381,host1=http://127.0.0.1:2382," +
		"host2=http://127.0.0.1:2383,host2=http://127.0.0.1:2384," +
		"host3=http://127.0.0.1:2385,host3=http://127.0.0.1:2386"
	um, err := NewURLsMap(s)
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}

	if um.String() != urlsMap.String() {
		t.Errorf("Expected:\n%+v\ngot:\n%+v", um, urlsMap)
	}
}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"math/rand"
	"net/http"
	"strconv"
	"time"

	"github.com/dghubble/sling"
)

//BaseURL holds the IP,PORT of the connected peer used for the communication
var BaseURL = ""

//ArkApiResponseError struct to hold error response from api node
type ArkApiResponseError struct {
	Success      bool   `json:"success,omitempty"`
	Message      string `json:"message,omitempty"`
	ErrorMessage string `json:"error,omitempty"`
	Data         string `json:"data,omitempty"`
	ErrorObj     error  `json:"ignore"`
}

//Error interface function
func (e ArkApiResponseError) Error() string {
	emsg := ""
	if e.ErrorObj != nil {
		emsg = e.ErrorObj.Error()
	}
	return fmt.Sprintf("ArkServiceApi: %v %v %v %v %v", emsg, e.Success, e.ErrorMessage, e.Data, e.Message)
}

//ArkClient sling rest pointer
type ArkClient struct {
	sling *sling.Sling
}

func init() {
	// switchNetwork(MAINNET)
}

//NewArkClient creations with supported network
func NewArkClient(httpClient *http.Client) *ArkClient {
	return &ArkClient{
		sling: sling.New().Client(httpClient).Base(BaseURL).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}
}

//NewArkClientFromPeer creations with supported network
func NewArkClientFromPeer(peer Peer) *ArkClient {
	BaseURL = "http://" + peer.IP + ":" + strconv.Itoa(peer.Port)
	EnvironmentParams.Network.ActivePeer = peer
	return &ArkClient{
		sling: sling.New().Base(BaseURL).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}
}

//NewArkClientFromIP creations with supported network
func NewArkClientFromIP(ipAddress string) *ArkClient {
	port := 4001
	if EnvironmentParams.Network.Type == DEVNET {
		port = 4002
	}
	BaseURL = "http://" + ipAddress + ":" + strconv.Itoa(port)
	EnvironmentParams.Network.ActivePeer = Peer{IP: ipAddress, Port: port}
	return &ArkClient{
		sling: sling.New().Base(BaseURL).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}
}

//TestMethodNewArkClient creations with supported network
//A test method for local node testing when implementid
//Not for production use
func TestMethodNewArkClient(httpClient *http.Client) *ArkClient {
	return &ArkClient{
		sling: sling.New().Client(httpClient).Base("http://164.8.251.173:4001").
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}
}

//SwitchPeer switches client connection to another node
//usage: must reassing pointer: arkapi = arkapi.SwitchPeer()
func (s *ArkClient) SwitchPeer() *ArkClient {
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)

	//IF internal PeerList is empty - we do a full switch network - init from start
	if len(EnvironmentParams.Network.PeerList) == 0 {
		switchNetwork(EnvironmentParams.Network.Type)
		return NewArkClient(nil)
	}

	//if we have active memory peer list - we select a new random peer from already inited memlist
	//list is filled in LoadActiveConfiguration-where client init is made
	EnvironmentParams.Network.ActivePeer = EnvironmentParams.Network.PeerList[r1.Intn(len(EnvironmentParams.Network.PeerList))]
	BaseURL = "http://" + EnvironmentParams.Network.ActivePeer.IP + ":" + strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)

	//updating with latest peer data - setting height level
	resPeer, _, err := s.GetConnectedPeerStatus()
	if err == nil && resPeer.Success {
		EnvironmentParams.Network.ActivePeer.Height = resPeer.Header.Height
	}
	return NewArkClient(nil)
}

//GetActivePeer returns active peer connected
//doesn't call rest to update it
//updates when calling SwitchPeer or Network is Changed
func (s *ArkClient) GetActivePeer() Peer {
	return EnvironmentParams.Network.ActivePeer
}

//GetRandomXPeers returns requested number of randomly selected peers from healthy peer list
//used in multiplethreadbroadcast
func (s *ArkClient) GetRandomXPeers(numberOfPeers int) []Peer {
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)

	nrAllPeers := len(EnvironmentParams.Network.PeerList)
	var retPeers []Peer
	for i := 0; i < numberOfPeers; i++ {
		retPeers = append(retPeers, EnvironmentParams.Network.PeerList[r1.Intn(nrAllPeers)])
	}
	return retPeers
}
<commit_msg>fix: more typos<commit_after>package core

import (
	"fmt"
	"math/rand"
	"net/http"
	"strconv"
	"time"

	"github.com/dghubble/sling"
)

//BaseURL holds the IP,PORT of the connected peer used for the communication
var BaseURL = ""

//ArkApiResponseError struct to hold error response from api node
type ArkApiResponseError struct {
	Success      bool   `json:"success,omitempty"`
	Message      string `json:"message,omitempty"`
	ErrorMessage string `json:"error,omitempty"`
	Data         string `json:"data,omitempty"`
	ErrorObj     error  `json:"ignore"`
}

//Error interface function
func (e ArkApiResponseError) Error() string {
	emsg := ""
	if e.ErrorObj != nil {
		emsg = e.ErrorObj.Error()
	}
	return fmt.Sprintf("ArkServiceApi: %v %v %v %v %v", emsg, e.Success, e.ErrorMessage, e.Data, e.Message)
}

//ArkClient sling rest pointer
type ArkClient struct {
	sling *sling.Sling
}

func init() {
	// switchNetwork(MAINNET)
}

//NewArkClient creations with supported network
func NewArkClient(httpClient *http.Client) *ArkClient {
	return &ArkClient{
		sling: sling.New().Client(httpClient).Base(BaseURL).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}
}

//NewArkClientFromPeer creations with supported network
func NewArkClientFromPeer(peer Peer) *ArkClient {
	BaseURL = "http://" + peer.IP + ":" + strconv.Itoa(peer.Port)
	EnvironmentParams.Network.ActivePeer = peer
	return &ArkClient{
		sling: sling.New().Base(BaseURL).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}
}

//NewArkClientFromIP creations with supported network
func NewArkClientFromIP(ipAddress string) *ArkClient {
	port := 4001
	if EnvironmentParams.Network.Type == DEVNET {
		port = 4002
	}
	BaseURL = "http://" + ipAddress + ":" + strconv.Itoa(port)
	EnvironmentParams.Network.ActivePeer = Peer{IP: ipAddress, Port: port}
	return &ArkClient{
		sling: sling.New().Base(BaseURL).
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}
}

//TestMethodNewArkClient creations with supported network
//A test method for local node testing when implemented
//Not for production use
func TestMethodNewArkClient(httpClient *http.Client) *ArkClient {
	return &ArkClient{
		sling: sling.New().Client(httpClient).Base("http://164.8.251.173:4001").
			Add("nethash", EnvironmentParams.Network.Nethash).
			Add("version", EnvironmentParams.Network.ActivePeer.Version).
			Add("port", strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)).
			Add("Content-Type", "application/json"),
	}
}

//SwitchPeer switches client connection to another node
//usage: must reassign pointer: arkapi = arkapi.SwitchPeer()
func (s *ArkClient) SwitchPeer() *ArkClient {
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)

	//IF internal PeerList is empty - we do a full switch network - init from start
	if len(EnvironmentParams.Network.PeerList) == 0 {
		switchNetwork(EnvironmentParams.Network.Type)
		return NewArkClient(nil)
	}

	//if we have active memory peer list - we select a new random peer from already initiated memlist
	//list is filled in LoadActiveConfiguration-where client init is made
	EnvironmentParams.Network.ActivePeer = EnvironmentParams.Network.PeerList[r1.Intn(len(EnvironmentParams.Network.PeerList))]
	BaseURL = "http://" + EnvironmentParams.Network.ActivePeer.IP + ":" + strconv.Itoa(EnvironmentParams.Network.ActivePeer.Port)

	//updating with latest peer data - setting height level
	resPeer, _, err := s.GetConnectedPeerStatus()
	if err == nil && resPeer.Success {
		EnvironmentParams.Network.ActivePeer.Height = resPeer.Header.Height
	}
	return NewArkClient(nil)
}

//GetActivePeer returns active peer connected
//doesn't call rest to update it
//updates when calling SwitchPeer or Network is Changed
func (s *ArkClient) GetActivePeer() Peer {
	return EnvironmentParams.Network.ActivePeer
}

//GetRandomXPeers returns requested number of randomly selected peers from healthy peer list
//used in multiplethreadbroadcast
func (s *ArkClient) GetRandomXPeers(numberOfPeers int) []Peer {
	s1 := rand.NewSource(time.Now().UnixNano())
	r1 := rand.New(s1)

	nrAllPeers := len(EnvironmentParams.Network.PeerList)

	var retPeers []Peer
	for i := 0; i < numberOfPeers; i++ {
		retPeers = append(retPeers, EnvironmentParams.Network.PeerList[r1.Intn(nrAllPeers)])
	}
	return retPeers
}
<|endoftext|>


<commit_before>package main

import (
	"math/rand"
	"time"
	"fmt"
	"strconv"
)
type Marshaler interface {
    MarshalJSON() ([]byte, error)
}
type JSONTime time.Time

func (t *JSONTime)MarshalJSON() ([]byte, error) {
    //do your serializing here
    stamp := fmt.Sprint(time.Now().Unix())
    return []byte(stamp), nil
}

func (t *JSONTime) UnmarshalJSON(b []byte) error {
	ts, err := strconv.Atoi(string(b))
	if err != nil {
		return err
	}

	*t = JSONTime(time.Unix(int64(ts), 0))

	return nil
}

const (
	variationTemperature = 5.00
	variationRadiation   = 20
	maxTrendSeconds      = 20
	minTrendSeconds      = 5
)

// Reading contains the current sensor readings
type Reading struct {
	SolarFlare         bool    `json:"solarFlare"`
	Temperature        float64 `json:"temperature"`
	Radiation          int     `json:"radiation"`
	temperatureUptrend bool
	radiationUptrend   bool
	Stamp		  JSONTime `json:"stamp"`
}

func (s *Reading) updateSolarFlare() {
	x := rand.Intn(2)
	if x != 0 {
		s.SolarFlare = true
	} else {
		s.SolarFlare = false
	}
}

func (s *Reading) updateTemperature() {
	var min float64
	var max float64

	if s.temperatureUptrend {
		max = s.Temperature + variationTemperature
		min = s.Temperature
	} else {
		max = s.Temperature
		min = s.Temperature - variationTemperature
	}

	temperature := (rand.Float64() * (max - min)) + min
	if temperature < minTemperature {
		temperature = minTemperature
	} else if temperature > maxTemperature {
		temperature = maxTemperature
	}
	s.Temperature = temperature
}

func (s *Reading) updateTemperatureTrend() {
	ratio := (s.Temperature - minTemperature) / (maxTemperature - minTemperature)
	chance := rand.Float64()
	s.temperatureUptrend = chance > ratio || s.SolarFlare
	//log.Printf("[Temperature] Ratio: %.2f, Change: %.2f, Uptrend: %t\n", ratio, chance, s.temperatureUptrend)
}

func (s *Reading) updateRadiation() {
	var min int
	var max int

	if s.radiationUptrend {
		max = s.Radiation + variationRadiation
		min = s.Radiation
	} else {
		max = s.Radiation
		min = s.Radiation - variationRadiation
	}

	radiation := rand.Intn(max-min) + min
	if radiation < minRadiation {
		radiation = minRadiation
	} else if radiation > maxRadiation {
		radiation = maxRadiation
	}
	s.Radiation = radiation
}

func (s *Reading) updateRadiationTrend() {
	ratio := (float64)(s.Radiation-minRadiation) / (float64)(maxRadiation-minRadiation)
	chance := rand.Float64()
	s.radiationUptrend = chance > ratio || s.SolarFlare
	//log.Printf("[Radiation] Ratio: %.2f, Change: %.2f, Uptrend: %t\n", ratio, chance, s.radiationUptrend)
}

func solarFlareRoutine(reading *Reading) {
	ticker := time.NewTicker(1 * time.Second)
	timer := time.NewTimer(0)
	for {
		select {
		case <-timer.C:
			reading.updateSolarFlare()
			if reading.SolarFlare == true {
				timer.Reset(10 * time.Second)
			} else {
				timer.Reset(30 * time.Second)
			}
		case <-ticker.C:
			// Ticker to check exit condition
		}
	}
}

func temperatureRoutine(reading *Reading) {
	tickerUpdate := time.NewTicker(1 * time.Second)
	timerTrend := time.NewTimer(0)
	for {
		select {
		case <-tickerUpdate.C:
			reading.updateTemperature()
		case <-timerTrend.C:
			reading.updateTemperatureTrend()
			timerTrend.Reset(time.Duration(rand.Intn(maxTrendSeconds-minTrendSeconds)+minTrendSeconds) * time.Second)
		}
	}
}

func radiationRoutine(reading *Reading) {
	tickerUpdate := time.NewTicker(1 * time.Second)
	timerTrend := time.NewTimer(0)
	for {
		select {
		case <-tickerUpdate.C:
			reading.updateRadiation()
		case <-timerTrend.C:
			reading.updateRadiationTrend()
			timerTrend.Reset(time.Duration(rand.Intn(maxTrendSeconds-minTrendSeconds)+minTrendSeconds) * time.Second)
		}
	}
}
<commit_msg>Update generator.go<commit_after>package main

import (
	"math/rand"
	"time"
	"fmt"
)
type Marshaler interface {
    MarshalJSON() ([]byte, error)
}
type JSONTime time.Time

func (t *JSONTime)MarshalJSON() ([]byte, error) {
    //do your serializing here
    stamp := fmt.Sprint(time.Now().UTC().Format("2006-01-02T15:04:05"))
    return []byte(stamp), nil
}

const (
	variationTemperature = 5.00
	variationRadiation   = 20
	maxTrendSeconds      = 20
	minTrendSeconds      = 5
)

// Reading contains the current sensor readings
type Reading struct {
	SolarFlare         bool    `json:"solarFlare"`
	Temperature        float64 `json:"temperature"`
	Radiation          int     `json:"radiation"`
	temperatureUptrend bool
	radiationUptrend   bool
	Stamp		  JSONTime `json:"stamp"`
}

func (s *Reading) updateSolarFlare() {
	x := rand.Intn(2)
	if x != 0 {
		s.SolarFlare = true
	} else {
		s.SolarFlare = false
	}
}

func (s *Reading) updateTemperature() {
	var min float64
	var max float64

	if s.temperatureUptrend {
		max = s.Temperature + variationTemperature
		min = s.Temperature
	} else {
		max = s.Temperature
		min = s.Temperature - variationTemperature
	}

	temperature := (rand.Float64() * (max - min)) + min
	if temperature < minTemperature {
		temperature = minTemperature
	} else if temperature > maxTemperature {
		temperature = maxTemperature
	}
	s.Temperature = temperature
}

func (s *Reading) updateTemperatureTrend() {
	ratio := (s.Temperature - minTemperature) / (maxTemperature - minTemperature)
	chance := rand.Float64()
	s.temperatureUptrend = chance > ratio || s.SolarFlare
	//log.Printf("[Temperature] Ratio: %.2f, Change: %.2f, Uptrend: %t\n", ratio, chance, s.temperatureUptrend)
}

func (s *Reading) updateRadiation() {
	var min int
	var max int

	if s.radiationUptrend {
		max = s.Radiation + variationRadiation
		min = s.Radiation
	} else {
		max = s.Radiation
		min = s.Radiation - variationRadiation
	}

	radiation := rand.Intn(max-min) + min
	if radiation < minRadiation {
		radiation = minRadiation
	} else if radiation > maxRadiation {
		radiation = maxRadiation
	}
	s.Radiation = radiation
}

func (s *Reading) updateRadiationTrend() {
	ratio := (float64)(s.Radiation-minRadiation) / (float64)(maxRadiation-minRadiation)
	chance := rand.Float64()
	s.radiationUptrend = chance > ratio || s.SolarFlare
	//log.Printf("[Radiation] Ratio: %.2f, Change: %.2f, Uptrend: %t\n", ratio, chance, s.radiationUptrend)
}

func solarFlareRoutine(reading *Reading) {
	ticker := time.NewTicker(1 * time.Second)
	timer := time.NewTimer(0)
	for {
		select {
		case <-timer.C:
			reading.updateSolarFlare()
			if reading.SolarFlare == true {
				timer.Reset(10 * time.Second)
			} else {
				timer.Reset(30 * time.Second)
			}
		case <-ticker.C:
			// Ticker to check exit condition
		}
	}
}

func temperatureRoutine(reading *Reading) {
	tickerUpdate := time.NewTicker(1 * time.Second)
	timerTrend := time.NewTimer(0)
	for {
		select {
		case <-tickerUpdate.C:
			reading.updateTemperature()
		case <-timerTrend.C:
			reading.updateTemperatureTrend()
			timerTrend.Reset(time.Duration(rand.Intn(maxTrendSeconds-minTrendSeconds)+minTrendSeconds) * time.Second)
		}
	}
}

func radiationRoutine(reading *Reading) {
	tickerUpdate := time.NewTicker(1 * time.Second)
	timerTrend := time.NewTimer(0)
	for {
		select {
		case <-tickerUpdate.C:
			reading.updateRadiation()
		case <-timerTrend.C:
			reading.updateRadiationTrend()
			timerTrend.Reset(time.Duration(rand.Intn(maxTrendSeconds-minTrendSeconds)+minTrendSeconds) * time.Second)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"strconv"
	"strings"
	"time"

	"github.com/dghubble/go-twitter/twitter"
	"github.com/dghubble/oauth1"
)

var (
	twitterBot *TwitterBot
)

// TwitterBot ...
type TwitterBot struct {
	ID      string
	ImgPath string
	Client  *twitter.Client
	Follows map[string]string
}

// NewTwitterBot ...
func NewTwitterBot(cfg *TwitterConfig) *TwitterBot {
	config := oauth1.NewConfig(cfg.ConsumerKey, cfg.ConsumerSecret)
	token := oauth1.NewToken(cfg.AccessToken, cfg.AccessSecret)
	httpClient := config.Client(oauth1.NoContext, token)
	client := twitter.NewClient(httpClient)
	bot := &TwitterBot{
		ID:      cfg.SelfID,
		ImgPath: cfg.ImgPath,
		Client:  client,
		Follows: map[string]string{
			"KanColle_STAFF": "294025417",
			"komatan":        "96604067",
			"maesanpicture":  "2381595966",
			"Strangestone":   "93332575",
			// "kazuharukina":   "28787294",
			// "sinoalice_jp":   "818752826025181184",
			"imascg_stage": "3220191374",
			"fgoproject":   "2968069742",
		},
	}
	return bot
}

func hasHashTags(s string, tags []twitter.HashtagEntity) bool {
	for _, tag := range tags {
		if s == tag.Text {
			return true
		}
	}
	return false
}

func getMedias(tweet *twitter.Tweet) []twitter.MediaEntity {
	if tweet.ExtendedTweet != nil {
		if tweet.ExtendedTweet.ExtendedEntities != nil {
			return tweet.ExtendedTweet.ExtendedEntities.Media
		}
		return tweet.ExtendedTweet.Entities.Media
	}

	if tweet.ExtendedEntities != nil {
		return tweet.ExtendedEntities.Media
	}
	return tweet.Entities.Media
}

func sendPics(medias []twitter.MediaEntity) {
	for _, media := range medias {
		switch media.Type {
		case "photo":
			go qqBot.SendPics(qqBot.SendGroupMsg, media.MediaURLHttps)
		default:
			logger.Noticef("media type ignored: %+v", media.Type)
		}
	}
}

func logAllTrack(msg interface{}) {
	logger.Debugf("%+v", msg)
}

func getTweetTime(zone string, tweet *twitter.Tweet) string {
	t := tweet.CreatedAt
	ct, err := tweet.CreatedAtTime()
	if err == nil {
		tz, err := time.LoadLocation(zone)
		if err == nil {
			t = ct.In(tz).String()
		}
	}
	return t
}

func getFullLink(tweet *twitter.Tweet) string {
	return "https://twitter.com/" + tweet.User.IDStr + "/status/" + tweet.IDStr
}

func checkSendKancolle(tweet *twitter.Tweet, msg string) {
	// sleep 5s to wait for other bot
	time.Sleep(5 * time.Second)

	ct, err := tweet.CreatedAtTime()
	if err != nil {
		logger.Errorf("%+v", err)
		return
	}
	key := "kancolle_" + strconv.FormatInt(ct.Unix(), 10)
	exists, err := redisClient.Expire(key, 5*time.Second).Result()
	if err != nil {
		logger.Errorf("%+v", err)
		return
	}
	if exists {
		logger.Notice("other bot has sent")
		return
	}

	t := getTweetTime("Asia/Tokyo", tweet)

	qqBot.SendGroupMsg(tweet.User.Name + "\n" + t + "\n\n" + msg)
}

func (t *TwitterBot) trackTweet(tweet *twitter.Tweet) {
	if tweet.RetweetedStatus != nil {
		// logger.Debugf("ignore retweet (%s):{%s}", tweet.User.Name, tweet.Text)
		return
	}
	msg := tweet.Text
	medias := getMedias(tweet)
	if tweet.Truncated {
		if tweet.ExtendedTweet != nil {
			msg = tweet.ExtendedTweet.FullText
		}
		// logger.Debugf("no ExtendedTweet: %+v", tweet)
	}
	flattenedText := strconv.Quote(msg)
	tt := getTweetTime("Asia/Tokyo", tweet)

	switch tweet.User.IDStr {
	case t.Follows["KanColle_STAFF"]:
		logger.Infof("(%s):{%s} %d medias", tweet.User.Name, flattenedText, len(medias))
		sendPics(medias)
		go checkSendKancolle(tweet, msg)

	case t.Follows["imascg_stage"]:
		logger.Infof("(%s):{%s} %d medias", tweet.User.Name, flattenedText, len(medias))
		telegramBot.send(telegramBot.ChannelChatID, getFullLink(tweet))

	case t.Follows["fgoproject"]:
		logger.Infof("(%s):{%s} %d medias", tweet.User.Name, flattenedText, len(medias))
		qqBot.SendGroupMsg(tweet.User.Name + "\n" + tt + "\n\n" + msg)
		sendPics(medias)

	case t.Follows["komatan"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		sendPics(medias)

	case t.Follows["maesanpicture"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if hasHashTags("毎日五月雨", tweet.Entities.Hashtags) {
			qqBot.SendGroupMsg(msg)
			sendPics(medias)
		}

	case t.Follows["Strangestone"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if strings.HasPrefix(msg, "月曜日のたわわ") {
			qqBot.SendGroupMsg(msg)
			sendPics(medias)
		}

	default:
		// logger.Debugf("(%s):{%s}", tweet.User.Name, flattenedText)
	}
}

func (t *TwitterBot) selfProceedMedias(medias []twitter.MediaEntity, action int) {
	var url string
	for _, media := range medias {
		switch media.Type {
		case "photo":
			url = media.MediaURLHttps

		case "video":
			vs := media.VideoInfo.Variants
			vsLen := len(vs)
			for i := range vs {
				if vs[vsLen-i-1].ContentType == "video/mp4" {
					url = vs[vsLen-i-1].URL
					break
				}
			}
		case "animated_gif":
			vs := media.VideoInfo.Variants
			vsLen := len(vs)
			for i := range vs {
				if vs[vsLen-i-1].ContentType == "video/mp4" {
					url = vs[vsLen-i-1].URL
					break
				}
			}

		default:
			logger.Noticef("media type ignored: %+v", media.Type)
			continue
		}

		switch action {
		case 1:
			downloadFile(url, t.ImgPath)
		case -1:
			removeFile(url, t.ImgPath)
		}
	}
}

func (t *TwitterBot) selfEvent(event *twitter.Event) {
	if event.Source.IDStr != t.ID {
		logger.Debugf("%s: (%s)", event.Event, event.Source.Name)
		return
	}
	switch event.Event {
	case "favorite":
		medias := getMedias(event.TargetObject)
		logger.Infof("favorite: (%s):{%s} %d medias", event.TargetObject.User.Name, strconv.Quote(event.TargetObject.Text), len(medias))
		go t.selfProceedMedias(medias, 1)
		go telegramBot.send(telegramBot.ChannelChatID, getFullLink(event.TargetObject))
	case "unfavorite":
		medias := getMedias(event.TargetObject)
		logger.Debugf("unfavorite: (%s):{%s} %d medias", event.TargetObject.User.Name, strconv.Quote(event.TargetObject.Text), len(medias))
		go t.selfProceedMedias(medias, -1)
	default:
		logger.Debugf("%+v", event.Event)
	}
}

func (t *TwitterBot) selfTweet(tweet *twitter.Tweet) {
	if qqBot.Config.GroupName != "" {
		if hasHashTags(qqBot.Config.GroupName, tweet.Entities.Hashtags) {
			if tweet.QuotedStatus != nil {
				logger.Infof("(%s):{%s}", qqBot.Config.GroupName, strconv.Quote(tweet.QuotedStatus.Text))
				sendPics(getMedias(tweet.QuotedStatus))
			} else {
				logger.Infof("(%s):{%s}", qqBot.Config.GroupName, strconv.Quote(tweet.Text))
				sendPics(getMedias(tweet))
			}
		}
	}
}

// Track ...
func (t *TwitterBot) Track() {
	follows := []string{}
	for _, value := range t.Follows {
		follows = append(follows, value)
	}
	for i := 1; ; i++ {
		demux := twitter.NewSwitchDemux()
		demux.Tweet = t.trackTweet
		filterParams := &twitter.StreamFilterParams{
			Follow: follows,
		}
		stream, err := t.Client.Streams.Filter(filterParams)
		if err != nil {
			logger.Errorf("%+v", err)
			time.Sleep(time.Duration(i) * time.Second)
		}
		demux.HandleChan(stream.Messages)
	}
}

// Self ...
func (t *TwitterBot) Self() {
	for i := 1; ; i++ {
		demux := twitter.NewSwitchDemux()
		demux.Event = t.selfEvent
		demux.Tweet = t.selfTweet
		userParams := &twitter.StreamUserParams{
			With: t.ID,
		}
		stream, err := t.Client.Streams.User(userParams)
		if err != nil {
			logger.Errorf("%+v", err)
			time.Sleep(time.Duration(i) * time.Second)
		}
		demux.HandleChan(stream.Messages)
	}
}
<commit_msg>send to telegram instead of qq<commit_after>package main

import (
	"strconv"
	"strings"
	"time"

	"github.com/dghubble/go-twitter/twitter"
	"github.com/dghubble/oauth1"
)

var (
	twitterBot *TwitterBot
)

// TwitterBot ...
type TwitterBot struct {
	ID      string
	ImgPath string
	Client  *twitter.Client
	Follows map[string]string
}

// NewTwitterBot ...
func NewTwitterBot(cfg *TwitterConfig) *TwitterBot {
	config := oauth1.NewConfig(cfg.ConsumerKey, cfg.ConsumerSecret)
	token := oauth1.NewToken(cfg.AccessToken, cfg.AccessSecret)
	httpClient := config.Client(oauth1.NoContext, token)
	client := twitter.NewClient(httpClient)
	bot := &TwitterBot{
		ID:      cfg.SelfID,
		ImgPath: cfg.ImgPath,
		Client:  client,
		Follows: map[string]string{
			"KanColle_STAFF": "294025417",
			"komatan":        "96604067",
			"maesanpicture":  "2381595966",
			"Strangestone":   "93332575",
			// "kazuharukina":   "28787294",
			// "sinoalice_jp":   "818752826025181184",
			"imascg_stage": "3220191374",
			"fgoproject":   "2968069742",
		},
	}
	return bot
}

func hasHashTags(s string, tags []twitter.HashtagEntity) bool {
	for _, tag := range tags {
		if s == tag.Text {
			return true
		}
	}
	return false
}

func getMedias(tweet *twitter.Tweet) []twitter.MediaEntity {
	if tweet.ExtendedTweet != nil {
		if tweet.ExtendedTweet.ExtendedEntities != nil {
			return tweet.ExtendedTweet.ExtendedEntities.Media
		}
		return tweet.ExtendedTweet.Entities.Media
	}

	if tweet.ExtendedEntities != nil {
		return tweet.ExtendedEntities.Media
	}
	return tweet.Entities.Media
}

func sendPics(medias []twitter.MediaEntity) {
	for _, media := range medias {
		switch media.Type {
		case "photo":
			go qqBot.SendPics(qqBot.SendGroupMsg, media.MediaURLHttps)
		default:
			logger.Noticef("media type ignored: %+v", media.Type)
		}
	}
}

func logAllTrack(msg interface{}) {
	logger.Debugf("%+v", msg)
}

func getTweetTime(zone string, tweet *twitter.Tweet) string {
	t := tweet.CreatedAt
	ct, err := tweet.CreatedAtTime()
	if err == nil {
		tz, err := time.LoadLocation(zone)
		if err == nil {
			t = ct.In(tz).String()
		}
	}
	return t
}

func getFullLink(tweet *twitter.Tweet) string {
	return "https://twitter.com/" + tweet.User.IDStr + "/status/" + tweet.IDStr
}

func checkSendKancolle(tweet *twitter.Tweet, msg string) {
	// sleep 5s to wait for other bot
	time.Sleep(5 * time.Second)

	ct, err := tweet.CreatedAtTime()
	if err != nil {
		logger.Errorf("%+v", err)
		return
	}
	key := "kancolle_" + strconv.FormatInt(ct.Unix(), 10)
	exists, err := redisClient.Expire(key, 5*time.Second).Result()
	if err != nil {
		logger.Errorf("%+v", err)
		return
	}
	if exists {
		logger.Notice("other bot has sent")
		return
	}

	t := getTweetTime("Asia/Tokyo", tweet)

	qqBot.SendGroupMsg(tweet.User.Name + "\n" + t + "\n\n" + msg)
}

func (t *TwitterBot) trackTweet(tweet *twitter.Tweet) {
	if tweet.RetweetedStatus != nil {
		// logger.Debugf("ignore retweet (%s):{%s}", tweet.User.Name, tweet.Text)
		return
	}
	msg := tweet.Text
	medias := getMedias(tweet)
	if tweet.Truncated {
		if tweet.ExtendedTweet != nil {
			msg = tweet.ExtendedTweet.FullText
		}
		// logger.Debugf("no ExtendedTweet: %+v", tweet)
	}
	flattenedText := strconv.Quote(msg)
	tt := getTweetTime("Asia/Tokyo", tweet)

	switch tweet.User.IDStr {
	case t.Follows["KanColle_STAFF"]:
		logger.Infof("(%s):{%s} %d medias", tweet.User.Name, flattenedText, len(medias))
		sendPics(medias)
		go checkSendKancolle(tweet, msg)

	case t.Follows["imascg_stage"]:
		logger.Infof("(%s):{%s} %d medias", tweet.User.Name, flattenedText, len(medias))
		telegramBot.send(telegramBot.ChannelChatID, getFullLink(tweet))

	case t.Follows["fgoproject"]:
		logger.Infof("(%s):{%s} %d medias", tweet.User.Name, flattenedText, len(medias))
		qqBot.SendGroupMsg(tweet.User.Name + "\n" + tt + "\n\n" + msg)
		sendPics(medias)

	case t.Follows["komatan"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		telegramBot.send(telegramBot.ChannelChatID, getFullLink(tweet))
		sendPics(medias)

	case t.Follows["maesanpicture"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if hasHashTags("毎日五月雨", tweet.Entities.Hashtags) {
			telegramBot.send(telegramBot.ChannelChatID, getFullLink(tweet))
		}

	case t.Follows["Strangestone"]:
		if len(medias) == 0 {
			return
		}
		logger.Infof("(%s):{%s}", tweet.User.Name, flattenedText)
		if strings.HasPrefix(msg, "月曜日のたわわ") {
			telegramBot.send(telegramBot.ChannelChatID, getFullLink(tweet))
		}

	default:
		// logger.Debugf("(%s):{%s}", tweet.User.Name, flattenedText)
	}
}

func (t *TwitterBot) selfProceedMedias(medias []twitter.MediaEntity, action int) {
	var url string
	for _, media := range medias {
		switch media.Type {
		case "photo":
			url = media.MediaURLHttps

		case "video":
			vs := media.VideoInfo.Variants
			vsLen := len(vs)
			for i := range vs {
				if vs[vsLen-i-1].ContentType == "video/mp4" {
					url = vs[vsLen-i-1].URL
					break
				}
			}
		case "animated_gif":
			vs := media.VideoInfo.Variants
			vsLen := len(vs)
			for i := range vs {
				if vs[vsLen-i-1].ContentType == "video/mp4" {
					url = vs[vsLen-i-1].URL
					break
				}
			}

		default:
			logger.Noticef("media type ignored: %+v", media.Type)
			continue
		}

		switch action {
		case 1:
			downloadFile(url, t.ImgPath)
		case -1:
			removeFile(url, t.ImgPath)
		}
	}
}

func (t *TwitterBot) selfEvent(event *twitter.Event) {
	if event.Source.IDStr != t.ID {
		logger.Debugf("%s: (%s)", event.Event, event.Source.Name)
		return
	}
	switch event.Event {
	case "favorite":
		medias := getMedias(event.TargetObject)
		logger.Infof("favorite: (%s):{%s} %d medias", event.TargetObject.User.Name, strconv.Quote(event.TargetObject.Text), len(medias))
		go t.selfProceedMedias(medias, 1)
		go telegramBot.send(telegramBot.ChannelChatID, getFullLink(event.TargetObject))
	case "unfavorite":
		medias := getMedias(event.TargetObject)
		logger.Debugf("unfavorite: (%s):{%s} %d medias", event.TargetObject.User.Name, strconv.Quote(event.TargetObject.Text), len(medias))
		go t.selfProceedMedias(medias, -1)
	default:
		logger.Debugf("%+v", event.Event)
	}
}

func (t *TwitterBot) selfTweet(tweet *twitter.Tweet) {
	if qqBot.Config.GroupName != "" {
		if hasHashTags(qqBot.Config.GroupName, tweet.Entities.Hashtags) {
			if tweet.QuotedStatus != nil {
				logger.Infof("(%s):{%s}", qqBot.Config.GroupName, strconv.Quote(tweet.QuotedStatus.Text))
				sendPics(getMedias(tweet.QuotedStatus))
			} else {
				logger.Infof("(%s):{%s}", qqBot.Config.GroupName, strconv.Quote(tweet.Text))
				sendPics(getMedias(tweet))
			}
		}
	}
}

// Track ...
func (t *TwitterBot) Track() {
	follows := []string{}
	for _, value := range t.Follows {
		follows = append(follows, value)
	}
	for i := 1; ; i++ {
		demux := twitter.NewSwitchDemux()
		demux.Tweet = t.trackTweet
		filterParams := &twitter.StreamFilterParams{
			Follow: follows,
		}
		stream, err := t.Client.Streams.Filter(filterParams)
		if err != nil {
			logger.Errorf("%+v", err)
			time.Sleep(time.Duration(i) * time.Second)
		}
		demux.HandleChan(stream.Messages)
	}
}

// Self ...
func (t *TwitterBot) Self() {
	for i := 1; ; i++ {
		demux := twitter.NewSwitchDemux()
		demux.Event = t.selfEvent
		demux.Tweet = t.selfTweet
		userParams := &twitter.StreamUserParams{
			With: t.ID,
		}
		stream, err := t.Client.Streams.User(userParams)
		if err != nil {
			logger.Errorf("%+v", err)
			time.Sleep(time.Duration(i) * time.Second)
		}
		demux.HandleChan(stream.Messages)
	}
}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"pilosa/config"
	"pilosa/db"
	"pilosa/hold"
	"pilosa/index"
	"pilosa/interfaces"
	"syscall"

	"github.com/coreos/go-etcd/etcd"
	"github.com/davecgh/go-spew/spew"
	"tux21b.org/v1/gocql/uuid"
)

type Service struct {
	Stopper
	Id             *uuid.UUID
	Etcd           *etcd.Client
	Cluster        *db.Cluster
	TopologyMapper *TopologyMapper
	ProcessMapper  *ProcessMapper
	ProcessMap     *ProcessMap
	Transport      interfaces.Transporter
	Dispatch       interfaces.Dispatcher
	Executor       interfaces.Executorer
	WebService     *WebService
	Index          *index.FragmentContainer
	Hold           *hold.Holder
	version        string
}

func NewService() *Service {
	spew.Dump("NewService")
	service := new(Service)
	service.init_id()
	service.Etcd = etcd.NewClient(nil)
	service.Cluster = db.NewCluster()
	service.TopologyMapper = NewTopologyMapper(service, "/pilosa/0")
	service.ProcessMapper = NewProcessMapper(service, "/pilosa/0")
	service.ProcessMap = NewProcessMap()
	service.WebService = NewWebService(service)
	service.Index = index.NewFragmentContainer()
	service.Hold = hold.NewHolder()
	service.version = "0.0.8"
	service.PrepareLogging()
	return service
}

func (self *Service) PrepareLogging() {
	base_path := config.GetString("log_path")
	if base_path == "" {
		base_path = "/tmp"
	}
	f, err := os.OpenFile(fmt.Sprintf("%s/cruncher.%s", base_path, self.Id), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Error("error opening file: %v", err)
	}
	//defer f.Close()
	log.SetOutput(f)
}

func (service *Service) init_id() {
	var id uuid.UUID
	var err error
	id_string := config.GetString("id")
	if id_string == "" {
		log.Println("Service id not configured, generating...")
		id = uuid.RandomUUID()
		if err != nil {
			log.Fatal("problem generating uuid")
		}
	} else {
		id, err = uuid.ParseUUID(id_string)
		if err != nil {
			log.Fatalf("Service id '%s' not valid", id_string)
		}
	}
	service.Id = &id
}

func (self *Service) GetProcess() (*db.Process, error) {
	return self.ProcessMap.GetProcess(self.Id)
}

func (service *Service) GetSignals() (chan os.Signal, chan os.Signal) {
	hupChan := make(chan os.Signal, 1)
	termChan := make(chan os.Signal, 1)
	signal.Notify(hupChan, syscall.SIGHUP)
	signal.Notify(termChan, syscall.SIGINT, syscall.SIGTERM)
	return termChan, hupChan
}

func (service *Service) Run() {
	log.Println("Running service...")
	go service.TopologyMapper.Run()
	go service.ProcessMapper.Run()
	go service.WebService.Run()
	go service.Transport.Run()
	go service.Dispatch.Run()
	go service.Executor.Run()
	go service.Hold.Run()

	sigterm, sighup := service.GetSignals()
	for {
		select {
		case <-sighup:
			log.Println("SIGHUP! Reloading configuration...")
			// TODO: reload configuration
		case <-sigterm:
			log.Println("SIGTERM! Cleaning up...")
			service.Stop()
			return
		}
	}
}

type Message interface {
	Handle(*Service)
}
<commit_msg>added name to core/service<commit_after>package core

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"pilosa/config"
	"pilosa/db"
	"pilosa/hold"
	"pilosa/index"
	"pilosa/interfaces"
	"syscall"

	"github.com/coreos/go-etcd/etcd"
	"github.com/davecgh/go-spew/spew"
	"tux21b.org/v1/gocql/uuid"
)

type Service struct {
	Stopper
	Id             *uuid.UUID
	Etcd           *etcd.Client
	Cluster        *db.Cluster
	TopologyMapper *TopologyMapper
	ProcessMapper  *ProcessMapper
	ProcessMap     *ProcessMap
	Transport      interfaces.Transporter
	Dispatch       interfaces.Dispatcher
	Executor       interfaces.Executorer
	WebService     *WebService
	Index          *index.FragmentContainer
	Hold           *hold.Holder
	version        string
    name           string
}

func NewService() *Service {
	log.Println(spew.Sdump("NewService")
	service := new(Service)
	service.init_id()
	service.Etcd = etcd.NewClient(nil)
	service.Cluster = db.NewCluster()
	service.TopologyMapper = NewTopologyMapper(service, "/pilosa/0")
	service.ProcessMapper = NewProcessMapper(service, "/pilosa/0")
	service.ProcessMap = NewProcessMap()
	service.WebService = NewWebService(service)
	service.Index = index.NewFragmentContainer()
	service.Hold = hold.NewHolder()
	service.version = "0.0.8"
	service.name ="Cruncher"
	service.PrepareLogging()
	return service
}

func (self *Service) PrepareLogging() {
	base_path := config.GetString("log_path")
	if base_path == "" {
		base_path = "/tmp"
	}
	f, err := os.OpenFile(fmt.Sprintf("%s/%s.%s", base_path, self.name,self.Id), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Println("error opening file: %v", err)
	}
	//defer f.Close()
	log.SetOutput(f)
}

func (service *Service) init_id() {
	var id uuid.UUID
	var err error
	id_string := config.GetString("id")
	if id_string == "" {
		log.Println("Service id not configured, generating...")
		id = uuid.RandomUUID()
		if err != nil {
			log.Fatal("problem generating uuid")
		}
	} else {
		id, err = uuid.ParseUUID(id_string)
		if err != nil {
			log.Fatalf("Service id '%s' not valid", id_string)
		}
	}
	service.Id = &id
}

func (self *Service) GetProcess() (*db.Process, error) {
	return self.ProcessMap.GetProcess(self.Id)
}

func (service *Service) GetSignals() (chan os.Signal, chan os.Signal) {
	hupChan := make(chan os.Signal, 1)
	termChan := make(chan os.Signal, 1)
	signal.Notify(hupChan, syscall.SIGHUP)
	signal.Notify(termChan, syscall.SIGINT, syscall.SIGTERM)
	return termChan, hupChan
}

func (service *Service) Run() {
	log.Println("Running service...")
	go service.TopologyMapper.Run()
	go service.ProcessMapper.Run()
	go service.WebService.Run()
	go service.Transport.Run()
	go service.Dispatch.Run()
	go service.Executor.Run()
	go service.Hold.Run()

	sigterm, sighup := service.GetSignals()
	for {
		select {
		case <-sighup:
			log.Println("SIGHUP! Reloading configuration...")
			// TODO: reload configuration
		case <-sigterm:
			log.Println("SIGTERM! Cleaning up...")
			service.Stop()
			return
		}
	}
}

type Message interface {
	Handle(*Service)
}
<|endoftext|>


<commit_before>package todotxt

import (
        "time"
        "os"
        "bufio"
        "strings"
        "regexp"
        "sort"
)

type Task struct {
        todo string
        priority byte
        create_date time.Time
        contexts []string
        projects []string
        raw_todo string
}

type TaskList []Task

func LoadTaskList (filename string) (TaskList) {

        var f, err = os.Open(filename)

        if err != nil {
                panic(err)
        }

        defer f.Close()

        var tasklist = TaskList{}

        scanner := bufio.NewScanner(f)

        for scanner.Scan() {
                var task = Task{}
                text := scanner.Text()
                task.raw_todo = text

                splits := strings.Split(text, " ")

                head := splits[0]

                if (len(head) == 3) &&
                   (head[0] == '(') &&
                   (head[2] == ')') &&
                   (head[1] >= 65 && head[1] <= 90) { // checking if it's in range [A-Z]
                        task.priority = head[1]
                        splits = splits[1:]
                }

                date_regexp := "([\\d]{4})-([\\d]{2})-([\\d]{2})"
                if match, _ := regexp.MatchString(date_regexp, splits[0]); match {
                        if date, e := time.Parse("2006-01-02", splits[0]); e != nil {
                                panic(e)
                        } else {
                                task.create_date = date
                        }

                        task.todo = strings.Join(splits[1:], " ")
                } else {
                        task.todo = strings.Join(splits[0:], " ")
                }

                context_regexp, _ := regexp.Compile("@[[:word:]]+")
                contexts := context_regexp.FindAllStringSubmatch(text, -1)
                if len(contexts) != 0 {
                        task.contexts = contexts[0]
                }

                project_regexp, _ := regexp.Compile("\\+[[:word:]]+")
                projects := project_regexp.FindAllStringSubmatch(text, -1)
                if len(projects) != 0 {
                        task.projects = projects[0]
                }

                tasklist = append(tasklist, task)
        }

        if err := scanner.Err(); err != nil {
                panic(scanner.Err())
        }

        return tasklist
}

func (tasks TaskList) Len() int {
        return len(tasks)
}

type ByPriority TaskList
func (tasks ByPriority) Len() int {
        return len(tasks)
}
func (tasks ByPriority) Swap(i, j int) {
        tasks[i], tasks[j] = tasks[j], tasks[i]
}
func (tasks ByPriority) Less(i, j int) bool {
        return tasks[i].Priority() < tasks[j].Priority()
}
func (tasks TaskList) Sort() {
        sort.Sort(ByPriority(tasks))
}

type ByCreateDate TaskList
func (tasks ByCreateDate) Len() int {
        return len(tasks)
}
func (tasks ByCreateDate) Swap(i, j int) {
        tasks[i], tasks[j] = tasks[j], tasks[i]
}
func (tasks ByCreateDate) Less(i, j int) bool {
        t1 := tasks[i].CreateDate().Unix()
        t2 := tasks[j].CreateDate().Unix()

        // if the dates equal, let's use priority
        if t1 == t2 {
                return tasks[i].Priority() < tasks[j].Priority()
        } else {
                return t1 > t2
        }
}
func (tasks TaskList) SortByCreateDate() {
        sort.Sort(ByCreateDate(tasks))
}

func (task Task) Text() string {
        return task.todo
}

func (task Task) RawText() string {
        return task.raw_todo
}

func (task Task) Priority() byte {
        // if priority is not from [A-Z], let it be 94 (^)
        if task.priority < 65 || task.priority > 90 {
                return 94 // you know, ^
        } else {
                return task.priority
        }
}

func (task Task) Contexts() []string {
        return task.contexts
}

func (task Task) Projects() []string {
        return task.projects
}

func (task Task) CreateDate() time.Time {
        return task.create_date
}
<commit_msg>by length<commit_after>package todotxt

import (
        "time"
        "os"
        "bufio"
        "strings"
        "regexp"
        "sort"
)

type Task struct {
        todo string
        priority byte
        create_date time.Time
        contexts []string
        projects []string
        raw_todo string
}

type TaskList []Task

func LoadTaskList (filename string) (TaskList) {

        var f, err = os.Open(filename)

        if err != nil {
                panic(err)
        }

        defer f.Close()

        var tasklist = TaskList{}

        scanner := bufio.NewScanner(f)

        for scanner.Scan() {
                var task = Task{}
                text := scanner.Text()
                task.raw_todo = text

                splits := strings.Split(text, " ")

                head := splits[0]

                if (len(head) == 3) &&
                   (head[0] == '(') &&
                   (head[2] == ')') &&
                   (head[1] >= 65 && head[1] <= 90) { // checking if it's in range [A-Z]
                        task.priority = head[1]
                        splits = splits[1:]
                }

                date_regexp := "([\\d]{4})-([\\d]{2})-([\\d]{2})"
                if match, _ := regexp.MatchString(date_regexp, splits[0]); match {
                        if date, e := time.Parse("2006-01-02", splits[0]); e != nil {
                                panic(e)
                        } else {
                                task.create_date = date
                        }

                        task.todo = strings.Join(splits[1:], " ")
                } else {
                        task.todo = strings.Join(splits[0:], " ")
                }

                context_regexp, _ := regexp.Compile("@[[:word:]]+")
                contexts := context_regexp.FindAllStringSubmatch(text, -1)
                if len(contexts) != 0 {
                        task.contexts = contexts[0]
                }

                project_regexp, _ := regexp.Compile("\\+[[:word:]]+")
                projects := project_regexp.FindAllStringSubmatch(text, -1)
                if len(projects) != 0 {
                        task.projects = projects[0]
                }

                tasklist = append(tasklist, task)
        }

        if err := scanner.Err(); err != nil {
                panic(scanner.Err())
        }

        return tasklist
}

func (tasks TaskList) Len() int {
        return len(tasks)
}

type ByPriority TaskList
func (tasks ByPriority) Len() int {
        return len(tasks)
}
func (tasks ByPriority) Swap(i, j int) {
        tasks[i], tasks[j] = tasks[j], tasks[i]
}
func (tasks ByPriority) Less(i, j int) bool {
        return tasks[i].Priority() < tasks[j].Priority()
}
func (tasks TaskList) Sort() {
        sort.Sort(ByPriority(tasks))
}

type ByCreateDate TaskList
func (tasks ByCreateDate) Len() int {
        return len(tasks)
}
func (tasks ByCreateDate) Swap(i, j int) {
        tasks[i], tasks[j] = tasks[j], tasks[i]
}
func (tasks ByCreateDate) Less(i, j int) bool {
        t1 := tasks[i].CreateDate().Unix()
        t2 := tasks[j].CreateDate().Unix()

        // if the dates equal, let's use priority
        if t1 == t2 {
                return tasks[i].Priority() < tasks[j].Priority()
        } else {
                return t1 > t2
        }
}
func (tasks TaskList) SortByCreateDate() {
        sort.Sort(ByCreateDate(tasks))
}

type ByLength TaskList
func (tasks ByLength) Len() int {
        return len(tasks)
}
func (tasks ByLength) Swap(i, j int) {
        tasks[i], tasks[j] = tasks[j], tasks[i]
}
func (tasks ByLength) Less(i, j int) bool {
        t1 := len(tasks[i].raw_todo)
        t2 := len(tasks[j].raw_todo)
        if t1 == t2 {
                return tasks[i].Priority() < tasks[j].Priority()
        } else {
                return t1 > t2
        }
}
func (tasks TaskList) SortByLength() {
        sort.Sort(ByLength(tasks))
}

func (task Task) Text() string {
        return task.todo
}

func (task Task) RawText() string {
        return task.raw_todo
}

func (task Task) Priority() byte {
        // if priority is not from [A-Z], let it be 94 (^)
        if task.priority < 65 || task.priority > 90 {
                return 94 // you know, ^
        } else {
                return task.priority
        }
}

func (task Task) Contexts() []string {
        return task.contexts
}

func (task Task) Projects() []string {
        return task.projects
}

func (task Task) CreateDate() time.Time {
        return task.create_date
}
<|endoftext|>