<commit_before>package sparse

import (
	"fmt"
	"bytes"
	"gonum.org/v1/gonum/mat"
)

const (
	// maxLen is the biggest slice/array len one can create on a 32/64b platform.
	//bitLen = ^uint(0) >> 1
	maxDataLen = ^uint(0)

	// the wordSize of a binary vector.  Bits are stored in slices of words.
	wordSize = uint(64)

	// log2WordSize is the binary logarithm (log base 2) of (wordSize)
	log2WordSize = uint(6)
)

// BinaryVec is a Binary Vector or Bit Vector type.  This is useful
// for representing vectors of features with a binary state (1 or 0).
// Although part of the sparse package, this type is not sparse itself
// and stores all bits even 0s.  However, as it makes use of 64 bit
// integers to store each set of 64 bits and then bitwise operators to
// manipulate the elements it will be more efficient in terms of both
// storage requirements and performance than a slice of bool values
// (8 bits per element) or even a typical Dense matrix of float64
// elements.  A compressed bitmap scheme could be used to take advantage
// of sparseness but may have an associated overhead.
type BinaryVec struct {
	length int
	data []uint64
}

// New creates a new BitSet with a hint that length bits will be required
func NewBinaryVec(length int) *BinaryVec {
	maxSize := (maxDataLen - wordSize + uint(1))
	if uint(length) > maxSize {
		panic(fmt.Errorf("sparse: Requested bit length of Binary vector (%d) too large.  %d is the maximum allowed", length, maxSize))
	}
	elements := int((uint(length) + (wordSize - 1)) >> log2WordSize)

	vec := &BinaryVec{
		length: length,
		data: make([]uint64, elements),
	}

	return vec
}

// DistanceFrom is the number of bits that are different between the
// receiver and rhs i.e.
// 	recevier 	= 1001001
//	rhs 		= 1010101
// 	Distance	= 3
// because there are three bits that are different between the 2
// binary vectors.  This is sometimes referred to as the `Hamming
// distance` or `Matching distance`.  In this case, the distance
// is not normalised and is simply the raw count of differences.  To
// normalise the value simply divide this value by the vector's length.
func (b *BinaryVec) DistanceFrom(rhs *BinaryVec) int {
	differences := uint64(0)
	for i, word := range b.data {
		differences += popcount(word ^ rhs.data[i])
	}
	return int(differences)
}

// Dims returns the dimensions of the matrix as the number of rows, columns.
// As this is a vector, the second value representing the number of columns
// will be 1. This method is part of the Gonum mat.Matrix interface
func (b *BinaryVec) Dims() (int, int) {
	return b.Len(), 1
}

// At returns the value of the element at row i and column j.
// As this is a vector (only one column), j must be 0 otherwise the
// method panics.  This method is part of the Gonum mat.Matrix interface.
func (b *BinaryVec) At(i, j int) float64 {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	if uint(j) != 0 {
		panic(mat.ErrColAccess)
	}

	if b.bitIsSet(i) {
		return 1.0
	}
	return 0.0
}

// AtVec returns the value of the element at row i.  This method will panic if
// i > Len().  This method is part of the Gonum mat.Vector interface.
func (b *BinaryVec) AtVec(i int) float64 {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}

	if b.bitIsSet(i) {
		return 1.0
	}
	return 0.0
}

// T performs an implicit transpose by returning the receiver inside a Transpose.
// This method is part of the Gonum mat.Matrix interface
func (b *BinaryVec) T() mat.Matrix {
	return mat.Transpose{Matrix: b}
}

// NNZ returns the Number of Non-Zero elements (bits).  This is the number of set
// bits (represented by 1s rather than 0s) in the vector.  This is also known as the
// `Hamming weight` or `population count` (popcount).
func (b *BinaryVec) NNZ() int {
	nnz := uint64(0)
	for _, word := range b.data {
		nnz += popcount(word)
	}
	return int(nnz)
}

// Len returns the length of the vector or the total number of elements.  This method
// is part of the Gonum mat.Vector interface
func (b *BinaryVec) Len() int {
	return b.length
}

// BitIsSet tests whether the element (bit) at position i is set (equals 1) and
// returns true if so.  If the element (bit) is not set or has been unset (equal
// to 0) the the method will return false.  The method will panic if i is greater
// than Len().
func (b *BinaryVec) BitIsSet(i int) bool {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	return b.bitIsSet(i)
}

// bitIsSet tests whether the element (bit) at position i is set (equals 1) and
// returns true if so.  If the element (bit) is not set or has been unset (equal
// to 0) the the method will return false.
func (b *BinaryVec) bitIsSet(i int) bool {
	return b.data[i>>log2WordSize] & (1 << (uint(i) & (wordSize - 1))) != 0
}

// SetBit sets the bit at the specified index (i) to 1.  If the bit is already set
// there are no adverse effects.  The method will panic if index is larger
// than Len()
func (b *BinaryVec) SetBit(i int) {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	b.setBit(i)
}

// setBit sets the bit at the specified index (i) to 1.  If the bit is already set
// there are no adverse effects.
func (b *BinaryVec) setBit(i int) {
	b.data[i>>log2WordSize] |= 1 << (uint(i) & (wordSize - 1))
}

// UnsetBit unsets the bit at the specified index (i) (sets it to 0).  If the bit
// is already unset or has simply never been set (default bit values are 0)
// there are no adverse effects.  The method will panic if index is larger
// than Len()
func (b *BinaryVec) UnsetBit(i int) {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	b.unsetBit(i)
}

// unsetBit unsets the bit at the specified index (i) (sets it to 0).  If the bit
// is already unset or has simply never been set (default bit values are 0)
// there are no adverse effects.
func (b *BinaryVec) unsetBit(i int) {
	b.data[i>>log2WordSize] &^= 1 << (uint(i) & (wordSize - 1))
}

// Set sets the element of the matrix located at row i and column j to 1 if v != 0
// or 0 otherwise. Set will panic if specified values for i or j fall outside the
// dimensions of the matrix.
func (b *BinaryVec) Set(i int, j int, v float64) {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	if uint(j) != 0 {
		panic(mat.ErrColAccess)
	}

	if v != 0 {
		b.setBit(i)
		return
	}
	b.unsetBit(i)
}

// SetVec sets the element of the vector located at row i to 1 if v != 0
// or 0 otherwise. The method will panic if i is greater than Len().
func (b *BinaryVec) SetVec(i int, v float64) {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}

	if v != 0 {
		b.setBit(i)
		return
	}
	b.unsetBit(i)
}

// String will output the vector as a string representation of its bits
// This method implements the fmt.Stringer interface.
func (b BinaryVec) String() string {
	var buf bytes.Buffer

	width := b.length % int(wordSize)
	if width == 0 {
		width = 64
	}

	fmt.Fprintf(&buf, fmt.Sprintf("%%0%db", width), b.data[len(b.data)-1])
	for i := len(b.data)-2; i >= 0; i-- {
		fmt.Fprintf(&buf, "%064b", b.data[i])
	}

	return string(buf.Bytes())
}

// Format outputs the vector to f and allows the output format
// to be specified.  Supported values of c are `x`, `X`, `b`` and `s`
// to format the bits of the vector as a hex digit or binary digit string.
// `s` (the default format) will output as binary digits.
// Please refer to the fmt package documentation for more information.
// This method implements the fmt.Formatter interface.
func (b BinaryVec) Format(f fmt.State, c rune) {
	var buf bytes.Buffer
	var format string
	var leadFormat string
	switch c {
		case 'x':
			format = ".%x"
			leadFormat = "%x"
		case 'X':
			format = ".%X"
			leadFormat = "%X"
		case 'b':
			f.Write([]byte(b.String()))
			return
		case 's':
			f.Write([]byte(b.String()))
			return
		default:
			panic(fmt.Errorf("sparse: unsupported format verb '%c' for Binary vector", c))
	}
	fmt.Fprintf(&buf, leadFormat, b.data[len(b.data)-1])
	for i := len(b.data)-2; i >= 0; i-- {
		fmt.Fprintf(&buf, format, b.data[i])
	}
	f.Write(buf.Bytes())
}

// popcount calculates the population count of the vector (also known
// as `Hamming weight`).  This uses fewer arithmetic operations than
// any other known implementation on machines with fast multiplication.
// Thanks to Wikipedia and Hacker's Delight.
func popcount(x uint64) (n uint64) {
	x -= (x >> 1) & 0x5555555555555555
	x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
	x += x >> 4
	x &= 0x0f0f0f0f0f0f0f0f
	x *= 0x0101010101010101
	return x >> 56
}

// Binary is a Binary Matrix or Bit Matrix type.
// Although part of the sparse package, this type is not sparse itself
// and stores all bits even 0s.  However, as it makes use of 64 bit
// integers to store each set of 64 bits and then bitwise operators to
// manipulate the elements it will be more efficient in terms of both
// storage requirements and performance than a slice of bool values
// (8 bits per element) or even a typical Dense matrix of float64
// elements.  A compressed bitmap scheme could be used to take advantage
// of sparseness but may have an associated overhead.
type Binary struct {
	r, c int
	cols []BinaryVec
}

// NewBinary constructs a new Binary matrix or r rows and c columns.
// If vecs is not nil, it will be used as the underlying binary column vectors.
// If vecs is nil, new storage will be allocated.
func NewBinary(r, c int, vecs []BinaryVec) *Binary {
	if vecs == nil {
		vecs = make([]BinaryVec, c)
		for i := 0; i < c; i++ {
			vecs[i] = *NewBinaryVec(r)
		}
	}

	return &Binary{r: r, c: c, cols: vecs}
}

// Dims returns the dimensions of the matrix as the number of rows, columns.
// This method is part of the Gonum mat.Matrix interface
func (b *Binary) Dims() (int, int) {
	return b.r, b.c
}

// At returns the value of the element at row i and column k.
// i (row) and j (col) must be within the dimensions of the matrix otherwise the
// method panics.  This method is part of the Gonum mat.Matrix interface.
func (b *Binary) At(i int, j int) float64 {
	if uint(j) < 0 || uint(j) >= uint(b.c) {
		panic(mat.ErrColAccess)
	}
	return b.cols[j].At(i, j)
}

// T performs an implicit transpose by returning the receiver inside a Transpose.
// This method is part of the Gonum mat.Matrix interface
func (b *Binary) T() mat.Matrix {
	return mat.Transpose{Matrix: b}
}

// ColView returns the mat.Vector representing the column j.  This vector will
// be a BinaryVec and will share the same storage as the matrix so any changes
// to the vector will be reflected in the matrix and vice versa.
// if j is outside the dimensions of the matrix the method will panic.
func (b *Binary) ColView(j int) mat.Vector {
	if uint(j) < 0 || uint(j) >= uint(b.c) {
		panic(mat.ErrColAccess)
	}
	return &b.cols[j]
}<commit_msg>improved memory efficiency of String() method<commit_after>package sparse

import (
	"fmt"
	"bytes"
	"unsafe"
	"gonum.org/v1/gonum/mat"
)

const (
	// maxLen is the biggest slice/array len one can create on a 32/64b platform.
	//bitLen = ^uint(0) >> 1
	maxDataLen = ^uint(0)

	// the wordSize of a binary vector.  Bits are stored in slices of words.
	wordSize = uint(64)

	// log2WordSize is the binary logarithm (log base 2) of (wordSize)
	log2WordSize = uint(6)
)

// BinaryVec is a Binary Vector or Bit Vector type.  This is useful
// for representing vectors of features with a binary state (1 or 0).
// Although part of the sparse package, this type is not sparse itself
// and stores all bits even 0s.  However, as it makes use of 64 bit
// integers to store each set of 64 bits and then bitwise operators to
// manipulate the elements it will be more efficient in terms of both
// storage requirements and performance than a slice of bool values
// (8 bits per element) or even a typical Dense matrix of float64
// elements.  A compressed bitmap scheme could be used to take advantage
// of sparseness but may have an associated overhead.
type BinaryVec struct {
	length int
	data []uint64
}

// New creates a new BitSet with a hint that length bits will be required
func NewBinaryVec(length int) *BinaryVec {
	maxSize := (maxDataLen - wordSize + uint(1))
	if uint(length) > maxSize {
		panic(fmt.Errorf("sparse: Requested bit length of Binary vector (%d) too large.  %d is the maximum allowed", length, maxSize))
	}
	elements := int((uint(length) + (wordSize - 1)) >> log2WordSize)

	vec := &BinaryVec{
		length: length,
		data: make([]uint64, elements),
	}

	return vec
}

// DistanceFrom is the number of bits that are different between the
// receiver and rhs i.e.
// 	recevier 	= 1001001
//	rhs 		= 1010101
// 	Distance	= 3
// because there are three bits that are different between the 2
// binary vectors.  This is sometimes referred to as the `Hamming
// distance` or `Matching distance`.  In this case, the distance
// is not normalised and is simply the raw count of differences.  To
// normalise the value simply divide this value by the vector's length.
func (b *BinaryVec) DistanceFrom(rhs *BinaryVec) int {
	differences := uint64(0)
	for i, word := range b.data {
		differences += popcount(word ^ rhs.data[i])
	}
	return int(differences)
}

// Dims returns the dimensions of the matrix as the number of rows, columns.
// As this is a vector, the second value representing the number of columns
// will be 1. This method is part of the Gonum mat.Matrix interface
func (b *BinaryVec) Dims() (int, int) {
	return b.Len(), 1
}

// At returns the value of the element at row i and column j.
// As this is a vector (only one column), j must be 0 otherwise the
// method panics.  This method is part of the Gonum mat.Matrix interface.
func (b *BinaryVec) At(i, j int) float64 {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	if uint(j) != 0 {
		panic(mat.ErrColAccess)
	}

	if b.bitIsSet(i) {
		return 1.0
	}
	return 0.0
}

// AtVec returns the value of the element at row i.  This method will panic if
// i > Len().  This method is part of the Gonum mat.Vector interface.
func (b *BinaryVec) AtVec(i int) float64 {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}

	if b.bitIsSet(i) {
		return 1.0
	}
	return 0.0
}

// T performs an implicit transpose by returning the receiver inside a Transpose.
// This method is part of the Gonum mat.Matrix interface
func (b *BinaryVec) T() mat.Matrix {
	return mat.Transpose{Matrix: b}
}

// NNZ returns the Number of Non-Zero elements (bits).  This is the number of set
// bits (represented by 1s rather than 0s) in the vector.  This is also known as the
// `Hamming weight` or `population count` (popcount).
func (b *BinaryVec) NNZ() int {
	nnz := uint64(0)
	for _, word := range b.data {
		nnz += popcount(word)
	}
	return int(nnz)
}

// Len returns the length of the vector or the total number of elements.  This method
// is part of the Gonum mat.Vector interface
func (b *BinaryVec) Len() int {
	return b.length
}

// BitIsSet tests whether the element (bit) at position i is set (equals 1) and
// returns true if so.  If the element (bit) is not set or has been unset (equal
// to 0) the the method will return false.  The method will panic if i is greater
// than Len().
func (b *BinaryVec) BitIsSet(i int) bool {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	return b.bitIsSet(i)
}

// bitIsSet tests whether the element (bit) at position i is set (equals 1) and
// returns true if so.  If the element (bit) is not set or has been unset (equal
// to 0) the the method will return false.
func (b *BinaryVec) bitIsSet(i int) bool {
	return b.data[i>>log2WordSize] & (1 << (uint(i) & (wordSize - 1))) != 0
}

// SetBit sets the bit at the specified index (i) to 1.  If the bit is already set
// there are no adverse effects.  The method will panic if index is larger
// than Len()
func (b *BinaryVec) SetBit(i int) {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	b.setBit(i)
}

// setBit sets the bit at the specified index (i) to 1.  If the bit is already set
// there are no adverse effects.
func (b *BinaryVec) setBit(i int) {
	b.data[i>>log2WordSize] |= 1 << (uint(i) & (wordSize - 1))
}

// UnsetBit unsets the bit at the specified index (i) (sets it to 0).  If the bit
// is already unset or has simply never been set (default bit values are 0)
// there are no adverse effects.  The method will panic if index is larger
// than Len()
func (b *BinaryVec) UnsetBit(i int) {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	b.unsetBit(i)
}

// unsetBit unsets the bit at the specified index (i) (sets it to 0).  If the bit
// is already unset or has simply never been set (default bit values are 0)
// there are no adverse effects.
func (b *BinaryVec) unsetBit(i int) {
	b.data[i>>log2WordSize] &^= 1 << (uint(i) & (wordSize - 1))
}

// Set sets the element of the matrix located at row i and column j to 1 if v != 0
// or 0 otherwise. Set will panic if specified values for i or j fall outside the
// dimensions of the matrix.
func (b *BinaryVec) Set(i int, j int, v float64) {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}
	if uint(j) != 0 {
		panic(mat.ErrColAccess)
	}

	if v != 0 {
		b.setBit(i)
		return
	}
	b.unsetBit(i)
}

// SetVec sets the element of the vector located at row i to 1 if v != 0
// or 0 otherwise. The method will panic if i is greater than Len().
func (b *BinaryVec) SetVec(i int, v float64) {
	if uint(i) < 0 || uint(i) >= uint(b.length) {
		panic(mat.ErrRowAccess)
	}

	if v != 0 {
		b.setBit(i)
		return
	}
	b.unsetBit(i)
}

// String will output the vector as a string representation of its bits
// This method implements the fmt.Stringer interface.
func (b BinaryVec) String() string {
	//var buf bytes.Buffer
	buf := bytes.NewBuffer(make([]byte, 0, b.Len()))

	width := b.length % int(wordSize)
	if width == 0 {
		width = 64
	}

	fmt.Fprintf(buf, fmt.Sprintf("%%0%db", width), b.data[len(b.data)-1])
	for i := len(b.data)-2; i >= 0; i-- {
		fmt.Fprintf(buf, "%064b", b.data[i])
	}

	//return string(buf.Bytes())
	s := buf.Bytes()
	return *(*string)(unsafe.Pointer(&s))
}

// Format outputs the vector to f and allows the output format
// to be specified.  Supported values of c are `x`, `X`, `b`` and `s`
// to format the bits of the vector as a hex digit or binary digit string.
// `s` (the default format) will output as binary digits.
// Please refer to the fmt package documentation for more information.
// This method implements the fmt.Formatter interface.
func (b BinaryVec) Format(f fmt.State, c rune) {
	var buf bytes.Buffer
	var format string
	var leadFormat string
	switch c {
		case 'x':
			format = ".%x"
			leadFormat = "%x"
		case 'X':
			format = ".%X"
			leadFormat = "%X"
		case 'b':
			f.Write([]byte(b.String()))
			return
		case 's':
			f.Write([]byte(b.String()))
			return
		default:
			panic(fmt.Errorf("sparse: unsupported format verb '%c' for Binary vector", c))
	}
	fmt.Fprintf(&buf, leadFormat, b.data[len(b.data)-1])
	for i := len(b.data)-2; i >= 0; i-- {
		fmt.Fprintf(&buf, format, b.data[i])
	}
	f.Write(buf.Bytes())
}

// popcount calculates the population count of the vector (also known
// as `Hamming weight`).  This uses fewer arithmetic operations than
// any other known implementation on machines with fast multiplication.
// Thanks to Wikipedia and Hacker's Delight.
func popcount(x uint64) (n uint64) {
	x -= (x >> 1) & 0x5555555555555555
	x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
	x += x >> 4
	x &= 0x0f0f0f0f0f0f0f0f
	x *= 0x0101010101010101
	return x >> 56
}

// Binary is a Binary Matrix or Bit Matrix type.
// Although part of the sparse package, this type is not sparse itself
// and stores all bits even 0s.  However, as it makes use of 64 bit
// integers to store each set of 64 bits and then bitwise operators to
// manipulate the elements it will be more efficient in terms of both
// storage requirements and performance than a slice of bool values
// (8 bits per element) or even a typical Dense matrix of float64
// elements.  A compressed bitmap scheme could be used to take advantage
// of sparseness but may have an associated overhead.
type Binary struct {
	r, c int
	cols []BinaryVec
}

// NewBinary constructs a new Binary matrix or r rows and c columns.
// If vecs is not nil, it will be used as the underlying binary column vectors.
// If vecs is nil, new storage will be allocated.
func NewBinary(r, c int, vecs []BinaryVec) *Binary {
	if vecs == nil {
		vecs = make([]BinaryVec, c)
		for i := 0; i < c; i++ {
			vecs[i] = *NewBinaryVec(r)
		}
	}

	return &Binary{r: r, c: c, cols: vecs}
}

// Dims returns the dimensions of the matrix as the number of rows, columns.
// This method is part of the Gonum mat.Matrix interface
func (b *Binary) Dims() (int, int) {
	return b.r, b.c
}

// At returns the value of the element at row i and column k.
// i (row) and j (col) must be within the dimensions of the matrix otherwise the
// method panics.  This method is part of the Gonum mat.Matrix interface.
func (b *Binary) At(i int, j int) float64 {
	if uint(j) < 0 || uint(j) >= uint(b.c) {
		panic(mat.ErrColAccess)
	}
	return b.cols[j].At(i, j)
}

// T performs an implicit transpose by returning the receiver inside a Transpose.
// This method is part of the Gonum mat.Matrix interface
func (b *Binary) T() mat.Matrix {
	return mat.Transpose{Matrix: b}
}

// ColView returns the mat.Vector representing the column j.  This vector will
// be a BinaryVec and will share the same storage as the matrix so any changes
// to the vector will be reflected in the matrix and vice versa.
// if j is outside the dimensions of the matrix the method will panic.
func (b *Binary) ColView(j int) mat.Vector {
	if uint(j) < 0 || uint(j) >= uint(b.c) {
		panic(mat.ErrColAccess)
	}
	return &b.cols[j]
}<|endoftext|>


<commit_before>// Copyright (c) 2014 Filippo Valsorda
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"runtime/pprof"
	"syscall"
	"time"

	"github.com/bitly/dablooms/godablooms"
	"github.com/davecgh/go-spew/spew"

	"github.com/conformal/btcchain"
	"github.com/conformal/btcdb"
	_ "github.com/conformal/btcdb/ldb"
	"github.com/conformal/btcec"
	"github.com/conformal/btclog"
	"github.com/conformal/btcutil"
)

type stringSet map[string]struct{}

func (s stringSet) Add(item string) {
	s[item] = struct{}{}
}

func (s stringSet) Contains(item string) bool {
	_, ok := s[item]
	return ok
}

const (
	tickFreq  = 10
	bloomSize = 50000000 // https://blockchain.info/charts/n-transactions-total
)

func btcdbSetup(dataDir, dbType string) (log btclog.Logger, db btcdb.Db, cleanup func()) {
	// Setup logging
	backendLogger := btclog.NewDefaultBackendLogger()
	log = btclog.NewSubsystemLogger(backendLogger, "")
	btcdb.UseLogger(log)

	// Setup database access
	blockDbNamePrefix := "blocks"
	dbName := blockDbNamePrefix + "_" + dbType
	if dbType == "sqlite" {
		dbName = dbName + ".db"
	}
	dbPath := filepath.Join(dataDir, "mainnet", dbName)

	log.Infof("loading db %v", dbType)
	db, err := btcdb.OpenDB(dbType, dbPath)
	if err != nil {
		log.Warnf("db open failed: %v", err)
		return
	}
	log.Infof("db load complete")

	cleanup = func() {
		db.Close()
		backendLogger.Flush()
	}

	return
}

func popData(SignatureScript []byte) ([]byte, []byte, error) {
	if len(SignatureScript) < 1 {
		return nil, nil, fmt.Errorf("empty SignatureScript")
	}
	opcode := SignatureScript[0]

	if opcode >= 1 && opcode <= 75 {
		if len(SignatureScript) < int(opcode+1) {
			return nil, nil, fmt.Errorf("SignatureScript too short")
		}
		sigStr := SignatureScript[1 : opcode+1]
		remaining := SignatureScript[opcode+1:]
		return sigStr, remaining, nil
	}

	// TODO: OP_PUSHDATA1 OP_PUSHDATA2 OP_PUSHDATA3
	if opcode >= 76 && opcode <= 78 {
		return nil, nil, fmt.Errorf("FIXME: OP_PUSHDATA %v", opcode)
	}

	return nil, nil, fmt.Errorf("the first opcode (%x) is not a data push", opcode)
}

type rData struct {
	Sig       *btcec.Signature
	H         int64
	SigScript []byte
}

func getSignatures(maxHeigth int64, errorFile io.Writer, log btclog.Logger, db btcdb.Db) chan *rData {
	c := make(chan *rData)

	go func() {
		for h := int64(0); h < maxHeigth; h++ {
			sha, err := db.FetchBlockShaByHeight(h)
			if err != nil {
				log.Warnf("failed FetchBlockShaByHeight(%v): %v", h, err)
				return
			}
			blk, err := db.FetchBlockBySha(sha)
			if err != nil {
				log.Warnf("failed FetchBlockBySha(%v) - h %v: %v", sha, h, err)
				return
			}

			mblk := blk.MsgBlock()

			for i, tx := range mblk.Transactions {
				// txsha, err := tx.TxSha()
				// if err != nil {
				// 	log.Warnf("Block %v (%v)", h, sha)
				// 	log.Warnf("tx %v (%v)", i, &txsha)
				// 	log.Warnf("Error: %v", err)
				// 	continue
				// }

				if btcchain.IsCoinBase(btcutil.NewTx(tx)) {
					continue
				}

				for t, txin := range tx.TxIn {
					sigStr, _, err := popData(txin.SignatureScript)
					if err != nil {
						io.WriteString(errorFile, fmt.Sprintf(
							"Block %v (%v) tx %v txin %v (%v)\nError: %v\n%v",
							h, sha, i, t, "parseData", err,
							spew.Sdump(txin.SignatureScript)))
						continue
					}

					signature, err := btcec.ParseSignature(sigStr, btcec.S256())
					if err != nil {
						io.WriteString(errorFile, fmt.Sprintf(
							"Block %v (%v) tx %v txin %v (%v)\nError: %v\n%v",
							h, sha, i, t, "ParseSignature", err,
							spew.Sdump(sigStr)))
						continue
					}

					c <- &rData{
						Sig:       signature,
						H:         h,
						SigScript: txin.SignatureScript,
					}
				}
			}
		}

		close(c)
	}()

	return c
}

func search(log btclog.Logger, db btcdb.Db, errorFile io.Writer) map[string][]*rData {
	// Setup signal handler
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)

	filter := dablooms.NewScalingBloom(bloomSize, 0.01, "blockchainr_bloom.bin")
	if filter == nil {
		log.Warn("dablooms.NewScalingBloom failed")
		return nil
	}

	potentialValues := make(stringSet)
	rMap := make(map[string][]*rData)

	_, maxHeigth, err := db.NewestSha()
	if err != nil {
		log.Warnf("db NewestSha failed: %v", err)
		return nil
	}

	for step := 1; step <= 2; step++ {
		lastTime := time.Now()
		lastSig := int64(0)
		sigCounter := int64(0)
		ticker := time.Tick(tickFreq * time.Second)

		signatures := getSignatures(maxHeigth, errorFile, log, db)
		for rd := range signatures {
			select {
			case s := <-signalChan:
				log.Infof("Step %v - signal %v - %v signatures processed in %v, %v total, block %v of %v",
					step, s, sigCounter-lastSig, time.Since(lastTime), sigCounter, rd.H, maxHeigth)

				if s == syscall.SIGINT || s == syscall.SIGTERM {
					return rMap
				}

			case <-ticker:
				log.Infof("Step %v - %v signatures processed in %v, %v total, block %v of %v",
					step, sigCounter-lastSig, time.Since(lastTime), sigCounter, rd.H, maxHeigth)
				lastTime = time.Now()
				lastSig = sigCounter

			default:
				break
			}

			if step == 1 {
				b := rd.Sig.R.Bytes()
				if filter.Check(b) {
					// fmt.Print(rd.Sig.R.String())
					potentialValues.Add(rd.Sig.R.String())
				} else {
					if !filter.Add(b, 1) {
						log.Warn("Add failed (?)")
					}
				}
			} else if step == 2 {
				if potentialValues.Contains(rd.Sig.R.String()) {
					rMap[rd.Sig.R.String()] = append(rMap[rd.Sig.R.String()], rd)
				}
			}
			sigCounter += 1
		}

		if *memprofile != "" {
			f, err := os.Create(fmt.Sprintf("%s.%d", *memprofile, step))
			if err != nil {
				log.Warnf("open memprofile failed: %v", err)
				return nil
			}
			pprof.WriteHeapProfile(f)
			f.Close()
		}

		log.Infof("Step %v done - %v signatures processed", step, sigCounter)
	}
	return rMap
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	memprofile = flag.String("memprofile", "", "write memory profile to this file")
)

func main() {
	var (
		dataDir = flag.String("datadir", filepath.Join(btcutil.AppDataDir("btcd", false), "data"), "BTCD: Data directory")
		dbType  = flag.String("dbtype", "leveldb", "BTCD: Database backend")
	)
	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// Setup btcdb
	log, db, dbCleanup := btcdbSetup(*dataDir, *dbType)
	defer dbCleanup()

	errorFile, err := os.Create("blockchainr_error.log")
	if err != nil {
		log.Warnf("failed to create blockchainr_error.log: %v", err)
		return
	}
	defer errorFile.Close()

	duplicates := search(log, db, errorFile)

	realDuplicates := make(map[string][]*rData)
	for k, v := range duplicates {
		if len(v) > 1 {
			realDuplicates[k] = v
		}
	}

	resultsFile, err := os.Create("blockchainr.json")
	if err != nil {
		log.Warnf("failed to create blockchainr.json: %v", err)
		return
	}
	if json.NewEncoder(resultsFile).Encode(realDuplicates) != nil {
		log.Warnf("failed to Encode the result: %v", err)
		return
	}
}
<commit_msg>blockchainr: breaking change - only output H and TxNum; use btcscript.PushedData<commit_after>// Copyright (c) 2014 Filippo Valsorda
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"runtime/pprof"
	"syscall"
	"time"

	"github.com/bitly/dablooms/godablooms"
	"github.com/davecgh/go-spew/spew"

	"github.com/conformal/btcchain"
	"github.com/conformal/btcdb"
	_ "github.com/conformal/btcdb/ldb"
	"github.com/conformal/btcec"
	"github.com/conformal/btclog"
	"github.com/conformal/btcscript"
	"github.com/conformal/btcutil"
)

type stringSet map[string]struct{}

func (s stringSet) Add(item string) {
	s[item] = struct{}{}
}

func (s stringSet) Contains(item string) bool {
	_, ok := s[item]
	return ok
}

const (
	tickFreq  = 10
	bloomSize = 50000000 // https://blockchain.info/charts/n-transactions-total
)

func btcdbSetup(dataDir, dbType string) (log btclog.Logger, db btcdb.Db, cleanup func()) {
	// Setup logging
	backendLogger := btclog.NewDefaultBackendLogger()
	log = btclog.NewSubsystemLogger(backendLogger, "")
	btcdb.UseLogger(log)

	// Setup database access
	blockDbNamePrefix := "blocks"
	dbName := blockDbNamePrefix + "_" + dbType
	if dbType == "sqlite" {
		dbName = dbName + ".db"
	}
	dbPath := filepath.Join(dataDir, "mainnet", dbName)

	log.Infof("loading db %v", dbType)
	db, err := btcdb.OpenDB(dbType, dbPath)
	if err != nil {
		log.Warnf("db open failed: %v", err)
		return
	}
	log.Infof("db load complete")

	cleanup = func() {
		db.Close()
		backendLogger.Flush()
	}

	return
}

type rData struct {
	sig *btcec.Signature
	H   int64
	Tx  int
}

func getSignatures(maxHeigth int64, errorFile io.Writer, log btclog.Logger, db btcdb.Db) chan *rData {
	c := make(chan *rData)

	go func() {
		for h := int64(0); h < maxHeigth; h++ {
			sha, err := db.FetchBlockShaByHeight(h)
			if err != nil {
				log.Warnf("failed FetchBlockShaByHeight(%v): %v", h, err)
				return
			}
			blk, err := db.FetchBlockBySha(sha)
			if err != nil {
				log.Warnf("failed FetchBlockBySha(%v) - h %v: %v", sha, h, err)
				return
			}

			mblk := blk.MsgBlock()

			for i, tx := range mblk.Transactions {
				// txsha, err := tx.TxSha()
				// if err != nil {
				// 	log.Warnf("Block %v (%v)", h, sha)
				// 	log.Warnf("tx %v (%v)", i, &txsha)
				// 	log.Warnf("Error: %v", err)
				// 	continue
				// }

				if btcchain.IsCoinBase(btcutil.NewTx(tx)) {
					continue
				}

				for t, txin := range tx.TxIn {
					data, err := btcscript.PushedData(txin.SignatureScript)
					if err != nil {
						io.WriteString(errorFile, fmt.Sprintf(
							"Block %v (%v) tx %v txin %v (%v)\nError: %v\n%v",
							h, sha, i, t, "PushedData", err,
							spew.Sdump(txin.SignatureScript)))
						continue
					}

					if len(data) == 0 {
						continue
					}

					signature, err := btcec.ParseSignature(data[0], btcec.S256())
					if err != nil {
						io.WriteString(errorFile, fmt.Sprintf(
							"Block %v (%v) tx %v txin %v (%v)\nError: %v\n%v",
							h, sha, i, t, "ParseSignature", err,
							spew.Sdump(data)))
						continue
					}

					c <- &rData{
						sig: signature,
						H:   h,
						Tx:  i,
					}
				}
			}
		}

		close(c)
	}()

	return c
}

func search(log btclog.Logger, db btcdb.Db, errorFile io.Writer) map[string][]*rData {
	// Setup signal handler
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1)

	// Potential optimisation: keep the bloom filter between runs
	filter := dablooms.NewScalingBloom(bloomSize, 0.01, "blockchainr_bloom.bin")
	if filter == nil {
		log.Warn("dablooms.NewScalingBloom failed")
		return nil
	}

	potentialValues := make(stringSet)
	rMap := make(map[string][]*rData)

	_, maxHeigth, err := db.NewestSha()
	if err != nil {
		log.Warnf("db NewestSha failed: %v", err)
		return nil
	}

	for step := 1; step <= 2; step++ {
		lastTime := time.Now()
		lastSig := int64(0)
		sigCounter := int64(0)
		matches := int64(0)
		ticker := time.Tick(tickFreq * time.Second)

		signatures := getSignatures(maxHeigth, errorFile, log, db)
		for rd := range signatures {
			select {
			case s := <-signalChan:
				log.Infof("Step %v - signal %v - %v sigs in %.2fs, %v matches, %v total, block %v of %v",
					step, s, sigCounter-lastSig, time.Since(lastTime).Seconds(),
					matches, sigCounter, rd.H, maxHeigth)

				if s == syscall.SIGINT || s == syscall.SIGTERM {
					return rMap
				}

			case <-ticker:
				log.Infof("Step %v - %v sigs in %.2fs, %v matches, %v total, block %v of %v",
					step, sigCounter-lastSig, time.Since(lastTime).Seconds(),
					matches, sigCounter, rd.H, maxHeigth)
				lastTime = time.Now()
				lastSig = sigCounter

			default:
				break
			}

			// Potential optimisation: store in potentialValues also the block
			// height, and if step 2 finds the same h first, it's a bloom
			// false positive
			if step == 1 {
				b := rd.sig.R.Bytes()
				if filter.Check(b) {
					matches++
					potentialValues.Add(rd.sig.R.String())
				} else {
					if !filter.Add(b, 1) {
						log.Warn("Add failed (?)")
					}
				}
			} else if step == 2 {
				if potentialValues.Contains(rd.sig.R.String()) {
					matches++
					rMap[rd.sig.R.String()] = append(rMap[rd.sig.R.String()], rd)
				}
			}
			sigCounter += 1
		}

		if *memprofile != "" {
			f, err := os.Create(fmt.Sprintf("%s.%d", *memprofile, step))
			if err != nil {
				log.Warnf("open memprofile failed: %v", err)
				return nil
			}
			pprof.WriteHeapProfile(f)
			f.Close()
		}

		log.Infof("Step %v done - %v signatures processed - %v matches",
			step, sigCounter, matches)
	}
	return rMap
}

var (
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
	memprofile = flag.String("memprofile", "", "write memory profile to this file")
)

func main() {
	var (
		dataDir = flag.String("datadir", filepath.Join(btcutil.AppDataDir("btcd", false), "data"), "BTCD: Data directory")
		dbType  = flag.String("dbtype", "leveldb", "BTCD: Database backend")
	)
	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// Setup btcdb
	log, db, dbCleanup := btcdbSetup(*dataDir, *dbType)
	defer dbCleanup()

	errorFile, err := os.Create("blockchainr_error.log")
	if err != nil {
		log.Warnf("failed to create blockchainr_error.log: %v", err)
		return
	}
	defer errorFile.Close()

	duplicates := search(log, db, errorFile)

	realDuplicates := make(map[string][]*rData)
	for k, v := range duplicates {
		if len(v) > 1 {
			realDuplicates[k] = v
		}
	}

	resultsFile, err := os.Create("blockchainr.json")
	if err != nil {
		log.Warnf("failed to create blockchainr.json: %v", err)
		return
	}
	if json.NewEncoder(resultsFile).Encode(realDuplicates) != nil {
		log.Warnf("failed to Encode the result: %v", err)
		return
	}
}
<|endoftext|>


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

package main

import (
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru"
	"launchpad.net/gnuflag"
	"os"
)

const (
	version = "0.4"
	header  = "Supported-Tsuru"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header)
	m.Register(&tsuru.AppRun{})
	m.Register(&tsuru.AppInfo{})
	m.Register(&AppCreate{})
	m.Register(&AppRemove{})
	m.Register(&UnitAdd{})
	m.Register(&UnitRemove{})
	m.Register(&tsuru.AppList{})
	m.Register(&tsuru.AppLog{})
	m.Register(&tsuru.AppGrant{})
	m.Register(&tsuru.AppRevoke{})
	m.Register(&tsuru.AppRestart{})
	m.Register(&tsuru.EnvGet{})
	m.Register(&tsuru.EnvSet{})
	m.Register(&tsuru.EnvUnset{})
	m.Register(&KeyAdd{})
	m.Register(&KeyRemove{})
	m.Register(&tsuru.ServiceList{})
	m.Register(&tsuru.ServiceAdd{})
	m.Register(&tsuru.ServiceRemove{})
	m.Register(&tsuru.ServiceBind{})
	m.Register(&tsuru.ServiceUnbind{})
	m.Register(&tsuru.ServiceDoc{})
	m.Register(&tsuru.ServiceInfo{})
	m.Register(&tsuru.ServiceInstanceStatus{})
	return m
}

func main() {
	gnuflag.Parse(true)
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := gnuflag.Args()
	manager.Run(args)
}
<commit_msg>cmd/tsuru: update client version to 0.5<commit_after>// Copyright 2012 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"github.com/globocom/tsuru/cmd"
	"github.com/globocom/tsuru/cmd/tsuru"
	"launchpad.net/gnuflag"
	"os"
)

const (
	version = "0.5"
	header  = "Supported-Tsuru"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header)
	m.Register(&tsuru.AppRun{})
	m.Register(&tsuru.AppInfo{})
	m.Register(&AppCreate{})
	m.Register(&AppRemove{})
	m.Register(&UnitAdd{})
	m.Register(&UnitRemove{})
	m.Register(&tsuru.AppList{})
	m.Register(&tsuru.AppLog{})
	m.Register(&tsuru.AppGrant{})
	m.Register(&tsuru.AppRevoke{})
	m.Register(&tsuru.AppRestart{})
	m.Register(&tsuru.EnvGet{})
	m.Register(&tsuru.EnvSet{})
	m.Register(&tsuru.EnvUnset{})
	m.Register(&KeyAdd{})
	m.Register(&KeyRemove{})
	m.Register(&tsuru.ServiceList{})
	m.Register(&tsuru.ServiceAdd{})
	m.Register(&tsuru.ServiceRemove{})
	m.Register(&tsuru.ServiceBind{})
	m.Register(&tsuru.ServiceUnbind{})
	m.Register(&tsuru.ServiceDoc{})
	m.Register(&tsuru.ServiceInfo{})
	m.Register(&tsuru.ServiceInstanceStatus{})
	return m
}

func main() {
	gnuflag.Parse(true)
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := gnuflag.Args()
	manager.Run(args)
}
<|endoftext|>


<commit_before>package csv

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
)

type Encoder struct {
	Delimiter rune
	Tag       string
	LineBreak string
	written   bool
	w         io.Writer
}

func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{
		Delimiter: ',',
		Tag:       "csv",
		LineBreak: "\n",
		w:         w,
	}
}

func (enc *Encoder) SetDelimeter(delim rune) *Encoder       { enc.Delimiter = delim; return enc }
func (enc *Encoder) SetTag(tag string) *Encoder             { enc.Tag = tag; return enc }
func (enc *Encoder) SetLineBreak(lineBreak string) *Encoder { enc.LineBreak = lineBreak; return enc }

func (enc *Encoder) Encode(v interface{}) error {
	if err := enc.encode(reflect.ValueOf(v)); err != nil {
		return err
	}
	if _, err := enc.w.Write([]byte(enc.LineBreak)); err != nil {
		return err
	}
	return nil
}

func (enc *Encoder) encode(v reflect.Value) error {
	switch v.Kind() {
	case reflect.Struct:
		return enc.encodeStruct(v)
	case reflect.Slice:
		return nil
	case reflect.Ptr:
		if !v.IsNil() {
			return enc.encode(v.Elem())
		}
	default:
		if enc.written {
			_, err := enc.w.Write([]byte(string(enc.Delimiter)))
			if err != nil {
				return err
			}
		}
		_, err := fmt.Fprint(enc.w, v.Interface())
		if err != nil {
			return err
		}
		enc.written = true
		return nil
	}
	return nil
}

func (enc *Encoder) encodeStruct(v reflect.Value) error {
	t := v.Type()
	for i := 0; i < v.NumField(); i++ {
		field := t.Field(i)
		tag := field.Tag.Get(enc.Tag)
		if tag == "-" || (tag == "" && field.Type.Kind() != reflect.Struct) {
			continue
		}
		if err := enc.encode(v.Field(i)); err != nil {
			return err
		}
	}
	return nil
}

func Marshal(v interface{}) ([]byte, error) {
	w := new(bytes.Buffer)
	if err := NewEncoder(w).Encode(v); err != nil {
		return nil, err
	}
	return w.Bytes(), nil
}
<commit_msg>fix delimiter<commit_after>package csv

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"time"
)

const (
	sqlTime = "2006-01-02 15:04:05.000"
)

type Encoder struct {
	Delimiter rune
	Tag       string
	LineBreak string
	written   bool
	w         io.Writer
}

func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{
		Delimiter: ',',
		Tag:       "csv",
		LineBreak: "\n",
		w:         w,
	}
}

func (enc *Encoder) SetDelimeter(delim rune) *Encoder       { enc.Delimiter = delim; return enc }
func (enc *Encoder) SetTag(tag string) *Encoder             { enc.Tag = tag; return enc }
func (enc *Encoder) SetLineBreak(lineBreak string) *Encoder { enc.LineBreak = lineBreak; return enc }

func (enc *Encoder) Encode(v interface{}) error {
	if err := enc.encode(reflect.ValueOf(v)); err != nil {
		return err
	}
	if _, err := enc.w.Write([]byte(enc.LineBreak)); err != nil {
		return err
	}
	return nil
}

func (enc *Encoder) encode(v reflect.Value) error {
	switch v.Kind() {
	case reflect.Struct:
		if t, ok := v.Interface().(time.Time); ok {
			return enc.write([]byte(t.Format(sqlTime)))
		}
		return enc.encodeStruct(v)
	case reflect.Slice:
		return nil
	case reflect.Ptr:
		if !v.IsNil() {
			return enc.encode(v.Elem())
		}
	default:
		return enc.write([]byte(fmt.Sprint(v.Interface())))
	}
	return nil
}

func (enc *Encoder) write(bs []byte) error {
	if enc.written {
		_, err := enc.w.Write([]byte(string(enc.Delimiter)))
		if err != nil {
			return err
		}
	}
	_, err := enc.w.Write(bs)
	if err != nil {
		return err
	}
	enc.written = true
	return nil
}

func (enc *Encoder) encodeStruct(v reflect.Value) error {
	t := v.Type()
	for i := 0; i < v.NumField(); i++ {
		field := t.Field(i)
		tag := field.Tag.Get(enc.Tag)
		if tag == "-" || (tag == "" && field.Type.Kind() != reflect.Struct) {
			continue
		}
		if err := enc.encode(v.Field(i)); err != nil {
			return err
		}
	}
	return nil
}

func Marshal(v interface{}) ([]byte, error) {
	w := new(bytes.Buffer)
	if err := NewEncoder(w).Encode(v); err != nil {
		return nil, err
	}
	return w.Bytes(), nil
}
<|endoftext|>


<commit_before>package bencode

import (
	"bytes"

	"fmt"
	"io"
	"reflect"
	"sort"
)

type sortValues []reflect.Value

func (p sortValues) Len() int           { return len(p) }
func (p sortValues) Less(i, j int) bool { return p[i].String() < p[j].String() }
func (p sortValues) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

type sortFields []reflect.StructField

func (p sortFields) Len() int { return len(p) }
func (p sortFields) Less(i, j int) bool {
	iName, jName := p[i].Name, p[j].Name
	if name, _ := parseTag(p[i].Tag.Get("bencode")); name != "" {
		iName = name
	}
	if name, _ := parseTag(p[j].Tag.Get("bencode")); name != "" {
		jName = name
	}
	return iName < jName
}
func (p sortFields) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

//An Encoder writes bencoded objects to an output stream.
type Encoder struct {
	w io.Writer
}

//NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w}
}

//Encode writes the bencoded data of val to its output stream.
//See the documentation for Decode about the conversion of Go values to
//bencoded data.
func (e *Encoder) Encode(val interface{}) error {
	return encodeValue(e.w, reflect.ValueOf(val))
}

//EncodeString returns the bencoded data of val as a string.
func EncodeString(val interface{}) (string, error) {
	buf := new(bytes.Buffer)
	e := NewEncoder(buf)
	if err := e.Encode(val); err != nil {
		return "", err
	}
	return buf.String(), nil
}

//EncodeBool returns the bencoded data of val as a bool.
func EncodeBool(val interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	e := NewEncoder(buf)
	if err := e.Encode(val); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

//EncodeBytes returns the bencoded data of val as a slice of bytes.
func EncodeBytes(val interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	e := NewEncoder(buf)
	if err := e.Encode(val); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func encodeValue(w io.Writer, val reflect.Value) error {
	//inspect the val to check
	v := indirect(val)

	//send in a raw message if we have that type
	if rm, ok := v.Interface().(RawMessage); ok {
		_, err := io.Copy(w, bytes.NewReader(rm))
		return err
	}

	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		_, err := fmt.Fprintf(w, "i%de", v.Int())
		return err

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		_, err := fmt.Fprintf(w, "i%de", v.Uint())
		return err

	case reflect.Bool:
		i := 0
		if v.Bool() {
			i = 1
		}
		_, err := fmt.Fprintf(w, "i%de", i)
		return err

	case reflect.String:
		_, err := fmt.Fprintf(w, "%d:%s", len(v.String()), v.String())
		return err

	case reflect.Slice, reflect.Array:
		if _, err := fmt.Fprint(w, "l"); err != nil {
			return err
		}
		for i := 0; i < v.Len(); i++ {
			if err := encodeValue(w, v.Index(i)); err != nil {
				return err
			}
		}

		_, err := fmt.Fprint(w, "e")
		return err

	case reflect.Map:
		if _, err := fmt.Fprint(w, "d"); err != nil {
			return err
		}
		var (
			keys sortValues = v.MapKeys()
			mval reflect.Value
		)
		sort.Sort(keys)
		for i := range keys {
			if err := encodeValue(w, keys[i]); err != nil {
				return err
			}
			mval = v.MapIndex(keys[i])
			if err := encodeValue(w, mval); err != nil {
				return err
			}
		}
		_, err := fmt.Fprint(w, "e")
		return err

	case reflect.Struct:
		t := v.Type()
		if _, err := fmt.Fprint(w, "d"); err != nil {
			return err
		}
		//put keys into keys
		var (
			keys       = make(sortFields, t.NumField())
			fieldValue reflect.Value
			rkey       reflect.Value
		)
		for i := range keys {
			keys[i] = t.Field(i)
		}
		sort.Sort(keys)
		for _, key := range keys {
			rkey = reflect.ValueOf(key.Name)
			fieldValue = v.FieldByIndex(key.Index)

			// filter out unexported values etc.
			if !fieldValue.CanInterface() {
				continue
			}

			/* Tags
			* Near identical to usage in JSON except with key 'bencode'

			* Struct values encode as BEncode dictionaries. Each exported
			  struct field becomes a set in the dictionary unless
			  - the field's tag is "-", or
			  - the field is empty and its tag specifies the "omitempty"
			    option.

			* The default key string is the struct field name but can be
			  specified in the struct field's tag value.  The "bencode"
			  key in struct field's tag value is the key name, followed
			  by an optional comma and options.
			*/
			tagValue := key.Tag.Get("bencode")
			if tagValue != "" {
				// Keys with '-' are omit from output
				if tagValue == "-" {
					continue
				}

				name, options := parseTag(tagValue)
				// Keys with 'omitempty' are omitted if the field is empty
				if options.Contains("omitempty") && isEmptyValue(fieldValue) {
					continue
				}

				// All other values are treated as the key string
				if isValidTag(name) {
					rkey = reflect.ValueOf(name)
				}
			}

			//encode the key
			if err := encodeValue(w, rkey); err != nil {
				return err
			}
			//encode the value
			if err := encodeValue(w, fieldValue); err != nil {
				return err
			}
		}
		_, err := fmt.Fprint(w, "e")
		return err
	}

	return fmt.Errorf("Can't encode type: %s", v.Type())
}
<commit_msg>remove EncodeBool<commit_after>package bencode

import (
	"bytes"

	"fmt"
	"io"
	"reflect"
	"sort"
)

type sortValues []reflect.Value

func (p sortValues) Len() int           { return len(p) }
func (p sortValues) Less(i, j int) bool { return p[i].String() < p[j].String() }
func (p sortValues) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

type sortFields []reflect.StructField

func (p sortFields) Len() int { return len(p) }
func (p sortFields) Less(i, j int) bool {
	iName, jName := p[i].Name, p[j].Name
	if name, _ := parseTag(p[i].Tag.Get("bencode")); name != "" {
		iName = name
	}
	if name, _ := parseTag(p[j].Tag.Get("bencode")); name != "" {
		jName = name
	}
	return iName < jName
}
func (p sortFields) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

//An Encoder writes bencoded objects to an output stream.
type Encoder struct {
	w io.Writer
}

//NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w}
}

//Encode writes the bencoded data of val to its output stream.
//See the documentation for Decode about the conversion of Go values to
//bencoded data.
func (e *Encoder) Encode(val interface{}) error {
	return encodeValue(e.w, reflect.ValueOf(val))
}

//EncodeString returns the bencoded data of val as a string.
func EncodeString(val interface{}) (string, error) {
	buf := new(bytes.Buffer)
	e := NewEncoder(buf)
	if err := e.Encode(val); err != nil {
		return "", err
	}
	return buf.String(), nil
}

//EncodeBytes returns the bencoded data of val as a slice of bytes.
func EncodeBytes(val interface{}) ([]byte, error) {
	buf := new(bytes.Buffer)
	e := NewEncoder(buf)
	if err := e.Encode(val); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func encodeValue(w io.Writer, val reflect.Value) error {
	//inspect the val to check
	v := indirect(val)

	//send in a raw message if we have that type
	if rm, ok := v.Interface().(RawMessage); ok {
		_, err := io.Copy(w, bytes.NewReader(rm))
		return err
	}

	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		_, err := fmt.Fprintf(w, "i%de", v.Int())
		return err

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		_, err := fmt.Fprintf(w, "i%de", v.Uint())
		return err

	case reflect.Bool:
		i := 0
		if v.Bool() {
			i = 1
		}
		_, err := fmt.Fprintf(w, "i%de", i)
		return err

	case reflect.String:
		_, err := fmt.Fprintf(w, "%d:%s", len(v.String()), v.String())
		return err

	case reflect.Slice, reflect.Array:
		if _, err := fmt.Fprint(w, "l"); err != nil {
			return err
		}
		for i := 0; i < v.Len(); i++ {
			if err := encodeValue(w, v.Index(i)); err != nil {
				return err
			}
		}

		_, err := fmt.Fprint(w, "e")
		return err

	case reflect.Map:
		if _, err := fmt.Fprint(w, "d"); err != nil {
			return err
		}
		var (
			keys sortValues = v.MapKeys()
			mval reflect.Value
		)
		sort.Sort(keys)
		for i := range keys {
			if err := encodeValue(w, keys[i]); err != nil {
				return err
			}
			mval = v.MapIndex(keys[i])
			if err := encodeValue(w, mval); err != nil {
				return err
			}
		}
		_, err := fmt.Fprint(w, "e")
		return err

	case reflect.Struct:
		t := v.Type()
		if _, err := fmt.Fprint(w, "d"); err != nil {
			return err
		}
		//put keys into keys
		var (
			keys       = make(sortFields, t.NumField())
			fieldValue reflect.Value
			rkey       reflect.Value
		)
		for i := range keys {
			keys[i] = t.Field(i)
		}
		sort.Sort(keys)
		for _, key := range keys {
			rkey = reflect.ValueOf(key.Name)
			fieldValue = v.FieldByIndex(key.Index)

			// filter out unexported values etc.
			if !fieldValue.CanInterface() {
				continue
			}

			/* Tags
			* Near identical to usage in JSON except with key 'bencode'

			* Struct values encode as BEncode dictionaries. Each exported
			  struct field becomes a set in the dictionary unless
			  - the field's tag is "-", or
			  - the field is empty and its tag specifies the "omitempty"
			    option.

			* The default key string is the struct field name but can be
			  specified in the struct field's tag value.  The "bencode"
			  key in struct field's tag value is the key name, followed
			  by an optional comma and options.
			*/
			tagValue := key.Tag.Get("bencode")
			if tagValue != "" {
				// Keys with '-' are omit from output
				if tagValue == "-" {
					continue
				}

				name, options := parseTag(tagValue)
				// Keys with 'omitempty' are omitted if the field is empty
				if options.Contains("omitempty") && isEmptyValue(fieldValue) {
					continue
				}

				// All other values are treated as the key string
				if isValidTag(name) {
					rkey = reflect.ValueOf(name)
				}
			}

			//encode the key
			if err := encodeValue(w, rkey); err != nil {
				return err
			}
			//encode the value
			if err := encodeValue(w, fieldValue); err != nil {
				return err
			}
		}
		_, err := fmt.Fprint(w, "e")
		return err
	}

	return fmt.Errorf("Can't encode type: %s", v.Type())
}
<|endoftext|>


<commit_before>package MinecraftProxy

import (
	"os"
	"log"
	"net"
	"io"
	"fmt"
	"errors"
	"strconv"
)

func badUsage() {
	fmt.Fprintln(os.Stderr, "Usage: MinecraftProxy <Host:Port> <RemoteHost:RemotePort>"); os.Exit(1)
}

func Create() {
	if len(os.Args) < 2  || len(os.Args) > 3 { badUsage() }

	localHost := ParseAddress(os.Args[1])
	if localHost == nil { badUsage() }
	localAddress, _, err := localHost.Resolve()
	if err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) }

	remoteHost := ParseAddress(os.Args[2])
	if remoteHost == nil { badUsage() }
	_, _, err = remoteHost.Resolve()
	if err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) }

	fmt.Println("Listening to:", os.Args[1])
	fmt.Println("Proxying to:", os.Args[2])
	fmt.Println()

	log.SetPrefix("[MinecraftProxy] ")
	log.SetOutput(os.Stdout)
	Start(localAddress, remoteHost)
}

func Start(localAddress *net.TCPAddr, remoteAddress *ServerAddress) (err error) {
	local, err := net.ListenTCP("tcp", localAddress)
	if err != nil { return }
	defer local.Close()

	for {
		conn, err := local.AcceptTCP()
		if conn != nil {
			go proxy(conn, remoteAddress)
		} else {
			log.Fatalln("Connection failed: " + err.Error())
		}
	}
}

func transformHandshake(local *net.TCPConn, remote *net.TCPConn, address *ConnectAddress) (err error) {
	localMinecraft := &MinecraftStream { local }
	packetID, reader, err := packetReader(localMinecraft)
	if packetID != 0x00 { return errors.New("Invalid handshake packet: " + strconv.Itoa(packetID)) }

	version, err := readVarInt(reader); if err != nil { return }
	clientAddress, err := readString(reader); if err != nil { return }
	clientPort, err := readShort(reader); if err != nil { return }
	request, err := readVarInt(reader); if err != nil { return }

	log.Println("Client connected with", clientAddress, clientPort, "Version", version, "Request", request)
	log.Println("Connecting to server with", address.Host, address.Port, "Version", version, "Request", request)

	writer, err := packetWriter(0x00); if err != nil { return }
	err = writeVarInt(writer, version); if err != nil { return }
	err = writeString(writer, address.Host); if err != nil { return }
	err = writeShort(writer, address.Port); if err != nil { return }
	err = writeVarInt(writer, request); if err != nil { return }

	err = writeVarInt(remote, writer.Len()); if err != nil { return }
	_, err = remote.Write(writer.Bytes()); return
}

func proxy(local *net.TCPConn, remoteHost *ServerAddress) {
	defer local.Close()
	remoteAddress, connectAddress, err := remoteHost.Resolve()
	if err != nil { log.Println("Cannot resolve address: " + err.Error()); return }

	log.Println("Proxying " + local.RemoteAddr().String() + " to " + remoteAddress.String())

	remote, err := net.DialTCP("tcp", nil, remoteAddress)
	if remote == nil { log.Println("Unable to connect: " + err.Error()); return }
	defer remote.Close()

	transformHandshake(local, remote, connectAddress)

	copyError := make(chan string)
	go copyStream(local, remote, copyError, true)
	go copyStream(remote, local, copyError, false)

	copyErr := <- copyError
	if len(copyErr) > 0 {
		log.Println(copyErr)
	}

	log.Println("Disconnected " + local.RemoteAddr().String() + " from " + remoteAddress.String())
}

func copyStream(from, to net.Conn, out chan<- string, client bool) {
	_, err := io.Copy(to, from)
	if err != nil {
		name := "SERVER"; if client { name = "CLIENT" }
		out <- "An error occurred with [" + name + "|" + from.RemoteAddr().String() + "]\n" + err.Error()
	} else {
		out <- ""
	}
}
<commit_msg>Change output a little bit and catch errors when tranforming the handshake.<commit_after>package MinecraftProxy

import (
	"os"
	"log"
	"net"
	"io"
	"fmt"
	"errors"
	"strconv"
)

func badUsage() {
	fmt.Fprintln(os.Stderr, "Usage: MinecraftProxy <Host:Port> <RemoteHost:RemotePort>"); os.Exit(1)
}

func Create() {
	if len(os.Args) < 2  || len(os.Args) > 3 { badUsage() }

	localHost := ParseAddress(os.Args[1])
	if localHost == nil { badUsage() }
	localAddress, _, err := localHost.Resolve()
	if err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) }

	remoteHost := ParseAddress(os.Args[2])
	if remoteHost == nil { badUsage() }
	_, _, err = remoteHost.Resolve()
	if err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(1) }

	fmt.Println("Listening to:", os.Args[1])
	fmt.Println("Proxying to:", os.Args[2])
	fmt.Println()

	log.SetPrefix("[MinecraftProxy] ")
	log.SetOutput(os.Stdout)
	Start(localAddress, remoteHost)
}

func Start(localAddress *net.TCPAddr, remoteAddress *ServerAddress) (err error) {
	local, err := net.ListenTCP("tcp", localAddress)
	if err != nil { return }
	defer local.Close()

	for {
		conn, err := local.AcceptTCP()
		if err == nil {
			go proxy(conn, remoteAddress)
		} else {
			log.Println("Connection failed:", err)
		}
	}
}

func transformHandshake(local *net.TCPConn, remote *net.TCPConn, address *ConnectAddress) (err error) {
	localMinecraft := &MinecraftStream { local }
	packetID, reader, err := packetReader(localMinecraft)
	if packetID != 0x00 { return errors.New("Invalid handshake packet: " + strconv.Itoa(packetID)) }

	version, err := readVarInt(reader); if err != nil { return }
	clientAddress, err := readString(reader); if err != nil { return }
	clientPort, err := readShort(reader); if err != nil { return }
	request, err := readVarInt(reader); if err != nil { return }

	log.Println("Client connected with", clientAddress, clientPort, "Version", version, "Request", request)
	log.Println("Connecting to server with", address.Host, address.Port, "Version", version, "Request", request)

	writer, err := packetWriter(0x00); if err != nil { return }
	err = writeVarInt(writer, version); if err != nil { return }
	err = writeString(writer, address.Host); if err != nil { return }
	err = writeShort(writer, address.Port); if err != nil { return }
	err = writeVarInt(writer, request); if err != nil { return }

	err = writeVarInt(remote, writer.Len()); if err != nil { return }
	_, err = remote.Write(writer.Bytes()); return
}

func proxy(local *net.TCPConn, remoteHost *ServerAddress) {
	defer local.Close()
	remoteAddress, connectAddress, err := remoteHost.Resolve()
	if err != nil { log.Println("Cannot resolve address:", err.Error()); return }

	log.Println("Proxying", local.RemoteAddr(), "to", remoteAddress)

	remote, err := net.DialTCP("tcp", nil, remoteAddress)
	if err != nil { log.Println("Unable to connect:", err); return }
	defer remote.Close()

	err = transformHandshake(local, remote, connectAddress)
	if err != nil { log.Println("Unable to transform handshake:", err)}

	copyError := make(chan string)
	go copyStream(local, remote, copyError, true)
	go copyStream(remote, local, copyError, false)

	copyErr := <- copyError
	if len(copyErr) > 0 {
		log.Println(copyErr)
	}

	log.Println("Disconnected", local.RemoteAddr(), "from", remoteAddress)
}

func copyStream(from, to net.Conn, out chan<- string, client bool) {
	_, err := io.Copy(to, from)
	if err != nil {
		name := "SERVER"; if client { name = "CLIENT" }
		out <- "An error occurred with [" + name + "|" + from.RemoteAddr().String() + "]\n" + err.Error()
	} else {
		out <- ""
	}
}
<|endoftext|>


<commit_before>package api_test

import (
	. "cf/api"
	"cf/configuration"
	"code.google.com/p/go.net/websocket"
	"code.google.com/p/gogoprotobuf/proto"
	"github.com/cloudfoundry/loggregatorlib/logmessage"
	"github.com/stretchr/testify/assert"
	"net/http/httptest"
	"strings"
	testapi "testhelpers/api"

	. "github.com/onsi/ginkgo"
	mr "github.com/tjarratt/mr_t"
	"time"
)

func marshalledLogMessageWithTime(t mr.TestingT, messageString string, timestamp int64) []byte {
	messageType := logmessage.LogMessage_OUT
	sourceName := "DEA"
	protoMessage := &logmessage.LogMessage{
		Message:     []byte(messageString),
		AppId:       proto.String("my-app-guid"),
		MessageType: &messageType,
		SourceName:  &sourceName,
		Timestamp:   proto.Int64(timestamp),
	}

	message, err := proto.Marshal(protoMessage)
	assert.NoError(t, err)

	return message
}
func init() {
	Describe("Testing with ginkgo", func() {
		It("TestRecentLogsFor", func() {
			messagesSent := [][]byte{
				marshalledLogMessageWithTime(mr.T(), "My message", int64(3000)),
			}

			websocketEndpoint := func(conn *websocket.Conn) {
				request := conn.Request()
				assert.Equal(mr.T(), request.URL.Path, "/dump/")
				assert.Equal(mr.T(), request.URL.RawQuery, "app=my-app-guid")
				assert.Equal(mr.T(), request.Method, "GET")
				assert.Contains(mr.T(), request.Header.Get("Authorization"), "BEARER my_access_token")

				for _, msg := range messagesSent {
					conn.Write(msg)
				}
				time.Sleep(time.Duration(20) * time.Millisecond)
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			expectedMessage, err := logmessage.ParseMessage(messagesSent[0])
			assert.NoError(mr.T(), err)

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}

			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)

			connected := false
			onConnect := func() {
				connected = true
			}

			logChan := make(chan *logmessage.Message, 1000)

			err = logsRepo.RecentLogsFor("my-app-guid", onConnect, logChan)
			close(logChan)

			dumpedMessages := []*logmessage.Message{}
			for msg := range logChan {
				dumpedMessages = append(dumpedMessages, msg)
			}

			assert.NoError(mr.T(), err)

			assert.Equal(mr.T(), len(dumpedMessages), 1)
			assert.Equal(mr.T(), dumpedMessages[0].GetLogMessage().GetSourceName(), expectedMessage.GetLogMessage().GetSourceName())
			assert.Equal(mr.T(), dumpedMessages[0].GetLogMessage().GetMessage(), expectedMessage.GetLogMessage().GetMessage())
			assert.Equal(mr.T(), dumpedMessages[0].GetLogMessage().GetMessageType(), expectedMessage.GetLogMessage().GetMessageType())
		})
		It("TestRecentLogsSendsAllMessages", func() {

			websocketEndpoint := func(conn *websocket.Conn) {
				conn.Write(marshalledLogMessageWithTime(mr.T(), "My message", int64(3000)))
				time.Sleep(time.Duration(1) * time.Millisecond)
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)
			logChan := make(chan *logmessage.Message, 1000)

			logsRepo.RecentLogsFor("my-app-guid", func() {}, logChan)
			assert.Equal(mr.T(), len(logChan), 1)
		})
		It("TestTailsLogsFor", func() {

			messagesSent := [][]byte{
				marshalledLogMessageWithTime(mr.T(), "My message 3", int64(300000)),
				marshalledLogMessageWithTime(mr.T(), "My message 1", int64(100000)),
				marshalledLogMessageWithTime(mr.T(), "My message 2", int64(200000)),
			}

			websocketEndpoint := func(conn *websocket.Conn) {
				request := conn.Request()
				assert.Equal(mr.T(), request.URL.Path, "/tail/")
				assert.Equal(mr.T(), request.URL.RawQuery, "app=my-app-guid")
				assert.Equal(mr.T(), request.Method, "GET")
				assert.Contains(mr.T(), request.Header.Get("Authorization"), "BEARER my_access_token")

				for _, msg := range messagesSent {
					conn.Write(msg)
				}
				time.Sleep(time.Duration(1) * time.Millisecond)
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)

			connected := false
			onConnect := func() {
				connected = true
			}

			tailedMessages := []*logmessage.Message{}

			logChan := make(chan *logmessage.Message, 1000)

			controlChan := make(chan bool)

			logsRepo.TailLogsFor("my-app-guid", onConnect, logChan, controlChan, time.Duration(1))
			close(logChan)

			for msg := range logChan {
				tailedMessages = append(tailedMessages, msg)
			}

			assert.True(mr.T(), connected)

			assert.Equal(mr.T(), len(tailedMessages), 3)

			tailedMessage := tailedMessages[0]
			actualMessage, err := proto.Marshal(tailedMessage.GetLogMessage())
			assert.NoError(mr.T(), err)
			assert.Equal(mr.T(), actualMessage, messagesSent[1])

			tailedMessage = tailedMessages[1]
			actualMessage, err = proto.Marshal(tailedMessage.GetLogMessage())
			assert.NoError(mr.T(), err)
			assert.Equal(mr.T(), actualMessage, messagesSent[2])

			tailedMessage = tailedMessages[2]
			actualMessage, err = proto.Marshal(tailedMessage.GetLogMessage())
			assert.NoError(mr.T(), err)
			assert.Equal(mr.T(), actualMessage, messagesSent[0])
		})
		It("TestMessageOutputOrder", func() {

			startTime := time.Now()
			messagesSent := [][]byte{
				marshalledLogMessageWithTime(mr.T(), "My message 1", startTime.UnixNano()),
				marshalledLogMessageWithTime(mr.T(), "My message 2", startTime.UnixNano()),
				marshalledLogMessageWithTime(mr.T(), "My message 3", startTime.UnixNano()),
			}

			websocketEndpoint := func(conn *websocket.Conn) {
				request := conn.Request()
				assert.Equal(mr.T(), request.URL.Path, "/tail/")
				assert.Equal(mr.T(), request.URL.RawQuery, "app=my-app-guid")
				assert.Equal(mr.T(), request.Method, "GET")
				assert.Contains(mr.T(), request.Header.Get("Authorization"), "BEARER my_access_token")

				for _, msg := range messagesSent {
					conn.Write(msg)
				}
				time.Sleep(time.Duration(1) * time.Millisecond)
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)

			logChan := make(chan *logmessage.Message, 1000)
			controlChan := make(chan bool)

			go func() {
				defer close(logChan)
				logsRepo.TailLogsFor("my-app-guid", func() {}, logChan, controlChan, time.Duration(1*time.Second))
			}()

			var messages []string
			for msg := range logChan {
				messages = append(messages, string(msg.GetLogMessage().Message))
			}

			assert.Equal(mr.T(), messages, []string{"My message 1", "My message 2", "My message 3"})
		})
		It("TestMessageOutputWhenFlushingAfterServerDeath", func() {

			startTime := time.Now()
			messagesSent := [][]byte{
				marshalledLogMessageWithTime(mr.T(), "My message 1", startTime.UnixNano()),
				marshalledLogMessageWithTime(mr.T(), "My message 2", startTime.UnixNano()),
				marshalledLogMessageWithTime(mr.T(), "My message 3", startTime.UnixNano()),
			}

			websocketEndpoint := func(conn *websocket.Conn) {
				request := conn.Request()
				assert.Equal(mr.T(), request.URL.Path, "/tail/")
				assert.Equal(mr.T(), request.URL.RawQuery, "app=my-app-guid")
				assert.Equal(mr.T(), request.Method, "GET")
				assert.Contains(mr.T(), request.Header.Get("Authorization"), "BEARER my_access_token")

				for _, msg := range messagesSent {
					conn.Write(msg)
				}
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)

			firstMessageTime := time.Now().Add(-10 * time.Second).UnixNano()

			logChan := make(chan *logmessage.Message, 1000)
			controlChan := make(chan bool)

			go func() {
				defer close(logChan)
				logsRepo.TailLogsFor("my-app-guid", func() {}, logChan, controlChan, time.Duration(1*time.Second))
			}()

			for msg := range logChan {
				switch string(msg.GetLogMessage().Message) {
				case "My message 1":
					firstMessageTime = time.Now().UnixNano()
				case "My message 2":
					timeNow := time.Now().UnixNano()
					delta := timeNow - firstMessageTime
					assert.True(mr.T(), delta < (5*time.Millisecond).Nanoseconds())
					assert.True(mr.T(), delta >= 0)
				case "My message 3":
					timeNow := time.Now().UnixNano()
					delta := timeNow - firstMessageTime
					assert.True(mr.T(), delta < (5*time.Millisecond).Nanoseconds())
					assert.True(mr.T(), delta >= 0)
				}
			}
		})
	})
}
<commit_msg>Attempt to deflake logging tests<commit_after>package api_test

import (
	. "cf/api"
	"cf/configuration"
	"code.google.com/p/go.net/websocket"
	"code.google.com/p/gogoprotobuf/proto"
	"github.com/cloudfoundry/loggregatorlib/logmessage"
	"github.com/stretchr/testify/assert"
	"net/http/httptest"
	"strings"
	testapi "testhelpers/api"

	. "github.com/onsi/ginkgo"
	mr "github.com/tjarratt/mr_t"
	"time"
)

func marshalledLogMessageWithTime(t mr.TestingT, messageString string, timestamp int64) []byte {
	messageType := logmessage.LogMessage_OUT
	sourceName := "DEA"
	protoMessage := &logmessage.LogMessage{
		Message:     []byte(messageString),
		AppId:       proto.String("my-app-guid"),
		MessageType: &messageType,
		SourceName:  &sourceName,
		Timestamp:   proto.Int64(timestamp),
	}

	message, err := proto.Marshal(protoMessage)
	assert.NoError(t, err)

	return message
}
func init() {
	Describe("Testing with ginkgo", func() {
		It("TestRecentLogsFor", func() {
			messagesSent := [][]byte{
				marshalledLogMessageWithTime(mr.T(), "My message", int64(3000)),
			}

			websocketEndpoint := func(conn *websocket.Conn) {
				request := conn.Request()
				assert.Equal(mr.T(), request.URL.Path, "/dump/")
				assert.Equal(mr.T(), request.URL.RawQuery, "app=my-app-guid")
				assert.Equal(mr.T(), request.Method, "GET")
				assert.Contains(mr.T(), request.Header.Get("Authorization"), "BEARER my_access_token")

				for _, msg := range messagesSent {
					conn.Write(msg)
				}
			}

			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			expectedMessage, err := logmessage.ParseMessage(messagesSent[0])
			assert.NoError(mr.T(), err)

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}

			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)

			connected := false
			onConnect := func() {
				connected = true
			}

			logChan := make(chan *logmessage.Message, 1000)

			err = logsRepo.RecentLogsFor("my-app-guid", onConnect, logChan)
			close(logChan)

			dumpedMessages := []*logmessage.Message{}
			for msg := range logChan {
				dumpedMessages = append(dumpedMessages, msg)
			}

			assert.NoError(mr.T(), err)

			assert.Equal(mr.T(), len(dumpedMessages), 1)
			assert.Equal(mr.T(), dumpedMessages[0].GetLogMessage().GetSourceName(), expectedMessage.GetLogMessage().GetSourceName())
			assert.Equal(mr.T(), dumpedMessages[0].GetLogMessage().GetMessage(), expectedMessage.GetLogMessage().GetMessage())
			assert.Equal(mr.T(), dumpedMessages[0].GetLogMessage().GetMessageType(), expectedMessage.GetLogMessage().GetMessageType())
		})
		It("TestRecentLogsSendsAllMessages", func() {

			websocketEndpoint := func(conn *websocket.Conn) {
				conn.Write(marshalledLogMessageWithTime(mr.T(), "My message", int64(3000)))
				time.Sleep(time.Duration(1) * time.Millisecond)
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)
			logChan := make(chan *logmessage.Message, 1000)

			logsRepo.RecentLogsFor("my-app-guid", func() {}, logChan)
			assert.Equal(mr.T(), len(logChan), 1)
		})
		It("TestTailsLogsFor", func() {

			messagesSent := [][]byte{
				marshalledLogMessageWithTime(mr.T(), "My message 3", int64(300000)),
				marshalledLogMessageWithTime(mr.T(), "My message 1", int64(100000)),
				marshalledLogMessageWithTime(mr.T(), "My message 2", int64(200000)),
			}

			websocketEndpoint := func(conn *websocket.Conn) {
				request := conn.Request()
				assert.Equal(mr.T(), request.URL.Path, "/tail/")
				assert.Equal(mr.T(), request.URL.RawQuery, "app=my-app-guid")
				assert.Equal(mr.T(), request.Method, "GET")
				assert.Contains(mr.T(), request.Header.Get("Authorization"), "BEARER my_access_token")

				for _, msg := range messagesSent {
					conn.Write(msg)
				}
				time.Sleep(time.Duration(1) * time.Millisecond)
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)

			connected := false
			onConnect := func() {
				connected = true
			}

			tailedMessages := []*logmessage.Message{}

			logChan := make(chan *logmessage.Message, 1000)

			controlChan := make(chan bool)

			logsRepo.TailLogsFor("my-app-guid", onConnect, logChan, controlChan, time.Duration(1))
			close(logChan)

			for msg := range logChan {
				tailedMessages = append(tailedMessages, msg)
			}

			assert.True(mr.T(), connected)

			assert.Equal(mr.T(), len(tailedMessages), 3)

			tailedMessage := tailedMessages[0]
			actualMessage, err := proto.Marshal(tailedMessage.GetLogMessage())
			assert.NoError(mr.T(), err)
			assert.Equal(mr.T(), actualMessage, messagesSent[1])

			tailedMessage = tailedMessages[1]
			actualMessage, err = proto.Marshal(tailedMessage.GetLogMessage())
			assert.NoError(mr.T(), err)
			assert.Equal(mr.T(), actualMessage, messagesSent[2])

			tailedMessage = tailedMessages[2]
			actualMessage, err = proto.Marshal(tailedMessage.GetLogMessage())
			assert.NoError(mr.T(), err)
			assert.Equal(mr.T(), actualMessage, messagesSent[0])
		})
		It("TestMessageOutputOrder", func() {

			startTime := time.Now()
			messagesSent := [][]byte{
				marshalledLogMessageWithTime(mr.T(), "My message 1", startTime.UnixNano()),
				marshalledLogMessageWithTime(mr.T(), "My message 2", startTime.UnixNano()),
				marshalledLogMessageWithTime(mr.T(), "My message 3", startTime.UnixNano()),
			}

			websocketEndpoint := func(conn *websocket.Conn) {
				request := conn.Request()
				assert.Equal(mr.T(), request.URL.Path, "/tail/")
				assert.Equal(mr.T(), request.URL.RawQuery, "app=my-app-guid")
				assert.Equal(mr.T(), request.Method, "GET")
				assert.Contains(mr.T(), request.Header.Get("Authorization"), "BEARER my_access_token")

				for _, msg := range messagesSent {
					conn.Write(msg)
				}
				time.Sleep(time.Duration(1) * time.Millisecond)
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)

			logChan := make(chan *logmessage.Message, 1000)
			controlChan := make(chan bool)

			go func() {
				defer close(logChan)
				logsRepo.TailLogsFor("my-app-guid", func() {}, logChan, controlChan, time.Duration(1*time.Second))
			}()

			var messages []string
			for msg := range logChan {
				messages = append(messages, string(msg.GetLogMessage().Message))
			}

			assert.Equal(mr.T(), messages, []string{"My message 1", "My message 2", "My message 3"})
		})
		It("TestMessageOutputWhenFlushingAfterServerDeath", func() {

			startTime := time.Now()
			messagesSent := [][]byte{
				marshalledLogMessageWithTime(mr.T(), "My message 1", startTime.UnixNano()),
				marshalledLogMessageWithTime(mr.T(), "My message 2", startTime.UnixNano()),
				marshalledLogMessageWithTime(mr.T(), "My message 3", startTime.UnixNano()),
			}

			websocketEndpoint := func(conn *websocket.Conn) {
				request := conn.Request()
				assert.Equal(mr.T(), request.URL.Path, "/tail/")
				assert.Equal(mr.T(), request.URL.RawQuery, "app=my-app-guid")
				assert.Equal(mr.T(), request.Method, "GET")
				assert.Contains(mr.T(), request.Header.Get("Authorization"), "BEARER my_access_token")

				for _, msg := range messagesSent {
					conn.Write(msg)
				}
				conn.Close()
			}
			websocketServer := httptest.NewTLSServer(websocket.Handler(websocketEndpoint))
			defer websocketServer.Close()

			config := &configuration.Configuration{AccessToken: "BEARER my_access_token", Target: "https://localhost"}
			endpointRepo := &testapi.FakeEndpointRepo{}
			endpointRepo.LoggregatorEndpointReturns.Endpoint = strings.Replace(websocketServer.URL, "https", "wss", 1)

			logsRepo := NewLoggregatorLogsRepository(config, endpointRepo)

			firstMessageTime := time.Now().Add(-10 * time.Second).UnixNano()

			logChan := make(chan *logmessage.Message, 1000)
			controlChan := make(chan bool)

			go func() {
				defer close(logChan)
				logsRepo.TailLogsFor("my-app-guid", func() {}, logChan, controlChan, time.Duration(1*time.Second))
			}()

			for msg := range logChan {
				switch string(msg.GetLogMessage().Message) {
				case "My message 1":
					firstMessageTime = time.Now().UnixNano()
				case "My message 2":
					timeNow := time.Now().UnixNano()
					delta := timeNow - firstMessageTime
					assert.True(mr.T(), delta < (5*time.Millisecond).Nanoseconds())
					assert.True(mr.T(), delta >= 0)
				case "My message 3":
					timeNow := time.Now().UnixNano()
					delta := timeNow - firstMessageTime
					assert.True(mr.T(), delta < (5*time.Millisecond).Nanoseconds())
					assert.True(mr.T(), delta >= 0)
				}
			}
		})
	})
}
<|endoftext|>


<commit_before>package assertions

import (
	"fmt"
	"strconv"

	"ci.guzzler.io/guzzler/corcel/core"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

type AssertionTestCase struct {
	Actual               interface{}
	Instance             interface{}
	ActualStringNumber   bool
	InstanceStringNumber bool
}

func NewAsssertionTestCase(actual interface{}, instance interface{}) (newInstance AssertionTestCase) {
	newInstance.Actual = actual
	newInstance.Instance = instance
	switch actualType := actual.(type) {
	case string:
		_, err := strconv.ParseFloat(actualType, 64)
		if err == nil {
			newInstance.ActualStringNumber = true
		}
	}
	switch instanceType := instance.(type) {
	case string:
		_, err := strconv.ParseFloat(instanceType, 64)
		if err == nil {
			newInstance.InstanceStringNumber = true
		}
	}
	return
}

var _ = FDescribe("Assertions", func() {

	key := "some:key"

	assert := func(testCases []AssertionTestCase, test func(actual interface{}, instance interface{})) {

		for _, testCase := range testCases {
			actualValue := testCase.Actual
			instanceValue := testCase.Instance
			testName := fmt.Sprintf("When Actual is of type %T and Instance is of type %T", actualValue, instanceValue)
			if testCase.ActualStringNumber {
				testName = fmt.Sprintf("%s. Actual value is a STRING NUMBER in this case", testName)
			}
			if testCase.InstanceStringNumber {
				testName = fmt.Sprintf("%s. Instance value is a STRING NUMBER in this case", testName)
			}
			It(testName, func() {
				test(actualValue, instanceValue)
			})
		}
	}

	/*
	   Using this test function and the test cases we get a nice readable output.  If you run ginkgo -v here is an example of the output

	   Assertions Greater Than Succeeds
	     When Actual is of type int and Instance is of type string. Instance value is a STRING NUMBER
	*/

	var nilValue interface{}

	FContext("Greater Than", func() {

		Context("Succeeds", func() {
			var testCases = []AssertionTestCase{
				NewAsssertionTestCase(float64(1.1), nilValue),
				NewAsssertionTestCase(int(1), nilValue),
				NewAsssertionTestCase("1", nilValue),
				NewAsssertionTestCase("a", nilValue),
				NewAsssertionTestCase(float64(5), float64(1)),
				NewAsssertionTestCase(int(5), float64(1)),
				NewAsssertionTestCase("2.2", float64(1)),
				NewAsssertionTestCase(int(5), int(1)),
				NewAsssertionTestCase("5", int(1)),
				NewAsssertionTestCase("abc", "a"),
				NewAsssertionTestCase(float64(1.3), "1.2"),
				NewAsssertionTestCase(int(3), "1"),
				NewAsssertionTestCase("3.1", "2"),
			}

			assert(testCases, func(actualValue interface{}, instanceValue interface{}) {
				key := "some:key"
				executionResult := core.ExecutionResult{
					key: actualValue,
				}

				assertion := GreaterThanAssertion{
					Key:   key,
					Value: instanceValue,
				}

				result := assertion.Assert(executionResult)
				Expect(result["result"]).To(Equal(true))
				Expect(result["message"]).To(BeNil())
			})
		})

		FContext("Fails", func() {
			var testCases = []AssertionTestCase{
				NewAsssertionTestCase(nilValue, nilValue),
				NewAsssertionTestCase(nilValue, int(5)),
				NewAsssertionTestCase(nilValue, "5.1"),
				NewAsssertionTestCase(nilValue, "fubar"),
				NewAsssertionTestCase(nilValue, float64(6.1)),
				NewAsssertionTestCase(float64(5.1), float64(6.1)),
				NewAsssertionTestCase(int(5), float64(6.1)),
				NewAsssertionTestCase("5", float64(6.1)),
				NewAsssertionTestCase(float64(3.1), int(6)),
				NewAsssertionTestCase(int(3), int(6)),
				NewAsssertionTestCase("5.1", int(6)),
				NewAsssertionTestCase("fubar", int(6)),
				NewAsssertionTestCase("fubar", float64(1.1)),
				NewAsssertionTestCase("fubar", "1.1"),
				NewAsssertionTestCase("f", "fubar"),
				NewAsssertionTestCase(float64(6.1), "fubar"),
			}

			assert(testCases, func(actualValue interface{}, instanceValue interface{}) {
				executionResult := core.ExecutionResult{
					key: actualValue,
				}

				assertion := GreaterThanAssertion{
					Key:   key,
					Value: instanceValue,
				}

				result := assertion.Assert(executionResult)
				Expect(result["result"]).To(Equal(false))
				Expect(result["message"]).To(Equal(fmt.Sprintf("FAIL: %v is not greater %v", actualValue, instanceValue)))
			})
			/*
				PIt("When Actual is float64 and Instance is string", func() {

				})

				PIt("When Actual is int and Instance is string", func() {

				})

				PIt("When Actual string-number int and Instance is string", func() {

				})
			*/
		})

	})

	Context("Not Equal Assertion", func() {

		It("Succeeds", func() {
			executionResult := core.ExecutionResult{
				key: 8,
			}

			assertion := NotEqualAssertion{
				Key:   key,
				Value: 7,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(true))
			Expect(result["message"]).To(BeNil())
		})

		It("Fails", func() {
			executionResult := core.ExecutionResult{
				key: 7,
			}

			assertion := NotEqualAssertion{
				Key:   key,
				Value: 7,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: 7 does match 7"))
		})
	})

	Context("Exact Assertion", func() {
		It("Exact Assertion Succeeds", func() {
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: expectedValue,
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(true))
			Expect(result["message"]).To(BeNil())
		})

		It("Exact Assertion Fails", func() {
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: 8,
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: 8 does not match 7"))
		})

		//NOTHING is currently using the message when an assertion fails but we will need
		//it for when we put the errors into the report.  One of the edge cases with the message
		//is that say the actual value was a string "7" and the expected is an int 7.  The message
		//will not include the quotes so the message would read 7 does not equal 7 as opposed
		//to "7" does not equal 7.  Notice this is a type mismatch
		PIt("Exact Assertion Fails when actual and expected are different types", func() {
			key := "some:key"
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: "7",
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: \"7\" does not match 7"))
		})
	})

})
<commit_msg>Fails When Actual is of type int and Instance is of type string-number<commit_after>package assertions

import (
	"fmt"
	"strconv"

	"ci.guzzler.io/guzzler/corcel/core"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

type AssertionTestCase struct {
	Actual               interface{}
	Instance             interface{}
	ActualStringNumber   bool
	InstanceStringNumber bool
}

func NewAsssertionTestCase(actual interface{}, instance interface{}) (newInstance AssertionTestCase) {
	newInstance.Actual = actual
	newInstance.Instance = instance
	switch actualType := actual.(type) {
	case string:
		_, err := strconv.ParseFloat(actualType, 64)
		if err == nil {
			newInstance.ActualStringNumber = true
		}
	}
	switch instanceType := instance.(type) {
	case string:
		_, err := strconv.ParseFloat(instanceType, 64)
		if err == nil {
			newInstance.InstanceStringNumber = true
		}
	}
	return
}

var _ = FDescribe("Assertions", func() {

	key := "some:key"

	assert := func(testCases []AssertionTestCase, test func(actual interface{}, instance interface{})) {

		for _, testCase := range testCases {
			actualValue := testCase.Actual
			instanceValue := testCase.Instance
			testName := fmt.Sprintf("When Actual is of type %T and Instance is of type %T", actualValue, instanceValue)
			if testCase.ActualStringNumber {
				testName = fmt.Sprintf("%s. Actual value is a STRING NUMBER in this case", testName)
			}
			if testCase.InstanceStringNumber {
				testName = fmt.Sprintf("%s. Instance value is a STRING NUMBER in this case", testName)
			}
			It(testName, func() {
				test(actualValue, instanceValue)
			})
		}
	}

	/*
	   Using this test function and the test cases we get a nice readable output.  If you run ginkgo -v here is an example of the output

	   Assertions Greater Than Succeeds
	     When Actual is of type int and Instance is of type string. Instance value is a STRING NUMBER
	*/

	var nilValue interface{}

	FContext("Greater Than", func() {

		Context("Succeeds", func() {
			var testCases = []AssertionTestCase{
				NewAsssertionTestCase(float64(1.1), nilValue),
				NewAsssertionTestCase(int(1), nilValue),
				NewAsssertionTestCase("1", nilValue),
				NewAsssertionTestCase("a", nilValue),
				NewAsssertionTestCase(float64(5), float64(1)),
				NewAsssertionTestCase(int(5), float64(1)),
				NewAsssertionTestCase("2.2", float64(1)),
				NewAsssertionTestCase(int(5), int(1)),
				NewAsssertionTestCase("5", int(1)),
				NewAsssertionTestCase("abc", "a"),
				NewAsssertionTestCase(float64(1.3), "1.2"),
				NewAsssertionTestCase(int(3), "1"),
				NewAsssertionTestCase("3.1", "2"),
			}

			assert(testCases, func(actualValue interface{}, instanceValue interface{}) {
				key := "some:key"
				executionResult := core.ExecutionResult{
					key: actualValue,
				}

				assertion := GreaterThanAssertion{
					Key:   key,
					Value: instanceValue,
				}

				result := assertion.Assert(executionResult)
				Expect(result["result"]).To(Equal(true))
				Expect(result["message"]).To(BeNil())
			})
		})

		FContext("Fails", func() {
			var testCases = []AssertionTestCase{
				NewAsssertionTestCase(nilValue, nilValue),
				NewAsssertionTestCase(nilValue, int(5)),
				NewAsssertionTestCase(nilValue, "5.1"),
				NewAsssertionTestCase(nilValue, "fubar"),
				NewAsssertionTestCase(nilValue, float64(6.1)),
				NewAsssertionTestCase(float64(5.1), float64(6.1)),
				NewAsssertionTestCase(int(5), float64(6.1)),
				NewAsssertionTestCase("5", float64(6.1)),
				NewAsssertionTestCase(float64(3.1), int(6)),
				NewAsssertionTestCase(int(3), int(6)),
				NewAsssertionTestCase("5.1", int(6)),
				NewAsssertionTestCase("fubar", int(6)),
				NewAsssertionTestCase("fubar", float64(1.1)),
				NewAsssertionTestCase("fubar", "1.1"),
				NewAsssertionTestCase("f", "fubar"),
				NewAsssertionTestCase(float64(6.1), "fubar"),
				NewAsssertionTestCase(int(6), "fubar"),
			}

			assert(testCases, func(actualValue interface{}, instanceValue interface{}) {
				executionResult := core.ExecutionResult{
					key: actualValue,
				}

				assertion := GreaterThanAssertion{
					Key:   key,
					Value: instanceValue,
				}

				result := assertion.Assert(executionResult)
				Expect(result["result"]).To(Equal(false))
				Expect(result["message"]).To(Equal(fmt.Sprintf("FAIL: %v is not greater %v", actualValue, instanceValue)))
			})
			/*
				PIt("When Actual is int and Instance is string", func() {

				})

				PIt("When Actual string-number int and Instance is string", func() {

				})
			*/
		})

	})

	Context("Not Equal Assertion", func() {

		It("Succeeds", func() {
			executionResult := core.ExecutionResult{
				key: 8,
			}

			assertion := NotEqualAssertion{
				Key:   key,
				Value: 7,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(true))
			Expect(result["message"]).To(BeNil())
		})

		It("Fails", func() {
			executionResult := core.ExecutionResult{
				key: 7,
			}

			assertion := NotEqualAssertion{
				Key:   key,
				Value: 7,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: 7 does match 7"))
		})
	})

	Context("Exact Assertion", func() {
		It("Exact Assertion Succeeds", func() {
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: expectedValue,
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(true))
			Expect(result["message"]).To(BeNil())
		})

		It("Exact Assertion Fails", func() {
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: 8,
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: 8 does not match 7"))
		})

		//NOTHING is currently using the message when an assertion fails but we will need
		//it for when we put the errors into the report.  One of the edge cases with the message
		//is that say the actual value was a string "7" and the expected is an int 7.  The message
		//will not include the quotes so the message would read 7 does not equal 7 as opposed
		//to "7" does not equal 7.  Notice this is a type mismatch
		PIt("Exact Assertion Fails when actual and expected are different types", func() {
			key := "some:key"
			expectedValue := 7

			executionResult := core.ExecutionResult{
				key: "7",
			}

			assertion := ExactAssertion{
				Key:   key,
				Value: expectedValue,
			}

			result := assertion.Assert(executionResult)
			Expect(result["result"]).To(Equal(false))
			Expect(result["message"]).To(Equal("FAIL: \"7\" does not match 7"))
		})
	})

})
<|endoftext|>