<commit_before>package paillier

import (
	"crypto/rand"
	"io"
	"math/big"
)

// Generates a threshold Paillier key with an algorithm based on [DJN 10],
// section 5.1, "Key generation".
//
// Bear in mind that the algorithm assumes an existence of a trusted dealer
// to generate and distribute the keys.
//
//
//     [DJN 10]: Ivan Damgard, Mads Jurik, Jesper Buus Nielsen, (2010)
//               A Generalization of Paillier’s Public-Key System
//               with Applications to Electronic Voting
//               Aarhus University, Dept. of Computer Science, BRICS
type ThresholdKeyGenerator struct {
	nbits                          int
	TotalNumberOfDecryptionServers int
	Threshold                      int
	Random                         io.Reader

	// Both p1 and q1 are primes of length nbits - 1
	p1 *big.Int
	q1 *big.Int

	p       *big.Int // p is prime and p=2*p1+1
	q       *big.Int // q is prime and q=2*q1+1
	n       *big.Int // n=p*q
	m       *big.Int // m = p1*q1
	nSquare *big.Int // nSquare = n*n
	nm      *big.Int // nm = n*m

	// As specified in the paper, d must satify d=1 mod n and d=0 mod m
	d *big.Int

	// A generator of QR in Z_{n^2}
	v *big.Int

	// The polynomial coefficients to hide a secret. See Shamir.
	polynomialCoefficients []*big.Int
}

// Preferable way to construct the ThresholdKeyGenerator. No verification
// is done on the input values.  You need to be sure that nbits is big enough
// and that Threshold > TotalNumberOfDecryptionServers / 2.
// The plaintext space for the key will be Z_n.
func GetThresholdKeyGenerator(nbits, TotalNumberOfDecryptionServers, Threshold int, random io.Reader) *ThresholdKeyGenerator {
	ret := new(ThresholdKeyGenerator)
	ret.nbits = nbits
	ret.TotalNumberOfDecryptionServers = TotalNumberOfDecryptionServers
	ret.Threshold = Threshold
	ret.Random = random
	return ret
}

func (this *ThresholdKeyGenerator) generateSafePrimes() (*big.Int, *big.Int, error) {
	return GenerateSafePrimes(this.nbits, this.Random)
}

func (this *ThresholdKeyGenerator) initPandP1() error {
	var err error
	this.p, this.p1, err = this.generateSafePrimes()
	return err
}

func (this *ThresholdKeyGenerator) initQandQ1() error {
	var err error
	this.q, this.q1, err = this.generateSafePrimes()
	return err
}

func (this *ThresholdKeyGenerator) initShortcuts() {
	this.n = new(big.Int).Mul(this.p, this.q)
	this.m = new(big.Int).Mul(this.p1, this.q1)
	this.nSquare = new(big.Int).Mul(this.n, this.n)
	this.nm = new(big.Int).Mul(this.n, this.m)

}

func (this *ThresholdKeyGenerator) arePsAndQsGood() bool {
	if this.p.Cmp(this.q) == 0 {
		return false
	}
	if this.p.Cmp(this.q1) == 0 {
		return false
	}
	if this.p1.Cmp(this.q) == 0 {
		return false
	}
	return true
}

func (this *ThresholdKeyGenerator) initPsAndQs() error {
	if err := this.initPandP1(); err != nil {
		return err
	}
	if err := this.initQandQ1(); err != nil {
		return err
	}
	if !this.arePsAndQsGood() {
		return this.initPsAndQs()
	}
	return nil
}

// v generates a cyclic group of squares in Zn^2.
func (this *ThresholdKeyGenerator) computeV() error {
	var err error
	this.v, err = GetRandomGeneratorOfTheQuadraticResidue(this.nSquare, this.Random)
	return err
}

// Choose d such that d=0 (mod m) and d=1 (mod n).
//
// From Chinese Remainder Theorem:
// x = a1 (mod n1)
// x = a2 (mod n2)
//
// N = n1*n2
// y1 = N/n1
// y2 = N/n2
// z1 = y1^-1 mod n1
// z2 = y2^-1 mod n2
// Solution is x = a1*y1*z1 + a2*y2*z2
//
// In our case:
// x = 0 (mod m)
// x = 1 (mod n)
//
// Since a1 = 0, it's enough to compute a2*y2*z2 to get x.
//
// a2 = 1
// y2 = mn/n = m
// z2 = m^-1 mod n
//
// x = a2*y2*z2 = 1 * m * [m^-1 mod n]
func (this *ThresholdKeyGenerator) initD() {
	mInverse := new(big.Int).ModInverse(this.m, this.n)
	this.d = new(big.Int).Mul(mInverse, this.m)
}

func (this *ThresholdKeyGenerator) initNumerialValues() error {
	if err := this.initPsAndQs(); err != nil {
		return err
	}
	this.initShortcuts()
	this.initD()
	return this.computeV()
}

// f(X) = a_0 X^0 + a_1 X^1 + ... + a_(w-1) X^(w-1)
//
// where:
// `w` - threshold
// `a_i` - random value from {0, ... nm - 1} for 0<i<w
// `a_0` is always equal `d`
func (this *ThresholdKeyGenerator) generateHidingPolynomial() error {
	this.polynomialCoefficients = make([]*big.Int, this.Threshold)
	this.polynomialCoefficients[0] = this.d
	var err error
	for i := 1; i < this.Threshold; i++ {
		this.polynomialCoefficients[i], err = rand.Int(this.Random, this.nm)
		if err != nil {
			return err
		}
	}
	return nil
}

// The secred share of the i'th authority is `f(i) mod nm`, where `f` is
// the polynomial we generated in `GenerateHidingPolynomial` function.
func (this *ThresholdKeyGenerator) computeShare(index int) *big.Int {
	share := big.NewInt(0)
	for i := 0; i < this.Threshold; i++ {
		a := this.polynomialCoefficients[i]
		// we index authorities from 1, that's why we do index+1 here
		b := new(big.Int).Exp(big.NewInt(int64(index+1)), big.NewInt(int64(i)), nil)
		tmp := new(big.Int).Mul(a, b)
		share = new(big.Int).Add(share, tmp)
	}
	return new(big.Int).Mod(share, this.nm)
}

func (this *ThresholdKeyGenerator) createShares() []*big.Int {
	shares := make([]*big.Int, this.TotalNumberOfDecryptionServers)
	for i := 0; i < this.TotalNumberOfDecryptionServers; i++ {
		shares[i] = this.computeShare(i)
	}
	return shares
}

func (this *ThresholdKeyGenerator) delta() *big.Int {
	return Factorial(this.TotalNumberOfDecryptionServers)
}

// Generates verification keys for actions of decryption servers.
//
// For each decryption server `i`, we generate
// v_i = v^(l! s_i) mod n^2
//
// where:
// `l` is the number of decryption servers
// `s_i` is a secret share for server `i`.
// Secret shares were previously generated in the `CrateShares` function.
func (this *ThresholdKeyGenerator) createViArray(shares []*big.Int) (viArray []*big.Int) {
	viArray = make([]*big.Int, len(shares))
	delta := this.delta()
	for i, share := range shares {
		tmp := new(big.Int).Mul(share, delta)
		viArray[i] = new(big.Int).Exp(this.v, tmp, this.nSquare)
	}
	return viArray
}

func (this *ThresholdKeyGenerator) createPrivateKey(i int, share *big.Int, viArray []*big.Int) *ThresholdPrivateKey {
	ret := new(ThresholdPrivateKey)
	ret.N = this.n
	ret.V = this.v

	ret.TotalNumberOfDecryptionServers = this.TotalNumberOfDecryptionServers
	ret.Threshold = this.Threshold
	ret.Share = share
	ret.Id = i + 1
	ret.Vi = viArray
	return ret
}

func (this *ThresholdKeyGenerator) createPrivateKeys() []*ThresholdPrivateKey {
	shares := this.createShares()
	viArray := this.createViArray(shares)
	ret := make([]*ThresholdPrivateKey, this.TotalNumberOfDecryptionServers)
	for i := 0; i < this.TotalNumberOfDecryptionServers; i++ {
		ret[i] = this.createPrivateKey(i, shares[i], viArray)
	}
	return ret
}

func (this *ThresholdKeyGenerator) Generate() ([]*ThresholdPrivateKey, error) {
	if err := this.initNumerialValues(); err != nil {
		return nil, err
	}
	if err := this.generateHidingPolynomial(); err != nil {
		return nil, err
	}
	return this.createPrivateKeys(), nil
}
<commit_msg>ThresholdKeyGenerator self-ref renamed from this to tkg<commit_after>package paillier

import (
	"crypto/rand"
	"io"
	"math/big"
)

// Generates a threshold Paillier key with an algorithm based on [DJN 10],
// section 5.1, "Key generation".
//
// Bear in mind that the algorithm assumes an existence of a trusted dealer
// to generate and distribute the keys.
//
//
//     [DJN 10]: Ivan Damgard, Mads Jurik, Jesper Buus Nielsen, (2010)
//               A Generalization of Paillier’s Public-Key System
//               with Applications to Electronic Voting
//               Aarhus University, Dept. of Computer Science, BRICS
type ThresholdKeyGenerator struct {
	nbits                          int
	TotalNumberOfDecryptionServers int
	Threshold                      int
	Random                         io.Reader

	// Both p1 and q1 are primes of length nbits - 1
	p1 *big.Int
	q1 *big.Int

	p       *big.Int // p is prime and p=2*p1+1
	q       *big.Int // q is prime and q=2*q1+1
	n       *big.Int // n=p*q
	m       *big.Int // m = p1*q1
	nSquare *big.Int // nSquare = n*n
	nm      *big.Int // nm = n*m

	// As specified in the paper, d must satify d=1 mod n and d=0 mod m
	d *big.Int

	// A generator of QR in Z_{n^2}
	v *big.Int

	// The polynomial coefficients to hide a secret. See Shamir.
	polynomialCoefficients []*big.Int
}

// Preferable way to construct the ThresholdKeyGenerator. No verification
// is done on the input values.  You need to be sure that nbits is big enough
// and that Threshold > TotalNumberOfDecryptionServers / 2.
// The plaintext space for the key will be Z_n.
func GetThresholdKeyGenerator(nbits, TotalNumberOfDecryptionServers, Threshold int, random io.Reader) *ThresholdKeyGenerator {
	ret := new(ThresholdKeyGenerator)
	ret.nbits = nbits
	ret.TotalNumberOfDecryptionServers = TotalNumberOfDecryptionServers
	ret.Threshold = Threshold
	ret.Random = random
	return ret
}

func (tkg *ThresholdKeyGenerator) generateSafePrimes() (*big.Int, *big.Int, error) {
	return GenerateSafePrimes(tkg.nbits, tkg.Random)
}

func (tkg *ThresholdKeyGenerator) initPandP1() error {
	var err error
	tkg.p, tkg.p1, err = tkg.generateSafePrimes()
	return err
}

func (tkg *ThresholdKeyGenerator) initQandQ1() error {
	var err error
	tkg.q, tkg.q1, err = tkg.generateSafePrimes()
	return err
}

func (tkg *ThresholdKeyGenerator) initShortcuts() {
	tkg.n = new(big.Int).Mul(tkg.p, tkg.q)
	tkg.m = new(big.Int).Mul(tkg.p1, tkg.q1)
	tkg.nSquare = new(big.Int).Mul(tkg.n, tkg.n)
	tkg.nm = new(big.Int).Mul(tkg.n, tkg.m)
}

func (tkg *ThresholdKeyGenerator) arePsAndQsGood() bool {
	if tkg.p.Cmp(tkg.q) == 0 {
		return false
	}
	if tkg.p.Cmp(tkg.q1) == 0 {
		return false
	}
	if tkg.p1.Cmp(tkg.q) == 0 {
		return false
	}
	return true
}

func (tkg *ThresholdKeyGenerator) initPsAndQs() error {
	if err := tkg.initPandP1(); err != nil {
		return err
	}
	if err := tkg.initQandQ1(); err != nil {
		return err
	}
	if !tkg.arePsAndQsGood() {
		return tkg.initPsAndQs()
	}
	return nil
}

// v generates a cyclic group of squares in Zn^2.
func (tkg *ThresholdKeyGenerator) computeV() error {
	var err error
	tkg.v, err = GetRandomGeneratorOfTheQuadraticResidue(tkg.nSquare, tkg.Random)
	return err
}

// Choose d such that d=0 (mod m) and d=1 (mod n).
//
// From Chinese Remainder Theorem:
// x = a1 (mod n1)
// x = a2 (mod n2)
//
// N = n1*n2
// y1 = N/n1
// y2 = N/n2
// z1 = y1^-1 mod n1
// z2 = y2^-1 mod n2
// Solution is x = a1*y1*z1 + a2*y2*z2
//
// In our case:
// x = 0 (mod m)
// x = 1 (mod n)
//
// Since a1 = 0, it's enough to compute a2*y2*z2 to get x.
//
// a2 = 1
// y2 = mn/n = m
// z2 = m^-1 mod n
//
// x = a2*y2*z2 = 1 * m * [m^-1 mod n]
func (tkg *ThresholdKeyGenerator) initD() {
	mInverse := new(big.Int).ModInverse(tkg.m, tkg.n)
	tkg.d = new(big.Int).Mul(mInverse, tkg.m)
}

func (tkg *ThresholdKeyGenerator) initNumerialValues() error {
	if err := tkg.initPsAndQs(); err != nil {
		return err
	}
	tkg.initShortcuts()
	tkg.initD()
	return tkg.computeV()
}

// f(X) = a_0 X^0 + a_1 X^1 + ... + a_(w-1) X^(w-1)
//
// where:
// `w` - threshold
// `a_i` - random value from {0, ... nm - 1} for 0<i<w
// `a_0` is always equal `d`
func (tkg *ThresholdKeyGenerator) generateHidingPolynomial() error {
	tkg.polynomialCoefficients = make([]*big.Int, tkg.Threshold)
	tkg.polynomialCoefficients[0] = tkg.d
	var err error
	for i := 1; i < tkg.Threshold; i++ {
		tkg.polynomialCoefficients[i], err = rand.Int(tkg.Random, tkg.nm)
		if err != nil {
			return err
		}
	}
	return nil
}

// The secred share of the i'th authority is `f(i) mod nm`, where `f` is
// the polynomial we generated in `GenerateHidingPolynomial` function.
func (tkg *ThresholdKeyGenerator) computeShare(index int) *big.Int {
	share := big.NewInt(0)
	for i := 0; i < tkg.Threshold; i++ {
		a := tkg.polynomialCoefficients[i]
		// we index authorities from 1, that's why we do index+1 here
		b := new(big.Int).Exp(big.NewInt(int64(index+1)), big.NewInt(int64(i)), nil)
		tmp := new(big.Int).Mul(a, b)
		share = new(big.Int).Add(share, tmp)
	}
	return new(big.Int).Mod(share, tkg.nm)
}

func (tkg *ThresholdKeyGenerator) createShares() []*big.Int {
	shares := make([]*big.Int, tkg.TotalNumberOfDecryptionServers)
	for i := 0; i < tkg.TotalNumberOfDecryptionServers; i++ {
		shares[i] = tkg.computeShare(i)
	}
	return shares
}

func (tkg *ThresholdKeyGenerator) delta() *big.Int {
	return Factorial(tkg.TotalNumberOfDecryptionServers)
}

// Generates verification keys for actions of decryption servers.
//
// For each decryption server `i`, we generate
// v_i = v^(l! s_i) mod n^2
//
// where:
// `l` is the number of decryption servers
// `s_i` is a secret share for server `i`.
// Secret shares were previously generated in the `CrateShares` function.
func (tkg *ThresholdKeyGenerator) createViArray(shares []*big.Int) (viArray []*big.Int) {
	viArray = make([]*big.Int, len(shares))
	delta := tkg.delta()
	for i, share := range shares {
		tmp := new(big.Int).Mul(share, delta)
		viArray[i] = new(big.Int).Exp(tkg.v, tmp, tkg.nSquare)
	}
	return viArray
}

func (tkg *ThresholdKeyGenerator) createPrivateKey(i int, share *big.Int, viArray []*big.Int) *ThresholdPrivateKey {
	ret := new(ThresholdPrivateKey)
	ret.N = tkg.n
	ret.V = tkg.v

	ret.TotalNumberOfDecryptionServers = tkg.TotalNumberOfDecryptionServers
	ret.Threshold = tkg.Threshold
	ret.Share = share
	ret.Id = i + 1
	ret.Vi = viArray
	return ret
}

func (tkg *ThresholdKeyGenerator) createPrivateKeys() []*ThresholdPrivateKey {
	shares := tkg.createShares()
	viArray := tkg.createViArray(shares)
	ret := make([]*ThresholdPrivateKey, tkg.TotalNumberOfDecryptionServers)
	for i := 0; i < tkg.TotalNumberOfDecryptionServers; i++ {
		ret[i] = tkg.createPrivateKey(i, shares[i], viArray)
	}
	return ret
}

func (tkg *ThresholdKeyGenerator) Generate() ([]*ThresholdPrivateKey, error) {
	if err := tkg.initNumerialValues(); err != nil {
		return nil, err
	}
	if err := tkg.generateHidingPolynomial(); err != nil {
		return nil, err
	}
	return tkg.createPrivateKeys(), nil
}
<|endoftext|>


<commit_before>package hostdb

import (
	"crypto/rand"
	"errors"
	"math/big"
	"strconv"
	"testing"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// fakeAddr returns a modules.NetAddress to be used in a HostEntry. Such
// addresses are needed in order to satisfy the HostDB's "1 host per IP" rule.
func fakeAddr(n uint8) modules.NetAddress {
	return modules.NetAddress("127.0.0." + strconv.Itoa(int(n)) + ":0")
}

// uniformTreeVerification checks that everything makes sense in the tree given
// the number of entries that the tree is supposed to have and also given that
// every entropy has the same weight.
func uniformTreeVerification(hdb *HostDB, numEntries int) error {
	// Check that the weight of the hostTree is what is expected.
	expectedWeight := types.NewCurrency64(uint64(numEntries)).Mul(hdb.hostTree.hostEntry.weight)
	if hdb.hostTree.weight.Cmp(expectedWeight) != 0 {
		return errors.New("expected weight is incorrect")
	}

	// Check that the length of activeHosts and the count of hostTree are
	// consistent.
	if len(hdb.activeHosts) != numEntries {
		return errors.New("unexpected number of active hosts")
	}

	// Select many random hosts and do naive statistical analysis on the
	// results.
	if !testing.Short() {
		// Pull a bunch of random hosts and count how many times we pull each
		// host.
		selectionMap := make(map[modules.NetAddress]int)
		expected := 100
		for i := 0; i < expected*numEntries; i++ {
			entries := hdb.randomHosts(1, nil)
			if len(entries) == 0 {
				return errors.New("no hosts!")
			}
			selectionMap[entries[0].NetAddress] = selectionMap[entries[0].NetAddress] + 1
		}

		// See if each host was selected enough times.
		errorBound := 64 // Pretty large, but will still detect if something is seriously wrong.
		for _, count := range selectionMap {
			if count < expected-errorBound || count > expected+errorBound {
				return errors.New("error bound was breached")
			}
		}
	}

	// Try removing an re-adding all hosts.
	var removedEntries []*hostEntry
	for {
		if hdb.hostTree.weight.IsZero() {
			break
		}
		randWeight, err := rand.Int(rand.Reader, hdb.hostTree.weight.Big())
		if err != nil {
			break
		}
		node, err := hdb.hostTree.nodeAtWeight(types.NewCurrency(randWeight))
		if err != nil {
			break
		}
		node.removeNode()
		delete(hdb.activeHosts, node.hostEntry.NetAddress)

		// remove the entry from the hostdb so it won't be selected as a
		// repeat.
		removedEntries = append(removedEntries, node.hostEntry)
	}
	for _, entry := range removedEntries {
		hdb.insertNode(entry)
	}
	return nil
}

// TestWeightedList inserts and removes nodes in a semi-random manner and
// verifies that the tree stays consistent through the adjustments.
func TestWeightedList(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	// Create a hostdb and 3 equal entries to insert.
	hdb := &HostDB{
		activeHosts: make(map[modules.NetAddress]*hostNode),
		allHosts:    make(map[modules.NetAddress]*hostEntry),
		scanPool:    make(chan *hostEntry, scanPoolSize),
	}

	// Create a bunch of host entries of equal weight.
	firstInsertions := 64
	for i := 0; i < firstInsertions; i++ {
		entry := hostEntry{
			HostSettings: modules.HostSettings{NetAddress: fakeAddr(uint8(i))},
			weight:       types.NewCurrency64(10),
		}
		hdb.insertNode(&entry)
	}
	err := uniformTreeVerification(hdb, firstInsertions)
	if err != nil {
		t.Error(err)
	}

	// Remove a few hosts and check that the tree is still in order.
	removals := 12
	// Keep a map of what we've removed so far.
	removedMap := make(map[uint8]struct{})
	for i := 0; i < removals; i++ {
		// Try numbers until we roll a number that's not been removed yet.
		var randInt uint8
		for {
			randBig, err := rand.Int(rand.Reader, big.NewInt(int64(firstInsertions)))
			if err != nil {
				t.Fatal(err)
			}
			randInt = uint8(randBig.Int64())
			_, exists := removedMap[randInt]
			if !exists {
				break
			}
		}

		// Remove the entry and add it to the list of removed entries
		err := hdb.removeHost(fakeAddr(randInt))
		if err != nil {
			t.Fatal(err)
		}
		removedMap[randInt] = struct{}{}
	}
	err = uniformTreeVerification(hdb, firstInsertions-removals)
	if err != nil {
		t.Error(err)
	}

	// Do some more insertions.
	secondInsertions := 64
	for i := firstInsertions; i < firstInsertions+secondInsertions; i++ {
		entry := hostEntry{
			HostSettings: modules.HostSettings{NetAddress: fakeAddr(uint8(i))},
			weight:       types.NewCurrency64(10),
		}
		hdb.insertNode(&entry)
	}
	err = uniformTreeVerification(hdb, firstInsertions-removals+secondInsertions)
	if err != nil {
		t.Error(err)
	}
}

// TestVariedWeights runs broad statistical tests on selecting hosts with
// multiple different weights.
func TestVariedWeights(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	hdb := &HostDB{
		activeHosts: make(map[modules.NetAddress]*hostNode),
		allHosts:    make(map[modules.NetAddress]*hostEntry),
		scanPool:    make(chan *hostEntry, scanPoolSize),
	}

	// insert i hosts with the weights 0, 1, ..., i-1. 100e3 selections will be made
	// per weight added to the tree, the total number of selections necessary
	// will be tallied up as hosts are created.
	hostCount := 5
	expectedPerWeight := int(10e3)
	selections := 0
	for i := 0; i < hostCount; i++ {
		entry := hostEntry{
			HostSettings: modules.HostSettings{NetAddress: fakeAddr(uint8(i))},
			weight:       types.NewCurrency64(uint64(i)),
		}
		hdb.insertNode(&entry)
		selections += i * expectedPerWeight
	}

	// Perform many random selections, noting which host was selected each
	// time.
	selectionMap := make(map[string]int)
	for i := 0; i < selections; i++ {
		randEntry := hdb.randomHosts(1, nil)
		if len(randEntry) == 0 {
			t.Fatal("no hosts!")
		}
		node, exists := hdb.activeHosts[randEntry[0].NetAddress]
		if !exists {
			t.Fatal("can't find randomly selected node in tree")
		}
		selectionMap[node.hostEntry.weight.String()] += 1
	}

	// Check that each host was selected an expected number of times. An error
	// will be reported if the host of 0 weight is ever selected.
	acceptableError := 0.2
	for weight, timesSelected := range selectionMap {
		intWeight, err := strconv.Atoi(weight)
		if err != nil {
			t.Fatal(err)
		}

		expectedSelected := float64(intWeight * expectedPerWeight)
		if float64(expectedSelected)*acceptableError > float64(timesSelected) || float64(expectedSelected)/acceptableError < float64(timesSelected) {
			t.Error("weighted list not selecting in a uniform distribution based on weight")
			t.Error(expectedSelected)
			t.Error(timesSelected)
		}
	}
}

// TestRepeatInsert inserts 2 hosts with the same address.
func TestRepeatInsert(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	hdb := &HostDB{
		activeHosts: make(map[modules.NetAddress]*hostNode),
		allHosts:    make(map[modules.NetAddress]*hostEntry),
		scanPool:    make(chan *hostEntry, scanPoolSize),
	}

	entry1 := hostEntry{
		HostSettings: modules.HostSettings{NetAddress: fakeAddr(0)},
		weight:       types.NewCurrency64(1),
	}
	entry2 := entry1
	hdb.insertNode(&entry1)

	entry2.weight = types.NewCurrency64(100)
	hdb.insertNode(&entry2)
	if len(hdb.activeHosts) != 1 {
		t.Error("insterting the same entry twice should result in only 1 entry in the hostdb")
	}
}

// TestRandomHosts probles the randomHosts function.
func TestRandomHosts(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	hdb := &HostDB{
		activeHosts: make(map[modules.NetAddress]*hostNode),
		allHosts:    make(map[modules.NetAddress]*hostEntry),
		scanPool:    make(chan *hostEntry, scanPoolSize),
	}

	// Insert 3 hosts to be selected.
	entry1 := hostEntry{
		HostSettings: modules.HostSettings{NetAddress: fakeAddr(1)},
		weight:       types.NewCurrency64(1),
	}
	entry2 := hostEntry{
		HostSettings: modules.HostSettings{NetAddress: fakeAddr(2)},
		weight:       types.NewCurrency64(2),
	}
	entry3 := hostEntry{
		HostSettings: modules.HostSettings{NetAddress: fakeAddr(3)},
		weight:       types.NewCurrency64(3),
	}
	hdb.insertNode(&entry1)
	hdb.insertNode(&entry2)
	hdb.insertNode(&entry3)

	if len(hdb.activeHosts) != 3 {
		t.Error("wrong number of hosts")
	}
	if hdb.hostTree.weight.Cmp(types.NewCurrency64(6)) != 0 {
		t.Error("unexpected weight at initialization")
		t.Error(hdb.hostTree.weight)
	}

	// Grab 1 random host.
	randHosts := hdb.randomHosts(1, nil)
	if len(randHosts) != 1 {
		t.Error("didn't get 1 hosts")
	}
	if len(hdb.activeHosts) != 3 {
		t.Error("wrong number of hosts")
	}
	if hdb.hostTree.weight.Cmp(types.NewCurrency64(6)) != 0 {
		t.Error("unexpected weight at initialization")
	}

	// Grab 2 random hosts.
	randHosts = hdb.randomHosts(2, nil)
	if len(randHosts) != 2 {
		t.Error("didn't get 2 hosts")
	}
	if len(hdb.activeHosts) != 3 {
		t.Error("wrong number of hosts")
	}
	if hdb.hostTree.weight.Cmp(types.NewCurrency64(6)) != 0 {
		t.Error("unexpected weight at initialization")
	}
	if randHosts[0].NetAddress == randHosts[1].NetAddress {
		t.Error("doubled up")
	}

	// Grab 3 random hosts.
	randHosts = hdb.randomHosts(3, nil)
	if len(randHosts) != 3 {
		t.Error("didn't get 3 hosts")
	}
	if len(hdb.activeHosts) != 3 {
		t.Error("wrong number of hosts")
	}
	if hdb.hostTree.weight.Cmp(types.NewCurrency64(6)) != 0 {
		t.Error("unexpected weight at initialization")
	}
	if randHosts[0].NetAddress == randHosts[1].NetAddress || randHosts[0].NetAddress == randHosts[2].NetAddress || randHosts[1].NetAddress == randHosts[2].NetAddress {
		t.Error("doubled up")
	}

	// Grab 4 random hosts. 3 should be returned.
	randHosts = hdb.randomHosts(4, nil)
	if len(randHosts) != 3 {
		t.Error("didn't get 3 hosts")
	}
	if len(hdb.activeHosts) != 3 {
		t.Error("wrong number of hosts")
	}
	if hdb.hostTree.weight.Cmp(types.NewCurrency64(6)) != 0 {
		t.Error("unexpected weight at initialization")
	}
	if randHosts[0].NetAddress == randHosts[1].NetAddress || randHosts[0].NetAddress == randHosts[2].NetAddress || randHosts[1].NetAddress == randHosts[2].NetAddress {
		t.Error("doubled up")
	}

	// Ask for 3 hosts that are not in randHosts. No hosts should be
	// returned.
	uniqueHosts := hdb.randomHosts(3, []modules.NetAddress{
		randHosts[0].NetAddress,
		randHosts[1].NetAddress,
		randHosts[2].NetAddress,
	})
	if len(uniqueHosts) != 0 {
		t.Error("didn't get 0 hosts")
	}
}
<commit_msg>95.8% test coverage for hostdb/weightedlist.go<commit_after>package hostdb

import (
	"crypto/rand"
	"errors"
	"math/big"
	"strconv"
	"testing"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)

// fakeAddr returns a modules.NetAddress to be used in a HostEntry. Such
// addresses are needed in order to satisfy the HostDB's "1 host per IP" rule.
func fakeAddr(n uint8) modules.NetAddress {
	return modules.NetAddress("127.0.0." + strconv.Itoa(int(n)) + ":0")
}

// uniformTreeVerification checks that everything makes sense in the tree given
// the number of entries that the tree is supposed to have and also given that
// every entropy has the same weight.
func uniformTreeVerification(hdb *HostDB, numEntries int) error {
	// Check that the weight of the hostTree is what is expected.
	expectedWeight := types.NewCurrency64(uint64(numEntries)).Mul(hdb.hostTree.hostEntry.weight)
	if hdb.hostTree.weight.Cmp(expectedWeight) != 0 {
		return errors.New("expected weight is incorrect")
	}

	// Check that the length of activeHosts and the count of hostTree are
	// consistent.
	if len(hdb.activeHosts) != numEntries {
		return errors.New("unexpected number of active hosts")
	}

	// Select many random hosts and do naive statistical analysis on the
	// results.
	if !testing.Short() {
		// Pull a bunch of random hosts and count how many times we pull each
		// host.
		selectionMap := make(map[modules.NetAddress]int)
		expected := 100
		for i := 0; i < expected*numEntries; i++ {
			entries := hdb.randomHosts(1, nil)
			if len(entries) == 0 {
				return errors.New("no hosts!")
			}
			selectionMap[entries[0].NetAddress] = selectionMap[entries[0].NetAddress] + 1
		}

		// See if each host was selected enough times.
		errorBound := 64 // Pretty large, but will still detect if something is seriously wrong.
		for _, count := range selectionMap {
			if count < expected-errorBound || count > expected+errorBound {
				return errors.New("error bound was breached")
			}
		}
	}

	// Try removing an re-adding all hosts.
	var removedEntries []*hostEntry
	for {
		if hdb.hostTree.weight.IsZero() {
			break
		}
		randWeight, err := rand.Int(rand.Reader, hdb.hostTree.weight.Big())
		if err != nil {
			break
		}
		node, err := hdb.hostTree.nodeAtWeight(types.NewCurrency(randWeight))
		if err != nil {
			break
		}
		node.removeNode()
		delete(hdb.activeHosts, node.hostEntry.NetAddress)

		// remove the entry from the hostdb so it won't be selected as a
		// repeat.
		removedEntries = append(removedEntries, node.hostEntry)
	}
	for _, entry := range removedEntries {
		hdb.insertNode(entry)
	}
	return nil
}

// TestWeightedList inserts and removes nodes in a semi-random manner and
// verifies that the tree stays consistent through the adjustments.
func TestWeightedList(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	// Create a hostdb and 3 equal entries to insert.
	hdb := &HostDB{
		activeHosts: make(map[modules.NetAddress]*hostNode),
		allHosts:    make(map[modules.NetAddress]*hostEntry),
		scanPool:    make(chan *hostEntry, scanPoolSize),
	}

	// Create a bunch of host entries of equal weight.
	firstInsertions := 64
	for i := 0; i < firstInsertions; i++ {
		entry := hostEntry{
			HostSettings: modules.HostSettings{NetAddress: fakeAddr(uint8(i))},
			weight:       types.NewCurrency64(10),
		}
		hdb.insertNode(&entry)
	}
	err := uniformTreeVerification(hdb, firstInsertions)
	if err != nil {
		t.Error(err)
	}

	// Remove a few hosts and check that the tree is still in order.
	removals := 12
	// Keep a map of what we've removed so far.
	removedMap := make(map[uint8]struct{})
	for i := 0; i < removals; i++ {
		// Try numbers until we roll a number that's not been removed yet.
		var randInt uint8
		for {
			randBig, err := rand.Int(rand.Reader, big.NewInt(int64(firstInsertions)))
			if err != nil {
				t.Fatal(err)
			}
			randInt = uint8(randBig.Int64())
			_, exists := removedMap[randInt]
			if !exists {
				break
			}
		}

		// Remove the entry and add it to the list of removed entries
		err := hdb.removeHost(fakeAddr(randInt))
		if err != nil {
			t.Fatal(err)
		}
		removedMap[randInt] = struct{}{}
	}
	err = uniformTreeVerification(hdb, firstInsertions-removals)
	if err != nil {
		t.Error(err)
	}

	// Do some more insertions.
	secondInsertions := 64
	for i := firstInsertions; i < firstInsertions+secondInsertions; i++ {
		entry := hostEntry{
			HostSettings: modules.HostSettings{NetAddress: fakeAddr(uint8(i))},
			weight:       types.NewCurrency64(10),
		}
		hdb.insertNode(&entry)
	}
	err = uniformTreeVerification(hdb, firstInsertions-removals+secondInsertions)
	if err != nil {
		t.Error(err)
	}
}

// TestVariedWeights runs broad statistical tests on selecting hosts with
// multiple different weights.
func TestVariedWeights(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	hdb := &HostDB{
		activeHosts: make(map[modules.NetAddress]*hostNode),
		allHosts:    make(map[modules.NetAddress]*hostEntry),
		scanPool:    make(chan *hostEntry, scanPoolSize),
	}

	// insert i hosts with the weights 0, 1, ..., i-1. 100e3 selections will be made
	// per weight added to the tree, the total number of selections necessary
	// will be tallied up as hosts are created.
	hostCount := 5
	expectedPerWeight := int(10e3)
	selections := 0
	for i := 0; i < hostCount; i++ {
		entry := hostEntry{
			HostSettings: modules.HostSettings{NetAddress: fakeAddr(uint8(i))},
			weight:       types.NewCurrency64(uint64(i)),
		}
		hdb.insertNode(&entry)
		selections += i * expectedPerWeight
	}

	// Perform many random selections, noting which host was selected each
	// time.
	selectionMap := make(map[string]int)
	for i := 0; i < selections; i++ {
		randEntry := hdb.randomHosts(1, nil)
		if len(randEntry) == 0 {
			t.Fatal("no hosts!")
		}
		node, exists := hdb.activeHosts[randEntry[0].NetAddress]
		if !exists {
			t.Fatal("can't find randomly selected node in tree")
		}
		selectionMap[node.hostEntry.weight.String()] += 1
	}

	// Check that each host was selected an expected number of times. An error
	// will be reported if the host of 0 weight is ever selected.
	acceptableError := 0.2
	for weight, timesSelected := range selectionMap {
		intWeight, err := strconv.Atoi(weight)
		if err != nil {
			t.Fatal(err)
		}

		expectedSelected := float64(intWeight * expectedPerWeight)
		if float64(expectedSelected)*acceptableError > float64(timesSelected) || float64(expectedSelected)/acceptableError < float64(timesSelected) {
			t.Error("weighted list not selecting in a uniform distribution based on weight")
			t.Error(expectedSelected)
			t.Error(timesSelected)
		}
	}
}

// TestRepeatInsert inserts 2 hosts with the same address.
func TestRepeatInsert(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}
	hdb := &HostDB{
		activeHosts: make(map[modules.NetAddress]*hostNode),
		allHosts:    make(map[modules.NetAddress]*hostEntry),
		scanPool:    make(chan *hostEntry, scanPoolSize),
	}

	entry1 := hostEntry{
		HostSettings: modules.HostSettings{NetAddress: fakeAddr(0)},
		weight:       types.NewCurrency64(1),
	}
	entry2 := entry1
	hdb.insertNode(&entry1)

	entry2.weight = types.NewCurrency64(100)
	hdb.insertNode(&entry2)
	if len(hdb.activeHosts) != 1 {
		t.Error("insterting the same entry twice should result in only 1 entry in the hostdb")
	}
}

// TestNodeAtWeight tests the nodeAtWeight method.
func TestNodeAtWeight(t *testing.T) {
	// create hostTree
	h1 := new(hostEntry)
	h1.NetAddress = "foo"
	h1.weight = baseWeight
	ht := createNode(nil, h1)

	// overweight
	_, err := ht.nodeAtWeight(baseWeight.Mul(types.NewCurrency64(2)))
	if err != ErrOverweight {
		t.Errorf("expected %v, got %v", ErrOverweight, err)
	}

	h, err := ht.nodeAtWeight(baseWeight)
	if err != nil {
		t.Error(err)
	} else if h.hostEntry != h1 {
		t.Errorf("nodeAtWeight returned wrong node: expected %v, got %v", h1, h.hostEntry)
	}
}

// TestRandomHosts probes the randomHosts function.
func TestRandomHosts(t *testing.T) {
	// Create the hostdb (no dependencies needed).
	hdb := newHostDB(nil, nil, nil, nil, nil, nil)

	// Empty.
	if hosts := hdb.randomHosts(1, nil); len(hosts) != 0 {
		t.Errorf("empty hostdb returns %v hosts: %v", len(hosts), hosts)
	}

	// Insert 3 hosts to be selected.
	entry1 := hostEntry{
		HostSettings: modules.HostSettings{NetAddress: fakeAddr(1)},
		weight:       types.NewCurrency64(1),
	}
	entry2 := hostEntry{
		HostSettings: modules.HostSettings{NetAddress: fakeAddr(2)},
		weight:       types.NewCurrency64(2),
	}
	entry3 := hostEntry{
		HostSettings: modules.HostSettings{NetAddress: fakeAddr(3)},
		weight:       types.NewCurrency64(3),
	}
	hdb.insertNode(&entry1)
	hdb.insertNode(&entry2)
	hdb.insertNode(&entry3)

	if len(hdb.activeHosts) != 3 {
		t.Error("wrong number of hosts")
	}
	if hdb.hostTree.weight.Cmp(types.NewCurrency64(6)) != 0 {
		t.Error("unexpected weight at initialization")
		t.Error(hdb.hostTree.weight)
	}

	// Grab 1 random host.
	randHosts := hdb.randomHosts(1, nil)
	if len(randHosts) != 1 {
		t.Error("didn't get 1 hosts")
	}

	// Grab 2 random hosts.
	randHosts = hdb.randomHosts(2, nil)
	if len(randHosts) != 2 {
		t.Error("didn't get 2 hosts")
	}
	if randHosts[0].NetAddress == randHosts[1].NetAddress {
		t.Error("doubled up")
	}

	// Grab 3 random hosts.
	randHosts = hdb.randomHosts(3, nil)
	if len(randHosts) != 3 {
		t.Error("didn't get 3 hosts")
	}
	if randHosts[0].NetAddress == randHosts[1].NetAddress || randHosts[0].NetAddress == randHosts[2].NetAddress || randHosts[1].NetAddress == randHosts[2].NetAddress {
		t.Error("doubled up")
	}

	// Grab 4 random hosts. 3 should be returned.
	randHosts = hdb.randomHosts(4, nil)
	if len(randHosts) != 3 {
		t.Error("didn't get 3 hosts")
	}
	if randHosts[0].NetAddress == randHosts[1].NetAddress || randHosts[0].NetAddress == randHosts[2].NetAddress || randHosts[1].NetAddress == randHosts[2].NetAddress {
		t.Error("doubled up")
	}

	// Ask for 3 hosts that are not in randHosts. No hosts should be
	// returned.
	uniqueHosts := hdb.randomHosts(3, []modules.NetAddress{
		randHosts[0].NetAddress,
		randHosts[1].NetAddress,
		randHosts[2].NetAddress,
	})
	if len(uniqueHosts) != 0 {
		t.Error("didn't get 0 hosts")
	}

	// Ask for 3 hosts, blacklisting non-existent hosts. 3 should be returned.
	randHosts = hdb.randomHosts(3, []modules.NetAddress{"foo", "bar", "baz"})
	if len(randHosts) != 3 {
		t.Error("didn't get 3 hosts")
	}
	if randHosts[0].NetAddress == randHosts[1].NetAddress || randHosts[0].NetAddress == randHosts[2].NetAddress || randHosts[1].NetAddress == randHosts[2].NetAddress {
		t.Error("doubled up")
	}

}
<|endoftext|>


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

package main

import (
	"encoding/json"
	stderrors "errors"
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

var _ = Suite(&S{})

type S struct{}

func Test(t *testing.T) { TestingT(t) }

type InChecker struct{}

func (c *InChecker) Info() *CheckerInfo {
	return &CheckerInfo{Name: "In", Params: []string{"value", "list"}}
}

func (c *InChecker) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "you should provide two parameters"
	}
	value, ok := params[0].(string)
	if !ok {
		return false, "first parameter should be a string"
	}
	list, ok := params[1].([]string)
	if !ok {
		return false, "second parameter should be a slice"
	}
	for _, item := range list {
		if value == item {
			return true, ""
		}
	}
	return false, ""
}

var In Checker = &InChecker{}

func (s *S) TestAdd(c *C) {
	request, err := http.NewRequest("POST", "/resources/", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Add(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
}

func (s *S) TestBindShouldReturnsLocalhostWhenThePublicHostEnvIsNil(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	os.Setenv("MONGODB_PUBLIC_URI", "")
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	result, err := ioutil.ReadAll(recorder.Body)
	c.Assert(err, IsNil)
	data := map[string]string{}
	json.Unmarshal(result, &data)
	c.Assert(data["MONGO_URI"], Equals, "127.0.0.1:27017")
	c.Assert(data["MONGO_USER"], Equals, "myapp")
	c.Assert(data["MONGO_DATABASE_NAME"], Equals, "myapp")
	c.Assert(data["MONGO_PASSWORD"], Not(HasLen), 0)
}

func (s *S) TestBindWithReplicaSet(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	publicHost := "mongoapi.com:27017"
	os.Setenv("MONGODB_PUBLIC_URI", publicHost)
	os.Setenv("MONGODB_REPLICA_SET", "tsuru")
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	var data map[string]string
	err = json.NewDecoder(recorder.Body).Decode(&data)
	c.Assert(err, IsNil)
	c.Assert(data["MONGO_REPLICA_SET"], Equals, "tsuru")
}

func (s *S) TestBindShouldReturnTheVariables(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	publicHost := "mongoapi.com:27017"
	os.Setenv("MONGODB_PUBLIC_URI", publicHost)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	result, err := ioutil.ReadAll(recorder.Body)
	c.Assert(err, IsNil)
	data := map[string]string{}
	json.Unmarshal(result, &data)
	c.Assert(data["MONGO_URI"], Equals, publicHost)
	c.Assert(data["MONGO_USER"], Equals, "myapp")
	c.Assert(data["MONGO_DATABASE_NAME"], Equals, "myapp")
	c.Assert(data["MONGO_PASSWORD"], Not(HasLen), 0)
}

func (s *S) TestBindShouldCreateTheDatabase(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	databases, err := session().DatabaseNames()
	c.Assert("myapp", In, databases)
}

func (s *S) TestBindShouldAddUserInTheDatabase(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	collection := session().DB("myapp").C("system.users")
	lenght, err := collection.Find(bson.M{"user": "myapp"}).Count()
	c.Assert(lenght, Equals, 1)
}

func (s *S) TestUnbindShouldRemoveTheUser(c *C) {
	name := "myapp"
	database := session().DB(name)
	database.AddUser(name, "", false)
	defer func() {
		database.DropDatabase()
	}()
	request, err := http.NewRequest("DELETE", "/resources/myapp/hostname/10.10.10.10?:name=myapp&hostname=10.10.10.10", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Unbind(recorder, request)
	c.Assert(err, IsNil)
	c.Assert(recorder.Code, Equals, http.StatusOK)
	collection := session().DB(name).C("system.users")
	lenght, err := collection.Find(bson.M{"user": name}).Count()
	c.Assert(lenght, Equals, 0)
}

func (s *S) TestRemoveShouldRemovesTheDatabase(c *C) {
	name := "myapp"
	database := session().DB(name)
	database.AddUser(name, "", false)
	request, err := http.NewRequest("DELETE", "/resources/name?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Remove(recorder, request)
	c.Assert(err, IsNil)
	c.Assert(recorder.Code, Equals, http.StatusOK)
	databases, err := session().DatabaseNames()
	c.Assert(name, Not(In), databases)
}

func (s *S) TestStatus(c *C) {
	name := "myapp"
	database := session().DB(name)
	database.AddUser(name, "", false)
	defer func() {
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	request, err := http.NewRequest("GET", "/resources/myapp/status?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Status(recorder, request)
	c.Assert(err, IsNil)
	c.Assert(recorder.Code, Equals, http.StatusNoContent)
}

func errorHandler(w http.ResponseWriter, r *http.Request) error {
	return stderrors.New("some error")
}

func simpleHandler(w http.ResponseWriter, r *http.Request) error {
	fmt.Fprint(w, "success")
	return nil
}

func (s *S) TestHandlerReturns500WhenInternalHandlerReturnsAnError(c *C) {
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/apps", nil)
	c.Assert(err, IsNil)

	Handler(errorHandler).ServeHTTP(recorder, request)
	c.Assert(recorder.Code, Equals, 500)
	c.Assert(recorder.Body.String(), Equals, "some error\n")
}

func (s *S) TestHandlerShouldPassAnHandlerWithoutError(c *C) {
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/apps", nil)
	c.Assert(err, IsNil)

	Handler(simpleHandler).ServeHTTP(recorder, request)
	c.Assert(recorder.Code, Equals, 200)
	c.Assert(recorder.Body.String(), Equals, "success")
}
<commit_msg>handler: fix test names<commit_after>// Copyright 2013 mongoapi authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	stderrors "errors"
	"fmt"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

var _ = Suite(&S{})

type S struct{}

func Test(t *testing.T) { TestingT(t) }

type InChecker struct{}

func (c *InChecker) Info() *CheckerInfo {
	return &CheckerInfo{Name: "In", Params: []string{"value", "list"}}
}

func (c *InChecker) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "you should provide two parameters"
	}
	value, ok := params[0].(string)
	if !ok {
		return false, "first parameter should be a string"
	}
	list, ok := params[1].([]string)
	if !ok {
		return false, "second parameter should be a slice"
	}
	for _, item := range list {
		if value == item {
			return true, ""
		}
	}
	return false, ""
}

var In Checker = &InChecker{}

func (s *S) TestAdd(c *C) {
	request, err := http.NewRequest("POST", "/resources/", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	Add(recorder, request)
	c.Assert(recorder.Code, Equals, http.StatusCreated)
}

func (s *S) TestBindShouldReturnLocalhostWhenThePublicHostEnvIsNil(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	os.Setenv("MONGODB_PUBLIC_URI", "")
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	result, err := ioutil.ReadAll(recorder.Body)
	c.Assert(err, IsNil)
	data := map[string]string{}
	json.Unmarshal(result, &data)
	c.Assert(data["MONGO_URI"], Equals, "127.0.0.1:27017")
	c.Assert(data["MONGO_USER"], Equals, "myapp")
	c.Assert(data["MONGO_DATABASE_NAME"], Equals, "myapp")
	c.Assert(data["MONGO_PASSWORD"], Not(HasLen), 0)
}

func (s *S) TestBindWithReplicaSet(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	publicHost := "mongoapi.com:27017"
	os.Setenv("MONGODB_PUBLIC_URI", publicHost)
	os.Setenv("MONGODB_REPLICA_SET", "tsuru")
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	var data map[string]string
	err = json.NewDecoder(recorder.Body).Decode(&data)
	c.Assert(err, IsNil)
	c.Assert(data["MONGO_REPLICA_SET"], Equals, "tsuru")
}

func (s *S) TestBindShouldReturnTheVariables(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	publicHost := "mongoapi.com:27017"
	os.Setenv("MONGODB_PUBLIC_URI", publicHost)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	result, err := ioutil.ReadAll(recorder.Body)
	c.Assert(err, IsNil)
	data := map[string]string{}
	json.Unmarshal(result, &data)
	c.Assert(data["MONGO_URI"], Equals, publicHost)
	c.Assert(data["MONGO_USER"], Equals, "myapp")
	c.Assert(data["MONGO_DATABASE_NAME"], Equals, "myapp")
	c.Assert(data["MONGO_PASSWORD"], Not(HasLen), 0)
}

func (s *S) TestBindShouldCreateTheDatabase(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	databases, err := session().DatabaseNames()
	c.Assert("myapp", In, databases)
}

func (s *S) TestBindShouldAddUserInTheDatabase(c *C) {
	request, err := http.NewRequest("POST", "/resources/myapp?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Bind(recorder, request)
	c.Assert(err, IsNil)
	defer func() {
		database := session().DB("myapp")
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	c.Assert(recorder.Code, Equals, http.StatusCreated)
	collection := session().DB("myapp").C("system.users")
	lenght, err := collection.Find(bson.M{"user": "myapp"}).Count()
	c.Assert(lenght, Equals, 1)
}

func (s *S) TestUnbindShouldRemoveTheUser(c *C) {
	name := "myapp"
	database := session().DB(name)
	database.AddUser(name, "", false)
	defer func() {
		database.DropDatabase()
	}()
	request, err := http.NewRequest("DELETE", "/resources/myapp/hostname/10.10.10.10?:name=myapp&hostname=10.10.10.10", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Unbind(recorder, request)
	c.Assert(err, IsNil)
	c.Assert(recorder.Code, Equals, http.StatusOK)
	collection := session().DB(name).C("system.users")
	lenght, err := collection.Find(bson.M{"user": name}).Count()
	c.Assert(lenght, Equals, 0)
}

func (s *S) TestRemoveShouldRemovesTheDatabase(c *C) {
	name := "myapp"
	database := session().DB(name)
	database.AddUser(name, "", false)
	request, err := http.NewRequest("DELETE", "/resources/name?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Remove(recorder, request)
	c.Assert(err, IsNil)
	c.Assert(recorder.Code, Equals, http.StatusOK)
	databases, err := session().DatabaseNames()
	c.Assert(name, Not(In), databases)
}

func (s *S) TestStatus(c *C) {
	name := "myapp"
	database := session().DB(name)
	database.AddUser(name, "", false)
	defer func() {
		database.RemoveUser("myapp")
		database.DropDatabase()
	}()
	request, err := http.NewRequest("GET", "/resources/myapp/status?:name=myapp", nil)
	c.Assert(err, IsNil)
	recorder := httptest.NewRecorder()
	err = Status(recorder, request)
	c.Assert(err, IsNil)
	c.Assert(recorder.Code, Equals, http.StatusNoContent)
}

func errorHandler(w http.ResponseWriter, r *http.Request) error {
	return stderrors.New("some error")
}

func simpleHandler(w http.ResponseWriter, r *http.Request) error {
	fmt.Fprint(w, "success")
	return nil
}

func (s *S) TestHandlerReturns500WhenInternalHandlerReturnsAnError(c *C) {
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/apps", nil)
	c.Assert(err, IsNil)

	Handler(errorHandler).ServeHTTP(recorder, request)
	c.Assert(recorder.Code, Equals, 500)
	c.Assert(recorder.Body.String(), Equals, "some error\n")
}

func (s *S) TestHandlerShouldPassAnHandlerWithoutError(c *C) {
	recorder := httptest.NewRecorder()
	request, err := http.NewRequest("GET", "/apps", nil)
	c.Assert(err, IsNil)

	Handler(simpleHandler).ServeHTTP(recorder, request)
	c.Assert(recorder.Code, Equals, 200)
	c.Assert(recorder.Body.String(), Equals, "success")
}
<|endoftext|>


<commit_before>package handlers

import (
	"errors"
	"strconv"

	"github.com/byuoitav/sony-control-microservice/helpers"
	"github.com/labstack/echo"
)

func PowerOn(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "wakeup")
	if err != nil {
		return err
	}

	return nil
}

func Standby(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "poweroff")
	if err != nil {
		return err
	}

	return nil
}

func SwitchInput(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), context.Param("port")) // Input must be hdmi1, hdmi2, etc.
	if err != nil {
		return err
	}

	return nil
}

func SetVolume(context echo.Context) error {
	address := context.Param("address")
	difference, err := strconv.Atoi(context.Param("difference"))
	if err != nil {
		return err
	}
	//Setting volume up
	if difference > 0 {
		for i := 0; i < difference; i++ {
			_, err := helpers.SendCommand(address, "volumeup")
			if err != nil {
				return err
			}
		}
	} else if difference < 0 {
		for i := 0; i > difference; i-- {
			_, err := helpers.SendCommand(address, "volumedown")
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func CalibrateVolume(context echo.Context) error {
	address := context.Param("address")
	def, err := strconv.Atoi(context.Param("default"))
	if err != nil {
		return err
	}
	if def < 0 || def > 100 {
		return errors.New("Invalid default value, must be in range 0-100")
	}

	//drop volume to zero.
	for i := 0; i < 125; i++ {
		_, err := helpers.SendCommand(address, "volumedown")
		if err != nil {
			return err
		}
	}
	//set voulme to 25
	for i := 0; i < def; i++ {
		_, err := helpers.SendCommand(address, "volumeup")
		if err != nil {
			return err
		}
	}
	return nil
}

func VolumeUp(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "volumeup")
	if err != nil {
		return err
	}

	return nil
}

func VolumeDown(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "volumedown")
	if err != nil {
		return err
	}

	return nil
}
func VolumeUnmute(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "mute")
	if err != nil {
		return err
	}

	return nil
}
func VolumeMute(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "mute")
	if err != nil {
		return err
	}

	return nil
}

func BlankDisplay(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "pictureoff")
	if err != nil {
		return err
	}

	return nil
}

func UnblankDisplay(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "pictureoff")
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Logging<commit_after>package handlers

import (
	"errors"
	"log"
	"strconv"

	"github.com/byuoitav/sony-control-microservice/helpers"
	"github.com/labstack/echo"
)

func PowerOn(context echo.Context) error {
	log.Printf("Powering on %s...", context.Param("address"))
	_, err := helpers.SendCommand(context.Param("address"), "wakeup")
	if err != nil {
		return err
	}
	log.Printf("Done.")
	return nil
}

func Standby(context echo.Context) error {
	log.Printf("Powering off %s...", context.Param("address"))
	_, err := helpers.SendCommand(context.Param("address"), "poweroff")
	if err != nil {
		return err
	}
	log.Printf("Done.")
	return nil
}

func SwitchInput(context echo.Context) error {
	log.Printf("Switching input for %s to %s ...", context.Param("address"), context.Param("port"))
	_, err := helpers.SendCommand(context.Param("address"), context.Param("port")) // Input must be hdmi1, hdmi2, etc.
	if err != nil {
		return err
	}
	log.Printf("Done.")
	return nil
}

func SetVolume(context echo.Context) error {
	address := context.Param("address")
	difference, err := strconv.Atoi(context.Param("difference"))
	if err != nil {
		return err
	}

	log.Printf("Setting volume for %s by %v...", address, difference)
	//Setting volume up
	if difference > 0 {
		for i := 0; i < difference; i++ {
			_, err := helpers.SendCommand(address, "volumeup")
			if err != nil {
				return err
			}
		}
	} else if difference < 0 {
		for i := 0; i > difference; i-- {
			_, err := helpers.SendCommand(address, "volumedown")
			if err != nil {
				return err
			}
		}
	}
	log.Printf("Done.")
	return nil
}

func CalibrateVolume(context echo.Context) error {
	address := context.Param("address")
	log.Printf("Calibrating volume for %s...", address)
	def, err := strconv.Atoi(context.Param("default"))
	if err != nil {
		return err
	}
	if def < 0 || def > 100 {
		return errors.New("Invalid default value, must be in range 0-100")
	}

	//drop volume to zero.
	for i := 0; i < 125; i++ {
		_, err := helpers.SendCommand(address, "volumedown")
		if err != nil {
			return err
		}
	}
	//set voulme to 25
	for i := 0; i < def; i++ {
		_, err := helpers.SendCommand(address, "volumeup")
		if err != nil {
			return err
		}
	}
	log.Printf("Done.")
	return nil
}

func VolumeUp(context echo.Context) error {
	log.Printf("Setting volume up for %s...", context.Param("address"))
	_, err := helpers.SendCommand(context.Param("address"), "volumeup")
	if err != nil {
		return err
	}

	return nil
}

func VolumeDown(context echo.Context) error {
	log.Printf("Setting volume down for %s...", context.Param("address"))
	_, err := helpers.SendCommand(context.Param("address"), "volumedown")
	if err != nil {
		return err
	}

	log.Printf("Done.")
	return nil
}
func VolumeUnmute(context echo.Context) error {
	log.Printf("Unmuting %s...", context.Param("address"))
	_, err := helpers.SendCommand(context.Param("address"), "mute")
	if err != nil {
		return err
	}

	return nil
}
func VolumeMute(context echo.Context) error {
	log.Printf("Muting %s...", context.Param("address"))
	_, err := helpers.SendCommand(context.Param("address"), "mute")
	if err != nil {
		return err
	}

	log.Printf("Done.")
	return nil
}

func BlankDisplay(context echo.Context) error {
	_, err := helpers.SendCommand(context.Param("address"), "pictureoff")
	if err != nil {
		return err
	}

	log.Printf("Done.")
	return nil
}

func UnblankDisplay(context echo.Context) error {
	log.Printf("Blanking %s...", context.Param("address"))
	_, err := helpers.SendCommand(context.Param("address"), "pictureoff")
	if err != nil {
		return err
	}
	log.Printf("Done.")
	return nil
}
<|endoftext|>


<commit_before>package gofakeit

import (
	"fmt"
	"math/rand"
	"strings"
)

// DomainName will generate a random url domain name
func DomainName() string {
	return strings.ToLower(JobDescriptor()+BS()) + "." + DomainSuffix()
}

// DomainSuffix will generate a random domain suffix
func DomainSuffix() string {
	return getRandValue([]string{"internet", "domain_suffix"})
}

// URL will generate a random url string
func URL() string {
	url := "http" + RandString([]string{"s", ""}) + "://www."
	url += DomainName()

	// Slugs
	num := Number(1, 4)
	slug := make([]string, num)
	for i := 0; i < num; i++ {
		slug[i] = BS()
	}
	url += "/" + strings.ToLower(strings.Join(slug, "/"))

	return url
}

// HTTPMethod will generate a random http method
func HTTPMethod() string {
	return getRandValue([]string{"internet", "http_method"})
}

// IPv4Address will generate a random version 4 ip address
func IPv4Address() string {
	num := func() int { return 2 + rand.Intn(254) }
	return fmt.Sprintf("%d.%d.%d.%d", num(), num(), num(), num())
}

// IPv6Address will generate a random version 6 ip address
func IPv6Address() string {
	num := 65536
	return fmt.Sprintf("2001:cafe:%x:%x:%x:%x:%x:%x", rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num))
}

// MacAddress will generate a random mac address
func MacAddress() string {
	num := 255
	return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num))
}

// Username will genrate a random username based upon picking a random lastname and random numbers at the end
func Username() string {
	return getRandValue([]string{"person", "last"}) + replaceWithNumbers("####")
}
<commit_msg>internet - fix possible spacing in url string<commit_after>package gofakeit

import (
	"fmt"
	"math/rand"
	"strings"
)

// DomainName will generate a random url domain name
func DomainName() string {
	return strings.Replace(strings.ToLower(JobDescriptor()+BS()), " ", "", -1) + "." + DomainSuffix()
}

// DomainSuffix will generate a random domain suffix
func DomainSuffix() string {
	return getRandValue([]string{"internet", "domain_suffix"})
}

// URL will generate a random url string
func URL() string {
	url := "http" + RandString([]string{"s", ""}) + "://www."
	url += DomainName()

	// Slugs
	num := Number(1, 4)
	slug := make([]string, num)
	for i := 0; i < num; i++ {
		slug[i] = BS()
	}
	url += "/" + strings.ToLower(strings.Join(slug, "/"))

	return url
}

// HTTPMethod will generate a random http method
func HTTPMethod() string {
	return getRandValue([]string{"internet", "http_method"})
}

// IPv4Address will generate a random version 4 ip address
func IPv4Address() string {
	num := func() int { return 2 + rand.Intn(254) }
	return fmt.Sprintf("%d.%d.%d.%d", num(), num(), num(), num())
}

// IPv6Address will generate a random version 6 ip address
func IPv6Address() string {
	num := 65536
	return fmt.Sprintf("2001:cafe:%x:%x:%x:%x:%x:%x", rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num))
}

// MacAddress will generate a random mac address
func MacAddress() string {
	num := 255
	return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num))
}

// Username will genrate a random username based upon picking a random lastname and random numbers at the end
func Username() string {
	return getRandValue([]string{"person", "last"}) + replaceWithNumbers("####")
}
<|endoftext|>


<commit_before>package gofakeit

import (
	"fmt"
	"math/rand"
	"strings"
)

// DomainName will generate a random url domain name
func DomainName() string {
	return strings.Replace(strings.ToLower(JobDescriptor()+BS()), " ", "", -1) + "." + DomainSuffix()
}

// DomainSuffix will generate a random domain suffix
func DomainSuffix() string {
	return getRandValue([]string{"internet", "domain_suffix"})
}

// URL will generate a random url string
func URL() string {
	// Slugs
	num := Number(1, 4)
	slug := make([]string, num)
	for i := 0; i < num; i++ {
		slug[i] = BS()
	}
	url := "http" + RandString([]string{"s", ""}) + "://www." + DomainName() + "/" + strings.ToLower(strings.Join(slug, "/"))

	return url
}

// HTTPMethod will generate a random http method
func HTTPMethod() string {
	return getRandValue([]string{"internet", "http_method"})
}

// IPv4Address will generate a random version 4 ip address
func IPv4Address() string {
	num := func() int { return 2 + rand.Intn(254) }
	return fmt.Sprintf("%d.%d.%d.%d", num(), num(), num(), num())
}

// IPv6Address will generate a random version 6 ip address
func IPv6Address() string {
	num := 65536
	return fmt.Sprintf("2001:cafe:%x:%x:%x:%x:%x:%x", rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num))
}

// MacAddress will generate a random mac address
func MacAddress() string {
	num := 255
	return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num))
}

// Username will genrate a random username based upon picking a random lastname and random numbers at the end
func Username() string {
	return getRandValue([]string{"person", "last"}) + replaceWithNumbers("####")
}
<commit_msg>url - fix possible space in url<commit_after>package gofakeit

import (
	"fmt"
	"math/rand"
	"strings"
)

// DomainName will generate a random url domain name
func DomainName() string {
	return strings.Replace(strings.ToLower(JobDescriptor()+BS()), " ", "", -1) + "." + DomainSuffix()
}

// DomainSuffix will generate a random domain suffix
func DomainSuffix() string {
	return getRandValue([]string{"internet", "domain_suffix"})
}

// URL will generate a random url string
func URL() string {
	// Slugs
	num := Number(1, 4)
	slug := make([]string, num)
	for i := 0; i < num; i++ {
		slug[i] = BS()
	}
	url := "http" + RandString([]string{"s", ""}) + "://www." + DomainName() + "/" + strings.ToLower(strings.Join(slug, "/"))
	url = strings.ReplaceAll(url, " ", "")

	return url
}

// HTTPMethod will generate a random http method
func HTTPMethod() string {
	return getRandValue([]string{"internet", "http_method"})
}

// IPv4Address will generate a random version 4 ip address
func IPv4Address() string {
	num := func() int { return 2 + rand.Intn(254) }
	return fmt.Sprintf("%d.%d.%d.%d", num(), num(), num(), num())
}

// IPv6Address will generate a random version 6 ip address
func IPv6Address() string {
	num := 65536
	return fmt.Sprintf("2001:cafe:%x:%x:%x:%x:%x:%x", rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num))
}

// MacAddress will generate a random mac address
func MacAddress() string {
	num := 255
	return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num), rand.Intn(num))
}

// Username will genrate a random username based upon picking a random lastname and random numbers at the end
func Username() string {
	return getRandValue([]string{"person", "last"}) + replaceWithNumbers("####")
}
<|endoftext|>


<commit_before>// Package main is the entry point to directly run an Ios server as an executable
package main

import (
	"flag"
	"github.com/golang/glog"
	"github.com/heidi-ann/ios/config"
	"github.com/heidi-ann/ios/ios/server"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
)

// command line flags
var id = flag.Int("id", -1, "server ID [REQUIRED]")                                                                                // required flag
var configFile = flag.String("config", os.Getenv("GOPATH")+"/src/github.com/heidi-ann/ios/ios/example.conf", "Server configuration file") // optional flag
var diskPath = flag.String("disk", "persistent_id", "Path to directory to store persistent storage")                                      // optional flag
var peerPort = flag.Int("listen-peers", 0, "Overwrite the port specified in config file to listen for peers on")                          // optional flag
var clientPort = flag.Int("listen-clients", 0, "Overwrite the port specified in config file to listen for clients on")                    // optional flag

// entry point of server executable
func main() {
	// set up logging
	flag.Parse()
	defer glog.Flush()

	// check go path is set
	if *configFile == "/src/github.com/heidi-ann/ios/ios/example.conf" {
		glog.Fatal("GOPATH not set")
	}

	// parse configuration file
	conf := config.ParseServerConfig(*configFile)
	if *id == -1 {
		glog.Fatal("ID is required")
	}
	if *id >= len(conf.Peers.Address) {
		glog.Fatal("Node ID is ", *id, " but is configured with a ", len(conf.Peers.Address), " node cluster")
	}

	// add ID to diskPath
	disk := *diskPath + strconv.Itoa(*id)

	// overwrite ports if given
	if *peerPort != 0 {
		glog.Info("Peer port overwritten to ", *peerPort)
		ip := strings.Split(conf.Peers.Address[*id], ":")[0]
		conf.Peers.Address[*id] = ip + ":" + strconv.Itoa(*peerPort)
	}

	if *clientPort != 0 {
		glog.Info("Client port overwritten to ", *clientPort)
		ip := strings.Split(conf.Clients.Address[*id], ":")[0]
		conf.Clients.Address[*id] = ip + ":" + strconv.Itoa(*clientPort)
	}

	// logging
	glog.Info("Starting server ", *id)
	defer glog.Warning("Shutting down server ", *id)

	// start Ios server
	go server.RunIos(*id, conf, disk)

	// waiting for exit
	// always flush (whatever happens)
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	sig := <-sigs
	glog.Flush()
	glog.Warning("Shutting down due to ", sig)
}
<commit_msg>quick fix in master.go<commit_after>// Package main is the entry point to directly run an Ios server as an executable
package main

import (
	"flag"
	"github.com/golang/glog"
	"github.com/heidi-ann/ios/config"
	"github.com/heidi-ann/ios/ios/server"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
)

// command line flags
var id = flag.Int("id", -1, "server ID [REQUIRED]")                                                                                // required flag
var configFile = flag.String("config", os.Getenv("GOPATH")+"/src/github.com/heidi-ann/ios/ios/example.conf", "Server configuration file") // optional flag
var diskPath = flag.String("disk", "persistent_id", "Path to directory to store persistent storage")                                      // optional flag
var peerPort = flag.Int("listen-peers", 0, "Overwrite the port specified in config file to listen for peers on")                          // optional flag
var clientPort = flag.Int("listen-clients", 0, "Overwrite the port specified in config file to listen for clients on")                    // optional flag

// entry point of server executable
func main() {
	// set up logging
	flag.Parse()
	defer glog.Flush()

	// check go path is set
	if *configFile == "/src/github.com/heidi-ann/ios/ios/example.conf" {
		glog.Fatal("GOPATH not set")
	}

	// parse configuration file
	conf := config.ParseServerConfig(*configFile)
	if *id == -1 {
		glog.Fatal("ID is required")
	}
	if *id >= len(conf.Peers.Address) {
		glog.Fatal("Node ID is ", *id, " but is configured with a ", len(conf.Peers.Address), " node cluster")
	}

	// add ID to diskPath
	disk := *diskPath
	if disk == "persistent_id" {
		disk = "persistent_id" + strconv.Itoa(*id)
	}

	// overwrite ports if given
	if *peerPort != 0 {
		glog.Info("Peer port overwritten to ", *peerPort)
		ip := strings.Split(conf.Peers.Address[*id], ":")[0]
		conf.Peers.Address[*id] = ip + ":" + strconv.Itoa(*peerPort)
	}

	if *clientPort != 0 {
		glog.Info("Client port overwritten to ", *clientPort)
		ip := strings.Split(conf.Clients.Address[*id], ":")[0]
		conf.Clients.Address[*id] = ip + ":" + strconv.Itoa(*clientPort)
	}

	// logging
	glog.Info("Starting server ", *id)
	defer glog.Warning("Shutting down server ", *id)

	// start Ios server
	go server.RunIos(*id, conf, disk)

	// waiting for exit
	// always flush (whatever happens)
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	sig := <-sigs
	glog.Flush()
	glog.Warning("Shutting down due to ", sig)
}
<|endoftext|>


<commit_before>// irc descibes the basic client functionalities of irken
package irc

import (
	"bufio"
	"net"
	"time"
)

const DEFAULT_PORT = "6667"

type Conn struct {
	// user info
	nick string

	// network utils
	io   *bufio.ReadWriter
	sock *net.TCPConn

	// server properties
	pingFreq time.Duration
}

// NewConn takes a remote network address and a default nick.
// It then tries to connect to the supplied address with the
// properties of the supplied session
func NewConn(addr string, nick string) (*Conn, error) {

	//TODO: check if addr already contains another port then the default port.

	addr += ":" + DEFAULT_PORT
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}
	sock, err := net.DialTCP("tcp", nil, tcpAddr)
	if err != nil {
		return nil, err
	}

	io := bufio.NewReadWriter(bufio.NewReader(sock), bufio.NewWriter(sock))

	return &Conn{nick, io, sock, time.Minute}, nil
}

// Read attempts to read from the connected server and puts the data into io buffer.
// It will wait until it gets one line of a string.
func (c *Conn) Read() (string, error) {
	data, err := c.io.ReadString('\n')
	return data, err
}

// Write attempts to write a string into the io buffer and
// flushes it, sending the data to the connected server
func (c *Conn) Write(s string) error {
	_, err := c.io.WriteString(s + "\r\n")
	if err != nil {
		return err
	}
	err = c.io.Flush()
	if err != nil {
		return err
	}

	return nil
}

// Close attempts to close the connection to the server
func (c *Conn) Close() {
	c.sock.Close()
}
<commit_msg>starting parser code<commit_after>// irc descibes the basic client functionalities of irken
package irc

import (
	"bufio"
	"net"
	"strings"
	"time"
)

const DEFAULT_PORT = "6667"

type Conn struct {
	// user info
	nick string

	// network utils
	io   *bufio.ReadWriter
	sock *net.TCPConn

	// server properties
	pingFreq time.Duration
}

// NewConn takes a remote network address and a default nick.
// It then tries to connect to the supplied address with the
// properties of the supplied session
func NewConn(addr string, nick string) (*Conn, error) {

	//TODO: check if addr already contains another port then the default port.

	addr += ":" + DEFAULT_PORT
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return nil, err
	}
	sock, err := net.DialTCP("tcp", nil, tcpAddr)
	if err != nil {
		return nil, err
	}

	io := bufio.NewReadWriter(bufio.NewReader(sock), bufio.NewWriter(sock))

	return &Conn{nick, io, sock, time.Minute}, nil
}

// Read attempts to read from the connected server and puts the data into io buffer.
// It will wait until it gets one line of a string.
func (c *Conn) Read() (string, error) {
	data, err := c.io.ReadString('\n')
	return strings.Replace(data, "\n", "", -1), err
}

// Write attempts to write a string into the io buffer and
// flushes it, sending the data to the connected server
func (c *Conn) Write(s string) error {
	_, err := c.io.WriteString(s + "\r\n")
	if err != nil {
		return err
	}
	err = c.io.Flush()
	if err != nil {
		return err
	}

	return nil
}

// Close attempts to close the connection to the server
func (c *Conn) Close() {
	c.sock.Close()
}
<|endoftext|>


<commit_before>/*
	Copyright (c) 2016, Percona LLC and/or its affiliates. All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package pmm

import (
	"crypto/tls"
	"fmt"
	"math"
	"net"
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

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

// CheckNetwork check connectivity between client and server.
func (a *Admin) CheckNetwork(noEmoji bool) error {
	// Check QAN API health.
	qanStatus := false
	url := a.qanAPI.URL(a.serverURL, qanAPIBasePath, "ping")
	if resp, _, err := a.qanAPI.Get(url); err == nil {
		if resp.StatusCode == http.StatusOK && resp.Header.Get("X-Percona-Qan-Api-Version") != "" {
			qanStatus = true
		}
	}

	// Check Prometheus API by retriving all "up" time series.
	promStatus := true
	promData, err := a.promQueryAPI.Query(context.Background(), "up", time.Now())
	if err != nil {
		promStatus = false
	}

	fmt.Print("PMM Network Status\n\n")
	fmt.Printf("%-14s | %s\n", "Server Address", a.Config.ServerAddress)
	fmt.Printf("%-14s | %s\n\n", "Client Address", a.Config.ClientAddress)

	t := a.getNginxHeader("X-Server-Time")
	if t != "" {
		fmt.Println("* System Time")
		s, _ := strconv.ParseInt(t, 10, 64)
		serverTime := time.Unix(s, 0)
		clientTime := time.Now()
		fmt.Printf("%-10s | %s\n", "Server", serverTime.Format("2006-01-02 15:04:05 -0700 MST"))
		fmt.Printf("%-10s | %s\n", "Client", clientTime.Format("2006-01-02 15:04:05 -0700 MST"))
		drift := math.Abs(float64(serverTime.Unix()) - float64(clientTime.Unix()))
		driftText := emojiStatus(noEmoji, true)
		if drift > 300 {
			driftText = fmt.Sprintf("%s  %.0fs", emojiStatus(noEmoji, false), drift)
			driftText += "\n\nTime is out of sync. Please make sure the server time is correct to see the metrics."
		}
		fmt.Printf("%-10s | %s\n\n\n", "Time Drift", driftText)
	}

	fmt.Println("* Client --> Server")
	fmt.Printf("%-15s %-13s\n", strings.Repeat("-", 15), strings.Repeat("-", 8))
	fmt.Printf("%-15s %-13s\n", "SERVER SERVICE", "STATUS")
	fmt.Printf("%-15s %-13s\n", strings.Repeat("-", 15), strings.Repeat("-", 8))
	// Consul is always alive if we are at this point.
	fmt.Printf("%-15s %-13s\n", "Consul API", emojiStatus(noEmoji, true))
	fmt.Printf("%-15s %-13s\n", "QAN API", emojiStatus(noEmoji, qanStatus))
	fmt.Printf("%-15s %-13s\n\n", "Prometheus API", emojiStatus(noEmoji, promStatus))

	a.testNetwork()
	fmt.Println()

	node, _, err := a.consulAPI.Catalog().Node(a.Config.ClientName, nil)
	if err != nil || node == nil {
		fmt.Printf("%s '%s'.\n\n", noMonitoring, a.Config.ClientName)
		return nil
	}

	if !promStatus {
		fmt.Print("Prometheus is down. Please check if PMM server container runs properly.\n\n")
		return nil
	}

	fmt.Println()
	fmt.Println("* Client <-- Server")
	if len(node.Services) == 0 {
		fmt.Print("No metric endpoints registered.\n\n")
		return nil
	}

	// Check Prometheus endpoint status.
	svcTable := []instanceStatus{}
	errStatus := false
	for _, svc := range node.Services {
		if !strings.HasSuffix(svc.Service, ":metrics") {
			continue
		}

		name := "-"
		for _, tag := range svc.Tags {
			if strings.HasPrefix(tag, "alias_") {
				name = tag[6:]
				continue
			}

		}

		status := checkPromTargetStatus(promData.String(), name, strings.Split(svc.Service, ":")[0])
		if !status {
			errStatus = true
		}
		row := instanceStatus{
			Type:   svc.Service,
			Name:   name,
			Port:   fmt.Sprintf("%d", svc.Port),
			Status: emojiStatus(noEmoji, status),
		}
		svcTable = append(svcTable, row)
	}

	maxTypeLen := len("SERVICE TYPE")
	maxNameLen := len("NAME")
	for _, in := range svcTable {
		if len(in.Type) > maxTypeLen {
			maxTypeLen = len(in.Type)
		}
		if len(in.Name) > maxNameLen {
			maxNameLen = len(in.Name)
		}
	}
	maxTypeLen++
	maxNameLen++
	linefmt := "%-" + fmt.Sprintf("%d", maxTypeLen) + "s %-" + fmt.Sprintf("%d", maxNameLen) + "s %-22s %-8s\n"
	fmt.Printf(linefmt, strings.Repeat("-", maxTypeLen), strings.Repeat("-", maxNameLen), strings.Repeat("-", 22),
		strings.Repeat("-", 8))
	fmt.Printf(linefmt, "SERVICE TYPE", "NAME", "REMOTE ENDPOINT", "STATUS")
	fmt.Printf(linefmt, strings.Repeat("-", maxTypeLen), strings.Repeat("-", maxNameLen), strings.Repeat("-", 22),
		strings.Repeat("-", 8))
	sort.Sort(sortOutput(svcTable))
	for _, i := range svcTable {
		fmt.Printf(linefmt, i.Type, i.Name, a.Config.ClientAddress+":"+i.Port, i.Status)
	}

	if errStatus {
		fmt.Println(`
When an endpoint is down it may indicate that the corresponding service is stopped (run 'pmm-admin list' to verify).
If it's running, check out the logs /var/log/pmm-*.log

When all endpoints are down but 'pmm-admin list' shows they are up and no errors in the logs,
check the firewall settings whether this system allows incoming connections from server to address:port in question.`)
	}
	fmt.Println()
	return nil
}

// testNetwork measure round trip duration of server connection.
func (a *Admin) testNetwork() {
	insecureFlag := false
	if a.Config.ServerInsecureSSL {
		insecureFlag = true
	}

	conn := &networkTransport{
		dialer: &net.Dialer{
			Timeout:   a.apiTimeout,
			KeepAlive: a.apiTimeout,
		},
	}
	conn.rtp = &http.Transport{
		Proxy:           http.ProxyFromEnvironment,
		Dial:            conn.dial,
		TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureFlag},
	}
	client := &http.Client{Transport: conn}

	resp, err := client.Get(a.serverURL)
	if err != nil {
		fmt.Println("Unable to measure the connection performance.")
		return
	}
	defer resp.Body.Close()

	fmt.Printf("%-19s | %v\n", "Connection duration", conn.connEnd.Sub(conn.connStart))
	fmt.Printf("%-19s | %v\n", "Request duration", conn.reqEnd.Sub(conn.reqStart)-conn.connEnd.Sub(conn.connStart))
	fmt.Printf("%-19s | %v\n", "Full round trip", conn.reqEnd.Sub(conn.reqStart))
}

type networkTransport struct {
	rtp       http.RoundTripper
	dialer    *net.Dialer
	connStart time.Time
	connEnd   time.Time
	reqStart  time.Time
	reqEnd    time.Time
}

func (conn *networkTransport) RoundTrip(r *http.Request) (*http.Response, error) {
	conn.reqStart = time.Now()
	resp, err := conn.rtp.RoundTrip(r)
	conn.reqEnd = time.Now()
	return resp, err
}

func (conn *networkTransport) dial(network, addr string) (net.Conn, error) {
	conn.connStart = time.Now()
	cn, err := conn.dialer.Dial(network, addr)
	conn.connEnd = time.Now()
	return cn, err
}

// checkPromTargetStatus check Prometheus target state by metric labels.
func checkPromTargetStatus(data, alias, job string) bool {
	r, _ := regexp.Compile(fmt.Sprintf(`up{.*instance="%s".*job="%s".*} => 1`, alias, job))
	for _, row := range strings.Split(data, "\n") {
		if r.MatchString(row) {
			return true
		}
	}
	return false
}

// Map status to emoji or text.
func emojiStatus(noEmoji, status bool) string {
	switch true {
	case noEmoji && status:
		return "OK"
	case noEmoji && !status:
		return "PROBLEM"
	case !noEmoji && status:
		return emojiHappy
	case !noEmoji && !status:
		return emojiUnhappy
	}
	return "N/A"
}
<commit_msg>Improved time check.<commit_after>/*
	Copyright (c) 2016, Percona LLC and/or its affiliates. All rights reserved.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package pmm

import (
	"crypto/tls"
	"fmt"
	"math"
	"net"
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"

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

// CheckNetwork check connectivity between client and server.
func (a *Admin) CheckNetwork(noEmoji bool) error {
	// Check QAN API health.
	qanStatus := false
	url := a.qanAPI.URL(a.serverURL, qanAPIBasePath, "ping")
	if resp, _, err := a.qanAPI.Get(url); err == nil {
		if resp.StatusCode == http.StatusOK && resp.Header.Get("X-Percona-Qan-Api-Version") != "" {
			qanStatus = true
		}
	}

	// Check Prometheus API by retriving all "up" time series.
	promStatus := true
	promData, err := a.promQueryAPI.Query(context.Background(), "up", time.Now())
	if err != nil {
		promStatus = false
	}

	fmt.Print("PMM Network Status\n\n")
	fmt.Printf("%-14s | %s\n", "Server Address", a.Config.ServerAddress)
	fmt.Printf("%-14s | %s\n\n", "Client Address", a.Config.ClientAddress)

	t := a.getNginxHeader("X-Server-Time")
	if t != "" {
		fmt.Println("* System Time")
		var serverTime time.Time
		if s, err := strconv.ParseInt(t, 10, 64); err == nil {
			serverTime = time.Unix(s, 0)
		} else {
			serverTime, _ = time.Parse("Monday, 02-Jan-2006 15:04:05 MST", t)
		}
		clientTime := time.Now()
		fmt.Printf("%-10s | %s\n", "Server", serverTime.Format("2006-01-02 15:04:05 -0700 MST"))
		fmt.Printf("%-10s | %s\n", "Client", clientTime.Format("2006-01-02 15:04:05 -0700 MST"))
		drift := math.Abs(float64(serverTime.Unix()) - float64(clientTime.Unix()))
		driftText := emojiStatus(noEmoji, true)
		if drift > 120 {
			driftText = fmt.Sprintf("%s  %.0fs", emojiStatus(noEmoji, false), drift)
			driftText += "\n\nTime is out of sync. Please make sure the server time is correct to see the metrics."
		}
		fmt.Printf("%-10s | %s\n\n\n", "Time Drift", driftText)
	}

	fmt.Println("* Client --> Server")
	fmt.Printf("%-15s %-13s\n", strings.Repeat("-", 15), strings.Repeat("-", 8))
	fmt.Printf("%-15s %-13s\n", "SERVER SERVICE", "STATUS")
	fmt.Printf("%-15s %-13s\n", strings.Repeat("-", 15), strings.Repeat("-", 8))
	// Consul is always alive if we are at this point.
	fmt.Printf("%-15s %-13s\n", "Consul API", emojiStatus(noEmoji, true))
	fmt.Printf("%-15s %-13s\n", "QAN API", emojiStatus(noEmoji, qanStatus))
	fmt.Printf("%-15s %-13s\n\n", "Prometheus API", emojiStatus(noEmoji, promStatus))

	a.testNetwork()
	fmt.Println()

	node, _, err := a.consulAPI.Catalog().Node(a.Config.ClientName, nil)
	if err != nil || node == nil {
		fmt.Printf("%s '%s'.\n\n", noMonitoring, a.Config.ClientName)
		return nil
	}

	if !promStatus {
		fmt.Print("Prometheus is down. Please check if PMM server container runs properly.\n\n")
		return nil
	}

	fmt.Println()
	fmt.Println("* Client <-- Server")
	if len(node.Services) == 0 {
		fmt.Print("No metric endpoints registered.\n\n")
		return nil
	}

	// Check Prometheus endpoint status.
	svcTable := []instanceStatus{}
	errStatus := false
	for _, svc := range node.Services {
		if !strings.HasSuffix(svc.Service, ":metrics") {
			continue
		}

		name := "-"
		for _, tag := range svc.Tags {
			if strings.HasPrefix(tag, "alias_") {
				name = tag[6:]
				continue
			}

		}

		status := checkPromTargetStatus(promData.String(), name, strings.Split(svc.Service, ":")[0])
		if !status {
			errStatus = true
		}
		row := instanceStatus{
			Type:   svc.Service,
			Name:   name,
			Port:   fmt.Sprintf("%d", svc.Port),
			Status: emojiStatus(noEmoji, status),
		}
		svcTable = append(svcTable, row)
	}

	maxTypeLen := len("SERVICE TYPE")
	maxNameLen := len("NAME")
	for _, in := range svcTable {
		if len(in.Type) > maxTypeLen {
			maxTypeLen = len(in.Type)
		}
		if len(in.Name) > maxNameLen {
			maxNameLen = len(in.Name)
		}
	}
	maxTypeLen++
	maxNameLen++
	linefmt := "%-" + fmt.Sprintf("%d", maxTypeLen) + "s %-" + fmt.Sprintf("%d", maxNameLen) + "s %-22s %-8s\n"
	fmt.Printf(linefmt, strings.Repeat("-", maxTypeLen), strings.Repeat("-", maxNameLen), strings.Repeat("-", 22),
		strings.Repeat("-", 8))
	fmt.Printf(linefmt, "SERVICE TYPE", "NAME", "REMOTE ENDPOINT", "STATUS")
	fmt.Printf(linefmt, strings.Repeat("-", maxTypeLen), strings.Repeat("-", maxNameLen), strings.Repeat("-", 22),
		strings.Repeat("-", 8))
	sort.Sort(sortOutput(svcTable))
	for _, i := range svcTable {
		fmt.Printf(linefmt, i.Type, i.Name, a.Config.ClientAddress+":"+i.Port, i.Status)
	}

	if errStatus {
		fmt.Println(`
When an endpoint is down it may indicate that the corresponding service is stopped (run 'pmm-admin list' to verify).
If it's running, check out the logs /var/log/pmm-*.log

When all endpoints are down but 'pmm-admin list' shows they are up and no errors in the logs,
check the firewall settings whether this system allows incoming connections from server to address:port in question.`)
	}
	fmt.Println()
	return nil
}

// testNetwork measure round trip duration of server connection.
func (a *Admin) testNetwork() {
	insecureFlag := false
	if a.Config.ServerInsecureSSL {
		insecureFlag = true
	}

	conn := &networkTransport{
		dialer: &net.Dialer{
			Timeout:   a.apiTimeout,
			KeepAlive: a.apiTimeout,
		},
	}
	conn.rtp = &http.Transport{
		Proxy:           http.ProxyFromEnvironment,
		Dial:            conn.dial,
		TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureFlag},
	}
	client := &http.Client{Transport: conn}

	resp, err := client.Get(a.serverURL)
	if err != nil {
		fmt.Println("Unable to measure the connection performance.")
		return
	}
	defer resp.Body.Close()

	fmt.Printf("%-19s | %v\n", "Connection duration", conn.connEnd.Sub(conn.connStart))
	fmt.Printf("%-19s | %v\n", "Request duration", conn.reqEnd.Sub(conn.reqStart)-conn.connEnd.Sub(conn.connStart))
	fmt.Printf("%-19s | %v\n", "Full round trip", conn.reqEnd.Sub(conn.reqStart))
}

type networkTransport struct {
	rtp       http.RoundTripper
	dialer    *net.Dialer
	connStart time.Time
	connEnd   time.Time
	reqStart  time.Time
	reqEnd    time.Time
}

func (conn *networkTransport) RoundTrip(r *http.Request) (*http.Response, error) {
	conn.reqStart = time.Now()
	resp, err := conn.rtp.RoundTrip(r)
	conn.reqEnd = time.Now()
	return resp, err
}

func (conn *networkTransport) dial(network, addr string) (net.Conn, error) {
	conn.connStart = time.Now()
	cn, err := conn.dialer.Dial(network, addr)
	conn.connEnd = time.Now()
	return cn, err
}

// checkPromTargetStatus check Prometheus target state by metric labels.
func checkPromTargetStatus(data, alias, job string) bool {
	r, _ := regexp.Compile(fmt.Sprintf(`up{.*instance="%s".*job="%s".*} => 1`, alias, job))
	for _, row := range strings.Split(data, "\n") {
		if r.MatchString(row) {
			return true
		}
	}
	return false
}

// Map status to emoji or text.
func emojiStatus(noEmoji, status bool) string {
	switch true {
	case noEmoji && status:
		return "OK"
	case noEmoji && !status:
		return "PROBLEM"
	case !noEmoji && status:
		return emojiHappy
	case !noEmoji && !status:
		return emojiUnhappy
	}
	return "N/A"
}
<|endoftext|>


<commit_before>// +build linux
// +build !ppc64,!ppc64le
// run

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

// Test that a -B option is passed through when using both internal
// and external linking mode.

package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
)

func main() {
	test("internal")
	test("external")
}

func test(linkmode string) {
	out, err := exec.Command("go", "run", "-ldflags", "-B=0x12345678 -linkmode="+linkmode, filepath.Join("fixedbugs", "issue10607a.go")).CombinedOutput()
	if err != nil {
		fmt.Printf("BUG: linkmode=%s %v\n%s\n", linkmode, err, out)
		os.Exit(1)
	}
}
<commit_msg>Revert "test: do not run external linking test on ppc64le"<commit_after>// +build linux
// run

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

// Test that a -B option is passed through when using both internal
// and external linking mode.

package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
)

func main() {
	test("internal")
	test("external")
}

func test(linkmode string) {
	out, err := exec.Command("go", "run", "-ldflags", "-B=0x12345678 -linkmode="+linkmode, filepath.Join("fixedbugs", "issue10607a.go")).CombinedOutput()
	if err != nil {
		fmt.Printf("BUG: linkmode=%s %v\n%s\n", linkmode, err, out)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package hashmap

import (
	"strconv"
	"testing"
)

type Animal struct {
	name string
}

func TestMapCreation(t *testing.T) {
	m := New()
	if m == nil {
		t.Error("map is null.")
	}

	if m.Len() != 0 {
		t.Error("new map should be empty.")
	}
}

func TestInsert(t *testing.T) {
	m := New()
	elephant := Animal{"elephant"}
	monkey := Animal{"monkey"}

	m.Add(1, elephant)
	m.Add(2, monkey)

	if m.Len() != 2 {
		t.Error("map should contain exactly two elements.")
	}
}

func TestGet(t *testing.T) {
	m := New()

	val, ok := m.Get(1) // Get a missing element.

	if ok == true {
		t.Error("ok should be false when item is missing from map.")
	}

	if val != nil {
		t.Error("Missing values should return as null.")
	}

	elephant := Animal{"elephant"}
	m.Add(2, elephant)

	// Retrieve inserted element.

	tmp, ok := m.Get(2)
	elephant = tmp.(Animal) // Type assertion.

	if ok == false {
		t.Error("ok should be true for item stored within the map.")
	}

	if &elephant == nil {
		t.Error("expecting an element, not null.")
	}

	if elephant.name != "elephant" {
		t.Error("item was modified.")
	}
}

func TestRemove(t *testing.T) {
	m := New()

	monkey := Animal{"monkey"}
	m.Add(1, monkey)
	m.Add(1, monkey)

	m.Del(1)

	if m.Len() != 0 {
		t.Error("Expecting count to be zero once item was removed.")
	}

	temp, ok := m.Get(1)
	if ok != false {
		t.Error("Expecting ok to be false for missing items.")
	}
	if temp != nil {
		t.Error("Expecting item to be nil after its removal.")
	}

	m.Del(2) // Remove a none existing element.
}

func TestCount(t *testing.T) {
	m := New()
	for i := 0; i < 1024; i++ {
		m.Add(uint64(i), Animal{strconv.Itoa(i)})
	}

	if m.Len() != 1024 {
		t.Error("Expecting 100 element within map.")
	}
}
<commit_msg>Test for 0 value on an empty map which can cause problems in case the default value of an uninitialised hash results in a match for the hash 0<commit_after>package hashmap

import (
	"strconv"
	"testing"
)

type Animal struct {
	name string
}

func TestMapCreation(t *testing.T) {
	m := New()
	if m == nil {
		t.Error("map is null.")
	}

	if m.Len() != 0 {
		t.Error("new map should be empty.")
	}
}

func TestInsert(t *testing.T) {
	m := New()
	elephant := Animal{"elephant"}
	monkey := Animal{"monkey"}

	m.Add(1, elephant)
	m.Add(2, monkey)

	if m.Len() != 2 {
		t.Error("map should contain exactly two elements.")
	}
}

func TestGet(t *testing.T) {
	m := New()

	val, ok := m.Get(0) // Get a missing element.

	if ok == true {
		t.Error("ok should be false when item is missing from map.")
	}

	if val != nil {
		t.Error("Missing values should return as null.")
	}

	elephant := Animal{"elephant"}
	m.Add(2, elephant)

	// Retrieve inserted element.

	tmp, ok := m.Get(2)
	elephant = tmp.(Animal) // Type assertion.

	if ok == false {
		t.Error("ok should be true for item stored within the map.")
	}

	if &elephant == nil {
		t.Error("expecting an element, not null.")
	}

	if elephant.name != "elephant" {
		t.Error("item was modified.")
	}
}

func TestRemove(t *testing.T) {
	m := New()

	monkey := Animal{"monkey"}
	m.Add(1, monkey)
	m.Add(1, monkey)

	m.Del(1)

	if m.Len() != 0 {
		t.Error("Expecting count to be zero once item was removed.")
	}

	temp, ok := m.Get(1)
	if ok != false {
		t.Error("Expecting ok to be false for missing items.")
	}
	if temp != nil {
		t.Error("Expecting item to be nil after its removal.")
	}

	m.Del(2) // Remove a none existing element.
}

func TestCount(t *testing.T) {
	m := New()
	for i := 0; i < 1024; i++ {
		m.Add(uint64(i), Animal{strconv.Itoa(i)})
	}

	if m.Len() != 1024 {
		t.Error("Expecting 100 element within map.")
	}
}
<|endoftext|>


<commit_before>package hashmap

import (
	"strconv"
	"testing"
)

func TestNewHashMap(t *testing.T) {
	cases := []struct {
		in, want int
	}{
		{10, 10},
		{20, 20},
		{0, 0},
	}

	for _, c := range cases {
		h, err := NewHashMap(c.in)
		if c.in == 0 && err == nil {
			t.Errorf("Expected error, didn't get it")
		} else {
			if h.size != c.want {
				t.Errorf("NewHashMap(%q) == %q, want %q", c.in, h.size, c.want)
			}
		}
	}
}

func TestSize(t *testing.T) {
	cases := []struct {
		in, want int
	}{
		{10, 10},
		{20, 20},
	}

	for _, c := range cases {
		h, _ := NewHashMap(c.in)
		got := h.Size()
		if got != c.want {
			t.Errorf("Size(%d) == %d, want %d", c.in, got, c.want)
		}
	}
}

func TestLenAndLoad(t *testing.T) {
	cases := []struct {
		in, want int
	}{
		{10, 10},
		{20, 20},
	}

	for _, c := range cases {
		h, _ := NewHashMap(c.in * 10)
		for i := 1; i <= c.in; i++ {
			key := strconv.Itoa(i)
			h.Set(key, c.in*10)
		}
		got := h.Len()
		if got != c.want {
			t.Errorf("Len(%d) == %d, want %d", c.in, got, c.want)
		}
	}
}

func TestGetAndSet(t *testing.T) {
	h, _ := NewHashMap(100)
	keys := []string{"alpha", "beta", "charlie", "gamma", "delta"}

	// testing primitives
	for _, key := range keys {
		h.Set(key, len(key))
	}

	for _, key := range keys {
		got, _ := h.Get(key)
		want := len(key)
		if got.Value.(int) != len(key) {
			t.Errorf("want: %q, got: %q", want, got)
		}
	}

	// testing strings
	for _, key := range keys {
		h.Set(key, key+key)
	}

	for _, key := range keys {
		got, _ := h.Get(key)
		want := key + key
		if got.Value.(string) != want {
			t.Errorf("want: %q, got: %q", want, got)
		}
	}

	// testing references to compound types
	arr := []int{2, 3, 4}
	h.Set("myArray", arr)
	a, _ := h.Get("myArray")
	k := a.Value.([]int)
	k[0] = 100
	if k[0] != arr[0] {
		t.Errorf("Reference has not been mutated")
	}
}
<commit_msg>Completed testcases :sparkles:<commit_after>package hashmap

import (
	"strconv"
	"testing"
)

func TestNewHashMap(t *testing.T) {
	cases := []struct {
		in, want int
	}{
		{10, 10},
		{20, 20},
		{0, 0},
	}

	for _, c := range cases {
		h, err := NewHashMap(c.in)
		if c.in == 0 && err == nil {
			t.Errorf("Expected error, didn't get it")
		} else {
			if h.size != c.want {
				t.Errorf("NewHashMap(%q) == %q, want %q", c.in, h.size, c.want)
			}
		}
	}
}

func TestSize(t *testing.T) {
	cases := []struct {
		in, want int
	}{
		{10, 10},
		{20, 20},
	}

	for _, c := range cases {
		h, _ := NewHashMap(c.in)
		got := h.Size()
		if got != c.want {
			t.Errorf("Size(%d) == %d, want %d", c.in, got, c.want)
		}
	}
}

func TestLenAndLoad(t *testing.T) {
	cases := []struct {
		in, want int
	}{
		{10, 10},
		{20, 20},
	}

	for _, c := range cases {
		h, _ := NewHashMap(c.in * 10)
		for i := 1; i <= c.in; i++ {
			key := strconv.Itoa(i)
			h.Set(key, c.in*10)
		}
		got := h.Len()
		if got != c.want {
			t.Errorf("Len(%d) == %d, want %d", c.in, got, c.want)
		}

		load := h.Load()
		want := float32(c.in) / float32(c.in*10)
		if load != want {
			t.Errorf("Load(%d) == %d, want %d", c.in, load, want)
		}
	}
}

func TestGetAndSet(t *testing.T) {
	h, _ := NewHashMap(100)
	keys := []string{"alpha", "beta", "charlie", "gamma", "delta"}

	// testing primitives
	for _, key := range keys {
		h.Set(key, len(key))
	}

	for _, key := range keys {
		got, _ := h.Get(key)
		want := len(key)
		if got.Value.(int) != len(key) {
			t.Errorf("want: %q, got: %q", want, got)
		}
	}

	// testing strings
	for _, key := range keys {
		h.Set(key, key+key)
	}

	for _, key := range keys {
		got, _ := h.Get(key)
		want := key + key
		if got.Value.(string) != want {
			t.Errorf("want: %q, got: %q", want, got)
		}
	}

	// testing references to compound types
	arr := []int{2, 3, 4}
	h.Set("myArray", arr)
	a, _ := h.Get("myArray")
	k := a.Value.([]int)
	k[0] = 100
	if k[0] != arr[0] {
		t.Errorf("Reference has not been mutated")
	}
}

func TestCollisions(t *testing.T) {
	// a small hashmap that is bound to have collisions
	h, _ := NewHashMap(5)

	keys := []string{"alpha", "beta", "charlie", "gamma", "delta"}

	for _, key := range keys {
		h.Set(key, len(key))
	}

	for _, key := range keys {
		got, _ := h.Get(key)
		want := len(key)
		if got.Value.(int) != len(key) {
			t.Errorf("want: %q, got: %q", want, got)
		}
	}
}

func TestDelete(t *testing.T) {
	// a hashtable with just one elem
	h, _ := NewHashMap(1)
	h.Set("alpha", 10)

	// should not be allowed to add
	status := h.Set("beta", 20)
	if status {
		t.Errorf("Able to add more elements than the allowed size")
	}

	// lets delete first
	_, status = h.Delete("alpha")
	if !status {
		t.Errorf("Unable to delete")
	}

	// and add beta now
	status = h.Set("beta", 20)
	if !status {
		t.Errorf("Unable to add element")
	}

	// lastly, lets delete a non-existent element
	_, status = h.Delete("gamma")
	if status {
		t.Errorf("Deleted a missing key")
	}
}
<|endoftext|>