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

package rpctest

import (
	"fmt"
	"net"
	"os"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/wire"
	rpc "github.com/btcsuite/btcrpcclient"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcwallet/chain"
	"github.com/btcsuite/btcwallet/waddrmgr"
	"github.com/btcsuite/btcwallet/wallet"
	_ "github.com/btcsuite/btcwallet/walletdb/bdb" // Required to register boltdb.
)

var (
	// tempDataDir is the name of the temporary directory used by the test harness.
	tempDataDir = "testnode"

	// current number of active test nodes.
	numTestInstances = 0

	defaultP2pPort = 18555
	defaultRPCPort = 18556

	// testInstances is a private package-level slice used to keep track of
	// allvactive test harnesses. This global can be used to perform various
	// "joins", shutdown several active harnesses after a test, etc.
	testInstances map[string]*Harness

	// Used to protest concurrent access to above declared variables.
	testCreationLock sync.Mutex
)

// Harness ...
type Harness struct {
	ActiveNet *chaincfg.Params

	Node     *rpc.Client
	node     *node
	handlers *rpc.NotificationHandlers

	Wallet       *wallet.Wallet
	chainClient  *chain.RPCClient
	coinbaseKey  *btcec.PrivateKey
	coinbaseAddr btcutil.Address

	testNodeDir    string
	maxConnRetries int
}

// New creates and initializes new instance of the rpc test harness.
// Optionally, websocket handlers and a specified configuration may be passed.
// In the case that a nil config is passed, a default configuration will be used.
func New(activeNet *chaincfg.Params, handlers *rpc.NotificationHandlers, extraArgs []string) (*Harness, error) {
	testCreationLock.Lock()
	defer testCreationLock.Unlock()

	nodeTestData := tempDataDir + strconv.Itoa(int(numTestInstances))
	certFile := filepath.Join(nodeTestData, "rpc.cert")
	keyFile := filepath.Join(nodeTestData, "rpc.key")

	// Create folder to store our tls info.
	if err := os.Mkdir(nodeTestData, 0700); err != nil {
		return nil, err
	}

	// Generate the default config if needed.
	if err := genCertPair(certFile, keyFile); err != nil {
		return nil, err
	}

	// Since this btcd process which will eventually be created by this
	// Harness is running in simnet mode, we'll be able to easily generate
	// blocks. So we generate a fresh private key to use for our coinbase
	// payouts. This private key will also be imported into the wallet so
	// tests are able to move coins around at will.
	coinbaseAddr, coinbaseKey, err := generateCoinbasePayout(activeNet)
	if err != nil {
		return nil, err
	}
	miningAddr := fmt.Sprintf("--miningaddr=%s", coinbaseAddr)
	extraArgs = append(extraArgs, miningAddr)

	config, err := newConfig("rpctest", certFile, keyFile, extraArgs)
	if err != nil {
		return nil, err
	}

	// Generate p2p+rpc listening addresses.
	p2p, rpc := generateListeningAddresses()
	config.listen = p2p
	config.rpcListen = rpc

	// Create the testing node bounded to the simnet.
	node, err := newNode(config, nodeTestData)
	if err != nil {
		return nil, err
	}

	numTestInstances++

	// TODO(Roasbeef):
	//  * joinNodes(joinType)
	//  * syncBLocks + syncMempools?
	//  * connectAllNodes?

	h := &Harness{
		handlers:       handlers,
		node:           node,
		maxConnRetries: 20,
		testNodeDir:    nodeTestData,
		coinbaseKey:    coinbaseKey,
		coinbaseAddr:   coinbaseAddr,
		ActiveNet:      activeNet,
	}

	testInstances = append(testInstances, h)

	return h, nil
}

// SetUp initializes the rpc test state. Initialization includes: starting up a
// simnet node, creating a websocket client and connecting to the started node,
// and finally: optionally generating and submitting a testchain with a configurable
// number of mature coinbase outputs coinbase outputs.
func (h *Harness) SetUp(createTestChain bool, numMatureOutputs uint32) error {
	var err error

	// Start the btcd node itself. This spawns a new process which will be
	// managed
	if err = h.node.start(); err != nil {
		return err
	}
	if err := h.connectRPCClient(); err != nil {
		return err
	}

	// Create a test chain with the desired number of mature coinbase
	// outputs.
	if createTestChain {
		numToGenerate := blockchain.CoinbaseMaturity + numMatureOutputs
		_, err := h.Node.Generate(numToGenerate)
		if err != nil {
			return err
		}
	}

	netDir := filepath.Join(h.testNodeDir, h.ActiveNet.Name)
	walletLoader := wallet.NewLoader(h.ActiveNet, netDir)

	h.Wallet, err = walletLoader.CreateNewWallet([]byte("pub"),
		[]byte("password"), nil)
	if err != nil {
		return err
	}
	if err := h.Wallet.Manager.Unlock([]byte("password")); err != nil {
		return err
	}

	rpcConf := h.node.config.rpcConnConfig()
	rpcc, err := chain.NewRPCClient(h.ActiveNet, rpcConf.Host, rpcConf.User,
		rpcConf.Pass, rpcConf.Certificates, false, 20)
	if err != nil {
		return err
	}

	// Start the goroutines in the underlying wallet.
	h.chainClient = rpcc
	if err := h.chainClient.Start(); err != nil {
		return err
	}
	h.Wallet.Start()

	// Encode our coinbase private key in WIF format, then import it into
	// the wallet so we'll be able to generate spends, and update the
	// balance of the wallet as blocks are generated.
	wif, err := btcutil.NewWIF(h.coinbaseKey, h.ActiveNet, true)
	if err != nil {
		return err
	}
	if _, err := h.Wallet.ImportPrivateKey(wif, nil, false); err != nil {
		return err
	}

	h.Wallet.SynchronizeRPC(rpcc)

	// Wait for the wallet to sync up to the current height.
	ticker := time.NewTicker(time.Millisecond * 100)
	desiredHeight := int32(numMatureOutputs + blockchain.CoinbaseMaturity)
out:
	// TODO(roasbeef): use wallet's notification server here instead?
	for {
		select {
		case <-ticker.C:
			if h.Wallet.Manager.SyncedTo().Height == desiredHeight {
				break out
			}
		}
	}
	ticker.Stop()

	// Now that the wallet has synced up, submit a re-scan, blocking until
	// it's finished.
	if err := h.Wallet.Rescan([]btcutil.Address{h.coinbaseAddr}, nil); err != nil {
		return err
	}

	return nil
}

// TearDown stops the running rpc test instance. All created processes are
// killed, and temporary directories removed.
func (h *Harness) TearDown() error {
	if h.Node != nil {
		h.Node.Shutdown()
	}

	if h.Wallet != nil {
		h.Wallet.Stop()
	}
	if h.chainClient != nil {
		h.chainClient.Shutdown()
	}

	if err := h.node.shutdown(); err != nil {
		return err
	}

	if err := os.RemoveAll(h.testNodeDir); err != nil {
		return err
	}

	return nil
}

// connectRPCClient attempts to establish an RPC connection to the created
// btcd process belonging to this Harness instance. If the initial connection
// attempt fails, this function will retry h.maxConnRetries times, backing off
// the time between subsequent attempts. If after h.maxConnRetries attempts,
// we're not able to establish a connection, this function returns with an error.
func (h *Harness) connectRPCClient() error {
	var client *rpc.Client
	var err error

	rpcConf := h.node.config.rpcConnConfig()
	for i := 0; i < h.maxConnRetries; i++ {
		if client, err = rpc.New(&rpcConf, h.handlers); err != nil {
			time.Sleep(time.Duration(i) * 50 * time.Millisecond)
			continue
		}
		break
	}

	if client == nil {
		return fmt.Errorf("connection timedout")
	}

	h.Node = client
	return nil
}

// CoinbaseSpend creates, signs, and finally broadcasts a transaction spending
// the harness' available mature coinbase outputs creating new outputs according
// to targetOutputs. targetOutputs maps a string encoding of a Bitcoin address,
// to the amount of coins which should be created for that output.
func (h *Harness) CoinbaseSpend(targetOutputs map[string]btcutil.Amount) (*wire.ShaHash, error) {
	return h.Wallet.SendPairs(targetOutputs, waddrmgr.ImportedAddrAccount, 1)
}

// RPCConfig ...
func (h *Harness) RPCConfig() rpc.ConnConfig {
	return h.node.config.rpcConnConfig()
}

// generateListeningAddresses returns two strings representing listening
// addresses designated for the current rpc test. If there haven't been any
// test instances created, the default ports are used. Otherwise, in order to
// support multiple test nodes running at once, the p2p and rpc port are
// incremented after each initialization.
func generateListeningAddresses() (string, string) {
	var p2p, rpc string
	localhost := "127.0.0.1"
	if numTestInstances == 0 {
		p2p = net.JoinHostPort(localhost, strconv.Itoa(defaultP2pPort))
		rpc = net.JoinHostPort(localhost, strconv.Itoa(defaultRPCPort))
	} else {
		p2p = net.JoinHostPort(localhost,
			strconv.Itoa(defaultP2pPort+numTestInstances))
		rpc = net.JoinHostPort(localhost,
			strconv.Itoa(defaultRPCPort+numTestInstances))
	}

	return p2p, rpc
}

// generateCoinbasePayout generates a fresh private key, and the corresponding
// p2pkh address for use within all coinbase outputs produced for an instance
// of the test harness.
func generateCoinbasePayout(net *chaincfg.Params) (btcutil.Address, *btcec.PrivateKey, error) {
	privKey, err := btcec.NewPrivateKey(btcec.S256())
	if err != nil {
		return nil, nil, err
	}

	addr, err := btcutil.NewAddressPubKey(privKey.PubKey().SerializeCompressed(),
		net)
	if err != nil {
		return nil, nil, err
	}

	return addr.AddressPubKeyHash(), privKey, nil
}

func init() {
	// Create the testInstances map once the package has been imported.
	testInstances = make(map[string]*Harness)
}
<commit_msg>p2p ports are odd numbers, rpc ports even<commit_after>// Copyright (c) 2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpctest

import (
	"fmt"
	"net"
	"os"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/wire"
	rpc "github.com/btcsuite/btcrpcclient"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcwallet/chain"
	"github.com/btcsuite/btcwallet/waddrmgr"
	"github.com/btcsuite/btcwallet/wallet"
	_ "github.com/btcsuite/btcwallet/walletdb/bdb" // Required to register boltdb.
)

var (
	// tempDataDir is the name of the temporary directory used by the test harness.
	tempDataDir = "testnode"

	// current number of active test nodes.
	numTestInstances = 0

	// defaultP2pPort is the initial p2p port which will be used by the
	// first created rpc harnesses to listen on for incoming p2p connections.
	// Subsequent allocated ports for future rpc harness instances will be
	// monotonically increasing odd numbers calculated as such:
	// defaultP2pPort + (2 * harness.nodeNum).
	defaultP2pPort = 18555

	// defaultRPCPort is the initial rpc port which will be used by the first created
	// rpc harnesses to listen on for incoming rpc connections. Subsequent
	// allocated ports for future rpc harness instances will be monotonically
	// increasing even numbers calculated as such:
	// defaultP2pPort + (2 * harness.nodeNum).
	defaultRPCPort = 18556

	// testInstances is a private package-level slice used to keep track of
	// allvactive test harnesses. This global can be used to perform various
	// "joins", shutdown several active harnesses after a test, etc.
	testInstances map[string]*Harness

	// Used to protest concurrent access to above declared variables.
	testCreationLock sync.Mutex
)

// Harness ...
type Harness struct {
	ActiveNet *chaincfg.Params

	Node     *rpc.Client
	node     *node
	handlers *rpc.NotificationHandlers

	Wallet       *wallet.Wallet
	chainClient  *chain.RPCClient
	coinbaseKey  *btcec.PrivateKey
	coinbaseAddr btcutil.Address

	testNodeDir    string
	maxConnRetries int
}

// New creates and initializes new instance of the rpc test harness.
// Optionally, websocket handlers and a specified configuration may be passed.
// In the case that a nil config is passed, a default configuration will be used.
func New(activeNet *chaincfg.Params, handlers *rpc.NotificationHandlers, extraArgs []string) (*Harness, error) {
	testCreationLock.Lock()
	defer testCreationLock.Unlock()

	nodeTestData := tempDataDir + strconv.Itoa(int(numTestInstances))
	certFile := filepath.Join(nodeTestData, "rpc.cert")
	keyFile := filepath.Join(nodeTestData, "rpc.key")

	// Create folder to store our tls info.
	if err := os.Mkdir(nodeTestData, 0700); err != nil {
		return nil, err
	}

	// Generate the default config if needed.
	if err := genCertPair(certFile, keyFile); err != nil {
		return nil, err
	}

	// Since this btcd process which will eventually be created by this
	// Harness is running in simnet mode, we'll be able to easily generate
	// blocks. So we generate a fresh private key to use for our coinbase
	// payouts. This private key will also be imported into the wallet so
	// tests are able to move coins around at will.
	coinbaseAddr, coinbaseKey, err := generateCoinbasePayout(activeNet)
	if err != nil {
		return nil, err
	}
	miningAddr := fmt.Sprintf("--miningaddr=%s", coinbaseAddr)
	extraArgs = append(extraArgs, miningAddr)

	config, err := newConfig("rpctest", certFile, keyFile, extraArgs)
	if err != nil {
		return nil, err
	}

	// Generate p2p+rpc listening addresses.
	p2p, rpc := generateListeningAddresses()
	config.listen = p2p
	config.rpcListen = rpc

	// Create the testing node bounded to the simnet.
	node, err := newNode(config, nodeTestData)
	if err != nil {
		return nil, err
	}

	nodeNum := numTestInstances
	numTestInstances++

	h := &Harness{
		handlers:       handlers,
		node:           node,
		maxConnRetries: 20,
		testNodeDir:    nodeTestData,
		coinbaseKey:    coinbaseKey,
		coinbaseAddr:   coinbaseAddr,
		ActiveNet:      activeNet,
		nodeNum:        nodeNum,
	}

	testInstances = append(testInstances, h)

	return h, nil
}

// SetUp initializes the rpc test state. Initialization includes: starting up a
// simnet node, creating a websocket client and connecting to the started node,
// and finally: optionally generating and submitting a testchain with a configurable
// number of mature coinbase outputs coinbase outputs.
func (h *Harness) SetUp(createTestChain bool, numMatureOutputs uint32) error {
	var err error

	// Start the btcd node itself. This spawns a new process which will be
	// managed
	if err = h.node.start(); err != nil {
		return err
	}
	if err := h.connectRPCClient(); err != nil {
		return err
	}

	// Create a test chain with the desired number of mature coinbase
	// outputs.
	if createTestChain {
		numToGenerate := blockchain.CoinbaseMaturity + numMatureOutputs
		_, err := h.Node.Generate(numToGenerate)
		if err != nil {
			return err
		}
	}

	netDir := filepath.Join(h.testNodeDir, h.ActiveNet.Name)
	walletLoader := wallet.NewLoader(h.ActiveNet, netDir)

	h.Wallet, err = walletLoader.CreateNewWallet([]byte("pub"),
		[]byte("password"), nil)
	if err != nil {
		return err
	}
	if err := h.Wallet.Manager.Unlock([]byte("password")); err != nil {
		return err
	}

	rpcConf := h.node.config.rpcConnConfig()
	rpcc, err := chain.NewRPCClient(h.ActiveNet, rpcConf.Host, rpcConf.User,
		rpcConf.Pass, rpcConf.Certificates, false, 20)
	if err != nil {
		return err
	}

	// Start the goroutines in the underlying wallet.
	h.chainClient = rpcc
	if err := h.chainClient.Start(); err != nil {
		return err
	}
	h.Wallet.Start()

	// Encode our coinbase private key in WIF format, then import it into
	// the wallet so we'll be able to generate spends, and update the
	// balance of the wallet as blocks are generated.
	wif, err := btcutil.NewWIF(h.coinbaseKey, h.ActiveNet, true)
	if err != nil {
		return err
	}
	if _, err := h.Wallet.ImportPrivateKey(wif, nil, false); err != nil {
		return err
	}

	h.Wallet.SynchronizeRPC(rpcc)

	// Wait for the wallet to sync up to the current height.
	ticker := time.NewTicker(time.Millisecond * 100)
	desiredHeight := int32(numMatureOutputs + blockchain.CoinbaseMaturity)
out:
	// TODO(roasbeef): use wallet's notification server here instead?
	for {
		select {
		case <-ticker.C:
			if h.Wallet.Manager.SyncedTo().Height == desiredHeight {
				break out
			}
		}
	}
	ticker.Stop()

	// Now that the wallet has synced up, submit a re-scan, blocking until
	// it's finished.
	if err := h.Wallet.Rescan([]btcutil.Address{h.coinbaseAddr}, nil); err != nil {
		return err
	}

	return nil
}

// TearDown stops the running rpc test instance. All created processes are
// killed, and temporary directories removed.
func (h *Harness) TearDown() error {
	if h.Node != nil {
		h.Node.Shutdown()
	}

	if h.Wallet != nil {
		h.Wallet.Stop()
	}
	if h.chainClient != nil {
		h.chainClient.Shutdown()
	}

	if err := h.node.shutdown(); err != nil {
		return err
	}

	if err := os.RemoveAll(h.testNodeDir); err != nil {
		return err
	}

	return nil
}

// connectRPCClient attempts to establish an RPC connection to the created
// btcd process belonging to this Harness instance. If the initial connection
// attempt fails, this function will retry h.maxConnRetries times, backing off
// the time between subsequent attempts. If after h.maxConnRetries attempts,
// we're not able to establish a connection, this function returns with an error.
func (h *Harness) connectRPCClient() error {
	var client *rpc.Client
	var err error

	rpcConf := h.node.config.rpcConnConfig()
	for i := 0; i < h.maxConnRetries; i++ {
		if client, err = rpc.New(&rpcConf, h.handlers); err != nil {
			time.Sleep(time.Duration(i) * 50 * time.Millisecond)
			continue
		}
		break
	}

	if client == nil {
		return fmt.Errorf("connection timedout")
	}

	h.Node = client
	return nil
}

// CoinbaseSpend creates, signs, and finally broadcasts a transaction spending
// the harness' available mature coinbase outputs creating new outputs according
// to targetOutputs. targetOutputs maps a string encoding of a Bitcoin address,
// to the amount of coins which should be created for that output.
func (h *Harness) CoinbaseSpend(targetOutputs map[string]btcutil.Amount) (*wire.ShaHash, error) {
	return h.Wallet.SendPairs(targetOutputs, waddrmgr.ImportedAddrAccount, 1)
}

// RPCConfig ...
func (h *Harness) RPCConfig() rpc.ConnConfig {
	return h.node.config.rpcConnConfig()
}

// generateListeningAddresses returns two strings representing listening
// addresses designated for the current rpc test. If there haven't been any
// test instances created, the default ports are used. Otherwise, in order to
// support multiple test nodes running at once, the p2p and rpc port are
// incremented after each initialization.
func generateListeningAddresses() (string, string) {
	var p2p, rpc string
	localhost := "127.0.0.1"
	if numTestInstances == 0 {
		p2p = net.JoinHostPort(localhost, strconv.Itoa(defaultP2pPort))
		rpc = net.JoinHostPort(localhost, strconv.Itoa(defaultRPCPort))
	} else {
		p2p = net.JoinHostPort(localhost,
			strconv.Itoa(defaultP2pPort+(2*numTestInstances)))
		rpc = net.JoinHostPort(localhost,
			strconv.Itoa(defaultRPCPort+(2*numTestInstances)))
	}

	return p2p, rpc
}

// generateCoinbasePayout generates a fresh private key, and the corresponding
// p2pkh address for use within all coinbase outputs produced for an instance
// of the test harness.
func generateCoinbasePayout(net *chaincfg.Params) (btcutil.Address, *btcec.PrivateKey, error) {
	privKey, err := btcec.NewPrivateKey(btcec.S256())
	if err != nil {
		return nil, nil, err
	}

	addr, err := btcutil.NewAddressPubKey(privKey.PubKey().SerializeCompressed(),
		net)
	if err != nil {
		return nil, nil, err
	}

	return addr.AddressPubKeyHash(), privKey, nil
}

func init() {
	// Create the testInstances map once the package has been imported.
	testInstances = make(map[string]*Harness)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"fmt"
	"flag"
	"log"
	mrand "math/rand"
	"net"
	"net/http"
	"crypto/rand"
	"strings"
	"sync"
	"time"
)

type RtpMsg struct {
	sn uint16
	delay uint32
}

type RtpStats struct {
	unixtime int64
	recv uint16
	ooo uint16 // Out Of Order packets
	delay uint32
	last_sn uint16
}

var rtpproxyAddr string
var rtpproxyPort uint
var listenPort uint
var payloadSize uint
var payloadType uint
var histSize uint
var histTime uint
var window *MovingWindow
var currRtpStats RtpStats

func init() {
	flag.UintVar(&listenPort, "hport", 8080, "Port to run HTTP server at")
	flag.UintVar(&histSize, "hsize", 10, "History backlog size (in steps)")
	flag.UintVar(&histTime, "htime", 60, "History interval (in seconds)")
	flag.StringVar(&rtpproxyAddr, "rhost", "127.0.0.1", "RTPproxy address")
	flag.UintVar(&rtpproxyPort, "rport", 22222, "RTPproxy port")
	flag.UintVar(&payloadSize, "psize", 160, "RTP payload size (in bytes)")
	flag.UintVar(&payloadType, "ptype", 8, "RTP payload type")
}

func viewHandlerRobo(w http.ResponseWriter, r *http.Request) {
	log.Printf("ROBO FROM: %s REQ: %s\n", r.RemoteAddr, r.URL.Path)
	var retStr string
	retStr += "["

	for i := range window.arr {
		retStr += fmt.Sprintf("{\"unixtime\":%d,\"received\":%d,\"ooo\":%d,\"delay\":%d},",
		window.arr[i].unixtime,
		window.arr[i].recv,
		window.arr[i].ooo,
		window.arr[i].delay)
	}

	retStr += "{}]"
	fmt.Fprintf(w, retStr)
}
func viewHandlerHuman(w http.ResponseWriter, r *http.Request) {
	log.Printf("FROM: %s REQ: %s\n", r.RemoteAddr, r.URL.Path)

	var retStr string

	retStr += "
"

	for i := range window.arr {
		retStr += fmt.Sprintf("
%d	%d	%d	%d
",
		window.arr[i].unixtime,
		window.arr[i].recv,
		window.arr[i].ooo,
		window.arr[i].delay)
	}

	fmt.Fprintf(w, "
%s
", retStr)
}

// Number of seconds ellapsed from 1900 to 1970, see RFC 5905
const ntpEpochOffset = 2208988800

func getNtpStamp() uint32 {
	tm := time.Now().UnixNano()
	seconds := uint32(tm/1e9 + ntpEpochOffset) // Go uses ns, thus divide by 1e9 to get seconds
	msecs := (seconds % 1e6) * 8000 // 8 KHz
	return msecs + uint32((tm % 1e9) / (1e6 / 8)) // 8 KHz
}

func getRandStr(n uint) string {
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	var bytes = make([]byte, n)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b % byte(len(alphanum))]
	}
	return string(bytes)
}

func makeCon(name string, haddr string, hport string) *net.UDPConn {
	addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%s", haddr, hport))
	if err != nil {
		log.Printf("ERR1: udp:%s:%s: %v\n", haddr, hport, err)
		return nil
	}

	con, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		log.Printf("ERR2: udp:%s:%s: %v\n", haddr, hport, err)
		return nil
	}
	log.Printf("Connected %s: [udp:%s:%s]\n", name, haddr, hport)
	return con
}

func main() {
	flag.Parse()

	const delay = 20 * time.Millisecond

	var n int

	window = New(int(histSize), 1)

	ca := make(chan RtpMsg)
	cb := make(chan RtpMsg)

	// Buffer for the control connection (~1 MTU)
	var buffer [1500]byte

	const rtpHeader uint = 0x80
	const rtpHeaderSize uint = 12

	var apayload []byte = make([]byte, rtpHeaderSize + payloadSize)

	aSSRC := mrand.Int31()

	apayload[0] = byte(rtpHeader)
	apayload[1] = byte(payloadType)
	binary.BigEndian.PutUint32(apayload[8:], uint32(aSSRC))
	for i := range apayload[rtpHeaderSize:] {
		apayload[rtpHeaderSize + uint(i)] = byte(i % 255)
	}

	var bpayload []byte = make([]byte, rtpHeaderSize + payloadSize)

	bSSRC := mrand.Int31()

	bpayload[0] = byte(rtpHeader)
	bpayload[1] = byte(payloadType)
	binary.BigEndian.PutUint32(bpayload[8:], uint32(bSSRC))
	for i := range bpayload[rtpHeaderSize:]  {
		bpayload[rtpHeaderSize + uint(i)] = byte(255 - i % 255)
	}

	// Synchronizaion object
	var w sync.WaitGroup

	// Wait for the following objects
	// - HTTP server
	// - Alice's sender
	// - Alice's receiver
	// - Bob's sender
	// - Bob's receiver
	// - Stats recalculator
	w.Add(6)

	go func(in1 <-chan RtpMsg, in2 <-chan RtpMsg) {
		var msg RtpMsg
		var tm int64
		for {
			select {
			case msg = <-in1:
				// Alice's receiver
				tm = time.Now().Unix()
				if (tm >= currRtpStats.unixtime + int64(histTime)){
					log.Printf("A RESET: %d: %d samples (%d time): %d %d %d %d %d\n", msg.sn, msg.delay, tm, currRtpStats.unixtime, currRtpStats.recv, currRtpStats.ooo, currRtpStats.delay, currRtpStats.last_sn) // 8 KHz
					// Push it to the Window
					window.PushBack(currRtpStats)
					// ...and clean up
					currRtpStats.unixtime = tm + int64(histTime)
					currRtpStats.recv = 0
					currRtpStats.ooo = 0
					currRtpStats.delay = 0
				}

				//log.Printf("A: %d: %d samples (%d time)\n", msg.sn, msg.delay, tm) // 8 KHz
				// Append stats
				if(msg.sn > currRtpStats.last_sn) {
					currRtpStats.recv++
					currRtpStats.delay += msg.delay
					currRtpStats.ooo += (msg.sn - (currRtpStats.last_sn + 1))
					currRtpStats.last_sn = msg.sn
				}

			case msg = <-in2:
				// Bob's receiver
				//log.Printf("B: %d: %d samples\n", msg.sn, msg.delay) // 8 KHz
			}
		}
		w.Done()
	} (ca, cb)

	// Open control connection
	rtpproxyCon := makeCon("RTPproxy", rtpproxyAddr, fmt.Sprintf("%d", rtpproxyPort))
	// Don't forget to close control connection before exit
	defer rtpproxyCon.Close()

	// Create random Cookie, CallID, FromTag, ToTag
	cookie := getRandStr(8)
	callid := getRandStr(32)
	tagf := getRandStr(16)
	tagt := getRandStr(16)

	// Generate Offer
	offerStr := strings.Join([]string{
		cookie,
		"Uc0,8,18,101",
		callid,
		"192.168.1.100",
		"10560",
		strings.Join([]string{tagf, ";1"},"")}, " ")

	log.Printf("Offer: %s\n", offerStr)
	// Send Offer to RTPproxy
	n, _ = rtpproxyCon.Write([]byte(offerStr))

	// Read Offer reply
	n, _ = rtpproxyCon.Read(buffer[0:])

	// Parse Offer reply
	offerReply := strings.Split(strings.TrimRight(string(buffer[:n]), "\n"), " ")
	log.Printf("Offer: %s [udp:%s:%s]\n", offerReply[0], offerReply[2], offerReply[1])

	// Open Bob's connection
	bobCon := makeCon("Bob", offerReply[2], offerReply[1])
	// Don't forget to close Bob's connection before exit
	defer bobCon.Close()

	// Run Bob's sender
	go func() {
		var sn uint16
		var ts uint32
		sn = 0
		for {
			ts = getNtpStamp()
			binary.BigEndian.PutUint16(bpayload[2:], sn)
			binary.BigEndian.PutUint32(bpayload[4:], ts)
			_, _ = bobCon.Write(bpayload)
			time.Sleep(delay)
			sn++
		}
		w.Done()
	} ()

	// Run Bob's receiver
	go func() {
		var recvbuf []byte = make([]byte, rtpHeaderSize + payloadSize)
		msg := RtpMsg{}
		for {
			_, _ = bobCon.Read(recvbuf[0:])
			msg.sn = binary.BigEndian.Uint16(recvbuf[2:])
			msg.delay = getNtpStamp() - binary.BigEndian.Uint32(recvbuf[4:])
			cb <- msg
		}
		w.Done()
	} ()

	// Generate Answer
	answerStr := strings.Join([]string{
		cookie,
		"Lc0,8,18,101",
		callid,
		"192.168.2.200",
		"20560",
		strings.Join([]string{tagf, ";1"}, ""),
		strings.Join([]string{tagt, ";1"}, "")}, " ")
	log.Printf("Answer: %s\n", answerStr)

	// Send Answer to RTPproxy
	n, _ = rtpproxyCon.Write([]byte(answerStr))

	// Read Answer reply
	n, _ = rtpproxyCon.Read(buffer[0:])

	// Parse Answer reply
	answerReply := strings.Split(strings.TrimRight(string(buffer[:n]), "\n"), " ")
	log.Printf("Answer: %s [udp:%s:%s]\n", answerReply[0], answerReply[2], answerReply[1])

	// Open Alice's connection
	aliceCon := makeCon("Alice", answerReply[2], answerReply[1])
	// Don't forget to close Alice's connection before exit
	defer aliceCon.Close()

	// Run Alice's sender
	go func() {
		var sn uint16
		var ts uint32
		sn = 0
		for {
			ts = getNtpStamp()
			binary.BigEndian.PutUint16(apayload[2:], sn)
			binary.BigEndian.PutUint32(apayload[4:], ts)
			_, _ = aliceCon.Write(apayload)
			time.Sleep(delay)
			sn++
		}
		w.Done()
	} ()

	// Run Alice's  receiver
	go func() {
		var recvbuf []byte = make([]byte, rtpHeaderSize + payloadSize)
		msg := RtpMsg{}
		for {
			_, _ = aliceCon.Read(recvbuf[0:])
			msg.sn = binary.BigEndian.Uint16(recvbuf[2:])
			msg.delay = getNtpStamp() - binary.BigEndian.Uint32(recvbuf[4:])
			ca <- msg
		}
		w.Done()
	} ()

	go func() {
		// Run HTTP stats listener
		http.HandleFunc("/json", viewHandlerRobo)
		http.HandleFunc("/", viewHandlerHuman)
		log.Printf("HTTP started.\n")
		http.ListenAndServe(fmt.Sprintf(":%d", listenPort), nil)
		log.Printf("HTTP stopped.\n")

		w.Done()
	} ()

	w.Wait()

	// Generate Delete
	deleteStr := strings.Join([]string{
		cookie,
		"D",
		callid,
		tagf,
		tagt}, " ")
	log.Printf("Delete: %s\n", deleteStr)

	// Send Delete to RTPproxy
	n, _ = rtpproxyCon.Write([]byte(deleteStr))

	// Read Delete reply
	_, _ = rtpproxyCon.Read(buffer[0:])
}
<commit_msg>Properly init timestamping<commit_after>package main

import (
	"encoding/binary"
	"fmt"
	"flag"
	"log"
	mrand "math/rand"
	"net"
	"net/http"
	"crypto/rand"
	"strings"
	"sync"
	"time"
)

type RtpMsg struct {
	sn uint16
	delay uint32
}

type RtpStats struct {
	unixtime int64
	recv uint16
	ooo uint16 // Out Of Order packets
	delay uint32
	last_sn uint16
}

var rtpproxyAddr string
var rtpproxyPort uint
var listenPort uint
var payloadSize uint
var payloadType uint
var histSize uint
var histTime uint
var window *MovingWindow
var currRtpStats RtpStats

func init() {
	flag.UintVar(&listenPort, "hport", 8080, "Port to run HTTP server at")
	flag.UintVar(&histSize, "hsize", 10, "History backlog size (in steps)")
	flag.UintVar(&histTime, "htime", 60, "History interval (in seconds)")
	flag.StringVar(&rtpproxyAddr, "rhost", "127.0.0.1", "RTPproxy address")
	flag.UintVar(&rtpproxyPort, "rport", 22222, "RTPproxy port")
	flag.UintVar(&payloadSize, "psize", 160, "RTP payload size (in bytes)")
	flag.UintVar(&payloadType, "ptype", 8, "RTP payload type")
}

func viewHandlerRobo(w http.ResponseWriter, r *http.Request) {
	log.Printf("ROBO FROM: %s REQ: %s\n", r.RemoteAddr, r.URL.Path)
	var retStr string
	retStr += "["

	for i := range window.arr {
		retStr += fmt.Sprintf("{\"unixtime\":%d,\"received\":%d,\"ooo\":%d,\"delay\":%d},",
		window.arr[i].unixtime,
		window.arr[i].recv,
		window.arr[i].ooo,
		window.arr[i].delay)
	}

	retStr += "{}]"
	fmt.Fprintf(w, retStr)
}
func viewHandlerHuman(w http.ResponseWriter, r *http.Request) {
	log.Printf("FROM: %s REQ: %s\n", r.RemoteAddr, r.URL.Path)

	var retStr string

	retStr += "
"

	for i := range window.arr {
		retStr += fmt.Sprintf("
%d	%d	%d	%d
",
		window.arr[i].unixtime,
		window.arr[i].recv,
		window.arr[i].ooo,
		window.arr[i].delay)
	}

	fmt.Fprintf(w, "
%s
", retStr)
}

// Number of seconds ellapsed from 1900 to 1970, see RFC 5905
const ntpEpochOffset = 2208988800

func getNtpStamp() uint32 {
	tm := time.Now().UnixNano()
	seconds := uint32(tm/1e9 + ntpEpochOffset) // Go uses ns, thus divide by 1e9 to get seconds
	msecs := (seconds % 1e6) * 8000 // 8 KHz
	return msecs + uint32((tm % 1e9) / (1e6 / 8)) // 8 KHz
}

func getRandStr(n uint) string {
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	var bytes = make([]byte, n)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b % byte(len(alphanum))]
	}
	return string(bytes)
}

func makeCon(name string, haddr string, hport string) *net.UDPConn {
	addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%s", haddr, hport))
	if err != nil {
		log.Printf("ERR1: udp:%s:%s: %v\n", haddr, hport, err)
		return nil
	}

	con, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		log.Printf("ERR2: udp:%s:%s: %v\n", haddr, hport, err)
		return nil
	}
	log.Printf("Connected %s: [udp:%s:%s]\n", name, haddr, hport)
	return con
}

func main() {
	flag.Parse()

	const delay = 20 * time.Millisecond

	var n int

	window = New(int(histSize), 1)

	ca := make(chan RtpMsg)
	cb := make(chan RtpMsg)

	// Buffer for the control connection (~1 MTU)
	var buffer [1500]byte

	const rtpHeader uint = 0x80
	const rtpHeaderSize uint = 12

	var apayload []byte = make([]byte, rtpHeaderSize + payloadSize)

	aSSRC := mrand.Int31()

	apayload[0] = byte(rtpHeader)
	apayload[1] = byte(payloadType)
	binary.BigEndian.PutUint32(apayload[8:], uint32(aSSRC))
	for i := range apayload[rtpHeaderSize:] {
		apayload[rtpHeaderSize + uint(i)] = byte(i % 255)
	}

	var bpayload []byte = make([]byte, rtpHeaderSize + payloadSize)

	bSSRC := mrand.Int31()

	bpayload[0] = byte(rtpHeader)
	bpayload[1] = byte(payloadType)
	binary.BigEndian.PutUint32(bpayload[8:], uint32(bSSRC))
	for i := range bpayload[rtpHeaderSize:]  {
		bpayload[rtpHeaderSize + uint(i)] = byte(255 - i % 255)
	}

	// Synchronizaion object
	var w sync.WaitGroup

	// Wait for the following objects
	// - HTTP server
	// - Alice's sender
	// - Alice's receiver
	// - Bob's sender
	// - Bob's receiver
	// - Stats recalculator
	w.Add(6)

	go func(in1 <-chan RtpMsg, in2 <-chan RtpMsg) {
		var msg RtpMsg
		var tm int64
		currRtpStats.unixtime = time.Now().Unix()
		for {
			select {
			case msg = <-in1:
				// Alice's receiver
				tm = time.Now().Unix()
				if (tm >= currRtpStats.unixtime + int64(histTime)){
					log.Printf("A RESET: %d: %d samples (%d time): %d %d %d %d %d\n", msg.sn, msg.delay, tm, currRtpStats.unixtime, currRtpStats.recv, currRtpStats.ooo, currRtpStats.delay, currRtpStats.last_sn) // 8 KHz
					// Push it to the Window
					window.PushBack(currRtpStats)
					// ...and clean up
					currRtpStats.unixtime += int64(histTime)
					currRtpStats.recv = 0
					currRtpStats.ooo = 0
					currRtpStats.delay = 0
				}

				//log.Printf("A: %d: %d samples (%d time)\n", msg.sn, msg.delay, tm) // 8 KHz
				// Append stats
				if(msg.sn > currRtpStats.last_sn) {
					currRtpStats.recv++
					currRtpStats.delay += msg.delay
					currRtpStats.ooo += (msg.sn - (currRtpStats.last_sn + 1))
					currRtpStats.last_sn = msg.sn
				}

			case msg = <-in2:
				// Bob's receiver
				//log.Printf("B: %d: %d samples\n", msg.sn, msg.delay) // 8 KHz
			}
		}
		w.Done()
	} (ca, cb)

	// Open control connection
	rtpproxyCon := makeCon("RTPproxy", rtpproxyAddr, fmt.Sprintf("%d", rtpproxyPort))
	// Don't forget to close control connection before exit
	defer rtpproxyCon.Close()

	// Create random Cookie, CallID, FromTag, ToTag
	cookie := getRandStr(8)
	callid := getRandStr(32)
	tagf := getRandStr(16)
	tagt := getRandStr(16)

	// Generate Offer
	offerStr := strings.Join([]string{
		cookie,
		"Uc0,8,18,101",
		callid,
		"192.168.1.100",
		"10560",
		strings.Join([]string{tagf, ";1"},"")}, " ")

	log.Printf("Offer: %s\n", offerStr)
	// Send Offer to RTPproxy
	n, _ = rtpproxyCon.Write([]byte(offerStr))

	// Read Offer reply
	n, _ = rtpproxyCon.Read(buffer[0:])

	// Parse Offer reply
	offerReply := strings.Split(strings.TrimRight(string(buffer[:n]), "\n"), " ")
	log.Printf("Offer: %s [udp:%s:%s]\n", offerReply[0], offerReply[2], offerReply[1])

	// Open Bob's connection
	bobCon := makeCon("Bob", offerReply[2], offerReply[1])
	// Don't forget to close Bob's connection before exit
	defer bobCon.Close()

	// Run Bob's sender
	go func() {
		var sn uint16
		var ts uint32
		sn = 0
		for {
			ts = getNtpStamp()
			binary.BigEndian.PutUint16(bpayload[2:], sn)
			binary.BigEndian.PutUint32(bpayload[4:], ts)
			_, _ = bobCon.Write(bpayload)
			time.Sleep(delay)
			sn++
		}
		w.Done()
	} ()

	// Run Bob's receiver
	go func() {
		var recvbuf []byte = make([]byte, rtpHeaderSize + payloadSize)
		msg := RtpMsg{}
		for {
			_, _ = bobCon.Read(recvbuf[0:])
			msg.sn = binary.BigEndian.Uint16(recvbuf[2:])
			msg.delay = getNtpStamp() - binary.BigEndian.Uint32(recvbuf[4:])
			cb <- msg
		}
		w.Done()
	} ()

	// Generate Answer
	answerStr := strings.Join([]string{
		cookie,
		"Lc0,8,18,101",
		callid,
		"192.168.2.200",
		"20560",
		strings.Join([]string{tagf, ";1"}, ""),
		strings.Join([]string{tagt, ";1"}, "")}, " ")
	log.Printf("Answer: %s\n", answerStr)

	// Send Answer to RTPproxy
	n, _ = rtpproxyCon.Write([]byte(answerStr))

	// Read Answer reply
	n, _ = rtpproxyCon.Read(buffer[0:])

	// Parse Answer reply
	answerReply := strings.Split(strings.TrimRight(string(buffer[:n]), "\n"), " ")
	log.Printf("Answer: %s [udp:%s:%s]\n", answerReply[0], answerReply[2], answerReply[1])

	// Open Alice's connection
	aliceCon := makeCon("Alice", answerReply[2], answerReply[1])
	// Don't forget to close Alice's connection before exit
	defer aliceCon.Close()

	// Run Alice's sender
	go func() {
		var sn uint16
		var ts uint32
		sn = 0
		for {
			ts = getNtpStamp()
			binary.BigEndian.PutUint16(apayload[2:], sn)
			binary.BigEndian.PutUint32(apayload[4:], ts)
			_, _ = aliceCon.Write(apayload)
			time.Sleep(delay)
			sn++
		}
		w.Done()
	} ()

	// Run Alice's  receiver
	go func() {
		var recvbuf []byte = make([]byte, rtpHeaderSize + payloadSize)
		msg := RtpMsg{}
		for {
			_, _ = aliceCon.Read(recvbuf[0:])
			msg.sn = binary.BigEndian.Uint16(recvbuf[2:])
			msg.delay = getNtpStamp() - binary.BigEndian.Uint32(recvbuf[4:])
			ca <- msg
		}
		w.Done()
	} ()

	go func() {
		// Run HTTP stats listener
		http.HandleFunc("/json", viewHandlerRobo)
		http.HandleFunc("/", viewHandlerHuman)
		log.Printf("HTTP started.\n")
		http.ListenAndServe(fmt.Sprintf(":%d", listenPort), nil)
		log.Printf("HTTP stopped.\n")

		w.Done()
	} ()

	w.Wait()

	// Generate Delete
	deleteStr := strings.Join([]string{
		cookie,
		"D",
		callid,
		tagf,
		tagt}, " ")
	log.Printf("Delete: %s\n", deleteStr)

	// Send Delete to RTPproxy
	n, _ = rtpproxyCon.Write([]byte(deleteStr))

	// Read Delete reply
	_, _ = rtpproxyCon.Read(buffer[0:])
}
<|endoftext|>


<commit_before>package main_test

import (
	"fmt"
	"syscall"
	"time"

	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/gunk/timeprovider"
	"github.com/cloudfoundry/storeadapter/storerunner/etcdstorerunner"
	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/converger/converger_runner"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
)

var _ = Describe("Main", func() {
	var (
		etcdRunner       *etcdstorerunner.ETCDClusterRunner
		bbs              *Bbs.BBS
		runner           *converger_runner.ConvergerRunner
		taskKickInterval = 1 * time.Second
	)

	BeforeSuite(func() {
		etcdPort := 5001 + config.GinkgoConfig.ParallelNode
		etcdCluster := fmt.Sprintf("http://127.0.0.1:%d", etcdPort)
		etcdRunner = etcdstorerunner.NewETCDClusterRunner(etcdPort, 1)

		logSink := steno.NewTestingSink()

		steno.Init(&steno.Config{
			Sinks: []steno.Sink{logSink},
		})

		logger := steno.NewLogger("the-logger")
		steno.EnterTestMode()
		bbs = Bbs.NewBBS(etcdRunner.Adapter(), timeprovider.NewTimeProvider(), logger)

		convergerBinPath, err := gexec.Build("github.com/cloudfoundry-incubator/converger", "-race")
		Ω(err).ShouldNot(HaveOccurred())

		runner = converger_runner.New(convergerBinPath, etcdCluster, "info")
	})

	AfterSuite(func() {
		gexec.CleanupBuildArtifacts()
	})

	BeforeEach(func() {
		etcdRunner.Start()
	})

	AfterEach(func() {
		runner.KillWithFire()
		etcdRunner.Stop()
	})

	Context("when the converger is running", func() {
		BeforeEach(func() {
			runner.Start(1*time.Second, taskKickInterval, 30*time.Minute, 30*time.Second, 300*time.Second)
			time.Sleep(10 * time.Millisecond)
			Ω(runner.Session.ExitCode()).Should(Equal(-1))
		})

		Context("and a claimed task with a dead executor is present", func() {
			BeforeEach(func() {
				task := models.Task{
					Guid:  "task-guid",
					Stack: "stack",
					Actions: []models.ExecutorAction{
						{
							Action: models.RunAction{
								Script: "cat /tmp/file",
							},
						},
					},
				}

				err := bbs.DesireTask(task)
				Ω(err).ShouldNot(HaveOccurred())
				err = bbs.ClaimTask(task.Guid, "dead-executor")
				Ω(err).ShouldNot(HaveOccurred())
			})

			It("marks the task as failed", func() {
				Eventually(bbs.GetAllCompletedTasks, taskKickInterval*2).Should(HaveLen(1))
				tasks, err := bbs.GetAllTasks()
				Ω(err).ShouldNot(HaveOccurred())
				Ω(tasks).Should(HaveLen(1))
				Ω(tasks[0].State).Should(Equal(models.TaskStateCompleted))
				Ω(tasks[0].Failed).Should(BeTrue())
			})
		})

		Describe("then receives the SIGINT signal", func() {
			It("exits successfully", func() {
				runner.Session.Command.Process.Signal(syscall.SIGINT)
				Eventually(runner.Session, 4).Should(gexec.Exit(0))
			})
		})

		Describe("then receives the SIGTERM signal", func() {
			It("exits successfully", func() {
				runner.Session.Command.Process.Signal(syscall.SIGTERM)
				Eventually(runner.Session, 4).Should(gexec.Exit(0))
			})
		})
	})
})
<commit_msg>Script -> Path,Args<commit_after>package main_test

import (
	"fmt"
	"syscall"
	"time"

	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/gunk/timeprovider"
	"github.com/cloudfoundry/storeadapter/storerunner/etcdstorerunner"
	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/converger/converger_runner"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
)

var _ = Describe("Main", func() {
	var (
		etcdRunner       *etcdstorerunner.ETCDClusterRunner
		bbs              *Bbs.BBS
		runner           *converger_runner.ConvergerRunner
		taskKickInterval = 1 * time.Second
	)

	BeforeSuite(func() {
		etcdPort := 5001 + config.GinkgoConfig.ParallelNode
		etcdCluster := fmt.Sprintf("http://127.0.0.1:%d", etcdPort)
		etcdRunner = etcdstorerunner.NewETCDClusterRunner(etcdPort, 1)

		logSink := steno.NewTestingSink()

		steno.Init(&steno.Config{
			Sinks: []steno.Sink{logSink},
		})

		logger := steno.NewLogger("the-logger")
		steno.EnterTestMode()
		bbs = Bbs.NewBBS(etcdRunner.Adapter(), timeprovider.NewTimeProvider(), logger)

		convergerBinPath, err := gexec.Build("github.com/cloudfoundry-incubator/converger", "-race")
		Ω(err).ShouldNot(HaveOccurred())

		runner = converger_runner.New(convergerBinPath, etcdCluster, "info")
	})

	AfterSuite(func() {
		gexec.CleanupBuildArtifacts()
	})

	BeforeEach(func() {
		etcdRunner.Start()
	})

	AfterEach(func() {
		runner.KillWithFire()
		etcdRunner.Stop()
	})

	Context("when the converger is running", func() {
		BeforeEach(func() {
			runner.Start(1*time.Second, taskKickInterval, 30*time.Minute, 30*time.Second, 300*time.Second)
			time.Sleep(10 * time.Millisecond)
			Ω(runner.Session.ExitCode()).Should(Equal(-1))
		})

		Context("and a claimed task with a dead executor is present", func() {
			BeforeEach(func() {
				task := models.Task{
					Guid:  "task-guid",
					Stack: "stack",
					Actions: []models.ExecutorAction{
						{
							Action: models.RunAction{
								Path: "cat",
								Args: []string{"/tmp/file"},
							},
						},
					},
				}

				err := bbs.DesireTask(task)
				Ω(err).ShouldNot(HaveOccurred())
				err = bbs.ClaimTask(task.Guid, "dead-executor")
				Ω(err).ShouldNot(HaveOccurred())
			})

			It("marks the task as failed", func() {
				Eventually(bbs.GetAllCompletedTasks, taskKickInterval*2).Should(HaveLen(1))
				tasks, err := bbs.GetAllTasks()
				Ω(err).ShouldNot(HaveOccurred())
				Ω(tasks).Should(HaveLen(1))
				Ω(tasks[0].State).Should(Equal(models.TaskStateCompleted))
				Ω(tasks[0].Failed).Should(BeTrue())
			})
		})

		Describe("then receives the SIGINT signal", func() {
			It("exits successfully", func() {
				runner.Session.Command.Process.Signal(syscall.SIGINT)
				Eventually(runner.Session, 4).Should(gexec.Exit(0))
			})
		})

		Describe("then receives the SIGTERM signal", func() {
			It("exits successfully", func() {
				runner.Session.Command.Process.Signal(syscall.SIGTERM)
				Eventually(runner.Session, 4).Should(gexec.Exit(0))
			})
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strconv"
	"syscall"
	"testing"

	dockerClient "github.com/fsouza/go-dockerclient"
)

func init() {
	INTERVAL = 100
}

func TestParseNoRun(t *testing.T) {
	_, err := parseContext([]string{"a", "b", "-d"})
	if err == nil {
		t.Fatal("parse succeeded")
	}
}

func TestParseCgroupsAll(t *testing.T) {
	c, err := parseContext([]string{"--cgroups", "all", "run"})
	if err != nil {
		t.Fatal("parse failed", err)
	}

	if !c.AllCgroups {
		t.Fatal("all cgroups should be true")
	}
}

func TestParseCgroupList(t *testing.T) {
	c, err := parseContext([]string{"--cgroups", "a", "--cgroups", "b", "run"})
	if err != nil {
		t.Fatal("parse failed", err)
	}

	if c.AllCgroups {
		t.Fatal("all cgroups should be false")
	}

	if c.Cgroups[0] != "a" ||
		c.Cgroups[1] != "b" {
		t.Fatal("Invalid cgroups value", c.Cgroups)
	}
}

func TestParseNotify(t *testing.T) {
	c, err := parseContext([]string{"run"})
	if err != nil {
		t.Fatal("parse failed", err)
	}

	if c.Notify {
		t.Fatal("notify should be false")
	}

	c, err = parseContext([]string{"--notify", "run"})
	if err != nil {
		t.Fatal("parse failed", err)
	}

	if c.Notify {
		t.Fatal("notify should be false because NOTIFY_SOCKET is unset")
	}
}

func TestParseArgs(t *testing.T) {
	c, err := parseContext([]string{"--logs=false", "run", "c", "-rm", "d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Args[0] != "-d" ||
		c.Args[1] != "c" ||
		c.Args[2] != "d" {
		t.Fatal("Invalid args", c.Args)
	}
}

func TestParseEnv(t *testing.T) {
	c, err := parseContext([]string{"run", "--env", "-d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Env {
		t.Fatal("env shouldn't be set")
	}

	c, err = parseContext([]string{"--env", "run", "-d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if !c.Env {
		t.Fatal("env should be set")
	}
}

func TestParseLogs(t *testing.T) {
	c, err := parseContext([]string{"run", "--logs", "false", "-d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if !c.Logs {
		t.Fatal("logs should be set")
	}

	c, err = parseContext([]string{"--logs=false", "run", "-d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Logs {
		t.Fatal("logs shouldn't be set")
	}
}

func TestParseName(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "--name=blah"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Name != "blah" {
		t.Fatal("failed to parse name", c.Name)
	}
}

func TestParseName2(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "--name", "blah"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Name != "blah" {
		t.Fatal("failed to parse name", c.Name)
	}
}

func TestParseName3(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "-name", "blah"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Name != "blah" {
		t.Fatal("failed to parse name", c.Name)
	}
}

func TestParseName4(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "-name"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if len(c.Name) != 0 {
		t.Fatal("failed to parse name", c.Name)
	}
}

func TestParseRm(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "-name"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Rm {
		t.Fatal("failed to parse rm", c.Rm)
	}
}

func TestParseRmSet(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "-rm"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if !c.Rm {
		t.Fatal("failed to parse rm", c.Rm)
	}
}

func TestBadExec(t *testing.T) {
	c := &Context{
		Args: []string{"-bad"},
	}

	err := runContainer(c)

	if err == nil {
		t.Fatal("Exec should have failed")
		return
	}

	if e, ok := err.(*exec.ExitError); ok {
		if status, ok := e.Sys().(syscall.WaitStatus); ok {
			if status.ExitStatus() != 2 {
				log.Fatal("Expect 2 exit code got ", status.ExitStatus())
			}
		}
	} else {
		t.Fatal("Expect exec.ExitError", err)
	}
}

func TestGoodExec(t *testing.T) {
	c := &Context{
		Args: []string{"-d", "busybox", "echo", "hi"},
	}

	err := runContainer(c)

	if err != nil {
		t.Fatal("Exec should not have failed", err)
		return
	}

	if c.Cmd.ProcessState.Pid() <= 0 {
		t.Fatal("Bad pid", c.Cmd.ProcessState.Pid())
	}

	if c.Pid <= 0 {
		t.Fatal("Bad container pid", c.Pid)
	}
}

func TestParseCgroups(t *testing.T) {
	cgroups, err := getCgroupsForPid(os.Getpid())
	if err != nil {
		log.Fatal("Error:", err)
	}

	if val, ok := cgroups["cpu"]; ok {
		p := path.Join(SYSFS, "cpu", val)
		if _, err := os.Stat(p); os.IsNotExist(err) {
			log.Fatalf("Path does not exist %s", p, err)
		}
	} else {
		log.Fatal("Failed to find cpu cgroup", val)
	}
}

func TestMoveCgroup(t *testing.T) {
	c := &Context{
		Args: []string{"-d", "busybox", "echo", "hi"},
	}

	err := runContainer(c)

	if err != nil {
		t.Fatal("Exec should not have failed", err)
		return
	}

	if c.Cmd.ProcessState.Pid() <= 0 {
		t.Fatal("Bad pid", c.Cmd.ProcessState.Pid())
	}

	if c.Pid <= 0 {
		t.Fatal("Bad container pid", c.Pid)
	}

	moved, err := moveCgroups(c)
	if !moved || err != nil {
		t.Fatal("Failed to move namespaces ", moved, err)
	}
}

func TestRemoveNoLogs(t *testing.T) {
	c, err := mainWithArgs([]string{"--logs=false", "run", "-rm", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	client, err := getClient(c)
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.InspectContainer(c.Id)
	if _, ok := err.(*dockerClient.NoSuchContainer); !ok {
		t.Fatal("Should have failed")
	}
}

func TestRemoveWithLogs(t *testing.T) {
	c, err := mainWithArgs([]string{"--logs", "run", "-rm", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	client, err := getClient(c)
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.InspectContainer(c.Id)
	if _, ok := err.(*dockerClient.NoSuchContainer); !ok {
		t.Fatal("Should have failed")
	}
}

func deleteTestContainer(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	container, err := client.InspectContainer("systemd-docker-test")
	if err == nil {
		log.Println("Deleting existing container", container.ID)
		err = client.RemoveContainer(dockerClient.RemoveContainerOptions{
			ID:    container.ID,
			Force: true,
		})

		if err != nil {
			log.Fatal(err)
		}
	}
}

func TestNamedContainerNoRm(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	deleteTestContainer(t)

	c, err := mainWithArgs([]string{"--logs", "run", "--privileged=true", "--name", "systemd-docker-test", "--privileged=true", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := client.InspectContainer("systemd-docker-test")
	if err != nil {
		t.Fatal(err)
	}

	if container.State.Running {
		t.Fatal("Should not be running")
	}

	c, err = mainWithArgs([]string{"--logs", "run", "--privileged=true", "--name", "systemd-docker-test", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	container2, err := client.InspectContainer(c.Id)
	if err != nil {
		t.Fatal(err)
	}

	if container2.State.Running {
		t.Fatal("Should not be running")
	}

	if container.ID != container2.ID {
		t.Fatal("Should be the same container", container.ID, container2.ID)
	}

        if !container2.HostConfig.Privileged {
                t.Fatal("Container2 is not privileged")
        }

	deleteTestContainer(t)
}

func TestNamedContainerRmPrevious(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	deleteTestContainer(t)

	c, err := mainWithArgs([]string{"--logs", "run", "--name", "systemd-docker-test", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := client.InspectContainer("systemd-docker-test")
	if err != nil {
		t.Fatal(err)
	}

	if container.State.Running {
		t.Fatal("Should not be running")
	}

	c, err = mainWithArgs([]string{"--logs", "run", "--rm", "--name", "systemd-docker-test", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.InspectContainer(c.Id)
	if err == nil {
		t.Fatal("Should not exists")
	}

	if container.ID == c.Id {
		t.Fatal("Should not be the same container", container.ID, c.Id)
	}

	deleteTestContainer(t)
}

func TestNamedContainerAttach(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	deleteTestContainer(t)

	c, err := mainWithArgs([]string{"--logs=false", "run", "--name", "systemd-docker-test", "busybox", "sleep", "2"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := client.InspectContainer("systemd-docker-test")
	if err != nil {
		t.Fatal(err)
	}

	if !container.State.Running {
		t.Fatal("Should be running")
	}

	c, err = mainWithArgs([]string{"--logs=false", "run", "--name", "systemd-docker-test", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	container2, err := client.InspectContainer(c.Id)
	if err != nil {
		t.Fatal("Should exists", err)
	}

	if !container2.State.Running {
		t.Fatal("Should be running")
	}

	if container.ID != container2.ID {
		t.Fatal("Should not be the same container", container.ID, container2.ID)
	}

	deleteTestContainer(t)
}

func Exist(path string) bool {
	_, err := os.Stat(path)
	return os.IsExist(err)
}

func TestPidFile(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	pidFileName := "./pid-file"

	os.Remove(pidFileName)

	c, err := mainWithArgs([]string{"--logs=false", "--pid-file", "./pid-file", "run", "--rm", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.InspectContainer(c.Id)
	if err == nil {
		t.Fatal("Container should not exist")
	}

	bytes, err := ioutil.ReadFile(pidFileName)
	if err != nil {
		t.Fatal(err)
	}

	if string(bytes) != strconv.Itoa(c.Pid) {
		t.Fatal("Failed to write pid file")
	}

	os.Remove(pidFileName)
}
<commit_msg>Fix test to work where cgroup is cpu,cpuacct<commit_after>package main

import (
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strconv"
	"syscall"
	"testing"

	dockerClient "github.com/fsouza/go-dockerclient"
)

func init() {
	INTERVAL = 100
}

func TestParseNoRun(t *testing.T) {
	_, err := parseContext([]string{"a", "b", "-d"})
	if err == nil {
		t.Fatal("parse succeeded")
	}
}

func TestParseCgroupsAll(t *testing.T) {
	c, err := parseContext([]string{"--cgroups", "all", "run"})
	if err != nil {
		t.Fatal("parse failed", err)
	}

	if !c.AllCgroups {
		t.Fatal("all cgroups should be true")
	}
}

func TestParseCgroupList(t *testing.T) {
	c, err := parseContext([]string{"--cgroups", "a", "--cgroups", "b", "run"})
	if err != nil {
		t.Fatal("parse failed", err)
	}

	if c.AllCgroups {
		t.Fatal("all cgroups should be false")
	}

	if c.Cgroups[0] != "a" ||
		c.Cgroups[1] != "b" {
		t.Fatal("Invalid cgroups value", c.Cgroups)
	}
}

func TestParseNotify(t *testing.T) {
	c, err := parseContext([]string{"run"})
	if err != nil {
		t.Fatal("parse failed", err)
	}

	if c.Notify {
		t.Fatal("notify should be false")
	}

	c, err = parseContext([]string{"--notify", "run"})
	if err != nil {
		t.Fatal("parse failed", err)
	}

	if c.Notify {
		t.Fatal("notify should be false because NOTIFY_SOCKET is unset")
	}
}

func TestParseArgs(t *testing.T) {
	c, err := parseContext([]string{"--logs=false", "run", "c", "-rm", "d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Args[0] != "-d" ||
		c.Args[1] != "c" ||
		c.Args[2] != "d" {
		t.Fatal("Invalid args", c.Args)
	}
}

func TestParseEnv(t *testing.T) {
	c, err := parseContext([]string{"run", "--env", "-d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Env {
		t.Fatal("env shouldn't be set")
	}

	c, err = parseContext([]string{"--env", "run", "-d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if !c.Env {
		t.Fatal("env should be set")
	}
}

func TestParseLogs(t *testing.T) {
	c, err := parseContext([]string{"run", "--logs", "false", "-d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if !c.Logs {
		t.Fatal("logs should be set")
	}

	c, err = parseContext([]string{"--logs=false", "run", "-d"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Logs {
		t.Fatal("logs shouldn't be set")
	}
}

func TestParseName(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "--name=blah"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Name != "blah" {
		t.Fatal("failed to parse name", c.Name)
	}
}

func TestParseName2(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "--name", "blah"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Name != "blah" {
		t.Fatal("failed to parse name", c.Name)
	}
}

func TestParseName3(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "-name", "blah"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Name != "blah" {
		t.Fatal("failed to parse name", c.Name)
	}
}

func TestParseName4(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "-name"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if len(c.Name) != 0 {
		t.Fatal("failed to parse name", c.Name)
	}
}

func TestParseRm(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "-name"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if c.Rm {
		t.Fatal("failed to parse rm", c.Rm)
	}
}

func TestParseRmSet(t *testing.T) {
	c, err := parseContext([]string{"run", "-d", "--logs", "-rm"})
	if err != nil {
		t.Fatal("failed to parse:", err)
	}

	if !c.Rm {
		t.Fatal("failed to parse rm", c.Rm)
	}
}

func TestBadExec(t *testing.T) {
	c := &Context{
		Args: []string{"-bad"},
	}

	err := runContainer(c)

	if err == nil {
		t.Fatal("Exec should have failed")
		return
	}

	if e, ok := err.(*exec.ExitError); ok {
		if status, ok := e.Sys().(syscall.WaitStatus); ok {
			if status.ExitStatus() != 2 {
				log.Fatal("Expect 2 exit code got ", status.ExitStatus())
			}
		}
	} else {
		t.Fatal("Expect exec.ExitError", err)
	}
}

func TestGoodExec(t *testing.T) {
	c := &Context{
		Args: []string{"-d", "busybox", "echo", "hi"},
	}

	err := runContainer(c)

	if err != nil {
		t.Fatal("Exec should not have failed", err)
		return
	}

	if c.Cmd.ProcessState.Pid() <= 0 {
		t.Fatal("Bad pid", c.Cmd.ProcessState.Pid())
	}

	if c.Pid <= 0 {
		t.Fatal("Bad container pid", c.Pid)
	}
}

func TestParseCgroups(t *testing.T) {
	cgroups, err := getCgroupsForPid(os.Getpid())
	if err != nil {
		log.Fatal("Error:", err)
	}

	if val, ok := cgroups["blkio"]; ok {
		p := path.Join(SYSFS, "blkio", val)
		if _, err := os.Stat(p); os.IsNotExist(err) {
			log.Fatalf("Path does not exist %s", p, err)
		}
	} else {
		log.Fatal("Failed to find blkio cgroup", val)
	}
}

func TestMoveCgroup(t *testing.T) {
	c := &Context{
		Args: []string{"-d", "busybox", "echo", "hi"},
	}

	err := runContainer(c)

	if err != nil {
		t.Fatal("Exec should not have failed", err)
		return
	}

	if c.Cmd.ProcessState.Pid() <= 0 {
		t.Fatal("Bad pid", c.Cmd.ProcessState.Pid())
	}

	if c.Pid <= 0 {
		t.Fatal("Bad container pid", c.Pid)
	}

	moved, err := moveCgroups(c)
	if !moved || err != nil {
		t.Fatal("Failed to move namespaces ", moved, err)
	}
}

func TestRemoveNoLogs(t *testing.T) {
	c, err := mainWithArgs([]string{"--logs=false", "run", "-rm", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	client, err := getClient(c)
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.InspectContainer(c.Id)
	if _, ok := err.(*dockerClient.NoSuchContainer); !ok {
		t.Fatal("Should have failed")
	}
}

func TestRemoveWithLogs(t *testing.T) {
	c, err := mainWithArgs([]string{"--logs", "run", "-rm", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	client, err := getClient(c)
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.InspectContainer(c.Id)
	if _, ok := err.(*dockerClient.NoSuchContainer); !ok {
		t.Fatal("Should have failed")
	}
}

func deleteTestContainer(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	container, err := client.InspectContainer("systemd-docker-test")
	if err == nil {
		log.Println("Deleting existing container", container.ID)
		err = client.RemoveContainer(dockerClient.RemoveContainerOptions{
			ID:    container.ID,
			Force: true,
		})

		if err != nil {
			log.Fatal(err)
		}
	}
}

func TestNamedContainerNoRm(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	deleteTestContainer(t)

	c, err := mainWithArgs([]string{"--logs", "run", "--privileged=true", "--name", "systemd-docker-test", "--privileged=true", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := client.InspectContainer("systemd-docker-test")
	if err != nil {
		t.Fatal(err)
	}

	if container.State.Running {
		t.Fatal("Should not be running")
	}

	c, err = mainWithArgs([]string{"--logs", "run", "--privileged=true", "--name", "systemd-docker-test", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	container2, err := client.InspectContainer(c.Id)
	if err != nil {
		t.Fatal(err)
	}

	if container2.State.Running {
		t.Fatal("Should not be running")
	}

	if container.ID != container2.ID {
		t.Fatal("Should be the same container", container.ID, container2.ID)
	}

        if !container2.HostConfig.Privileged {
                t.Fatal("Container2 is not privileged")
        }

	deleteTestContainer(t)
}

func TestNamedContainerRmPrevious(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	deleteTestContainer(t)

	c, err := mainWithArgs([]string{"--logs", "run", "--name", "systemd-docker-test", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := client.InspectContainer("systemd-docker-test")
	if err != nil {
		t.Fatal(err)
	}

	if container.State.Running {
		t.Fatal("Should not be running")
	}

	c, err = mainWithArgs([]string{"--logs", "run", "--rm", "--name", "systemd-docker-test", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.InspectContainer(c.Id)
	if err == nil {
		t.Fatal("Should not exists")
	}

	if container.ID == c.Id {
		t.Fatal("Should not be the same container", container.ID, c.Id)
	}

	deleteTestContainer(t)
}

func TestNamedContainerAttach(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	deleteTestContainer(t)

	c, err := mainWithArgs([]string{"--logs=false", "run", "--name", "systemd-docker-test", "busybox", "sleep", "2"})
	if err != nil {
		t.Fatal(err)
	}

	container, err := client.InspectContainer("systemd-docker-test")
	if err != nil {
		t.Fatal(err)
	}

	if !container.State.Running {
		t.Fatal("Should be running")
	}

	c, err = mainWithArgs([]string{"--logs=false", "run", "--name", "systemd-docker-test", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	container2, err := client.InspectContainer(c.Id)
	if err != nil {
		t.Fatal("Should exists", err)
	}

	if !container2.State.Running {
		t.Fatal("Should be running")
	}

	if container.ID != container2.ID {
		t.Fatal("Should not be the same container", container.ID, container2.ID)
	}

	deleteTestContainer(t)
}

func Exist(path string) bool {
	_, err := os.Stat(path)
	return os.IsExist(err)
}

func TestPidFile(t *testing.T) {
	client, err := getClient(&Context{})
	if err != nil {
		t.Fatal(err)
	}

	pidFileName := "./pid-file"

	os.Remove(pidFileName)

	c, err := mainWithArgs([]string{"--logs=false", "--pid-file", "./pid-file", "run", "--rm", "busybox", "echo", "hi"})
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.InspectContainer(c.Id)
	if err == nil {
		t.Fatal("Container should not exist")
	}

	bytes, err := ioutil.ReadFile(pidFileName)
	if err != nil {
		t.Fatal(err)
	}

	if string(bytes) != strconv.Itoa(c.Pid) {
		t.Fatal("Failed to write pid file")
	}

	os.Remove(pidFileName)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
)

var endpoint string = "http://localhost:8080"
var token string = ""

func Do(method string, postUrl string) (bodyStr string, status int, err error) {
	req, err := http.NewRequest(method, postUrl, nil)
	if err != nil {
		return
	}

	if token != "" {
		req.Header.Set("Authorization", "Bearer "+token)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}

	status = resp.StatusCode

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	bodyStr = string(body)

	return

}

func TestApi(t *testing.T) {

	go main()
	time.Sleep(time.Second * 1)

	Convey("Test login", t, func() {

		resp, err := http.PostForm(
			endpoint+"/login",
			url.Values{
				"username": {"admin"},
				"password": {""},
			},
		)

		So(err, ShouldEqual, nil)
		So(resp.StatusCode, ShouldEqual, 200)

		body, err := ioutil.ReadAll(resp.Body)
		So(err, ShouldEqual, nil)

		var objmap map[string]string

		err = json.Unmarshal(body, &objmap)
		So(err, ShouldEqual, nil)

		//So(objmap, ShouldEqual, "")

		tokenFound, gotToken := objmap["token"]

		So(gotToken, ShouldEqual, true)
		token = tokenFound

	})

	Convey("Test scan", t, func() {

		_, status, err := Do("POST", endpoint+"/api/scan")
		So(err, ShouldEqual, nil)
		So(status, ShouldEqual, 200)

	})

	Convey("Tests for albums", t, func() {

		Convey("Test get albums", func() {

			body, status, err := Do("GET", endpoint+"/api/albums")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

			albums := []map[string]interface{}{}
			//So(body, ShouldEqual, -1)
			err = json.Unmarshal([]byte(body), &albums)
			So(err, ShouldEqual, nil)
			So(len(albums), ShouldBeGreaterThanOrEqualTo, 1)
			So(albums[0]["name"], ShouldEqual, "Curse the Day (Single versions)")

		})

		Convey("Test single album", func() {

			body, status, err := Do("GET", endpoint+"/api/albums/1")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

			album := map[string]interface{}{}
			//So(body, ShouldEqual, -1)
			err = json.Unmarshal([]byte(body), &album)
			So(err, ShouldEqual, nil)

			So(album["id"], ShouldEqual, 1)
			So(album["name"], ShouldEqual, "Curse the Day (Single versions)")
			So(album["year"], ShouldEqual, 2016)
			So(album["cover"], ShouldEqual, "/images/8806119b2782b3f3eaa32129c20533bd.jpg")

		})

		Convey("Test albums playlist m3u8", func() {

			_, status, err := Do("GET", endpoint+"/api/albums/1/playlist.m3u8")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

		})

	})

	Convey("Tests for songs", t, func() {

		Convey("Test song stream", func() {

			_, status, err := Do("GET", endpoint+"/api/songs/1/stream")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

		})

		Convey("Test song played", func() {

			_, status, err := Do("POST", endpoint+"/api/songs/1/played")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

		})

	})

	Convey("Tests for playlists", t, func() {

		Convey("Test playlists", func() {

			_, status, err := Do("GET", endpoint+"/api/playlists")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

		})

		Convey("Test single playlist", func() {

			_, status, err := Do("GET", endpoint+"/api/playlist/1")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 404)

			// Need to add one via post, then test again for code 200
			// and test DELETE of playlist

		})

	})

}
<commit_msg>Fixed test<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
)

var endpoint string = "http://localhost:8080"
var token string = ""

func Do(method string, postUrl string) (bodyStr string, status int, err error) {
	req, err := http.NewRequest(method, postUrl, nil)
	if err != nil {
		return
	}

	if token != "" {
		req.Header.Set("Authorization", "Bearer "+token)
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}

	status = resp.StatusCode

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	bodyStr = string(body)

	return

}

func TestApi(t *testing.T) {

	go main()
	time.Sleep(time.Second * 1)

	Convey("Test login", t, func() {

		resp, err := http.PostForm(
			endpoint+"/api/login",
			url.Values{
				"username": {"admin"},
				"password": {""},
			},
		)

		So(err, ShouldEqual, nil)
		So(resp.StatusCode, ShouldEqual, 200)

		body, err := ioutil.ReadAll(resp.Body)
		So(err, ShouldEqual, nil)

		var objmap map[string]string

		err = json.Unmarshal(body, &objmap)
		So(err, ShouldEqual, nil)

		//So(objmap, ShouldEqual, "")

		tokenFound, gotToken := objmap["token"]

		So(gotToken, ShouldEqual, true)
		token = tokenFound

	})

	Convey("Test scan", t, func() {

		_, status, err := Do("POST", endpoint+"/api/scan")
		So(err, ShouldEqual, nil)
		So(status, ShouldEqual, 200)

	})

	Convey("Tests for albums", t, func() {

		Convey("Test get albums", func() {

			body, status, err := Do("GET", endpoint+"/api/albums")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

			albums := []map[string]interface{}{}
			//So(body, ShouldEqual, -1)
			err = json.Unmarshal([]byte(body), &albums)
			So(err, ShouldEqual, nil)
			So(len(albums), ShouldBeGreaterThanOrEqualTo, 1)
			So(albums[0]["name"], ShouldEqual, "Curse the Day (Single versions)")

		})

		Convey("Test single album", func() {

			body, status, err := Do("GET", endpoint+"/api/albums/1")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

			album := map[string]interface{}{}
			//So(body, ShouldEqual, -1)
			err = json.Unmarshal([]byte(body), &album)
			So(err, ShouldEqual, nil)

			So(album["id"], ShouldEqual, 1)
			So(album["name"], ShouldEqual, "Curse the Day (Single versions)")
			So(album["year"], ShouldEqual, 2016)
			So(album["cover"], ShouldEqual, "/images/8806119b2782b3f3eaa32129c20533bd.jpg")

		})

		Convey("Test albums playlist m3u8", func() {

			_, status, err := Do("GET", endpoint+"/api/albums/1/playlist.m3u8")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

		})

	})

	Convey("Tests for songs", t, func() {

		Convey("Test song stream", func() {

			_, status, err := Do("GET", endpoint+"/api/songs/1/stream")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

		})

		Convey("Test song played", func() {

			_, status, err := Do("POST", endpoint+"/api/songs/1/played")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

		})

	})

	Convey("Tests for playlists", t, func() {

		Convey("Test playlists", func() {

			_, status, err := Do("GET", endpoint+"/api/playlists")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 200)

		})

		Convey("Test single playlist", func() {

			_, status, err := Do("GET", endpoint+"/api/playlist/1")
			So(err, ShouldEqual, nil)
			So(status, ShouldEqual, 404)

			// Need to add one via post, then test again for code 200
			// and test DELETE of playlist

		})

	})

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"strings"
	"testing"
)

func TestRun_versionFlag(t *testing.T) {
	outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
	cli := &CLI{outStream: outStream, errStream: errStream}
	args := strings.Split("binrep --version", " ")

	status := cli.Run(args)
	if status != 0 {
		t.Errorf("expected %d to eq %d", status, 0)
	}

	expected := fmt.Sprintf("binrep version %s", version)
	if !strings.Contains(errStream.String(), expected) {
		t.Errorf("expected %q to eq %q", errStream.String(), expected)
	}
}

func TestRun_parseError(t *testing.T) {
	outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
	cli := &CLI{outStream: outStream, errStream: errStream}
	args := strings.Split("binrep --not-exist", " ")

	status := cli.Run(args)
	if status != 1 {
		t.Errorf("expected %d to eq %d", status, 1)
	}

	expected := "--not-exist is undefined subcommand or option"
	if !strings.Contains(errStream.String(), expected) {
		t.Fatalf("expected %q to contain %q", errStream.String(), expected)
	}
}

func TestRun_subCommand(t *testing.T) {
	tests := []struct {
		desc           string
		arg            string
		expectedStatus int
		expectedSubOut string
	}{
		// list
		{
			desc:           "list: display help",
			arg:            "binrep list --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep list",
		},
		{
			desc:           "list: missing endpoint error",
			arg:            "binrep list",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "list: extra arguments error",
			arg:            "binrep list --endpoint s3://testing hoge",
			expectedStatus: 2,
			expectedSubOut: "extra arguments",
		},

		// show
		{
			desc:           "show: display help",
			arg:            "binrep show --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep show",
		},
		{
			desc:           "show: missing endpoint error",
			arg:            "binrep show",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "show: arguments error",
			arg:            "binrep show --endpoint s3://testing",
			expectedStatus: 2,
			expectedSubOut: "too few arguments",
		},

		// push
		{
			desc:           "push: display help",
			arg:            "binrep push --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep push",
		},
		{
			desc:           "push: missing endpoint error",
			arg:            "binrep push",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "push: arguments error (len: 0)",
			arg:            "binrep push --endpoint s3://testing",
			expectedStatus: 2,
			expectedSubOut: "too few arguments",
		},
		{
			desc:           "push: arguments error (len: 1)",
			arg:            "binrep push --endpoint s3://testing hoge",
			expectedStatus: 2,
			expectedSubOut: "too few arguments",
		},

		// pull
		{
			desc:           "pull: display help",
			arg:            "binrep pull --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep pull",
		},
		{
			desc:           "pull: missing endpoint error",
			arg:            "binrep pull",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "pull: arguments error (len: 1)",
			arg:            "binrep pull --endpoint s3://testing hoge",
			expectedStatus: 2,
			expectedSubOut: "too few or many arguments",
		},
		{
			desc:           "pull: arguments error (len: 3)",
			arg:            "binrep pull --endpoint s3://testing hoge foo bar",
			expectedStatus: 2,
			expectedSubOut: "too few or many arguments",
		},
		// sync
		{
			desc:           "sync: display help",
			arg:            "binrep sync --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep sync",
		},
		{
			desc:           "sync: missing endpoint error",
			arg:            "binrep sync",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "sync: arguments error (len: 0)",
			arg:            "binrep sync --endpoint s3://testing",
			expectedStatus: 2,
			expectedSubOut: "too few arguments",
		},
	}
	for _, tc := range tests {
		outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
		cli := &CLI{outStream: outStream, errStream: errStream}
		args := strings.Split(tc.arg, " ")

		status := cli.Run(args)
		if status != tc.expectedStatus {
			t.Errorf("desc: %q, status should be %v, not %v", tc.desc, tc.expectedStatus, status)
		}

		if !strings.Contains(errStream.String(), tc.expectedSubOut) {
			t.Errorf("desc: %q, subout should contain %q, not %q", tc.desc, tc.expectedSubOut, errStream.String())
		}
	}
}
<commit_msg>Improve global option testing<commit_after>package main

import (
	"bytes"
	"fmt"
	"strings"
	"testing"
)

func TestRun_global(t *testing.T) {
	tests := []struct {
		desc           string
		arg            string
		expectedStatus int
		expectedSubOut string
		expectedSubErr string
	}{
		{
			desc:           "version flag",
			arg:            "binrep --version",
			expectedStatus: 0,
			expectedSubErr: fmt.Sprintf("binrep version %s, build %s, date %s", version, commit, date),
		},
		{
			desc:           "undefined flag",
			arg:            "binrep --undefined",
			expectedStatus: 1,
			expectedSubErr: "--undefined is undefined subcommand or option",
		},
		{
			desc:           "credits flag",
			arg:            "binrep --credits",
			expectedStatus: 0,
			expectedSubOut: "= Binrep licensed under: =",
		},
	}
	for _, tc := range tests {
		outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
		cli := &CLI{outStream: outStream, errStream: errStream}
		args := strings.Split(tc.arg, " ")

		status := cli.Run(args)
		if status != tc.expectedStatus {
			t.Errorf("desc: %q, status should be %v, not %v", tc.desc, tc.expectedStatus, status)
		}

		if !strings.Contains(outStream.String(), tc.expectedSubOut) {
			t.Errorf("desc: %q, subout should contain %q, got %q", tc.desc, tc.expectedSubOut, outStream.String())
		}
		if !strings.Contains(errStream.String(), tc.expectedSubErr) {
			t.Errorf("desc: %q, subout should contain %q, got %q", tc.desc, tc.expectedSubErr, errStream.String())
		}
	}
}

func TestRun_subCommand(t *testing.T) {
	tests := []struct {
		desc           string
		arg            string
		expectedStatus int
		expectedSubOut string
	}{
		// list
		{
			desc:           "list: display help",
			arg:            "binrep list --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep list",
		},
		{
			desc:           "list: missing endpoint error",
			arg:            "binrep list",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "list: extra arguments error",
			arg:            "binrep list --endpoint s3://testing hoge",
			expectedStatus: 2,
			expectedSubOut: "extra arguments",
		},

		// show
		{
			desc:           "show: display help",
			arg:            "binrep show --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep show",
		},
		{
			desc:           "show: missing endpoint error",
			arg:            "binrep show",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "show: arguments error",
			arg:            "binrep show --endpoint s3://testing",
			expectedStatus: 2,
			expectedSubOut: "too few arguments",
		},

		// push
		{
			desc:           "push: display help",
			arg:            "binrep push --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep push",
		},
		{
			desc:           "push: missing endpoint error",
			arg:            "binrep push",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "push: arguments error (len: 0)",
			arg:            "binrep push --endpoint s3://testing",
			expectedStatus: 2,
			expectedSubOut: "too few arguments",
		},
		{
			desc:           "push: arguments error (len: 1)",
			arg:            "binrep push --endpoint s3://testing hoge",
			expectedStatus: 2,
			expectedSubOut: "too few arguments",
		},

		// pull
		{
			desc:           "pull: display help",
			arg:            "binrep pull --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep pull",
		},
		{
			desc:           "pull: missing endpoint error",
			arg:            "binrep pull",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "pull: arguments error (len: 1)",
			arg:            "binrep pull --endpoint s3://testing hoge",
			expectedStatus: 2,
			expectedSubOut: "too few or many arguments",
		},
		{
			desc:           "pull: arguments error (len: 3)",
			arg:            "binrep pull --endpoint s3://testing hoge foo bar",
			expectedStatus: 2,
			expectedSubOut: "too few or many arguments",
		},
		// sync
		{
			desc:           "sync: display help",
			arg:            "binrep sync --help",
			expectedStatus: 2,
			expectedSubOut: "Usage: binrep sync",
		},
		{
			desc:           "sync: missing endpoint error",
			arg:            "binrep sync",
			expectedStatus: 2,
			expectedSubOut: "--endpoint required",
		},
		{
			desc:           "sync: arguments error (len: 0)",
			arg:            "binrep sync --endpoint s3://testing",
			expectedStatus: 2,
			expectedSubOut: "too few arguments",
		},
	}
	for _, tc := range tests {
		outStream, errStream := new(bytes.Buffer), new(bytes.Buffer)
		cli := &CLI{outStream: outStream, errStream: errStream}
		args := strings.Split(tc.arg, " ")

		status := cli.Run(args)
		if status != tc.expectedStatus {
			t.Errorf("desc: %q, status should be %v, not %v", tc.desc, tc.expectedStatus, status)
		}

		if !strings.Contains(errStream.String(), tc.expectedSubOut) {
			t.Errorf("desc: %q, subout should contain %q, got %q", tc.desc, tc.expectedSubOut, errStream.String())
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"testing"

	"github.com/nicksnyder/go-i18n/i18n"
	mylog "github.com/patrickalin/GoMyLog"
	"github.com/spf13/viper"
)

func TestSomething(t *testing.T) {
	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	if err := viper.ReadInConfig(); err != nil {
		fmt.Printf("%v", err)
	}
}
func TestMain(m *testing.M) {
	i18n.MustLoadTranslationFile("lang/en-US.all.json")
	i18n.MustLoadTranslationFile("lang/fr.all.json")
	mylog.Init(mylog.ERROR)

	os.Exit(m.Run())
}

func TestReadConfigFound(t *testing.T) {
	if err := readConfig("configForTest"); err != nil {
		fmt.Printf("%v", err)
	}
}

/*func TestReadConfigNotFound(t *testing.T) {
	if err := readConfig("configError"); err != nil {
		fmt.Printf("%v", err)
	}
}*/
<commit_msg>Test + travis = error<commit_after>package main

import (
	"fmt"
	"testing"

	"github.com/spf13/viper"
)

func TestSomething(t *testing.T) {
	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	if err := viper.ReadInConfig(); err != nil {
		fmt.Printf("%v", err)
	}
}

/*
func TestMain(m *testing.M) {
	i18n.MustLoadTranslationFile("lang/en-US.all.json")
	i18n.MustLoadTranslationFile("lang/fr.all.json")
	mylog.Init(mylog.ERROR)

	os.Exit(m.Run())
}

func TestReadConfigFound(t *testing.T) {
	if err := readConfig("configForTest"); err != nil {
		fmt.Printf("%v", err)
	}
}*/

/*func TestReadConfigNotFound(t *testing.T) {
	if err := readConfig("configError"); err != nil {
		fmt.Printf("%v", err)
	}
}*/
<|endoftext|>


<commit_before>package main_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strings"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var (
	session *gexec.Session
)

func startMainWithArgs(args ...string) *gexec.Session {
	args = append(args, fmt.Sprintf("-port=%d", port))
	command := exec.Command(garagepiBinPath, args...)
	var err error
	session, err = gexec.Start(command, GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())
	Eventually(session).Should(gbytes.Say(".*garagepi started"))
	return session
}

func validateSuccessAnyLengthBody(resp *http.Response, err error) {
	Expect(err).NotTo(HaveOccurred())
	Expect(resp.StatusCode).To(Equal(http.StatusOK))

	validateBody(resp, true)
}

func validateSuccessNonZeroLengthBody(resp *http.Response, err error) {
	Expect(err).NotTo(HaveOccurred())
	Expect(resp.StatusCode).To(Equal(http.StatusOK))

	validateBody(resp, false)
}

func validateBody(resp *http.Response, anySize bool) {
	body, err := ioutil.ReadAll(resp.Body)
	Expect(err).NotTo(HaveOccurred())

	if anySize {
		Expect(len(body)).Should(BeNumerically(">=", 0))
	} else {

		Expect(len(body)).Should(BeNumerically(">", 0))
	}
}

var _ = Describe("GaragepiExecutable", func() {
	BeforeEach(func() {
		startMainWithArgs()
	})

	AfterEach(func() {
		session.Terminate()
	})

	It("Should accept GET requests to /", func() {
		validateSuccessNonZeroLengthBody(http.Get(fmt.Sprintf("http://127.0.0.1:%d", port)))
	})

	It("Should reject GET requests to /toggle with 404", func() {
		resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/toggle", port))
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusNotFound))
	})

	It("Should accept POST requests to /toggle", func() {
		validateSuccessNonZeroLengthBody(http.Post(fmt.Sprintf("http://127.0.0.1:%d/toggle", port), "", strings.NewReader("")))
	})

	It("Should accept GET requests to /light", func() {
		resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/light", port))
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusServiceUnavailable))
	})

	It("Should accept POST requests to /light", func() {
		validateSuccessNonZeroLengthBody(http.Post(fmt.Sprintf("http://127.0.0.1:%d/light", port), "", strings.NewReader("")))
	})

	It("Should accept GET requests to /webcam", func() {
		resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/webcam", port))
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusServiceUnavailable))
	})
})
<commit_msg>Remove unused regex in main test.<commit_after>package main_test

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strings"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
)

var (
	session *gexec.Session
)

func startMainWithArgs(args ...string) *gexec.Session {
	args = append(args, fmt.Sprintf("-port=%d", port))
	command := exec.Command(garagepiBinPath, args...)
	var err error
	session, err = gexec.Start(command, GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())
	Eventually(session).Should(gbytes.Say("garagepi started"))
	return session
}

func validateSuccessAnyLengthBody(resp *http.Response, err error) {
	Expect(err).NotTo(HaveOccurred())
	Expect(resp.StatusCode).To(Equal(http.StatusOK))

	validateBody(resp, true)
}

func validateSuccessNonZeroLengthBody(resp *http.Response, err error) {
	Expect(err).NotTo(HaveOccurred())
	Expect(resp.StatusCode).To(Equal(http.StatusOK))

	validateBody(resp, false)
}

func validateBody(resp *http.Response, anySize bool) {
	body, err := ioutil.ReadAll(resp.Body)
	Expect(err).NotTo(HaveOccurred())

	if anySize {
		Expect(len(body)).Should(BeNumerically(">=", 0))
	} else {

		Expect(len(body)).Should(BeNumerically(">", 0))
	}
}

var _ = Describe("GaragepiExecutable", func() {
	BeforeEach(func() {
		startMainWithArgs()
	})

	AfterEach(func() {
		session.Terminate()
	})

	It("Should accept GET requests to /", func() {
		validateSuccessNonZeroLengthBody(http.Get(fmt.Sprintf("http://127.0.0.1:%d", port)))
	})

	It("Should reject GET requests to /toggle with 404", func() {
		resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/toggle", port))
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusNotFound))
	})

	It("Should accept POST requests to /toggle", func() {
		validateSuccessNonZeroLengthBody(http.Post(fmt.Sprintf("http://127.0.0.1:%d/toggle", port), "", strings.NewReader("")))
	})

	It("Should accept GET requests to /light", func() {
		resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/light", port))
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusServiceUnavailable))
	})

	It("Should accept POST requests to /light", func() {
		validateSuccessNonZeroLengthBody(http.Post(fmt.Sprintf("http://127.0.0.1:%d/light", port), "", strings.NewReader("")))
	})

	It("Should accept GET requests to /webcam", func() {
		resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/webcam", port))
		Expect(err).NotTo(HaveOccurred())
		Expect(resp.StatusCode).To(Equal(http.StatusServiceUnavailable))
	})
})
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"testing"
	"time"
	// "runtime"
	"encoding/json"
	"fmt"

	"github.com/jcelliott/lumber"

	"github.com/nanobox-io/nanobox-logtap/collector"
	"github.com/nanobox-io/nanobox-logtap/drain"

	"github.com/nanobox-io/nanobox-server/api"
	"github.com/nanobox-io/nanobox-server/config"
	"github.com/nanobox-io/nanobox-server/jobs"
	"github.com/nanobox-io/nanobox-server/util/docker"
	"github.com/nanopack/mist/core"
)

var apiClient = api.Init()

func TestMain(m *testing.M) {
	config.Log = lumber.NewConsoleLogger(lumber.ERROR)
	config.Log = lumber.NewConsoleLogger(lumber.DEBUG)
	if testing.Verbose() {
		// not working.. not sure why

	}

	curDir, err := os.Getwd()
	if err != nil {
		os.Exit(1)
	}
	config.MountFolder = curDir + "/test/"
	config.DockerMount = curDir + "/test/"

	config.Logtap.AddDrain("console", drain.AdaptLogger(config.Log))
	config.Logtap.AddDrain("mist", drain.AdaptPublisher(config.Mist))
	// define logtap collectors/drains; we don't need to defer Close() anything here,
	// because these want to live as long as the server
	if _, err := collector.SyslogUDPStart("app", config.Ports["logtap"]+"1", config.Logtap); err != nil {
		panic(err)
	}

	//
	if _, err := collector.SyslogTCPStart("app", config.Ports["logtap"]+"1", config.Logtap); err != nil {
		panic(err)
	}

	// we will be adding a 0 to the end of the logtap port because we cant have 2 tcp listeneres
	// on the same port
	if _, err := collector.StartHttpCollector("deploy", config.Ports["logtap"]+"0", config.Logtap); err != nil {
		panic(err)
	}

	go func() {
		// start nanobox
		if err := apiClient.Start(config.Ports["api"]); err != nil {
			os.Exit(1)
		}
	}()

	// make sure the images are up to date
	iu := jobs.ImageUpdate{}
	iu.Process()
	rtn := m.Run()

	// Remove all containers
	containers, _ := docker.ListContainers()
	for _, container := range containers {
		docker.RemoveContainer(container.ID)
	}

	os.Exit(rtn)
}

func TestPing(t *testing.T) {
	r, err := http.Get("http://localhost:1757/ping")
	if err != nil || r.StatusCode != 200 {
		t.Errorf("unable to ping")
	}
	bytes, _ := ioutil.ReadAll(r.Body)
	body := string(bytes)
	if body != "pong" {
		t.Errorf("expected pong but got %s", body)
	}
}

func TestDeploy(t *testing.T) {
	r, err := http.Post("http://localhost:1757/deploys?run=true", "json", nil)
	if err != nil || r.StatusCode != 200 {
		fmt.Println(r, err)
		t.Errorf("unable to deploy")
	}
	bytes, _ := ioutil.ReadAll(r.Body)
	deploy := map[string]string{}
	err = json.Unmarshal(bytes, &deploy)
	if err != nil {
		t.Errorf("unable to unmarshal body %s", bytes)
	}

	id := deploy["id"]

	mistClient := mist.NewLocalClient(config.Mist, 1)
	mistClient.Subscribe([]string{"job", "deploy"})

	message := <-mistClient.Messages()

	data := map[string]interface{}{}

	err = json.Unmarshal([]byte(message.Data), &data)
	if err != nil {
		t.Errorf("unable to unmarshal data %s\nerr: %s", message.Data, err.Error())
	}

	if data["document"].(map[string]interface{})["id"] != id {
		t.Errorf("the message is not for my deploy: %+v", data["document"])
	}
	if data["document"].(map[string]interface{})["status"] != "complete" {
		t.Errorf("I recieved a bad status: %+v", data["document"])
	}
	if list, err := docker.ListContainers(); err != nil || len(list) == 0 {
		t.Errorf("I should have atleast one docker container")
	}

	if c, err := docker.GetContainer("build1"); err != nil || c.Name == "" {
		t.Errorf("There should be a build1 container")
	}
}

func TestBuild(t *testing.T) {
	r, err := http.Post("http://localhost:1757/builds", "json", nil)
	if err != nil || r.StatusCode != 200 {
		fmt.Println(r, err)
		t.Errorf("unable to build")
	}
	bytes, _ := ioutil.ReadAll(r.Body)
	build := map[string]string{}
	err = json.Unmarshal(bytes, &build)
	if err != nil {
		t.Errorf("unable to unmarshal body %s", bytes)
	}

	id := build["id"]

	mistClient := mist.NewLocalClient(config.Mist, 1)
	mistClient.Subscribe([]string{"job", "build"})

	message := <-mistClient.Messages()

	data := map[string]interface{}{}

	err = json.Unmarshal([]byte(message.Data), &data)
	if err != nil {
		t.Errorf("unable to unmarshal data %s\nerr: %s", message.Data, err.Error())
	}

	if data["document"].(map[string]interface{})["id"] != id {
		t.Errorf("the message is not for my build: %+v", data["document"])
	}
	if data["document"].(map[string]interface{})["status"] != "complete" {
		t.Errorf("I recieved a bad status: %+v", data["document"])
	}
	if c, err := docker.GetContainer("build1"); err != nil || c.Name == "" {
		t.Errorf("There should be a build1 container")
	}
}

func TestDevelop(t *testing.T) {
	conn, err := net.Dial("tcp4", "localhost:1757")
	if err != nil {
		t.Errorf("unable to establish connection")
	}

	fmt.Fprintf(conn, "POST /develop? HTTP/1.1\r\n\r\n")

	// give the server time to start the dev
	<-time.After(2 * time.Second)

	if c, err := docker.GetContainer("dev1"); err != nil || c.Name == "" {
		t.Errorf("There should be a dev1 container")
	}
	conn.Close()

	// give the server time to start the dev
	<-time.After(2 * time.Second)
	if _, err := docker.GetContainer("dev1"); err == nil {
		t.Errorf("There should not be a dev1 container")
	}
}

func TestRoutes(t *testing.T) {
	r, err := http.Get("http://localhost:1757/routes")
	if err != nil || r.StatusCode != 200 {
		fmt.Println(r, err)
		t.Errorf("unable to get routes")
	}
	bytes, _ := ioutil.ReadAll(r.Body)
	routes := []map[string]interface{}{}
	err = json.Unmarshal(bytes, &routes)
	if err != nil {
		t.Errorf("unable to unmarshal body %s", bytes)
	}
	if len(routes) < 1 {
		t.Errorf("I should have one route")
		return
	}
	if routes[0]["Name"] != "app.dev" {
		t.Errorf("the Route I have is not app.dev")
	}
}
<commit_msg>fix a testing typo<commit_after>package main

import (
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"testing"
	"time"
	// "runtime"
	"encoding/json"
	"fmt"

	"github.com/jcelliott/lumber"

	"github.com/nanobox-io/nanobox-logtap/collector"
	"github.com/nanobox-io/nanobox-logtap/drain"

	"github.com/nanobox-io/nanobox-server/api"
	"github.com/nanobox-io/nanobox-server/config"
	"github.com/nanobox-io/nanobox-server/jobs"
	"github.com/nanobox-io/nanobox-server/util/docker"
	"github.com/nanopack/mist/core"
)

var apiClient = api.Init()

func TestMain(m *testing.M) {
	config.Log = lumber.NewConsoleLogger(lumber.ERROR)
	config.Log = lumber.NewConsoleLogger(lumber.DEBUG)
	if testing.Verbose() {
		// not working.. not sure why

	}

	curDir, err := os.Getwd()
	if err != nil {
		os.Exit(1)
	}
	config.MountFolder = curDir + "/test/"
	config.DockerMount = curDir + "/test/"

	config.Logtap.AddDrain("console", drain.AdaptLogger(config.Log))
	config.Logtap.AddDrain("mist", drain.AdaptPublisher(config.Mist))
	// define logtap collectors/drains; we don't need to defer Close() anything here,
	// because these want to live as long as the server
	if _, err := collector.SyslogUDPStart("app", config.Ports["logtap"]+"1", config.Logtap); err != nil {
		panic(err)
	}

	//
	if _, err := collector.SyslogTCPStart("app", config.Ports["logtap"]+"1", config.Logtap); err != nil {
		panic(err)
	}

	// we will be adding a 0 to the end of the logtap port because we cant have 2 tcp listeneres
	// on the same port
	if _, err := collector.StartHttpCollector("deploy", config.Ports["logtap"]+"0", config.Logtap); err != nil {
		panic(err)
	}

	go func() {
		// start nanobox
		if err := apiClient.Start(config.Ports["api"]); err != nil {
			os.Exit(1)
		}
	}()

	// make sure the images are up to date
	iu := jobs.ImageUpdate{}
	iu.Process()
	rtn := m.Run()

	// Remove all containers
	containers, _ := docker.ListContainers()
	for _, container := range containers {
		docker.RemoveContainer(container.ID)
	}

	os.Exit(rtn)
}

func TestPing(t *testing.T) {
	r, err := http.Get("http://localhost:1757/ping")
	if err != nil || r.StatusCode != 200 {
		t.Errorf("unable to ping")
		return
	}
	bytes, _ := ioutil.ReadAll(r.Body)
	body := string(bytes)
	if body != "pong" {
		t.Errorf("expected pong but got %s", body)
	}
}

func TestDeploy(t *testing.T) {
	r, err := http.Post("http://localhost:1757/deploys?run=true", "json", nil)
	if err != nil || r.StatusCode != 200 {
		fmt.Println(r, err)
		t.Errorf("unable to deploy")
	}
	bytes, _ := ioutil.ReadAll(r.Body)
	deploy := map[string]string{}
	err = json.Unmarshal(bytes, &deploy)
	if err != nil {
		t.Errorf("unable to unmarshal body %s", bytes)
	}

	id := deploy["id"]

	mistClient := mist.NewLocalClient(config.Mist, 1)
	mistClient.Subscribe([]string{"job", "deploy"})

	message := <-mistClient.Messages()

	data := map[string]interface{}{}

	err = json.Unmarshal([]byte(message.Data), &data)
	if err != nil {
		t.Errorf("unable to unmarshal data %s\nerr: %s", message.Data, err.Error())
	}

	if data["document"].(map[string]interface{})["id"] != id {
		t.Errorf("the message is not for my deploy: %+v", data["document"])
	}
	if data["document"].(map[string]interface{})["status"] != "complete" {
		t.Errorf("I recieved a bad status: %+v", data["document"])
	}
	if list, err := docker.ListContainers(); err != nil || len(list) == 0 {
		t.Errorf("I should have atleast one docker container")
	}

	if c, err := docker.GetContainer("build1"); err != nil || c.Name == "" {
		t.Errorf("There should be a build1 container")
	}
}

func TestBuild(t *testing.T) {
	r, err := http.Post("http://localhost:1757/builds", "json", nil)
	if err != nil || r.StatusCode != 200 {
		fmt.Println(r, err)
		t.Errorf("unable to build")
	}
	bytes, _ := ioutil.ReadAll(r.Body)
	build := map[string]string{}
	err = json.Unmarshal(bytes, &build)
	if err != nil {
		t.Errorf("unable to unmarshal body %s", bytes)
	}

	id := build["id"]

	mistClient := mist.NewLocalClient(config.Mist, 1)
	mistClient.Subscribe([]string{"job", "build"})

	message := <-mistClient.Messages()

	data := map[string]interface{}{}

	err = json.Unmarshal([]byte(message.Data), &data)
	if err != nil {
		t.Errorf("unable to unmarshal data %s\nerr: %s", message.Data, err.Error())
	}

	if data["document"].(map[string]interface{})["id"] != id {
		t.Errorf("the message is not for my build: %+v", data["document"])
	}
	if data["document"].(map[string]interface{})["status"] != "complete" {
		t.Errorf("I recieved a bad status: %+v", data["document"])
	}
	if c, err := docker.GetContainer("build1"); err != nil || c.Name == "" {
		t.Errorf("There should be a build1 container")
	}
}

func TestDevelop(t *testing.T) {
	conn, err := net.Dial("tcp4", "localhost:1757")
	if err != nil {
		t.Errorf("unable to establish connection")
	}

	fmt.Fprintf(conn, "POST /develop? HTTP/1.1\r\n\r\n")

	// give the server time to start the dev
	<-time.After(2 * time.Second)

	if c, err := docker.GetContainer("dev1"); err != nil || c.Name == "" {
		t.Errorf("There should be a dev1 container")
	}
	conn.Close()

	// give the server time to start the dev
	<-time.After(2 * time.Second)
	if _, err := docker.GetContainer("dev1"); err == nil {
		t.Errorf("There should not be a dev1 container")
	}
}

func TestRoutes(t *testing.T) {
	r, err := http.Get("http://localhost:1757/routes")
	if err != nil || r.StatusCode != 200 {
		fmt.Println(r, err)
		t.Errorf("unable to get routes")
	}
	bytes, _ := ioutil.ReadAll(r.Body)
	routes := []map[string]interface{}{}
	err = json.Unmarshal(bytes, &routes)
	if err != nil {
		t.Errorf("unable to unmarshal body %s", bytes)
	}
	if len(routes) < 1 {
		t.Errorf("I should have one route")
		return
	}
	if routes[0]["Name"] != "app.dev" {
		t.Errorf("the Route I have is not app.dev")
	}
}
<|endoftext|>