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

package gossip

import (
	"errors"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/base"
	"github.com/cockroachdb/cockroach/roachpb"
	"github.com/cockroachdb/cockroach/rpc"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/hlc"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/stop"
	"github.com/gogo/protobuf/proto"
)

// startGossip creates local and remote gossip instances.
// Both remote and local instances launch the gossip service.
func startGossip(t *testing.T) (local, remote *Gossip, stopper *stop.Stopper) {
	stopper = stop.NewStopper()
	lclock := hlc.NewClock(hlc.UnixNano)
	lRPCContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)

	laddr := util.CreateTestAddr("tcp")
	lserver := rpc.NewServer(lRPCContext)
	lTLSConfig, err := lRPCContext.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}
	lln, err := util.ListenAndServe(stopper, lserver, laddr, lTLSConfig)
	if err != nil {
		t.Fatal(err)
	}
	local = New(lRPCContext, TestBootstrap)
	local.SetNodeID(1)
	if err := local.SetNodeDescriptor(&roachpb.NodeDescriptor{
		NodeID:  1,
		Address: util.MakeUnresolvedAddr(laddr.Network(), laddr.String()),
	}); err != nil {
		t.Fatal(err)
	}

	rclock := hlc.NewClock(hlc.UnixNano)
	rRPCContext := rpc.NewContext(&base.Context{Insecure: true}, rclock, stopper)

	raddr := util.CreateTestAddr("tcp")
	rserver := rpc.NewServer(rRPCContext)
	rTLSConfig, err := rRPCContext.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}
	rln, err := util.ListenAndServe(stopper, rserver, raddr, rTLSConfig)
	if err != nil {
		t.Fatal(err)
	}
	remote = New(rRPCContext, TestBootstrap)
	remote.SetNodeID(2)
	if err := remote.SetNodeDescriptor(&roachpb.NodeDescriptor{
		NodeID:  2,
		Address: util.MakeUnresolvedAddr(raddr.Network(), raddr.String()),
	}); err != nil {
		t.Fatal(err)
	}
	local.start(lserver, lln.Addr(), stopper)
	remote.start(rserver, rln.Addr(), stopper)
	time.Sleep(time.Millisecond)
	return
}

type fakeGossipServer struct {
	nodeAddr   util.UnresolvedAddr
	nodeIDChan chan roachpb.NodeID
}

func newFakeGossipServer(rpcServer *rpc.Server, stopper *stop.Stopper) (*fakeGossipServer, error) {
	s := &fakeGossipServer{
		nodeIDChan: make(chan roachpb.NodeID),
	}
	if err := rpcServer.Register("Gossip.Gossip", s.Gossip, &Request{}); err != nil {
		return nil, util.Errorf("unable to register gossip service with RPC server: %s", err)
	}
	return s, nil
}

func (s *fakeGossipServer) Gossip(argsI proto.Message) (proto.Message, error) {
	args := argsI.(*Request)
	reply := &Response{}
	s.nodeIDChan <- args.NodeID

	return reply, nil
}

// startFakeServerGossip creates local gossip instances and remote faked gossip instance.
// The remote gossip instance launches its faked gossip service just for
// check the client message.
func startFakeServerGossip(t *testing.T) (local *Gossip, remote *fakeGossipServer, stopper *stop.Stopper) {
	stopper = stop.NewStopper()
	lclock := hlc.NewClock(hlc.UnixNano)
	lRPCContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)

	laddr := util.CreateTestAddr("tcp")
	lserver := rpc.NewServer(lRPCContext)
	lTLSConfig, err := lRPCContext.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}
	lln, err := util.ListenAndServe(stopper, lserver, laddr, lTLSConfig)
	if err != nil {
		t.Fatal(err)
	}
	local = New(lRPCContext, TestBootstrap)
	local.start(lserver, lln.Addr(), stopper)

	rclock := hlc.NewClock(hlc.UnixNano)
	rRPCContext := rpc.NewContext(&base.Context{Insecure: true}, rclock, stopper)

	raddr := util.CreateTestAddr("tcp")
	rserver := rpc.NewServer(rRPCContext)
	rTLSConfig, err := rRPCContext.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}
	rln, err := util.ListenAndServe(stopper, rserver, raddr, rTLSConfig)
	if err != nil {
		t.Fatal(err)
	}

	if remote, err = newFakeGossipServer(rserver, stopper); err != nil {
		t.Fatal(err)
	}
	addr := rln.Addr()
	remote.nodeAddr = util.MakeUnresolvedAddr(addr.Network(), addr.String())
	time.Sleep(time.Millisecond)
	return
}

// TestClientGossip verifies a client can gossip a delta to the server.
func TestClientGossip(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	disconnected := make(chan *client, 1)
	client := newClient(remote.is.NodeAddr)

	defer func() {
		stopper.Stop()
		if client != <-disconnected {
			t.Errorf("expected client disconnect after remote close")
		}
	}()

	if err := local.AddInfo("local-key", nil, time.Second); err != nil {
		t.Fatal(err)
	}
	if err := remote.AddInfo("remote-key", nil, time.Second); err != nil {
		t.Fatal(err)
	}

	// Use an insecure context. We're talking to tcp socket which are not in the certs.
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)
	client.start(local, disconnected, rpcContext, stopper)

	util.SucceedsWithin(t, 500*time.Millisecond, func() error {
		if _, err := remote.GetInfo("local-key"); err != nil {
			return err
		}
		if _, err := local.GetInfo("remote-key"); err != nil {
			return err
		}
		return nil
	})
}

// TestClientNodeID verifies a client's gossip request with correct NodeID.
func TestClientNodeID(t *testing.T) {
	defer leaktest.AfterTest(t)

	local, remote, stopper := startFakeServerGossip(t)
	disconnected := make(chan *client, 1)

	// Use an insecure context. We're talking to tcp socket which are not in the certs.
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)

	// Start a gossip client.
	c := newClient(remote.nodeAddr)
	defer func() {
		stopper.Stop()
		if c != <-disconnected {
			t.Errorf("expected client disconnect after remote close")
		}
	}()
	c.start(local, disconnected, rpcContext, stopper)
	// Wait for c.gossip to start.
	receivedNodeID := <-remote.nodeIDChan

	nodeID := roachpb.NodeID(1)
	// Simulate a nodeID setting after c.gossip started.
	local.SetNodeID(nodeID)
	// Check if client send the correct NodeID after new nodeID take effect.
	util.SucceedsWithin(t, time.Second, func() error {
		select {
		case receivedNodeID = <-remote.nodeIDChan:
			if receivedNodeID == nodeID {
				return nil
			}
		}
		return util.Errorf("client should send NodeID with %v, got %v", nodeID, receivedNodeID)
	})
}

func verifyServerMaps(g *Gossip, expCount int) bool {
	g.mu.Lock()
	defer g.mu.Unlock()
	return len(g.lAddrMap) == expCount && len(g.nodeMap) == expCount
}

// TestClientDisconnectLoopback verifies that the gossip server
// will drop an outgoing client connection that is already an
// inbound client connection of another node.
func TestClientDisconnectLoopback(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, _, stopper := startGossip(t)
	defer stopper.Stop()
	// startClient requires locks are held, so acquire here.
	local.mu.Lock()
	lAddr := local.is.NodeAddr
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)
	rpcContext.DisableCache = true
	local.startClient(lAddr, rpcContext, stopper)
	local.mu.Unlock()
	local.manage(stopper)
	util.SucceedsWithin(t, 10*time.Second, func() error {
		ok := local.findClient(func(c *client) bool { return c.addr.String() == lAddr.String() }) != nil
		if !ok && verifyServerMaps(local, 0) {
			return nil
		}
		return errors.New("local client still connected to itself")
	})
}

// TestClientDisconnectRedundant verifies that the gossip server
// will drop an outgoing client connection that is already an
// inbound client connection of another node.
func TestClientDisconnectRedundant(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	defer stopper.Stop()
	// startClient requires locks are held, so acquire here.
	local.mu.Lock()
	remote.mu.Lock()

	rAddr := remote.is.NodeAddr
	lAddr := local.is.NodeAddr
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)
	rpcContext.DisableCache = true
	local.startClient(rAddr, rpcContext, stopper)
	remote.startClient(lAddr, rpcContext, stopper)
	local.mu.Unlock()
	remote.mu.Unlock()
	local.manage(stopper)
	remote.manage(stopper)
	util.SucceedsWithin(t, 10*time.Second, func() error {
		// Check which of the clients is connected to the other.
		ok1 := local.findClient(func(c *client) bool { return c.addr.String() == rAddr.String() }) != nil
		ok2 := remote.findClient(func(c *client) bool { return c.addr.String() == lAddr.String() }) != nil
		// We expect node 1 to disconnect; if both are still connected,
		// it's possible that node 1 gossiped before node 2 connected, in
		// which case we have to gossip from node 1 to trigger the
		// disconnect redundant client code.
		if ok1 && ok2 {
			if err := local.AddInfo("local-key", nil, time.Second); err != nil {
				t.Fatal(err)
			}
		} else if !ok1 && ok2 && verifyServerMaps(local, 1) && verifyServerMaps(remote, 0) {
			return nil
		}
		return errors.New("local client to remote not yet closed as redundant")
	})
}

// TestClientDisallowMultipleConns verifies that the server disallows
// multiple connections from the same client node ID.
func TestClientDisallowMultipleConns(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	defer stopper.Stop()
	local.mu.Lock()
	remote.mu.Lock()
	rAddr := remote.is.NodeAddr
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)
	rpcContext.DisableCache = true
	// Start two clients from local to remote. RPC client cache is
	// disabled via the context, so we'll start two different outgoing
	// connections.
	local.startClient(rAddr, rpcContext, stopper)
	local.startClient(rAddr, rpcContext, stopper)
	local.mu.Unlock()
	remote.mu.Unlock()
	local.manage(stopper)
	remote.manage(stopper)
	util.SucceedsWithin(t, 10*time.Second, func() error {
		// Verify that the remote server has only a single incoming
		// connection and the local server has only a single outgoing
		// connection.
		local.mu.Lock()
		remote.mu.Lock()
		outgoing := local.outgoing.len()
		incoming := remote.incoming.len()
		local.mu.Unlock()
		remote.mu.Unlock()
		if outgoing == 1 && incoming == 1 && verifyServerMaps(local, 0) && verifyServerMaps(remote, 1) {
			return nil
		}
		return util.Errorf("incorrect number of incoming (%d) or outgoing (%d) connections", incoming, outgoing)
	})
}
<commit_msg>gossip/client_test: improve test robustness<commit_after>// Copyright 2014 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License. See the AUTHORS file
// for names of contributors.
//
// Author: Spencer Kimball (spencer.kimball@gmail.com)

package gossip

import (
	"errors"
	"math"
	"testing"
	"time"

	"github.com/cockroachdb/cockroach/base"
	"github.com/cockroachdb/cockroach/roachpb"
	"github.com/cockroachdb/cockroach/rpc"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/hlc"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/stop"
	"github.com/gogo/protobuf/proto"
)

// startGossip creates local and remote gossip instances.
// Both remote and local instances launch the gossip service.
func startGossip(t *testing.T) (local, remote *Gossip, stopper *stop.Stopper) {
	stopper = stop.NewStopper()
	lclock := hlc.NewClock(hlc.UnixNano)
	lRPCContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)

	laddr := util.CreateTestAddr("tcp")
	lserver := rpc.NewServer(lRPCContext)
	lTLSConfig, err := lRPCContext.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}
	lln, err := util.ListenAndServe(stopper, lserver, laddr, lTLSConfig)
	if err != nil {
		t.Fatal(err)
	}
	local = New(lRPCContext, TestBootstrap)
	local.SetNodeID(1)
	if err := local.SetNodeDescriptor(&roachpb.NodeDescriptor{
		NodeID:  1,
		Address: util.MakeUnresolvedAddr(laddr.Network(), laddr.String()),
	}); err != nil {
		t.Fatal(err)
	}

	rclock := hlc.NewClock(hlc.UnixNano)
	rRPCContext := rpc.NewContext(&base.Context{Insecure: true}, rclock, stopper)

	raddr := util.CreateTestAddr("tcp")
	rserver := rpc.NewServer(rRPCContext)
	rTLSConfig, err := rRPCContext.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}
	rln, err := util.ListenAndServe(stopper, rserver, raddr, rTLSConfig)
	if err != nil {
		t.Fatal(err)
	}
	remote = New(rRPCContext, TestBootstrap)
	remote.SetNodeID(2)
	if err := remote.SetNodeDescriptor(&roachpb.NodeDescriptor{
		NodeID:  2,
		Address: util.MakeUnresolvedAddr(raddr.Network(), raddr.String()),
	}); err != nil {
		t.Fatal(err)
	}
	local.start(lserver, lln.Addr(), stopper)
	remote.start(rserver, rln.Addr(), stopper)
	time.Sleep(time.Millisecond)
	return
}

type fakeGossipServer struct {
	nodeAddr   util.UnresolvedAddr
	nodeIDChan chan roachpb.NodeID
}

func newFakeGossipServer(rpcServer *rpc.Server, stopper *stop.Stopper) (*fakeGossipServer, error) {
	s := &fakeGossipServer{
		nodeIDChan: make(chan roachpb.NodeID, 1),
	}
	if err := rpcServer.Register("Gossip.Gossip", s.Gossip, &Request{}); err != nil {
		return nil, util.Errorf("unable to register gossip service with RPC server: %s", err)
	}
	return s, nil
}

func (s *fakeGossipServer) Gossip(argsI proto.Message) (proto.Message, error) {
	args := argsI.(*Request)
	reply := &Response{
		// Just don't conflict with other nodes.
		NodeID: math.MaxInt32,
	}
	select {
	case s.nodeIDChan <- args.NodeID:
	default:
	}

	return reply, nil
}

// startFakeServerGossip creates local gossip instances and remote faked gossip instance.
// The remote gossip instance launches its faked gossip service just for
// check the client message.
func startFakeServerGossip(t *testing.T) (local *Gossip, remote *fakeGossipServer, stopper *stop.Stopper) {
	stopper = stop.NewStopper()
	lclock := hlc.NewClock(hlc.UnixNano)
	lRPCContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)

	laddr := util.CreateTestAddr("tcp")
	lserver := rpc.NewServer(lRPCContext)
	lTLSConfig, err := lRPCContext.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}
	lln, err := util.ListenAndServe(stopper, lserver, laddr, lTLSConfig)
	if err != nil {
		t.Fatal(err)
	}
	local = New(lRPCContext, TestBootstrap)
	local.start(lserver, lln.Addr(), stopper)

	rclock := hlc.NewClock(hlc.UnixNano)
	rRPCContext := rpc.NewContext(&base.Context{Insecure: true}, rclock, stopper)

	raddr := util.CreateTestAddr("tcp")
	rserver := rpc.NewServer(rRPCContext)
	rTLSConfig, err := rRPCContext.GetServerTLSConfig()
	if err != nil {
		t.Fatal(err)
	}
	rln, err := util.ListenAndServe(stopper, rserver, raddr, rTLSConfig)
	if err != nil {
		t.Fatal(err)
	}

	if remote, err = newFakeGossipServer(rserver, stopper); err != nil {
		t.Fatal(err)
	}
	addr := rln.Addr()
	remote.nodeAddr = util.MakeUnresolvedAddr(addr.Network(), addr.String())
	time.Sleep(time.Millisecond)
	return
}

// TestClientGossip verifies a client can gossip a delta to the server.
func TestClientGossip(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	disconnected := make(chan *client, 1)
	client := newClient(remote.is.NodeAddr)

	defer func() {
		stopper.Stop()
		if client != <-disconnected {
			t.Errorf("expected client disconnect after remote close")
		}
	}()

	if err := local.AddInfo("local-key", nil, time.Second); err != nil {
		t.Fatal(err)
	}
	if err := remote.AddInfo("remote-key", nil, time.Second); err != nil {
		t.Fatal(err)
	}

	// Use an insecure context. We're talking to tcp socket which are not in the certs.
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)
	client.start(local, disconnected, rpcContext, stopper)

	util.SucceedsWithin(t, 500*time.Millisecond, func() error {
		if _, err := remote.GetInfo("local-key"); err != nil {
			return err
		}
		if _, err := local.GetInfo("remote-key"); err != nil {
			return err
		}
		return nil
	})
}

// TestClientNodeID verifies a client's gossip request with correct NodeID.
func TestClientNodeID(t *testing.T) {
	defer leaktest.AfterTest(t)

	local, remote, stopper := startFakeServerGossip(t)
	disconnected := make(chan *client, 1)

	// Use an insecure context. We're talking to tcp socket which are not in the certs.
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)

	// Start a gossip client.
	c := newClient(remote.nodeAddr)
	defer func() {
		stopper.Stop()
		if c != <-disconnected {
			t.Errorf("expected client disconnect after remote close")
		}
	}()
	c.start(local, disconnected, rpcContext, stopper)
	// Wait for c.gossip to start.
	receivedNodeID := <-remote.nodeIDChan

	nodeID := roachpb.NodeID(1)
	// Simulate a nodeID setting after c.gossip started.
	local.SetNodeID(nodeID)
	// Check if client send the correct NodeID after new nodeID take effect.
	util.SucceedsWithin(t, time.Second, func() error {
		select {
		case receivedNodeID = <-remote.nodeIDChan:
			if receivedNodeID == nodeID {
				return nil
			}
		default:
		}
		return util.Errorf("client should send NodeID with %v, got %v", nodeID, receivedNodeID)
	})
}

func verifyServerMaps(g *Gossip, expCount int) bool {
	g.mu.Lock()
	defer g.mu.Unlock()
	return len(g.lAddrMap) == expCount && len(g.nodeMap) == expCount
}

// TestClientDisconnectLoopback verifies that the gossip server
// will drop an outgoing client connection that is already an
// inbound client connection of another node.
func TestClientDisconnectLoopback(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, _, stopper := startGossip(t)
	defer stopper.Stop()
	// startClient requires locks are held, so acquire here.
	local.mu.Lock()
	lAddr := local.is.NodeAddr
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)
	rpcContext.DisableCache = true
	local.startClient(lAddr, rpcContext, stopper)
	local.mu.Unlock()
	local.manage(stopper)
	util.SucceedsWithin(t, 10*time.Second, func() error {
		ok := local.findClient(func(c *client) bool { return c.addr.String() == lAddr.String() }) != nil
		if !ok && verifyServerMaps(local, 0) {
			return nil
		}
		return errors.New("local client still connected to itself")
	})
}

// TestClientDisconnectRedundant verifies that the gossip server
// will drop an outgoing client connection that is already an
// inbound client connection of another node.
func TestClientDisconnectRedundant(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	defer stopper.Stop()
	// startClient requires locks are held, so acquire here.
	local.mu.Lock()
	remote.mu.Lock()

	rAddr := remote.is.NodeAddr
	lAddr := local.is.NodeAddr
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)
	rpcContext.DisableCache = true
	local.startClient(rAddr, rpcContext, stopper)
	remote.startClient(lAddr, rpcContext, stopper)
	local.mu.Unlock()
	remote.mu.Unlock()
	local.manage(stopper)
	remote.manage(stopper)
	util.SucceedsWithin(t, 10*time.Second, func() error {
		// Check which of the clients is connected to the other.
		ok1 := local.findClient(func(c *client) bool { return c.addr.String() == rAddr.String() }) != nil
		ok2 := remote.findClient(func(c *client) bool { return c.addr.String() == lAddr.String() }) != nil
		// We expect node 1 to disconnect; if both are still connected,
		// it's possible that node 1 gossiped before node 2 connected, in
		// which case we have to gossip from node 1 to trigger the
		// disconnect redundant client code.
		if ok1 && ok2 {
			if err := local.AddInfo("local-key", nil, time.Second); err != nil {
				t.Fatal(err)
			}
		} else if !ok1 && ok2 && verifyServerMaps(local, 1) && verifyServerMaps(remote, 0) {
			return nil
		}
		return errors.New("local client to remote not yet closed as redundant")
	})
}

// TestClientDisallowMultipleConns verifies that the server disallows
// multiple connections from the same client node ID.
func TestClientDisallowMultipleConns(t *testing.T) {
	defer leaktest.AfterTest(t)
	local, remote, stopper := startGossip(t)
	defer stopper.Stop()
	local.mu.Lock()
	remote.mu.Lock()
	rAddr := remote.is.NodeAddr
	lclock := hlc.NewClock(hlc.UnixNano)
	rpcContext := rpc.NewContext(&base.Context{Insecure: true}, lclock, stopper)
	rpcContext.DisableCache = true
	// Start two clients from local to remote. RPC client cache is
	// disabled via the context, so we'll start two different outgoing
	// connections.
	local.startClient(rAddr, rpcContext, stopper)
	local.startClient(rAddr, rpcContext, stopper)
	local.mu.Unlock()
	remote.mu.Unlock()
	local.manage(stopper)
	remote.manage(stopper)
	util.SucceedsWithin(t, 10*time.Second, func() error {
		// Verify that the remote server has only a single incoming
		// connection and the local server has only a single outgoing
		// connection.
		local.mu.Lock()
		remote.mu.Lock()
		outgoing := local.outgoing.len()
		incoming := remote.incoming.len()
		local.mu.Unlock()
		remote.mu.Unlock()
		if outgoing == 1 && incoming == 1 && verifyServerMaps(local, 0) && verifyServerMaps(remote, 1) {
			return nil
		}
		return util.Errorf("incorrect number of incoming (%d) or outgoing (%d) connections", incoming, outgoing)
	})
}
<|endoftext|>


<commit_before>package graph

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/opentable/sous/config"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/util/configloader"
	"github.com/opentable/sous/util/whitespace"
	"github.com/opentable/sous/util/yaml"
	"github.com/pkg/errors"
)

type (
	// PossiblyInvalidConfig is a config that has not been validated.
	// This is necessary for the 'sous config' command that should still work with
	// invalid configs.
	PossiblyInvalidConfig struct{ *config.Config }

	// DefaultConfig is the default config.
	DefaultConfig struct{ *config.Config }

	// ConfigLoader wraps the configloader.ConfigLoader interface
	ConfigLoader struct{ configloader.ConfigLoader }
)

func newSousConfig(lsc LocalSousConfig) *config.Config {
	return lsc.Config
}

func newPossiblyInvalidLocalSousConfig(u config.LocalUser, defaultConfig DefaultConfig, gcl *ConfigLoader) (PossiblyInvalidConfig, error) {
	v, err := newPossiblyInvalidConfig(u.ConfigFile(), defaultConfig, gcl)
	return v, initErr(err, "getting configuration")
}

func newLocalSousConfig(pic PossiblyInvalidConfig) (v LocalSousConfig, err error) {
	v.Config, err = pic.Config, pic.Validate()
	if err != nil {
		err = errors.Wrapf(err, "tip: run 'sous config' to see and manipulate your configuration")
	}
	return v, initErr(err, "validating configuration")
}

func newConfigLoader() *ConfigLoader {
	cl := configloader.New()
	sous.SetupLogging(cl)
	return &ConfigLoader{ConfigLoader: cl}
}

func newPossiblyInvalidConfig(path string, defaultConfig DefaultConfig, gcl *ConfigLoader) (PossiblyInvalidConfig, error) {
	cl := gcl.ConfigLoader

	config := defaultConfig

	configDir := filepath.Dir(path)
	if err := os.MkdirAll(configDir, os.ModeDir|0755); err != nil {
		return PossiblyInvalidConfig{}, err
	}

	var writeDefault bool
	defer func() {
		if !writeDefault {
			return
		}
		lsc := &LocalSousConfig{config.Config}
		lsc.Save(path)
		sous.Log.Info.Println("initialised config file: " + path)
	}()
	_, err := os.Stat(path)
	if os.IsNotExist(err) {
		err = nil
		writeDefault = true
	}
	if err != nil {
		return PossiblyInvalidConfig{}, err
	}

	return PossiblyInvalidConfig{Config: config.Config}, cl.Load(config.Config, path)
}

// Save the configuration to the configuration path (by default:
// $HOME/.config/sous/config)
func (c *LocalSousConfig) Save(path string) error {
	return ioutil.WriteFile(path, c.Bytes(), 0600)
}

// Bytes marshals the config to a []byte
func (c *LocalSousConfig) Bytes() []byte {
	y, err := yaml.Marshal(c.Config)
	if err != nil {
		panic("error marshalling config as yaml:" + err.Error())
	}
	return y
}

// GetValue retreives and returns a particular value from the configuration
func (c *LocalSousConfig) GetValue(name string) (string, error) {
	v, err := configloader.New().GetValue(c.Config, name)
	return fmt.Sprint(v), err
}

// SetValue stores a particular value on the config
func (c *LocalSousConfig) SetValue(path, name, value string) error {
	if err := configloader.New().SetValue(c.Config, name, value); err != nil {
		return err
	}
	return c.Save(path)
}

func (c *LocalSousConfig) String() string {
	// yaml marshaller adds a trailing newline
	return whitespace.Trim(string(c.Bytes()))
}
<commit_msg>graph: Add first-run config init interaction.<commit_after>package graph

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/crypto/ssh/terminal"

	"github.com/opentable/sous/config"
	"github.com/opentable/sous/lib"
	"github.com/opentable/sous/util/configloader"
	"github.com/opentable/sous/util/whitespace"
	"github.com/opentable/sous/util/yaml"
	"github.com/pkg/errors"
)

type (
	// PossiblyInvalidConfig is a config that has not been validated.
	// This is necessary for the 'sous config' command that should still work with
	// invalid configs.
	PossiblyInvalidConfig struct{ *config.Config }

	// DefaultConfig is the default config.
	DefaultConfig struct{ *config.Config }

	// ConfigLoader wraps the configloader.ConfigLoader interface
	ConfigLoader struct{ configloader.ConfigLoader }
)

func newSousConfig(lsc LocalSousConfig) *config.Config {
	return lsc.Config
}

func newPossiblyInvalidLocalSousConfig(u config.LocalUser, defaultConfig DefaultConfig, gcl *ConfigLoader) (PossiblyInvalidConfig, error) {
	v, err := newPossiblyInvalidConfig(u.ConfigFile(), defaultConfig, gcl)
	return v, initErr(err, "getting configuration")
}

func newLocalSousConfig(pic PossiblyInvalidConfig) (v LocalSousConfig, err error) {
	v.Config, err = pic.Config, pic.Validate()
	if err != nil {
		err = errors.Wrapf(err, "tip: run 'sous config' to see and manipulate your configuration")
	}
	return v, initErr(err, "validating configuration")
}

func newConfigLoader() *ConfigLoader {
	cl := configloader.New()
	sous.SetupLogging(cl)
	return &ConfigLoader{ConfigLoader: cl}
}

func newPossiblyInvalidConfig(path string, defaultConfig DefaultConfig, gcl *ConfigLoader) (PossiblyInvalidConfig, error) {
	cl := gcl.ConfigLoader

	pic := defaultConfig

	configDir := filepath.Dir(path)
	if err := os.MkdirAll(configDir, os.ModeDir|0755); err != nil {
		return PossiblyInvalidConfig{}, err
	}

	var writeDefault bool
	defer func() {
		if !writeDefault {
			return
		}
		// Since this is initialisation, let's get the user to confirm some stuff...
		userInitConfig(pic.Config)
		if err := pic.Validate(); err != nil {
			// If the config is invalid, warn but write it anyway and allow the
			// user to correct it themselves.
			sous.Log.Warn.Printf("Newly initialised config file is invalid: %s", err)
			sous.Log.Warn.Printf("Please correct the issue by editing %s", path)
		}
		lsc := &LocalSousConfig{pic.Config}
		lsc.Save(path)
		sous.Log.Info.Println("initialised config file: " + path)
	}()
	_, err := os.Stat(path)
	if os.IsNotExist(err) {
		err = nil
		writeDefault = true
	}
	if err != nil {
		return PossiblyInvalidConfig{}, err
	}

	return PossiblyInvalidConfig{Config: pic.Config}, cl.Load(pic.Config, path)
}

func userInput(prompt, vDefault, eg string, v *string) {
	if vDefault == "" {
		fmt.Printf("%s (e.g. %q): ", prompt, eg)
	} else {
		fmt.Printf("%s (e.g. %q): (enter for %q)", prompt, eg, vDefault)
	}
	reader := bufio.NewReader(os.Stdin)
	in, err := reader.ReadString('\n')
	if err != nil {
		sous.Log.Warn.Printf("Failed to read input: %s", err)
		return
	}
	// Strip the newline and any other whitespace.
	in = strings.TrimSpace(in)
	if in == "" {
		in = vDefault
	}
	*v = in
}

func userInitConfig(c *config.Config) {
	if !terminal.IsTerminal(int(os.Stdout.Fd())) {
		sous.Log.Warn.Println("Unable to run config wizard; no terminal attached.")
	}
	fmt.Println(`
	It looks like you haven't used Sous before (there's no config file).
	Please provide the following details to configure Sous...
	If you don't know some of the answers don't worry, you can use 'sous config'
	on the command line to change them later.
	`)
	userInput("Your email address", c.User.Email, "name@mycompany.com", &c.User.Email)
	userInput("Your full name", c.User.Name, "Alfie Noakes", &c.User.Name)
	userInput("Your company's primary sous server URL", c.Server, "http://sous.mycompany.com", &c.Server)

	fmt.Println("All done, thanks!")
}

// Save the configuration to the configuration path (by default:
// $HOME/.config/sous/config)
func (c *LocalSousConfig) Save(path string) error {
	return ioutil.WriteFile(path, c.Bytes(), 0600)
}

// Bytes marshals the config to a []byte
func (c *LocalSousConfig) Bytes() []byte {
	y, err := yaml.Marshal(c.Config)
	if err != nil {
		panic("error marshalling config as yaml:" + err.Error())
	}
	return y
}

// GetValue retreives and returns a particular value from the configuration
func (c *LocalSousConfig) GetValue(name string) (string, error) {
	v, err := configloader.New().GetValue(c.Config, name)
	return fmt.Sprint(v), err
}

// SetValue stores a particular value on the config
func (c *LocalSousConfig) SetValue(path, name, value string) error {
	if err := configloader.New().SetValue(c.Config, name, value); err != nil {
		return err
	}
	return c.Save(path)
}

func (c *LocalSousConfig) String() string {
	// yaml marshaller adds a trailing newline
	return whitespace.Trim(string(c.Bytes()))
}
<|endoftext|>


<commit_before>package gocassa

import (
	"fmt"
	"strings"
	"time"
)

type k struct {
	qe        QueryExecutor
	name      string
	debugMode bool
}

// Connect to a certain keyspace directly. Same as using Connect().KeySpace(keySpaceName)
func ConnectToKeySpace(keySpace string, nodeIps []string, username, password string) (KeySpace, error) {
	c, err := Connect(nodeIps, username, password)
	if err != nil {
		return nil, err
	}
	return c.KeySpace(keySpace), nil
}

func (k *k) DebugMode(b bool) {
	k.debugMode = true
}

func (k *k) Table(name string, entity interface{}, keys Keys) Table {
	n := name + "__" + strings.Join(keys.PartitionKeys, "_") + "__" + strings.Join(keys.ClusteringColumns, "_")
	return k.rawTable(n, entity, keys)
}

func (k *k) rawTable(name string, entity interface{}, keys Keys) Table {
	m, ok := toMap(entity)
	if !ok {
		panic("Unrecognized row type")
	}
	return k.table(name, entity, m, keys)
}

func (k *k) table(name string, entity interface{}, fieldSource map[string]interface{}, keys Keys) Table {
	ti := newTableInfo(k.name, name, keys, entity, fieldSource)
	return &t{
		keySpace: k,
		info:     ti,
	}
}

func (k *k) MapTable(name, id string, row interface{}) MapTable {
	return &mapT{
		t: k.rawTable(fmt.Sprintf("%s_map_%s", name, id), row, Keys{
			PartitionKeys: []string{id},
		}).(*t),
		idField: id,
	}
}

func (k *k) SetKeysSpaceName(name string) {
	k.name = name
}

func (k *k) MultimapTable(name, fieldToIndexBy, id string, row interface{}) MultimapTable {
	return &multimapT{
		t: k.rawTable(fmt.Sprintf("%s_multimap_%s_%s", name, fieldToIndexBy, id), row, Keys{
			PartitionKeys:     []string{fieldToIndexBy},
			ClusteringColumns: []string{id},
		}).(*t),
		idField:        id,
		fieldToIndexBy: fieldToIndexBy,
	}
}

func (k *k) TimeSeriesTable(name, timeField, idField string, bucketSize time.Duration, row interface{}) TimeSeriesTable {
	m, ok := toMap(row)
	if !ok {
		panic("Unrecognized row type")
	}
	m[bucketFieldName] = time.Now()
	return &timeSeriesT{
		t: k.table(fmt.Sprintf("%s_timeSeries_%s_%s_%s", name, timeField, idField, bucketSize.String()), row, m, Keys{
			PartitionKeys:     []string{bucketFieldName},
			ClusteringColumns: []string{timeField, idField},
		}).(*t),
		timeField:  timeField,
		idField:    idField,
		bucketSize: bucketSize,
	}
}

func (k *k) MultiTimeSeriesTable(name, indexField, timeField, idField string, bucketSize time.Duration, row interface{}) MultiTimeSeriesTable {
	m, ok := toMap(row)
	if !ok {
		panic("Unrecognized row type")
	}
	m[bucketFieldName] = time.Now()
	return &multiTimeSeriesT{
		t: k.table(fmt.Sprintf("%s_multiTimeSeries_%s_%s_%s_%s", name, indexField, timeField, idField, bucketSize.String()), row, m, Keys{
			PartitionKeys:     []string{indexField, bucketFieldName},
			ClusteringColumns: []string{timeField, idField},
		}).(*t),
		indexField: indexField,
		timeField:  timeField,
		idField:    idField,
		bucketSize: bucketSize,
	}
}

// Returns table names in a keyspace
func (k *k) Tables() ([]string, error) {
	const stmt = "SELECT columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?"
	maps, err := k.qe.Query(stmt, k.name)
	if err != nil {
		return nil, err
	}
	ret := []string{}
	for _, m := range maps {
		ret = append(ret, m["columnfamily_name"].(string))
	}
	return ret, nil
}

func (k *k) Exists(cf string) (bool, error) {
	ts, err := k.Tables()
	if err != nil {
		return false, err
	}
	for _, v := range ts {
		if strings.ToLower(v) == strings.ToLower(cf) {
			return true, nil
		}
	}
	return false, nil
}

func (k *k) DropTable(cf string) error {
	stmt := fmt.Sprintf("DROP TABLE IF EXISTS %s.%s", k.name, cf)
	return k.qe.Execute(stmt)
}

func (k *k) Name() string {
	return k.name
}
<commit_msg>Add overrides for table names for timeseries recipe tables<commit_after>package gocassa

import (
	"fmt"
	"strings"
	"time"
)

type k struct {
	qe        QueryExecutor
	name      string
	debugMode bool
}

// Connect to a certain keyspace directly. Same as using Connect().KeySpace(keySpaceName)
func ConnectToKeySpace(keySpace string, nodeIps []string, username, password string) (KeySpace, error) {
	c, err := Connect(nodeIps, username, password)
	if err != nil {
		return nil, err
	}
	return c.KeySpace(keySpace), nil
}

func (k *k) DebugMode(b bool) {
	k.debugMode = true
}

func (k *k) Table(name string, entity interface{}, keys Keys) Table {
	n := name + "__" + strings.Join(keys.PartitionKeys, "_") + "__" + strings.Join(keys.ClusteringColumns, "_")
	return k.rawTable(n, entity, keys)
}

func (k *k) rawTable(name string, entity interface{}, keys Keys) Table {
	m, ok := toMap(entity)
	if !ok {
		panic("Unrecognized row type")
	}
	return k.table(name, entity, m, keys)
}

func (k *k) table(name string, entity interface{}, fieldSource map[string]interface{}, keys Keys) Table {
	ti := newTableInfo(k.name, name, keys, entity, fieldSource)
	return &t{
		keySpace: k,
		info:     ti,
	}
}

func (k *k) MapTable(name, id string, row interface{}) MapTable {
	return &mapT{
		t: k.rawTable(fmt.Sprintf("%s_map_%s", name, id), row, Keys{
			PartitionKeys: []string{id},
		}).(*t),
		idField: id,
	}
}

func (k *k) SetKeysSpaceName(name string) {
	k.name = name
}

func (k *k) MultimapTable(name, fieldToIndexBy, id string, row interface{}) MultimapTable {
	return &multimapT{
		t: k.rawTable(fmt.Sprintf("%s_multimap_%s_%s", name, fieldToIndexBy, id), row, Keys{
			PartitionKeys:     []string{fieldToIndexBy},
			ClusteringColumns: []string{id},
		}).(*t),
		idField:        id,
		fieldToIndexBy: fieldToIndexBy,
	}
}

func (k *k) TimeSeriesTable(name, timeField, idField string, bucketSize time.Duration, row interface{}) TimeSeriesTable {
	m, ok := toMap(row)
	if !ok {
		panic("Unrecognized row type")
	}
	m[bucketFieldName] = time.Now()
	return &timeSeriesT{
		t: k.table(fmt.Sprintf("%s_timeSeries_%s_%s_%s", name, timeField, idField, bucketSize.String()), row, m, Keys{
			PartitionKeys:     []string{bucketFieldName},
			ClusteringColumns: []string{timeField, idField},
		}).(*t),
		timeField:  timeField,
		idField:    idField,
		bucketSize: bucketSize,
	}
}

// TimeSeriesTableWithName creates a TimeSeriesTable with an overridden table name
//
// This is needed as the current generator creates names which can exceed
// the 48 character table name limit.
// See https://github.com/hailocab/gocassa/issues/79
func (k *k) TimeSeriesTableWithName(tableName, timeField, idField string, bucketSize time.Duration, row interface{}) TimeSeriesTable {
	m, ok := toMap(row)
	if !ok {
		panic("Unrecognized row type")
	}
	m[bucketFieldName] = time.Now()
	return &timeSeriesT{
		t: k.table(tableName, row, m, Keys{
			PartitionKeys:     []string{bucketFieldName},
			ClusteringColumns: []string{timeField, idField},
		}).(*t),
		timeField:  timeField,
		idField:    idField,
		bucketSize: bucketSize,
	}
}

func (k *k) MultiTimeSeriesTable(name, indexField, timeField, idField string, bucketSize time.Duration, row interface{}) MultiTimeSeriesTable {
	m, ok := toMap(row)
	if !ok {
		panic("Unrecognized row type")
	}
	m[bucketFieldName] = time.Now()
	return &multiTimeSeriesT{
		t: k.table(fmt.Sprintf("%s_multiTimeSeries_%s_%s_%s_%s", name, indexField, timeField, idField, bucketSize.String()), row, m, Keys{
			PartitionKeys:     []string{indexField, bucketFieldName},
			ClusteringColumns: []string{timeField, idField},
		}).(*t),
		indexField: indexField,
		timeField:  timeField,
		idField:    idField,
		bucketSize: bucketSize,
	}
}

// MultiTimeSeriesTableWithName creates a MultiTimeSeriesTable with an overridden table name
//
// This is needed as the current generator creates names which can exceed
// the 48 character table name limit.
// See https://github.com/hailocab/gocassa/issues/79
func (k *k) MultiTimeSeriesTableWithName(tableName, indexField, timeField, idField string, bucketSize time.Duration, row interface{}) MultiTimeSeriesTable {
	m, ok := toMap(row)
	if !ok {
		panic("Unrecognized row type")
	}
	m[bucketFieldName] = time.Now()
	return &multiTimeSeriesT{
		t: k.table(tableName, row, m, Keys{
			PartitionKeys:     []string{indexField, bucketFieldName},
			ClusteringColumns: []string{timeField, idField},
		}).(*t),
		indexField: indexField,
		timeField:  timeField,
		idField:    idField,
		bucketSize: bucketSize,
	}
}

// Returns table names in a keyspace
func (k *k) Tables() ([]string, error) {
	const stmt = "SELECT columnfamily_name FROM system.schema_columnfamilies WHERE keyspace_name = ?"
	maps, err := k.qe.Query(stmt, k.name)
	if err != nil {
		return nil, err
	}
	ret := []string{}
	for _, m := range maps {
		ret = append(ret, m["columnfamily_name"].(string))
	}
	return ret, nil
}

func (k *k) Exists(cf string) (bool, error) {
	ts, err := k.Tables()
	if err != nil {
		return false, err
	}
	for _, v := range ts {
		if strings.ToLower(v) == strings.ToLower(cf) {
			return true, nil
		}
	}
	return false, nil
}

func (k *k) DropTable(cf string) error {
	stmt := fmt.Sprintf("DROP TABLE IF EXISTS %s.%s", k.name, cf)
	return k.qe.Execute(stmt)
}

func (k *k) Name() string {
	return k.name
}
<|endoftext|>


<commit_before>// +build ignore

/*
Copyright 2013 Brandon Philips

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

// This program builds a project and is a copy of third_party.go. See
// github.com/philips/third_party.go
//
// $ go run third_party.go
//
// See the README file for more details.
package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

const (
	DefaultThirdParty = "third_party"
)

// thirdPartyDir creates a string path to the third_party directory based on
// the current working directory.
func thirdPartyDir() string {
	root, err := os.Getwd()
	if err != nil {
		log.Fatalf("Failed to get the current working directory: %v", err)
	}
	return path.Join(root, DefaultThirdParty)
}

func srcDir() string {
	return path.Join(thirdPartyDir(), "src")
}

// binDir creates a string path to the GOBIN directory based on the current
// working directory.
func binDir() string {
	root, err := os.Getwd()
	if err != nil {
		log.Fatalf("Failed to get the current working directory: %v", err)
	}
	return path.Join(root, "bin")
}

// runEnv execs a command like a shell script piping everything to the parent's
// stderr/stdout and uses the given environment.
func runEnv(env []string, name string, arg ...string) {
	cmd := exec.Command(name, arg...)

	cmd.Env = env

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(1)
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(1)
	}
	err = cmd.Start()
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(1)
	}
	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)
	cmd.Wait()
}

// run calls runEnv with the GOPATH third_party packages.
func run(name string, arg ...string) {
	env := append(os.Environ(),
		"GOPATH="+thirdPartyDir(),
		"GOBIN="+binDir(),
	)

	runEnv(env, name, arg...)
}

// setupProject does the initial setup of the third_party src directory
// including setting up the symlink to the cwd from the src directory.
func setupProject(pkg string) {
	root, err := os.Getwd()
	if err != nil {
		log.Fatalf("Failed to get the current working directory: %v", err)
	}

	src := path.Join(thirdPartyDir(), "src", pkg)
	srcdir := path.Dir(src)

	os.MkdirAll(srcdir, 0755)

	rel, err := filepath.Rel(srcdir, root)
	if err != nil {
		log.Fatalf("creating relative third party path: %v", err)
	}

	err = os.Symlink(rel, src)
	if err != nil && os.IsExist(err) == false {
		log.Fatalf("creating project third party symlink: %v", err)
	}
}

func getVc(root string) versionControl {
	for _, v := range []string{".git", ".hg"} {
		r := path.Join(root, v)
		info, err := os.Stat(r)

		if err != nil || !info.IsDir() {
			continue
		}

		base := path.Base(r)
		switch base {
		case ".git":
			return vcGit(r)
		case ".hg":
			return vcHg(r)
		}
	}
	return new(vcNoop)
}

type versionControl interface {
	commit() string
	update(string) error
}

//  Performs noops on all VC operations.
type vcNoop struct{}

func (v *vcNoop) commit() string {
	return ""
}

func (v *vcNoop) update(dir string) error {
	return nil
}

type vcHg string

// vcHg.commit returns the current HEAD commit hash for a given hg dir.
func (v vcHg) commit() string {
	out, err := exec.Command("hg", "id", "-i", "-R", string(v)).Output()
	if err != nil {
		return ""
	}
	return string(out)
}

// vcHg.udpate updates the given hg dir to ref.
func (v vcHg) update(ref string) error {
	_, err := exec.Command("hg",
		"update",
		"-r", ref,
		"-R", string(v),
		"--cwd", path.Dir(string(v)),
	).Output()
	if err != nil {
		return err
	}
	return nil
}

type vcGit string

// vcGit.commit returns the current HEAD commit hash for a given git dir.
func (v vcGit) commit() string {
	out, err := exec.Command("git", "--git-dir="+string(v), "rev-parse", "HEAD").Output()
	if err != nil {
		return ""
	}
	return string(out)
}

// vcHg.udpate updates the given git dir to ref.
func (v vcGit) update(ref string) error {
	_, err := exec.Command("git",
		"--work-tree="+path.Dir(string(v)),
		"--git-dir="+string(v),
		"reset", "--hard", ref,
	).Output()
	if err != nil {
		return err
	}
	return nil
}

// commit grabs the commit id from hg or git as a string.
func commit(dir string) string {
	return getVc(dir).commit()
}

// removeVcs removes a .git or .hg directory from the given root if it exists.
func removeVcs(root string) (bool, string) {
	for _, v := range []string{".git", ".hg"} {
		r := path.Join(root, v)
		info, err := os.Stat(r)

		if err != nil {
			continue
		}

		// We didn't find it, next!
		if info.IsDir() == false {
			continue
		}

		// We found it, grab the commit and remove the directory
		c := commit(root)
		err = os.RemoveAll(r)
		if err != nil {
			log.Fatalf("removeVcs: %v", err)
		}
		return true, c
	}

	return false, ""
}

// bump takes care of grabbing a package, getting the package git hash and
// removing all of the version control stuff.
func bump(pkg, version string) {
	tpd := thirdPartyDir()

	temp, err := ioutil.TempDir(tpd, "bump")
	if err != nil {
		log.Fatalf("bump: %v", err)
	}
	defer os.RemoveAll(temp)

	env := append(os.Environ(),
		"GOPATH="+temp,
	)

	runEnv(env, "go", "get", "-u", "-d", pkg)

	for {
		root := path.Join(temp, "src", pkg) // the temp installation root
		home := path.Join(tpd, "src", pkg)  // where the package will end up

		if version != "" {
			err := getVc(root).update(version)
			if err != nil {
				log.Fatalf("bump: %v", err)
			}
		}

		ok, c := removeVcs(root)
		if ok {
			// Create the path leading up to the package
			err := os.MkdirAll(path.Dir(home), 0755)
			if err != nil {
				log.Fatalf("bump: %v", err)
			}

			// Remove anything that might have been there
			err = os.RemoveAll(home)
			if err != nil {
				log.Fatalf("bump: %v", err)
			}

			// Finally move the package
			err = os.Rename(root, home)
			if err != nil {
				log.Fatalf("bump: %v", err)
			}

			fmt.Printf("%s %s\n", pkg, strings.TrimSpace(c))
			break
		}

		// Pop off and try to find this directory!
		pkg = path.Dir(pkg)
		if pkg == "." {
			return
		}
	}
}

// validPkg uses go list to decide if the given path is a valid go package.
// This is used by the bumpAll walk to bump all of the existing packages.
func validPkg(pkg string) bool {
	env := append(os.Environ(),
		"GOPATH="+thirdPartyDir(),
	)
	cmd := exec.Command("go", "list", pkg)
	cmd.Env = env

	out, err := cmd.Output()
	if err != nil {
		return false
	}

	if pkg == strings.TrimSpace(string(out)) {
		return true
	}

	return false
}

// bumpWalk walks the third_party directory and bumps all of the packages that it finds.
func bumpWalk(path string, info os.FileInfo, err error) error {
	if err != nil {
		return nil
	}

	// go packages are always directories
	if info.IsDir() == false {
		return nil
	}

	parts := strings.Split(path, srcDir()+"/")
	if len(parts) == 1 {
		return nil
	}

	pkg := parts[1]

	if validPkg(pkg) == false {
		return nil
	}

	bump(pkg, "")

	return nil
}

func bumpAll() {
	err := filepath.Walk(srcDir(), bumpWalk)
	if err != nil {
		log.Fatalf(err.Error())
	}
}

func main() {
	log.SetFlags(0)

	if len(os.Args) <= 1 {
		log.Fatalf("No command")
	}

	cmd := os.Args[1]

	if cmd == "setup" && len(os.Args) > 2 {
		setupProject(os.Args[2])
		return
	}

	if cmd == "bump" && len(os.Args) > 2 {
		ref := ""
		if len(os.Args) > 3 {
			ref = os.Args[3]
		}

		bump(os.Args[2], ref)
		return
	}

	if cmd == "bump-all" && len(os.Args) > 1 {
		bumpAll()
		return
	}

	run("go", os.Args[1:]...)
}
<commit_msg>feat(third_party.go): exit with 1 on failure<commit_after>// +build ignore

/*
Copyright 2013 Brandon Philips

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

// This program builds a project and is a copy of third_party.go. See
// github.com/philips/third_party.go
//
// $ go run third_party.go
//
// See the README file for more details.
package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

const (
	DefaultThirdParty = "third_party"
)

// thirdPartyDir creates a string path to the third_party directory based on
// the current working directory.
func thirdPartyDir() string {
	root, err := os.Getwd()
	if err != nil {
		log.Fatalf("Failed to get the current working directory: %v", err)
	}
	return path.Join(root, DefaultThirdParty)
}

func srcDir() string {
	return path.Join(thirdPartyDir(), "src")
}

// binDir creates a string path to the GOBIN directory based on the current
// working directory.
func binDir() string {
	root, err := os.Getwd()
	if err != nil {
		log.Fatalf("Failed to get the current working directory: %v", err)
	}
	return path.Join(root, "bin")
}

// runEnv execs a command like a shell script piping everything to the parent's
// stderr/stdout and uses the given environment.
func runEnv(env []string, name string, arg ...string) *os.ProcessState {
	cmd := exec.Command(name, arg...)

	cmd.Env = env

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(1)
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(1)
	}
	err = cmd.Start()
	if err != nil {
		fmt.Fprintf(os.Stderr, err.Error())
		os.Exit(1)
	}
	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)
	cmd.Wait()

	return cmd.ProcessState
}

// run calls runEnv with the GOPATH third_party packages.
func run(name string, arg ...string) *os.ProcessState {
	env := append(os.Environ(),
		"GOPATH="+thirdPartyDir(),
		"GOBIN="+binDir(),
	)

	return runEnv(env, name, arg...)
}

// setupProject does the initial setup of the third_party src directory
// including setting up the symlink to the cwd from the src directory.
func setupProject(pkg string) {
	root, err := os.Getwd()
	if err != nil {
		log.Fatalf("Failed to get the current working directory: %v", err)
	}

	src := path.Join(thirdPartyDir(), "src", pkg)
	srcdir := path.Dir(src)

	os.MkdirAll(srcdir, 0755)

	rel, err := filepath.Rel(srcdir, root)
	if err != nil {
		log.Fatalf("creating relative third party path: %v", err)
	}

	err = os.Symlink(rel, src)
	if err != nil && os.IsExist(err) == false {
		log.Fatalf("creating project third party symlink: %v", err)
	}
}

func getVc(root string) versionControl {
	for _, v := range []string{".git", ".hg"} {
		r := path.Join(root, v)
		info, err := os.Stat(r)

		if err != nil || !info.IsDir() {
			continue
		}

		base := path.Base(r)
		switch base {
		case ".git":
			return vcGit(r)
		case ".hg":
			return vcHg(r)
		}
	}
	return new(vcNoop)
}

type versionControl interface {
	commit() string
	update(string) error
}

//  Performs noops on all VC operations.
type vcNoop struct{}

func (v *vcNoop) commit() string {
	return ""
}

func (v *vcNoop) update(dir string) error {
	return nil
}

type vcHg string

// vcHg.commit returns the current HEAD commit hash for a given hg dir.
func (v vcHg) commit() string {
	out, err := exec.Command("hg", "id", "-i", "-R", string(v)).Output()
	if err != nil {
		return ""
	}
	return string(out)
}

// vcHg.udpate updates the given hg dir to ref.
func (v vcHg) update(ref string) error {
	_, err := exec.Command("hg",
		"update",
		"-r", ref,
		"-R", string(v),
		"--cwd", path.Dir(string(v)),
	).Output()
	if err != nil {
		return err
	}
	return nil
}

type vcGit string

// vcGit.commit returns the current HEAD commit hash for a given git dir.
func (v vcGit) commit() string {
	out, err := exec.Command("git", "--git-dir="+string(v), "rev-parse", "HEAD").Output()
	if err != nil {
		return ""
	}
	return string(out)
}

// vcHg.udpate updates the given git dir to ref.
func (v vcGit) update(ref string) error {
	_, err := exec.Command("git",
		"--work-tree="+path.Dir(string(v)),
		"--git-dir="+string(v),
		"reset", "--hard", ref,
	).Output()
	if err != nil {
		return err
	}
	return nil
}

// commit grabs the commit id from hg or git as a string.
func commit(dir string) string {
	return getVc(dir).commit()
}

// removeVcs removes a .git or .hg directory from the given root if it exists.
func removeVcs(root string) (bool, string) {
	for _, v := range []string{".git", ".hg"} {
		r := path.Join(root, v)
		info, err := os.Stat(r)

		if err != nil {
			continue
		}

		// We didn't find it, next!
		if info.IsDir() == false {
			continue
		}

		// We found it, grab the commit and remove the directory
		c := commit(root)
		err = os.RemoveAll(r)
		if err != nil {
			log.Fatalf("removeVcs: %v", err)
		}
		return true, c
	}

	return false, ""
}

// bump takes care of grabbing a package, getting the package git hash and
// removing all of the version control stuff.
func bump(pkg, version string) {
	tpd := thirdPartyDir()

	temp, err := ioutil.TempDir(tpd, "bump")
	if err != nil {
		log.Fatalf("bump: %v", err)
	}
	defer os.RemoveAll(temp)

	env := append(os.Environ(),
		"GOPATH="+temp,
	)

	runEnv(env, "go", "get", "-u", "-d", pkg)

	for {
		root := path.Join(temp, "src", pkg) // the temp installation root
		home := path.Join(tpd, "src", pkg)  // where the package will end up

		if version != "" {
			err := getVc(root).update(version)
			if err != nil {
				log.Fatalf("bump: %v", err)
			}
		}

		ok, c := removeVcs(root)
		if ok {
			// Create the path leading up to the package
			err := os.MkdirAll(path.Dir(home), 0755)
			if err != nil {
				log.Fatalf("bump: %v", err)
			}

			// Remove anything that might have been there
			err = os.RemoveAll(home)
			if err != nil {
				log.Fatalf("bump: %v", err)
			}

			// Finally move the package
			err = os.Rename(root, home)
			if err != nil {
				log.Fatalf("bump: %v", err)
			}

			fmt.Printf("%s %s\n", pkg, strings.TrimSpace(c))
			break
		}

		// Pop off and try to find this directory!
		pkg = path.Dir(pkg)
		if pkg == "." {
			return
		}
	}
}

// validPkg uses go list to decide if the given path is a valid go package.
// This is used by the bumpAll walk to bump all of the existing packages.
func validPkg(pkg string) bool {
	env := append(os.Environ(),
		"GOPATH="+thirdPartyDir(),
	)
	cmd := exec.Command("go", "list", pkg)
	cmd.Env = env

	out, err := cmd.Output()
	if err != nil {
		return false
	}

	if pkg == strings.TrimSpace(string(out)) {
		return true
	}

	return false
}

// bumpWalk walks the third_party directory and bumps all of the packages that it finds.
func bumpWalk(path string, info os.FileInfo, err error) error {
	if err != nil {
		return nil
	}

	// go packages are always directories
	if info.IsDir() == false {
		return nil
	}

	parts := strings.Split(path, srcDir()+"/")
	if len(parts) == 1 {
		return nil
	}

	pkg := parts[1]

	if validPkg(pkg) == false {
		return nil
	}

	bump(pkg, "")

	return nil
}

func bumpAll() {
	err := filepath.Walk(srcDir(), bumpWalk)
	if err != nil {
		log.Fatalf(err.Error())
	}
}

func main() {
	log.SetFlags(0)

	if len(os.Args) <= 1 {
		log.Fatalf("No command")
	}

	cmd := os.Args[1]

	if cmd == "setup" && len(os.Args) > 2 {
		setupProject(os.Args[2])
		return
	}

	if cmd == "bump" && len(os.Args) > 2 {
		ref := ""
		if len(os.Args) > 3 {
			ref = os.Args[3]
		}

		bump(os.Args[2], ref)
		return
	}

	if cmd == "bump-all" && len(os.Args) > 1 {
		bumpAll()
		return
	}

	ps := run("go", os.Args[1:]...)

	if ps.Success() == false {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "math"

func getTestCases() []float64 {
	testCases := []float64{}
	var numberOfLines int
	fmt.Scanf("%d", &numberOfLines)

	if numberOfLines > 0 {
		for i := 0; i < numberOfLines; i++ {
			var testCase float64
			fmt.Scanf("%f", &testCase)
			testCases = append(testCases, testCase)
		}
	}

	// fmt.Println(numberOfLines)
	// fmt.Println(testCases)

	return testCases
}

func isPerfectSquare(number float64) bool {
	floatNumber := math.Sqrt(float64(number))
	// intNumber := big.NewFloat(floatNumber) // It seems like this line only works in go 1.5
	// isPerfectSquare := intNumber.IsInt()
	intNumber := float64(math.Trunc(floatNumber))
	isPerfectSquare := (intNumber == floatNumber)
	// fmt.Println(number)
	// fmt.Println(floatNumber)
	// fmt.Println(intNumber)
	// fmt.Println(isPerfectSquare)
	return isPerfectSquare
}

func isFibonacciNumber(number float64) bool {
	fiveByXSquare := float64(5 * number * number)
	isFibonacciNumber := (isPerfectSquare(fiveByXSquare+4) || isPerfectSquare(fiveByXSquare-4))
	return isFibonacciNumber
}

func main() {

	// https://www.hackerrank.com/challenges/is-fibo
	testCases := getTestCases()
	// testCases := []float64{7778742049}
	// testCases := []float64{5,7,8}
	for _, element := range testCases {
		if isFibonacciNumber(element) {
			fmt.Println("IsFibo")
		} else {
			fmt.Println("IsNotFibo")
		}
	}
}
<commit_msg>Update de link position in the file.<commit_after>// https://www.hackerrank.com/challenges/is-fibo
package main

import "fmt"
import "math"

func getTestCases() []float64 {
	testCases := []float64{}
	var numberOfLines int
	fmt.Scanf("%d", &numberOfLines)

	if numberOfLines > 0 {
		for i := 0; i < numberOfLines; i++ {
			var testCase float64
			fmt.Scanf("%f", &testCase)
			testCases = append(testCases, testCase)
		}
	}

	// fmt.Println(numberOfLines)
	// fmt.Println(testCases)

	return testCases
}

func isPerfectSquare(number float64) bool {
	floatNumber := math.Sqrt(float64(number))
	// intNumber := big.NewFloat(floatNumber) // It seems like this line only works in go 1.5
	// isPerfectSquare := intNumber.IsInt()
	intNumber := float64(math.Trunc(floatNumber))
	isPerfectSquare := (intNumber == floatNumber)
	// fmt.Println(number)
	// fmt.Println(floatNumber)
	// fmt.Println(intNumber)
	// fmt.Println(isPerfectSquare)
	return isPerfectSquare
}

func isFibonacciNumber(number float64) bool {
	fiveByXSquare := float64(5 * number * number)
	isFibonacciNumber := (isPerfectSquare(fiveByXSquare+4) || isPerfectSquare(fiveByXSquare-4))
	return isFibonacciNumber
}

func main() {

	testCases := getTestCases()
	// testCases := []float64{7778742049}
	// testCases := []float64{5,7,8}
	for _, element := range testCases {
		if isFibonacciNumber(element) {
			fmt.Println("IsFibo")
		} else {
			fmt.Println("IsNotFibo")
		}
	}
}
<|endoftext|>


<commit_before>package http

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/gorilla/mux"

	"github.com/tapglue/snaas/service/app"
	"github.com/tapglue/snaas/service/connection"
	"github.com/tapglue/snaas/service/event"
	"github.com/tapglue/snaas/service/object"
	"github.com/tapglue/snaas/service/user"
)

const (
	cursorTimeFormat = time.RFC3339Nano
	defaultLimit     = 100
	keyCommentID     = "commentID"
	keyCursorAfter   = "after"
	keyCursorBefore  = "before"
	keyLimit         = "limit"
	keyPostID        = "postID"
	keyState         = "state"
	keyUserID        = "userID"
	keyWhere         = "where"
	maxLimit         = 100

	refFmt = "%s://%s%s?limit=%d&%s"
)

var cursorEncoding = base64.URLEncoding.WithPadding(base64.NoPadding)

type payloadCursors struct {
	After  string `json:"after"`
	Before string `json:"before"`
}

type payloadPagination struct {
	after  string
	before string
	limit  int
	req    *http.Request
}

func pagination(
	req *http.Request,
	limit int,
	after, before string,
) *payloadPagination {
	return &payloadPagination{
		after:  after,
		before: before,
		limit:  limit,
		req:    req,
	}
}

func (p *payloadPagination) MarshalJSON() ([]byte, error) {
	var (
		next     = ""
		previous = ""
		scheme   = "http"
	)

	if p.req.TLS != nil {
		scheme = "https"
	}

	if p.after != "" {
		next = fmt.Sprintf(
			refFmt,
			scheme,
			p.req.Host,
			p.req.URL.Path,
			p.limit,
			fmt.Sprintf("%s=%s", keyCursorAfter, p.after),
		)
	}

	if p.before != "" {
		previous = fmt.Sprintf(
			refFmt,
			scheme,
			p.req.Host,
			p.req.URL.Path,
			p.limit,
			fmt.Sprintf("%s=%s", keyCursorBefore, p.before),
		)
	}

	f := struct {
		Cursors  payloadCursors `json:"cursors"`
		Next     string         `json:"next"`
		Previous string         `json:"previous"`
	}{
		Cursors: payloadCursors{
			After:  p.after,
			Before: p.before,
		},
		Next:     next,
		Previous: previous,
	}

	return json.Marshal(&f)
}

func extractAppOpts(r *http.Request) (app.QueryOptions, error) {
	return app.QueryOptions{}, nil
}

func extractCommentID(r *http.Request) (uint64, error) {
	return strconv.ParseUint(mux.Vars(r)[keyCommentID], 10, 64)
}

func extractCommentOpts(r *http.Request) (object.QueryOptions, error) {
	return object.QueryOptions{}, nil
}

func extractConnectionOpts(r *http.Request) (connection.QueryOptions, error) {
	return connection.QueryOptions{}, nil
}

type condition struct {
	EQ string   `json:"eq"`
	IN []string `json:"in"`
}

type eventCondition struct {
	Object *struct {
		ID   *condition `json:"id,omitempty"`
		Type *condition `json:"type,omitempty"`
	} `json:"object,omitempty"`
	Type *condition `json:"type,omitempty"`
}

func extractEventOpts(r *http.Request) (event.QueryOptions, error) {
	var (
		cond  = eventCondition{}
		opts  = event.QueryOptions{}
		param = r.URL.Query().Get(keyWhere)
	)

	if param == "" {
		return opts, nil
	}

	err := json.Unmarshal([]byte(param), &cond)
	if err != nil {
		return opts, err
	}

	if cond.Object != nil && cond.Object.ID != nil {
		if cond.Object.ID.EQ != "" {
			opts.ExternalObjectIDs = []string{
				cond.Object.ID.EQ,
			}
		}

		if cond.Object.ID.IN != nil {
			opts.ExternalObjectIDs = cond.Object.ID.IN
		}
	}

	if cond.Object != nil && cond.Object.Type != nil {
		if cond.Object.Type.EQ != "" {
			opts.ExternalObjectTypes = []string{
				cond.Object.Type.EQ,
			}
		}

		if cond.Object.Type.IN != nil {
			opts.ExternalObjectTypes = cond.Object.Type.IN
		}
	}

	if cond.Type != nil {
		if cond.Type.EQ != "" {
			opts.Types = []string{
				cond.Type.EQ,
			}
		}

		if cond.Type.IN != nil {
			opts.Types = cond.Type.IN
		}
	}

	return opts, nil
}

func extractIDCursorBefore(r *http.Request) (uint64, error) {
	var (
		id    uint64 = 0
		param        = r.URL.Query().Get(keyCursorBefore)
	)

	if param == "" {
		return id, nil
	}

	cursor, err := cursorEncoding.DecodeString(param)
	if err != nil {
		return id, err
	}

	return strconv.ParseUint(string(cursor), 10, 64)
}

func extractLikeOpts(r *http.Request) (event.QueryOptions, error) {
	return event.QueryOptions{}, nil
}

func extractLimit(r *http.Request) (int, error) {
	param := r.URL.Query().Get(keyLimit)

	if param == "" {
		return defaultLimit, nil
	}

	limit, err := strconv.Atoi(param)
	if err != nil {
		return 0, err
	}

	if limit > maxLimit {
		return maxLimit, nil
	}

	return limit, nil
}

func extractPostID(r *http.Request) (uint64, error) {
	return strconv.ParseUint(mux.Vars(r)[keyPostID], 10, 64)
}

func extractPostOpts(r *http.Request) (object.QueryOptions, error) {
	var (
		opts  = object.QueryOptions{}
		param = r.URL.Query().Get(keyWhere)
		w     = struct {
			Post *postWhere `json:"post"`
		}{}
	)

	if param == "" {
		return opts, nil
	}

	err := json.Unmarshal([]byte(param), &w)
	if err != nil {
		return opts, fmt.Errorf("error in where param: %s", err)
	}

	if w.Post != nil && w.Post.Tags != nil {
		opts.Tags = w.Post.Tags
	}

	return opts, nil
}

func extractState(r *http.Request) connection.State {
	return connection.State(mux.Vars(r)[keyState])
}

func extractTimeCursorBefore(r *http.Request) (time.Time, error) {
	var (
		before = time.Now()
		param  = r.URL.Query().Get(keyCursorBefore)
	)

	if param == "" {
		return before, nil
	}

	cursor, err := cursorEncoding.DecodeString(param)
	if err != nil {
		return before, err
	}

	return time.Parse(cursorTimeFormat, string(cursor))
}

func extractUserID(r *http.Request) (uint64, error) {
	return strconv.ParseUint(mux.Vars(r)[keyUserID], 10, 64)
}

func extractUserOpts(r *http.Request) (user.QueryOptions, error) {
	return user.QueryOptions{}, nil
}

func toIDCursor(id uint64) string {
	return cursorEncoding.EncodeToString([]byte(strconv.FormatUint(id, 10)))
}

func toTimeCursor(t time.Time) string {
	return cursorEncoding.EncodeToString([]byte(t.Format(cursorTimeFormat)))
}
<commit_msg>Set sensible limits for lists requests<commit_after>package http

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/gorilla/mux"

	"github.com/tapglue/snaas/service/app"
	"github.com/tapglue/snaas/service/connection"
	"github.com/tapglue/snaas/service/event"
	"github.com/tapglue/snaas/service/object"
	"github.com/tapglue/snaas/service/user"
)

const (
	cursorTimeFormat = time.RFC3339Nano

	keyCommentID    = "commentID"
	keyCursorAfter  = "after"
	keyCursorBefore = "before"
	keyLimit        = "limit"
	keyPostID       = "postID"
	keyState        = "state"
	keyUserID       = "userID"
	keyWhere        = "where"

	limitDefault = 25
	limitMax     = 50

	refFmt = "%s://%s%s?limit=%d&%s"
)

var cursorEncoding = base64.URLEncoding.WithPadding(base64.NoPadding)

type payloadCursors struct {
	After  string `json:"after"`
	Before string `json:"before"`
}

type payloadPagination struct {
	after  string
	before string
	limit  int
	req    *http.Request
}

func pagination(
	req *http.Request,
	limit int,
	after, before string,
) *payloadPagination {
	return &payloadPagination{
		after:  after,
		before: before,
		limit:  limit,
		req:    req,
	}
}

func (p *payloadPagination) MarshalJSON() ([]byte, error) {
	var (
		next     = ""
		previous = ""
		scheme   = "http"
	)

	if p.req.TLS != nil {
		scheme = "https"
	}

	if p.after != "" {
		next = fmt.Sprintf(
			refFmt,
			scheme,
			p.req.Host,
			p.req.URL.Path,
			p.limit,
			fmt.Sprintf("%s=%s", keyCursorAfter, p.after),
		)
	}

	if p.before != "" {
		previous = fmt.Sprintf(
			refFmt,
			scheme,
			p.req.Host,
			p.req.URL.Path,
			p.limit,
			fmt.Sprintf("%s=%s", keyCursorBefore, p.before),
		)
	}

	f := struct {
		Cursors  payloadCursors `json:"cursors"`
		Next     string         `json:"next"`
		Previous string         `json:"previous"`
	}{
		Cursors: payloadCursors{
			After:  p.after,
			Before: p.before,
		},
		Next:     next,
		Previous: previous,
	}

	return json.Marshal(&f)
}

func extractAppOpts(r *http.Request) (app.QueryOptions, error) {
	return app.QueryOptions{}, nil
}

func extractCommentID(r *http.Request) (uint64, error) {
	return strconv.ParseUint(mux.Vars(r)[keyCommentID], 10, 64)
}

func extractCommentOpts(r *http.Request) (object.QueryOptions, error) {
	return object.QueryOptions{}, nil
}

func extractConnectionOpts(r *http.Request) (connection.QueryOptions, error) {
	return connection.QueryOptions{}, nil
}

type condition struct {
	EQ string   `json:"eq"`
	IN []string `json:"in"`
}

type eventCondition struct {
	Object *struct {
		ID   *condition `json:"id,omitempty"`
		Type *condition `json:"type,omitempty"`
	} `json:"object,omitempty"`
	Type *condition `json:"type,omitempty"`
}

func extractEventOpts(r *http.Request) (event.QueryOptions, error) {
	var (
		cond  = eventCondition{}
		opts  = event.QueryOptions{}
		param = r.URL.Query().Get(keyWhere)
	)

	if param == "" {
		return opts, nil
	}

	err := json.Unmarshal([]byte(param), &cond)
	if err != nil {
		return opts, err
	}

	if cond.Object != nil && cond.Object.ID != nil {
		if cond.Object.ID.EQ != "" {
			opts.ExternalObjectIDs = []string{
				cond.Object.ID.EQ,
			}
		}

		if cond.Object.ID.IN != nil {
			opts.ExternalObjectIDs = cond.Object.ID.IN
		}
	}

	if cond.Object != nil && cond.Object.Type != nil {
		if cond.Object.Type.EQ != "" {
			opts.ExternalObjectTypes = []string{
				cond.Object.Type.EQ,
			}
		}

		if cond.Object.Type.IN != nil {
			opts.ExternalObjectTypes = cond.Object.Type.IN
		}
	}

	if cond.Type != nil {
		if cond.Type.EQ != "" {
			opts.Types = []string{
				cond.Type.EQ,
			}
		}

		if cond.Type.IN != nil {
			opts.Types = cond.Type.IN
		}
	}

	return opts, nil
}

func extractIDCursorBefore(r *http.Request) (uint64, error) {
	var (
		id    uint64 = 0
		param        = r.URL.Query().Get(keyCursorBefore)
	)

	if param == "" {
		return id, nil
	}

	cursor, err := cursorEncoding.DecodeString(param)
	if err != nil {
		return id, err
	}

	return strconv.ParseUint(string(cursor), 10, 64)
}

func extractLikeOpts(r *http.Request) (event.QueryOptions, error) {
	return event.QueryOptions{}, nil
}

func extractLimit(r *http.Request) (int, error) {
	param := r.URL.Query().Get(keyLimit)

	if param == "" {
		return limitDefault, nil
	}

	limit, err := strconv.Atoi(param)
	if err != nil {
		return 0, err
	}

	if limit > limitMax {
		return limitMax, nil
	}

	return limit, nil
}

func extractPostID(r *http.Request) (uint64, error) {
	return strconv.ParseUint(mux.Vars(r)[keyPostID], 10, 64)
}

func extractPostOpts(r *http.Request) (object.QueryOptions, error) {
	var (
		opts  = object.QueryOptions{}
		param = r.URL.Query().Get(keyWhere)
		w     = struct {
			Post *postWhere `json:"post"`
		}{}
	)

	if param == "" {
		return opts, nil
	}

	err := json.Unmarshal([]byte(param), &w)
	if err != nil {
		return opts, fmt.Errorf("error in where param: %s", err)
	}

	if w.Post != nil && w.Post.Tags != nil {
		opts.Tags = w.Post.Tags
	}

	return opts, nil
}

func extractState(r *http.Request) connection.State {
	return connection.State(mux.Vars(r)[keyState])
}

func extractTimeCursorBefore(r *http.Request) (time.Time, error) {
	var (
		before = time.Now()
		param  = r.URL.Query().Get(keyCursorBefore)
	)

	if param == "" {
		return before, nil
	}

	cursor, err := cursorEncoding.DecodeString(param)
	if err != nil {
		return before, err
	}

	return time.Parse(cursorTimeFormat, string(cursor))
}

func extractUserID(r *http.Request) (uint64, error) {
	return strconv.ParseUint(mux.Vars(r)[keyUserID], 10, 64)
}

func extractUserOpts(r *http.Request) (user.QueryOptions, error) {
	return user.QueryOptions{}, nil
}

func toIDCursor(id uint64) string {
	return cursorEncoding.EncodeToString([]byte(strconv.FormatUint(id, 10)))
}

func toTimeCursor(t time.Time) string {
	return cursorEncoding.EncodeToString([]byte(t.Format(cursorTimeFormat)))
}
<|endoftext|>


<commit_before>package hexmap

import (
	"testing"
	"fmt"
	"encoding/json"
	"strings"
)

func TestHexMapConstructor(t *testing.T) {
	hm0 := HexMap{Name: "testmap", Size: HexVector{3, 5}, Origin: ORIGIN}

	if hm0.Name != "testmap" {
		t.Error("HexMap.Name - expected: 'testmap', actual: '" +  hm0.Name + "'")
	}

	if ! hm0.Size.Equal(HexVector{3, 5}) {
		t.Error(fmt.Sprintf("HexMap.Size - expected: {3, 5}, actual: {%d, %d}", hm0.Size.Hx(), hm0.Size.Hy()))
	}

	if ! hm0.Origin.Equal(ORIGIN) {
		t.Error(fmt.Sprintf("HexMap.Size - expected: {0, 0}, actual: {%d, %d}", hm0.Origin.Hx(), hm0.Origin.Hy()))
	}

}

func TestHexMapMarshal(t *testing.T) {

	hm := HexMap{Name: "TestMap", Size: HexVector{22, 14}, Origin: ORIGIN}

	jhm, err := json.Marshal(hm)

	if err != nil {
		t.Error(fmt.Sprintf("HexMap.Marshal() - error: %s", err))
	}

	if strings.Compare(string(jhm), "{\"name\":\"TestMap\",\"size\":{\"hx\":22,\"hy\":14},\"origin\":{\"hx\":0,\"hy\":0},\"terrains\":null}") != 0 {
		t.Error(fmt.Sprintf("HexMap.Marshal(), - result: %s", jhm))
	}
}

// test containment and bias

func TestYbias(t *testing.T) {
	hm0 := HexMap{Name: "ybiastest", Size: HexVector{22,14}, Origin: ORIGIN}

	values := [][]int{{-3,-2}, {-2,-1}, {-1,-1}, {0,0}, {1,0}, {2,1}, {3,1}, {4,2}}

	for _, pair := range values {
		if hm0.ybias(pair[0]) != pair[1] {
			t.Error(fmt.Sprintf("HexMap.ybias() - %d -> expect: %d, actual: %d", pair[0], pair[1], hm0.ybias(pair[0])))

		}
	}
}

func TestContains(t *testing.T) {
	hm0 := HexMap{Name: "containmenttest", Size: HexVector{14,22}, Origin: ORIGIN}

	var values = []struct {
		hv HexVector
		contains bool
	}{
		{HexVector{0, 0}, true},
		{HexVector{-1,0}, false},
		{HexVector{13, 7}, true},
		{HexVector{14, 7}, false},
		{HexVector{0, 21}, true},
		{HexVector{0, 22}, false},
		{HexVector{13,5}, false},
		{HexVector{13,6}, true},
		{HexVector{13,21+6}, true},
		{HexVector{13,21+7}, false},
	}

	for _, testvalue := range values {
		if hm0.Contains(testvalue.hv) != testvalue.contains {
			t.Error(fmt.Sprintf("test contains is wrong: %s", testvalue.hv))
		}
	}

}
<commit_msg>added shape to map strings<commit_after>package hexmap

import (
	"testing"
	"fmt"
	"encoding/json"
	"strings"
)

func TestHexMapConstructor(t *testing.T) {
	hm0 := HexMap{Name: "testmap", Size: HexVector{3, 5}, Origin: ORIGIN}

	if hm0.Name != "testmap" {
		t.Error("HexMap.Name - expected: 'testmap', actual: '" +  hm0.Name + "'")
	}

	if ! hm0.Size.Equal(HexVector{3, 5}) {
		t.Error(fmt.Sprintf("HexMap.Size - expected: {3, 5}, actual: {%d, %d}", hm0.Size.Hx(), hm0.Size.Hy()))
	}

	if ! hm0.Origin.Equal(ORIGIN) {
		t.Error(fmt.Sprintf("HexMap.Size - expected: {0, 0}, actual: {%d, %d}", hm0.Origin.Hx(), hm0.Origin.Hy()))
	}

}

func TestHexMapMarshal(t *testing.T) {

	hm := HexMap{Name: "TestMap", Size: HexVector{22, 14}, Origin: ORIGIN}

	jhm, err := json.Marshal(hm)

	if err != nil {
		t.Error(fmt.Sprintf("HexMap.Marshal() - error: %s", err))
	}

	if strings.Compare(string(jhm), "{\"name\":\"TestMap\",\"shape\":\"\",\"size\":{\"hx\":22,\"hy\":14},\"origin\":{\"hx\":0,\"hy\":0},\"terrains\":null}") != 0 {
		t.Error(fmt.Sprintf("HexMap.Marshal(), - result: %s", jhm))
	}
}

// test containment and bias

func TestYbias(t *testing.T) {
	hm0 := HexMap{Name: "ybiastest", Size: HexVector{22,14}, Origin: ORIGIN}

	values := [][]int{{-3,-2}, {-2,-1}, {-1,-1}, {0,0}, {1,0}, {2,1}, {3,1}, {4,2}}

	for _, pair := range values {
		if hm0.ybias(pair[0]) != pair[1] {
			t.Error(fmt.Sprintf("HexMap.ybias() - %d -> expect: %d, actual: %d", pair[0], pair[1], hm0.ybias(pair[0])))

		}
	}
}

func TestContains(t *testing.T) {
	hm0 := HexMap{Name: "containmenttest", Size: HexVector{14,22}, Origin: ORIGIN}

	var values = []struct {
		hv HexVector
		contains bool
	}{
		{HexVector{0, 0}, true},
		{HexVector{-1,0}, false},
		{HexVector{13, 7}, true},
		{HexVector{14, 7}, false},
		{HexVector{0, 21}, true},
		{HexVector{0, 22}, false},
		{HexVector{13,5}, false},
		{HexVector{13,6}, true},
		{HexVector{13,21+6}, true},
		{HexVector{13,21+7}, false},
	}

	for _, testvalue := range values {
		if hm0.Contains(testvalue.hv) != testvalue.contains {
			t.Error(fmt.Sprintf("test contains is wrong: %s", testvalue.hv))
		}
	}

}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"net/http"
)

const (
	Ip   string = "cerekhillen.herokuapp.com"
	Port string = "80"
)

// Converting the Ip and Port variables into
// the actual string
func ConnectionString() string {
	return Ip + ":" + Port
}

// Initializing an starting the server
func InitHandlersAndStart() {
	// Alerting the user that the server is starting
	fmt.Println("Starting server on:", ConnectionString())

	// Adding all of the handlers
	http.HandleFunc("/static/", StaticHandler)
	http.HandleFunc("/blog/"  , BlogHandler)
	http.HandleFunc("/"       , HomeHandler)

	// Starting the server
	http.ListenAndServe(ConnectionString(), nil)
}
<commit_msg>Just trying to get it to work now.<commit_after>package handlers

import (
	"fmt"
	"net/http"
)

const (
	Ip   string = "cerekhillen.herokuapp.com"
	Port string = "80"
)

// Converting the Ip and Port variables into
// the actual string
func ConnectionString() string {
	return Ip + ":" + Port
}

// Initializing an starting the server
func InitHandlersAndStart() {
	// Alerting the user that the server is starting
	fmt.Println("Starting server on:", ConnectionString())

	// Adding all of the handlers
	http.HandleFunc("/static/", StaticHandler)
	http.HandleFunc("/blog/"  , BlogHandler)
	http.HandleFunc("/"       , HomeHandler)

	// Starting the server
	http.ListenAndServe(":80", nil)
}
<|endoftext|>


<commit_before>package handlers

import (
	"fmt"
	"github.com/haisum/recaptcha"
	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/html"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

type messageModel struct {
	Title   string
	Message string
}

var templates map[string]*template.Template
var reCaptchaSiteKey = os.Getenv("RECAPTCHA_SITE_KEY")
var reCaptcha = recaptcha.R{
	Secret: os.Getenv("RECAPTCHA_SECRET_KEY"),
}
var m = minify.New()

func compileTemplates(templatePaths ...string) (*template.Template, error) {
	var tmpl *template.Template
	for _, templatePath := range templatePaths {
		name := filepath.Base(templatePath)
		if tmpl == nil {
			tmpl = template.New(name)
		} else {
			tmpl = tmpl.New(name)
		}

		b, err := ioutil.ReadFile(templatePath)
		if err != nil {
			return nil, err
		}

		mb, err := m.Bytes("text/html", b)
		if err != nil {
			return nil, err
		}
		tmpl.Parse(string(mb))
	}
	return tmpl, nil
}

func minifyCSSFiles(templateDirectory string) {
	cssFileDirectory := filepath.Join(templateDirectory, "../assets/css/")
	cssFilePaths, _ := filepath.Glob(filepath.Join(cssFileDirectory, "*.css"))
	for _, cssFilePath := range cssFilePaths {
		if cssFilePath[len(cssFilePath)-8:] != ".min.css" {
			continue
		}
		cssFile, err := ioutil.ReadFile(cssFilePath)
		if err != nil {
			panic(err)
		}
		cssFile, err = m.Bytes("text/css", cssFile)
		if err != nil {
			panic(err)
		}
		cssFilePathBase := filepath.Base(cssFilePath)
		miniCSSFilePath := filepath.Join(cssFileDirectory, cssFilePathBase[:len(cssFilePathBase)-3]) + "min.css"
		err = ioutil.WriteFile(miniCSSFilePath, cssFile, 0666)
		if err != nil {
			panic(err)
		}
	}
}

// Execute loads templates from the specified directory and configures routes.
func Execute(templateDirectory string) error {
	if _, err := os.Stat(templateDirectory); err != nil {
		return fmt.Errorf("Could not find template directory '%s'.", templateDirectory)
	}

	m.AddFunc("text/html", html.Minify)
	m.AddFunc("text/css", css.Minify)
	minifyCSSFiles(templateDirectory)

	// Loads template paths.
	templatePaths, _ := filepath.Glob(filepath.Join(templateDirectory, "*.tmpl"))
	sharedPaths, _ := filepath.Glob(filepath.Join(templateDirectory, "shared/*.tmpl"))

	// Loads the templates.
	templates = make(map[string]*template.Template)

	for _, templatePath := range templatePaths {
		tmpl := template.Must(compileTemplates(append(sharedPaths, templatePath)...))

		name := strings.Split(filepath.Base(templatePath), ".")[0]
		templates[name] = tmpl
	}

	// Configures the routes.
	http.HandleFunc("/", index)
	http.HandleFunc("/events", events)
	http.HandleFunc("/team", team)
	http.HandleFunc("/gallery", gallery)
	http.HandleFunc("/partners", partners)
	http.HandleFunc("/sign-up", signUp)
	http.HandleFunc("/contact", contact)
	http.HandleFunc("/unsubscribe", unsubscribe)

	return nil
}
<commit_msg>Update handlers.go<commit_after>package handlers

import (
	"fmt"
	"github.com/haisum/recaptcha"
	"github.com/tdewolff/minify"
	"github.com/tdewolff/minify/css"
	"github.com/tdewolff/minify/html"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

type messageModel struct {
	Title   string
	Message string
}

var templates map[string]*template.Template
var reCaptchaSiteKey = os.Getenv("RECAPTCHA_SITE_KEY")
var reCaptcha = recaptcha.R{
	Secret: os.Getenv("RECAPTCHA_SECRET_KEY"),
}
var m = minify.New()

func compileTemplates(templatePaths ...string) (*template.Template, error) {
	var tmpl *template.Template
	for _, templatePath := range templatePaths {
		name := filepath.Base(templatePath)
		if tmpl == nil {
			tmpl = template.New(name)
		} else {
			tmpl = tmpl.New(name)
		}

		b, err := ioutil.ReadFile(templatePath)
		if err != nil {
			return nil, err
		}

		mb, err := m.Bytes("text/html", b)
		if err != nil {
			return nil, err
		}
		tmpl.Parse(string(mb))
	}
	return tmpl, nil
}

func minifyCSSFiles(templateDirectory string) {
	cssFileDirectory := filepath.Join(templateDirectory, "../assets/css/")
	cssFilePaths, _ := filepath.Glob(filepath.Join(cssFileDirectory, "*.css"))
	for _, cssFilePath := range cssFilePaths {
		if cssFilePath[len(cssFilePath)-8:] == ".min.css" {
			continue
		}
		cssFile, err := ioutil.ReadFile(cssFilePath)
		if err != nil {
			panic(err)
		}
		cssFile, err = m.Bytes("text/css", cssFile)
		if err != nil {
			panic(err)
		}
		cssFilePathBase := filepath.Base(cssFilePath)
		miniCSSFilePath := filepath.Join(cssFileDirectory, cssFilePathBase[:len(cssFilePathBase)-3]) + "min.css"
		err = ioutil.WriteFile(miniCSSFilePath, cssFile, 0666)
		if err != nil {
			panic(err)
		}
	}
}

// Execute loads templates from the specified directory and configures routes.
func Execute(templateDirectory string) error {
	if _, err := os.Stat(templateDirectory); err != nil {
		return fmt.Errorf("Could not find template directory '%s'.", templateDirectory)
	}

	m.AddFunc("text/html", html.Minify)
	m.AddFunc("text/css", css.Minify)
	minifyCSSFiles(templateDirectory)

	// Loads template paths.
	templatePaths, _ := filepath.Glob(filepath.Join(templateDirectory, "*.tmpl"))
	sharedPaths, _ := filepath.Glob(filepath.Join(templateDirectory, "shared/*.tmpl"))

	// Loads the templates.
	templates = make(map[string]*template.Template)

	for _, templatePath := range templatePaths {
		tmpl := template.Must(compileTemplates(append(sharedPaths, templatePath)...))

		name := strings.Split(filepath.Base(templatePath), ".")[0]
		templates[name] = tmpl
	}

	// Configures the routes.
	http.HandleFunc("/", index)
	http.HandleFunc("/events", events)
	http.HandleFunc("/team", team)
	http.HandleFunc("/gallery", gallery)
	http.HandleFunc("/partners", partners)
	http.HandleFunc("/sign-up", signUp)
	http.HandleFunc("/contact", contact)
	http.HandleFunc("/unsubscribe", unsubscribe)

	return nil
}
<|endoftext|>


<commit_before>// +build debug

package ticker

import (
	"sync"
	"sync/atomic"
	"time"
)

// Mock implements the Ticker interface, and provides a method of
// force-feeding ticks, even while paused.
type Mock struct {
	isActive uint32 // used atomically

	// Force is used to force-feed a ticks into the ticker. Useful for
	// debugging when trying to wake an event.
	Force chan time.Time

	ticker <-chan time.Time
	skip   chan struct{}

	wg   sync.WaitGroup
	quit chan struct{}
}

// MockNew returns a Mock Ticker, used for testing and debugging. It supports
// the ability to force-feed events that get output by the
func MockNew(interval time.Duration) *Mock {
	m := &Mock{
		ticker: time.NewTicker(interval).C,
		Force:  make(chan time.Time),
		skip:   make(chan struct{}),
		quit:   make(chan struct{}),
	}

	// Proxy the real ticks to our Force channel if we are active.
	m.wg.Add(1)
	go func() {
		defer m.wg.Done()
		for {
			select {
			case t := <-m.ticker:
				if atomic.LoadUint32(&m.isActive) == 0 {
					continue
				}

				select {
				case m.Force <- t:
				case <-m.skip:
				case <-m.quit:
					return
				}

			case <-m.quit:
				return
			}
		}
	}()

	return m
}

// Ticks returns a receive-only channel that delivers times at the ticker's
// prescribed interval when active. Force-fed ticks can be delivered at any
// time.
//
// NOTE: Part of the Ticker interface.
func (m *Mock) Ticks() <-chan time.Time {
	return m.Force
}

// Resumes starts underlying time.Ticker and causes the ticker to begin
// delivering scheduled events.
//
// NOTE: Part of the Ticker interface.
func (m *Mock) Resume() {
	atomic.StoreUint32(&m.isActive, 1)
}

// Pause suspends the underlying ticker, such that Ticks() stops signaling at
// regular intervals.
//
// NOTE: Part of the Ticker interface.
func (m *Mock) Pause() {
	atomic.StoreUint32(&m.isActive, 0)

	// If the ticker fired and read isActive as true, it may still send the
	// tick. We'll try to send on the skip channel to drop it.
	select {
	case m.skip <- struct{}{}:
	default:
	}
}

// Stop suspends the underlying ticker, such that Ticks() stops signaling at
// regular intervals, and permanently frees up any resources.
//
// NOTE: Part of the Ticker interface.
func (m *Mock) Stop() {
	m.Pause()
	close(m.quit)
	m.wg.Wait()
}
<commit_msg>ticker: remove debug build tag from mock.go<commit_after>package ticker

import (
	"sync"
	"sync/atomic"
	"time"
)

// Mock implements the Ticker interface, and provides a method of
// force-feeding ticks, even while paused.
type Mock struct {
	isActive uint32 // used atomically

	// Force is used to force-feed a ticks into the ticker. Useful for
	// debugging when trying to wake an event.
	Force chan time.Time

	ticker <-chan time.Time
	skip   chan struct{}

	wg   sync.WaitGroup
	quit chan struct{}
}

// MockNew returns a Mock Ticker, used for testing and debugging. It supports
// the ability to force-feed events that get output by the
func MockNew(interval time.Duration) *Mock {
	m := &Mock{
		ticker: time.NewTicker(interval).C,
		Force:  make(chan time.Time),
		skip:   make(chan struct{}),
		quit:   make(chan struct{}),
	}

	// Proxy the real ticks to our Force channel if we are active.
	m.wg.Add(1)
	go func() {
		defer m.wg.Done()
		for {
			select {
			case t := <-m.ticker:
				if atomic.LoadUint32(&m.isActive) == 0 {
					continue
				}

				select {
				case m.Force <- t:
				case <-m.skip:
				case <-m.quit:
					return
				}

			case <-m.quit:
				return
			}
		}
	}()

	return m
}

// Ticks returns a receive-only channel that delivers times at the ticker's
// prescribed interval when active. Force-fed ticks can be delivered at any
// time.
//
// NOTE: Part of the Ticker interface.
func (m *Mock) Ticks() <-chan time.Time {
	return m.Force
}

// Resumes starts underlying time.Ticker and causes the ticker to begin
// delivering scheduled events.
//
// NOTE: Part of the Ticker interface.
func (m *Mock) Resume() {
	atomic.StoreUint32(&m.isActive, 1)
}

// Pause suspends the underlying ticker, such that Ticks() stops signaling at
// regular intervals.
//
// NOTE: Part of the Ticker interface.
func (m *Mock) Pause() {
	atomic.StoreUint32(&m.isActive, 0)

	// If the ticker fired and read isActive as true, it may still send the
	// tick. We'll try to send on the skip channel to drop it.
	select {
	case m.skip <- struct{}{}:
	default:
	}
}

// Stop suspends the underlying ticker, such that Ticks() stops signaling at
// regular intervals, and permanently frees up any resources.
//
// NOTE: Part of the Ticker interface.
func (m *Mock) Stop() {
	m.Pause()
	close(m.quit)
	m.wg.Wait()
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package options

import (
	"github.com/spf13/pflag"
)

type GenPodOptions struct {
	Kubeconfig string
	Verbose    bool
	Namespace  string
	Format     string
}

func NewGenPodOptions() *GenPodOptions {
	return &GenPodOptions{}
}

func (s *GenPodOptions) AddFlags(fs *pflag.FlagSet) {
	fs.StringVar(&s.Kubeconfig, "kubeconfig", s.Kubeconfig, "Path to kubeconfig file with authorization and master location information.")
	fs.BoolVar(&s.Verbose, "verbose", s.Verbose, "Verbose mode")
	fs.StringVar(&s.Namespace, "namespace", s.Namespace, "Cluster namespace")
	fs.StringVar(&s.Format, "output", s.Format, "Output format")
}
<commit_msg>Fix genpod to have "default" namespace by default.<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

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

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

package options

import (
	"github.com/spf13/pflag"
)

type GenPodOptions struct {
	Kubeconfig string
	Verbose    bool
	Namespace  string
	Format     string
}

func NewGenPodOptions() *GenPodOptions {
	return &GenPodOptions{Namespace: "default"}
}

func (s *GenPodOptions) AddFlags(fs *pflag.FlagSet) {
	fs.StringVar(&s.Kubeconfig, "kubeconfig", s.Kubeconfig, "Path to kubeconfig file with authorization and master location information.")
	fs.BoolVar(&s.Verbose, "verbose", s.Verbose, "Verbose mode")
	fs.StringVar(&s.Namespace, "namespace", s.Namespace, "Cluster namespace")
	fs.StringVar(&s.Format, "output", s.Format, "Output format")
}
<|endoftext|>


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

package delete

import (
	"context"
	"fmt"

	"github.com/apigee/registry/cmd/registry/core"
	"github.com/apigee/registry/gapic"
	"github.com/apigee/registry/log"
	"github.com/apigee/registry/pkg/connection"
	"github.com/apigee/registry/rpc"
	"github.com/apigee/registry/server/registry/names"
	"github.com/spf13/cobra"
)

func Command() *cobra.Command {
	var filter string
	cmd := &cobra.Command{
		Use:   "delete",
		Short: "Delete resources from the API Registry",
		Args:  cobra.ExactArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
			ctx := cmd.Context()
			c, err := connection.ActiveConfig()
			if err != nil {
				log.FromContext(ctx).WithError(err).Fatal("Failed to get config")
			}
			args[0] = c.FQName(args[0])

			client, err := connection.NewRegistryClientWithSettings(ctx, c)
			if err != nil {
				log.FromContext(ctx).WithError(err).Fatal("Failed to get client")
			}

			// Initialize task queue.
			taskQueue, wait := core.WorkerPool(ctx, 64)
			defer wait()

			err = matchAndHandleDeleteCmd(ctx, client, taskQueue, args[0], filter)
			if err != nil {
				log.FromContext(ctx).WithError(err).Fatal("Failed to match or handle command")
			}
		},
	}

	cmd.Flags().StringVar(&filter, "filter", "", "Filter selected resources")
	return cmd
}

type deleteTask struct {
	client       connection.RegistryClient
	resourceName string
	resourceKind string
}

func (task *deleteTask) String() string {
	return "delete " + task.resourceName
}

func (task *deleteTask) Run(ctx context.Context) error {
	log.Debugf(ctx, "Deleting %s %s", task.resourceKind, task.resourceName)
	switch task.resourceKind {
	case "api":
		return task.client.DeleteApi(ctx, &rpc.DeleteApiRequest{Name: task.resourceName})
	case "version":
		return task.client.DeleteApiVersion(ctx, &rpc.DeleteApiVersionRequest{Name: task.resourceName})
	case "spec":
		return task.client.DeleteApiSpec(ctx, &rpc.DeleteApiSpecRequest{Name: task.resourceName})
	case "artifact":
		return task.client.DeleteArtifact(ctx, &rpc.DeleteArtifactRequest{Name: task.resourceName})
	default:
		return nil
	}
}

func matchAndHandleDeleteCmd(
	ctx context.Context,
	client connection.RegistryClient,
	taskQueue chan<- core.Task,
	name string,
	filter string,
) error {
	if api, err := names.ParseApi(name); err == nil {
		return deleteAPIs(ctx, client, api, filter, taskQueue)
	} else if version, err := names.ParseVersion(name); err == nil {
		return deleteVersions(ctx, client, version, filter, taskQueue)
	} else if spec, err := names.ParseSpec(name); err == nil {
		return deleteSpecs(ctx, client, spec, filter, taskQueue)
	} else if artifact, err := names.ParseArtifact(name); err == nil {
		return deleteArtifacts(ctx, client, artifact, filter, taskQueue)
	} else {
		return fmt.Errorf("unsupported resource name: see the 'registry rpc delete-' subcommands for alternatives")
	}
}

func deleteAPIs(
	ctx context.Context,
	client *gapic.RegistryClient,
	api names.Api,
	filterFlag string,
	taskQueue chan<- core.Task) error {
	return core.ListAPIs(ctx, client, api, filterFlag, func(api *rpc.Api) error {
		taskQueue <- &deleteTask{
			client:       client,
			resourceName: api.Name,
			resourceKind: "api",
		}
		return nil
	})
}

func deleteVersions(
	ctx context.Context,
	client *gapic.RegistryClient,
	version names.Version,
	filterFlag string,
	taskQueue chan<- core.Task) error {
	return core.ListVersions(ctx, client, version, filterFlag, func(version *rpc.ApiVersion) error {
		taskQueue <- &deleteTask{
			client:       client,
			resourceName: version.Name,
			resourceKind: "version",
		}
		return nil
	})
}

func deleteSpecs(
	ctx context.Context,
	client *gapic.RegistryClient,
	spec names.Spec,
	filterFlag string,
	taskQueue chan<- core.Task) error {
	return core.ListSpecs(ctx, client, spec, filterFlag, func(spec *rpc.ApiSpec) error {
		taskQueue <- &deleteTask{
			client:       client,
			resourceName: spec.Name,
			resourceKind: "spec",
		}
		return nil
	})
}

func deleteArtifacts(
	ctx context.Context,
	client *gapic.RegistryClient,
	artifact names.Artifact,
	filterFlag string,
	taskQueue chan<- core.Task) error {
	return core.ListArtifacts(ctx, client, artifact, filterFlag, false, func(artifact *rpc.Artifact) error {
		taskQueue <- &deleteTask{
			client:       client,
			resourceName: artifact.Name,
			resourceKind: "artifact",
		}
		return nil
	})
}
<commit_msg>Add --jobs flag to "registry delete" command. (#812)<commit_after>// Copyright 2020 Google LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package delete

import (
	"context"
	"fmt"

	"github.com/apigee/registry/cmd/registry/core"
	"github.com/apigee/registry/gapic"
	"github.com/apigee/registry/log"
	"github.com/apigee/registry/pkg/connection"
	"github.com/apigee/registry/rpc"
	"github.com/apigee/registry/server/registry/names"
	"github.com/spf13/cobra"
)

func Command() *cobra.Command {
	var filter string
	var jobs int
	cmd := &cobra.Command{
		Use:   "delete",
		Short: "Delete resources from the API Registry",
		Args:  cobra.ExactArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
			ctx := cmd.Context()
			c, err := connection.ActiveConfig()
			if err != nil {
				log.FromContext(ctx).WithError(err).Fatal("Failed to get config")
			}
			args[0] = c.FQName(args[0])

			client, err := connection.NewRegistryClientWithSettings(ctx, c)
			if err != nil {
				log.FromContext(ctx).WithError(err).Fatal("Failed to get client")
			}

			// Initialize task queue.
			taskQueue, wait := core.WorkerPool(ctx, jobs)
			defer wait()

			err = matchAndHandleDeleteCmd(ctx, client, taskQueue, args[0], filter)
			if err != nil {
				log.FromContext(ctx).WithError(err).Fatal("Failed to match or handle command")
			}
		},
	}

	cmd.Flags().StringVar(&filter, "filter", "", "Filter selected resources")
	cmd.Flags().IntVar(&jobs, "jobs", 10, "Number of actions to perform concurrently")
	return cmd
}

type deleteTask struct {
	client       connection.RegistryClient
	resourceName string
	resourceKind string
}

func (task *deleteTask) String() string {
	return "delete " + task.resourceName
}

func (task *deleteTask) Run(ctx context.Context) error {
	log.Debugf(ctx, "Deleting %s %s", task.resourceKind, task.resourceName)
	switch task.resourceKind {
	case "api":
		return task.client.DeleteApi(ctx, &rpc.DeleteApiRequest{Name: task.resourceName})
	case "version":
		return task.client.DeleteApiVersion(ctx, &rpc.DeleteApiVersionRequest{Name: task.resourceName})
	case "spec":
		return task.client.DeleteApiSpec(ctx, &rpc.DeleteApiSpecRequest{Name: task.resourceName})
	case "artifact":
		return task.client.DeleteArtifact(ctx, &rpc.DeleteArtifactRequest{Name: task.resourceName})
	default:
		return nil
	}
}

func matchAndHandleDeleteCmd(
	ctx context.Context,
	client connection.RegistryClient,
	taskQueue chan<- core.Task,
	name string,
	filter string,
) error {
	if api, err := names.ParseApi(name); err == nil {
		return deleteAPIs(ctx, client, api, filter, taskQueue)
	} else if version, err := names.ParseVersion(name); err == nil {
		return deleteVersions(ctx, client, version, filter, taskQueue)
	} else if spec, err := names.ParseSpec(name); err == nil {
		return deleteSpecs(ctx, client, spec, filter, taskQueue)
	} else if artifact, err := names.ParseArtifact(name); err == nil {
		return deleteArtifacts(ctx, client, artifact, filter, taskQueue)
	} else {
		return fmt.Errorf("unsupported resource name: see the 'registry rpc delete-' subcommands for alternatives")
	}
}

func deleteAPIs(
	ctx context.Context,
	client *gapic.RegistryClient,
	api names.Api,
	filterFlag string,
	taskQueue chan<- core.Task) error {
	return core.ListAPIs(ctx, client, api, filterFlag, func(api *rpc.Api) error {
		taskQueue <- &deleteTask{
			client:       client,
			resourceName: api.Name,
			resourceKind: "api",
		}
		return nil
	})
}

func deleteVersions(
	ctx context.Context,
	client *gapic.RegistryClient,
	version names.Version,
	filterFlag string,
	taskQueue chan<- core.Task) error {
	return core.ListVersions(ctx, client, version, filterFlag, func(version *rpc.ApiVersion) error {
		taskQueue <- &deleteTask{
			client:       client,
			resourceName: version.Name,
			resourceKind: "version",
		}
		return nil
	})
}

func deleteSpecs(
	ctx context.Context,
	client *gapic.RegistryClient,
	spec names.Spec,
	filterFlag string,
	taskQueue chan<- core.Task) error {
	return core.ListSpecs(ctx, client, spec, filterFlag, func(spec *rpc.ApiSpec) error {
		taskQueue <- &deleteTask{
			client:       client,
			resourceName: spec.Name,
			resourceKind: "spec",
		}
		return nil
	})
}

func deleteArtifacts(
	ctx context.Context,
	client *gapic.RegistryClient,
	artifact names.Artifact,
	filterFlag string,
	taskQueue chan<- core.Task) error {
	return core.ListArtifacts(ctx, client, artifact, filterFlag, false, func(artifact *rpc.Artifact) error {
		taskQueue <- &deleteTask{
			client:       client,
			resourceName: artifact.Name,
			resourceKind: "artifact",
		}
		return nil
	})
}
<|endoftext|>