<commit_before>package automaton

import (
	"github.com/balzaczyy/golucene/core/util"
	"math/big"
)

// util/automaton/Automaton.java

/*
Represents an automaton and all its states and transitions. States
are integers and must be created using {@link #createState}.  Mark a
state as an accept state using {@link #setAccept}.  Add transitions
using {@link #addTransition}.  Each state must have all of its
transitions added at once; if this is too restrictive then use
{@link Automaton.Builder} instead.  State 0 is always the
initial state.  Once a state is finished, either
because you've starting adding transitions to another state or you
call {@link #finishState}, then that states transitions are sorted
(first by min, then max, then dest) and reduced (transitions with
adjacent labels going to the same dest are combined).
*/
type Automaton struct {
	curState      int
	states        []int // 2x
	transitions   []int // 3x
	isAccept      *big.Int
	deterministic bool
}

func newEmptyAutomaton() *Automaton {
	return &Automaton{
		deterministic: true,
		curState:      -1,
		isAccept:      big.NewInt(0),
	}
}

/* Create a new state. */
func (a *Automaton) createState() int {
	state := len(a.states) / 2
	a.states = append(a.states, -1, 0)
	return state
}

/* Set or clear this state as an accept state. */
func (a *Automaton) setAccept(state int, accept bool) {
	assert2(state < a.numStates(), "state=%v is out of bounds (numStates=%v)", state, a.numStates())
	if accept {
		a.isAccept.SetBit(a.isAccept, state, 1)
	} else {
		a.isAccept.SetBit(a.isAccept, state, 0)
	}
}

/* Add a new transition with min = max = label. */
func (a *Automaton) addTransition(source, dest, label int) {
	a.addTransitionRange(source, dest, label, label)
}

/* Add a new transition with the specified source, dest, min, max. */
func (a *Automaton) addTransitionRange(source, dest, min, max int) {
	assert(len(a.transitions)%3 == 0)
	assert2(source < a.numStates(), "source=%v is out of bounds (maxState is %v)", source, a.numStates()-1)
	assert2(dest < a.numStates(), "dest=%v is out of bounds (maxState is %v)", dest, a.numStates()-1)

	if a.curState != source {
		if a.curState != -1 {
			a.finishCurrentState()
		}

		// move to next source:
		a.curState = source
		assert2(a.states[2*a.curState] == -1, "from state (%v) already had transitions added", source)
		assert(a.states[2*a.curState+1] == 0)
		a.states[2*a.curState] = len(a.transitions)
	}

	a.transitions = append(a.transitions, dest, min, max)

	// increment transition count for this state
	a.states[2*a.curState+1]++
}

/*
Add a [virtual] epsilon transition between source and dest. Dest
state must already have all transitions added because this method
simply copies those same transitions over to source.
*/
func (a *Automaton) addEpsilon(source, dest int) {
	panic("niy")
}

/*
Copies over all state/transition from other. The state numbers are
sequentially assigned (appended).
*/
func (a *Automaton) copy(other *Automaton) {
	panic("niy")
}

/* Freezes the last state, sorting and reducing the transitions. */
func (a *Automaton) finishCurrentState() {
	numTransitions := a.states[2*a.curState+1]
	assert(numTransitions > 0)

	offset := a.states[2*a.curState]
	start := offset / 3
	util.NewInPlaceMergeSorter(destMinMaxTransitions(a.transitions)).Sort(start, start+numTransitions)

	// reduce any "adjacent" transitions:
	upto, min, max, dest := 0, -1, -1, -1

	for i := 0; i < numTransitions; i++ {
		tDest := a.transitions[offset+3*i]
		tMin := a.transitions[offset+3*i+1]
		tMax := a.transitions[offset+3*i+2]

		if dest == tDest {
			panic("niy")
		} else {
			if dest != -1 {
				a.transitions[offset+3*upto] = dest
				a.transitions[offset+3*upto+1] = min
				a.transitions[offset+3*upto+2] = max
			}
			dest, min, max = tDest, tMin, tMax
		}
	}

	if dest != -1 {
		// last transition
		a.transitions[offset+3*upto] = dest
		a.transitions[offset+3*upto+1] = min
		a.transitions[offset+3*upto+2] = max
		upto++
	}

	a.transitions = a.transitions[:len(a.transitions)-(numTransitions-upto)*3]
	a.states[2*a.curState+1] = upto

	// sort transitions by min/max/dest:
	util.NewInPlaceMergeSorter(minMaxDestTransitions(a.transitions)).Sort(start, start+upto)

	if a.deterministic && upto > 1 {
		panic("niy")
	}
}

/*
Finishes the current state; call this once you are done adding
transitions for a state. This is automatically called if you start
adding transitions to a new source state, but for the last state you
add, you need to call this method yourself.
*/
func (a *Automaton) finishState() {
	if a.curState != -1 {
		a.finishCurrentState()
		a.curState = -1
	}
}

func (a *Automaton) numStates() int {
	return len(a.states) / 2
}

type destMinMaxTransitions []int

func (s destMinMaxTransitions) Len() int {
	panic("niy")
}

func (s destMinMaxTransitions) Swap(i, j int) {
	panic("niy")
}

func (s destMinMaxTransitions) Less(i, j int) bool {
	panic("niy")
}

type minMaxDestTransitions []int

func (s minMaxDestTransitions) Len() int {
	panic("niy")
}

func (s minMaxDestTransitions) Swap(i, j int) {
	panic("niy")
}

func (s minMaxDestTransitions) Less(i, j int) bool {
	panic("niy")
}

// Go doesn't have unicode.MinRune which should be 0
const MIN_CODE_POINT = 0

type AutomatonBuilder struct {
}
<commit_msg>implement Automaton.copy()<commit_after>package automaton

import (
	"github.com/balzaczyy/golucene/core/util"
	"math/big"
)

// util/automaton/Automaton.java

/*
Represents an automaton and all its states and transitions. States
are integers and must be created using {@link #createState}.  Mark a
state as an accept state using {@link #setAccept}.  Add transitions
using {@link #addTransition}.  Each state must have all of its
transitions added at once; if this is too restrictive then use
{@link Automaton.Builder} instead.  State 0 is always the
initial state.  Once a state is finished, either
because you've starting adding transitions to another state or you
call {@link #finishState}, then that states transitions are sorted
(first by min, then max, then dest) and reduced (transitions with
adjacent labels going to the same dest are combined).
*/
type Automaton struct {
	curState      int
	states        []int // 2x
	transitions   []int // 3x
	isAccept      *big.Int
	deterministic bool
}

func newEmptyAutomaton() *Automaton {
	return &Automaton{
		deterministic: true,
		curState:      -1,
		isAccept:      big.NewInt(0),
	}
}

/* Create a new state. */
func (a *Automaton) createState() int {
	state := len(a.states) / 2
	a.states = append(a.states, -1, 0)
	return state
}

/* Set or clear this state as an accept state. */
func (a *Automaton) setAccept(state int, accept bool) {
	assert2(state < a.numStates(), "state=%v is out of bounds (numStates=%v)", state, a.numStates())
	if accept {
		a.isAccept.SetBit(a.isAccept, state, 1)
	} else {
		a.isAccept.SetBit(a.isAccept, state, 0)
	}
}

/* Add a new transition with min = max = label. */
func (a *Automaton) addTransition(source, dest, label int) {
	a.addTransitionRange(source, dest, label, label)
}

/* Add a new transition with the specified source, dest, min, max. */
func (a *Automaton) addTransitionRange(source, dest, min, max int) {
	assert(len(a.transitions)%3 == 0)
	assert2(source < a.numStates(), "source=%v is out of bounds (maxState is %v)", source, a.numStates()-1)
	assert2(dest < a.numStates(), "dest=%v is out of bounds (maxState is %v)", dest, a.numStates()-1)

	if a.curState != source {
		if a.curState != -1 {
			a.finishCurrentState()
		}

		// move to next source:
		a.curState = source
		assert2(a.states[2*a.curState] == -1, "from state (%v) already had transitions added", source)
		assert(a.states[2*a.curState+1] == 0)
		a.states[2*a.curState] = len(a.transitions)
	}

	a.transitions = append(a.transitions, dest, min, max)

	// increment transition count for this state
	a.states[2*a.curState+1]++
}

/*
Add a [virtual] epsilon transition between source and dest. Dest
state must already have all transitions added because this method
simply copies those same transitions over to source.
*/
func (a *Automaton) addEpsilon(source, dest int) {
	panic("niy")
}

/*
Copies over all state/transition from other. The state numbers are
sequentially assigned (appended).
*/
func (a *Automaton) copy(other *Automaton) {
	// bulk copy and then fixup the state pointers
	stateOffset := a.numStates()
	a.states = append(a.states, other.states...)
	for i := 0; i < len(other.states); i += 2 {
		if a.states[stateOffset*2+i] != -1 {
			a.states[stateOffset*2+i] += len(a.transitions)
		}
	}
	otherNumStates := other.numStates()
	otherAcceptStates := other.isAccept
	for state := 0; state < otherNumStates; state++ {
		if otherAcceptStates.Bit(state) == 0 {
			continue
		}
		a.setAccept(stateOffset+state, true)
	}

	// bulk copy and then fixup dest for each transition
	transOffset := len(a.transitions)
	a.transitions = append(a.transitions, other.transitions...)
	for i := 0; i < len(other.transitions); i += 3 {
		a.transitions[transOffset+i] += stateOffset
	}

	if !other.deterministic {
		a.deterministic = false
	}
}

/* Freezes the last state, sorting and reducing the transitions. */
func (a *Automaton) finishCurrentState() {
	numTransitions := a.states[2*a.curState+1]
	assert(numTransitions > 0)

	offset := a.states[2*a.curState]
	start := offset / 3
	util.NewInPlaceMergeSorter(destMinMaxTransitions(a.transitions)).Sort(start, start+numTransitions)

	// reduce any "adjacent" transitions:
	upto, min, max, dest := 0, -1, -1, -1

	for i := 0; i < numTransitions; i++ {
		tDest := a.transitions[offset+3*i]
		tMin := a.transitions[offset+3*i+1]
		tMax := a.transitions[offset+3*i+2]

		if dest == tDest {
			panic("niy")
		} else {
			if dest != -1 {
				a.transitions[offset+3*upto] = dest
				a.transitions[offset+3*upto+1] = min
				a.transitions[offset+3*upto+2] = max
			}
			dest, min, max = tDest, tMin, tMax
		}
	}

	if dest != -1 {
		// last transition
		a.transitions[offset+3*upto] = dest
		a.transitions[offset+3*upto+1] = min
		a.transitions[offset+3*upto+2] = max
		upto++
	}

	a.transitions = a.transitions[:len(a.transitions)-(numTransitions-upto)*3]
	a.states[2*a.curState+1] = upto

	// sort transitions by min/max/dest:
	util.NewInPlaceMergeSorter(minMaxDestTransitions(a.transitions)).Sort(start, start+upto)

	if a.deterministic && upto > 1 {
		panic("niy")
	}
}

/*
Finishes the current state; call this once you are done adding
transitions for a state. This is automatically called if you start
adding transitions to a new source state, but for the last state you
add, you need to call this method yourself.
*/
func (a *Automaton) finishState() {
	if a.curState != -1 {
		a.finishCurrentState()
		a.curState = -1
	}
}

func (a *Automaton) numStates() int {
	return len(a.states) / 2
}

type destMinMaxTransitions []int

func (s destMinMaxTransitions) Len() int {
	panic("niy")
}

func (s destMinMaxTransitions) Swap(i, j int) {
	panic("niy")
}

func (s destMinMaxTransitions) Less(i, j int) bool {
	panic("niy")
}

type minMaxDestTransitions []int

func (s minMaxDestTransitions) Len() int {
	panic("niy")
}

func (s minMaxDestTransitions) Swap(i, j int) {
	panic("niy")
}

func (s minMaxDestTransitions) Less(i, j int) bool {
	panic("niy")
}

// Go doesn't have unicode.MinRune which should be 0
const MIN_CODE_POINT = 0

type AutomatonBuilder struct {
}
<|endoftext|>


<commit_before>package raft

import (
	"testing"
)

//------------------------------------------------------------------------------
//
// Tests
//
//------------------------------------------------------------------------------

//--------------------------------------
// Request Vote
//--------------------------------------

// Ensure that we can request a vote from a server that has not voted.
func TestServerRequestVote(t *testing.T) {
	server := newTestServer("1")
	resp := server.RequestVote(NewRequestVoteRequest(1, "foo", 0, 0))
	if !(resp.Term == 1 && resp.VoteGranted) {
		t.Fatalf("Invalid request vote response: %v/%v", resp.Term, resp.VoteGranted)
	}
}

// Ensure that a vote request is denied if it comes from an old term.
func TestServerRequestVoteDeniedForStaleTerm(t *testing.T) {
	server := newTestServer("1")
	server.state = Leader
	server.currentTerm = 2
	resp := server.RequestVote(NewRequestVoteRequest(1, "foo", 0, 0))
	if !(resp.Term == 2 && !resp.VoteGranted) {
		t.Fatalf("Invalid request vote response: %v/%v", resp.Term, resp.VoteGranted)
	}
	if server.currentTerm != 2 && server.state != Follower {
		t.Fatalf("Server did not update term and demote: %v / %v", server.currentTerm, server.state)
	}
}

// Ensure that a vote request is denied if we've already voted for a different candidate.
func TestServerRequestVoteDeniedIfAlreadyVoted(t *testing.T) {
	server := newTestServer("1")
	server.currentTerm = 2
	resp := server.RequestVote(NewRequestVoteRequest(2, "foo", 0, 0))
	if !(resp.Term == 2 && resp.VoteGranted) {
		t.Fatalf("First vote should not have been denied")
	}
	resp = server.RequestVote(NewRequestVoteRequest(2, "bar", 0, 0))
	if !(resp.Term == 2 && !resp.VoteGranted) {
		t.Fatalf("Second vote should have been denied")
	}
}

// TODO: Test out of date log.
// TODO: Test success with longer log.

//--------------------------------------
// Membership
//--------------------------------------

// Ensure that we can start a single server and append to its log.
func TestServerSingleNode(t *testing.T) {
	server := newTestServer("1")
	if server.state != Stopped {
		t.Fatalf("Unexpected server state: %v", server.state)
	}

	// Get the server running.
	if err := server.Start(); err != nil {
		t.Fatalf("Unable to start server: %v", err)
	}
	if server.state != Follower {
		t.Fatalf("Unexpected server state: %v", server.state)
	}

	// Join the server to itself.
	if err := server.Join("1"); err != nil {
		t.Fatalf("Unable to join: %v", err)
	}
	if server.state != Leader {
		t.Fatalf("Unexpected server state: %v", server.state)
	}

	// Stop the server.
	server.Stop()
	if server.state != Stopped {
		t.Fatalf("Unexpected server state: %v", server.state)
	}
}

// Ensure that we can start multiple servers and determine a leader.
/*
func TestServerMultiNode(t *testing.T) {
	warn("== begin multi-node ==")

	// Initialize the servers.
	names := []string{"1", "2", "3"}
	servers := map[string]*Server{}
	for _, name := range names {
		server := newTestServer(name)
		server.DoHandler = func(server *Server, peer *Peer, command Command) error {
			return servers[peer.name].Do(command)
		}
		if err := server.Start(); err != nil {
			t.Fatalf("Unable to start server[%s]: %v", name, err)
		}
		if err := server.Join("1"); err != nil {
			t.Fatalf("Unable to join server[%s]: %v", name, err)
		}
		servers[name] = server
	}

	// Check that two peers exist on leader.
	leader := servers["1"]
	if leader.MemberCount() != 3 {
		t.Fatalf("Expected member count to be 2, got %v", leader.MemberCount())
	}

	// Stop the servers.
	for _, server := range servers {
		server.Stop()
	}
	warn("== end multi-node ==")
}
*/
<commit_msg>Add test for revote in new term.<commit_after>package raft

import (
	"testing"
)

//------------------------------------------------------------------------------
//
// Tests
//
//------------------------------------------------------------------------------

//--------------------------------------
// Request Vote
//--------------------------------------

// Ensure that we can request a vote from a server that has not voted.
func TestServerRequestVote(t *testing.T) {
	server := newTestServer("1")
	resp := server.RequestVote(NewRequestVoteRequest(1, "foo", 0, 0))
	if !(resp.Term == 1 && resp.VoteGranted) {
		t.Fatalf("Invalid request vote response: %v/%v", resp.Term, resp.VoteGranted)
	}
}

// Ensure that a vote request is denied if it comes from an old term.
func TestServerRequestVoteDeniedForStaleTerm(t *testing.T) {
	server := newTestServer("1")
	server.state = Leader
	server.currentTerm = 2
	resp := server.RequestVote(NewRequestVoteRequest(1, "foo", 0, 0))
	if !(resp.Term == 2 && !resp.VoteGranted) {
		t.Fatalf("Invalid request vote response: %v/%v", resp.Term, resp.VoteGranted)
	}
	if server.currentTerm != 2 && server.state != Follower {
		t.Fatalf("Server did not update term and demote: %v / %v", server.currentTerm, server.state)
	}
}

// Ensure that a vote request is denied if we've already voted for a different candidate.
func TestServerRequestVoteDeniedIfAlreadyVoted(t *testing.T) {
	server := newTestServer("1")
	server.currentTerm = 2
	resp := server.RequestVote(NewRequestVoteRequest(2, "foo", 0, 0))
	if !(resp.Term == 2 && resp.VoteGranted) {
		t.Fatalf("First vote should not have been denied")
	}
	resp = server.RequestVote(NewRequestVoteRequest(2, "bar", 0, 0))
	if !(resp.Term == 2 && !resp.VoteGranted) {
		t.Fatalf("Second vote should have been denied")
	}
}

// Ensure that a vote request is approved if vote occurs in a new term.
func TestServerRequestVoteApprovedIfAlreadyVotedInOlderTerm(t *testing.T) {
	server := newTestServer("1")
	server.currentTerm = 2
	resp := server.RequestVote(NewRequestVoteRequest(2, "foo", 0, 0))
	if !(resp.Term == 2 && resp.VoteGranted && server.votedFor == "foo") {
		t.Fatalf("First vote should not have been denied")
	}
	resp = server.RequestVote(NewRequestVoteRequest(3, "bar", 0, 0))
	if !(resp.Term == 3 && resp.VoteGranted && server.votedFor == "bar") {
		t.Fatalf("Second vote should have been approved")
	}
}

// TODO: Test out of date log.
// TODO: Test success with longer log.

//--------------------------------------
// Membership
//--------------------------------------

// Ensure that we can start a single server and append to its log.
func TestServerSingleNode(t *testing.T) {
	server := newTestServer("1")
	if server.state != Stopped {
		t.Fatalf("Unexpected server state: %v", server.state)
	}

	// Get the server running.
	if err := server.Start(); err != nil {
		t.Fatalf("Unable to start server: %v", err)
	}
	if server.state != Follower {
		t.Fatalf("Unexpected server state: %v", server.state)
	}

	// Join the server to itself.
	if err := server.Join("1"); err != nil {
		t.Fatalf("Unable to join: %v", err)
	}
	if server.state != Leader {
		t.Fatalf("Unexpected server state: %v", server.state)
	}

	// Stop the server.
	server.Stop()
	if server.state != Stopped {
		t.Fatalf("Unexpected server state: %v", server.state)
	}
}

// Ensure that we can start multiple servers and determine a leader.
/*
func TestServerMultiNode(t *testing.T) {
	warn("== begin multi-node ==")

	// Initialize the servers.
	names := []string{"1", "2", "3"}
	servers := map[string]*Server{}
	for _, name := range names {
		server := newTestServer(name)
		server.DoHandler = func(server *Server, peer *Peer, command Command) error {
			return servers[peer.name].Do(command)
		}
		if err := server.Start(); err != nil {
			t.Fatalf("Unable to start server[%s]: %v", name, err)
		}
		if err := server.Join("1"); err != nil {
			t.Fatalf("Unable to join server[%s]: %v", name, err)
		}
		servers[name] = server
	}

	// Check that two peers exist on leader.
	leader := servers["1"]
	if leader.MemberCount() != 3 {
		t.Fatalf("Expected member count to be 2, got %v", leader.MemberCount())
	}

	// Stop the servers.
	for _, server := range servers {
		server.Stop()
	}
	warn("== end multi-node ==")
}
*/
<|endoftext|>


<commit_before>package revel

import (
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"os"
	"path"
	"path/filepath"
	"reflect"
	"strings"
	"testing"
)

// A copy of the hotel struct from the sample app.
type Hotel struct {
	HotelId          int
	Name, Address    string
	City, State, Zip string
	Country          string
	Price            int
}

type Hotels struct {
	*Controller
}

type Static struct {
	*Controller
}

func (c Hotels) Show(id int) Result {
	title := "View Hotel"
	hotel := &Hotel{id, "A Hotel", "300 Main St.", "New York", "NY", "10010", "USA", 300}
	return c.Render(title, hotel)
}

func (c Static) Serve(prefix, filepath string) Result {
	var basePath, dirName string

	if !path.IsAbs(dirName) {
		basePath = BasePath
	}

	fname := path.Join(basePath, prefix, filepath)
	file, err := os.Open(fname)
	if os.IsNotExist(err) {
		return c.NotFound("")
	} else if err != nil {
		WARN.Printf("Problem opening file (%s): %s ", fname, err)
		return c.NotFound("This was found but not sure why we couldn't open it.")
	}
	return c.RenderFile(file, "")
}

// This tries to benchmark the usual request-serving pipeline to get an overall
// performance metric.
//
// Each iteration runs one mock request to display a hotel's detail page by id.
//
// Contributing parts:
// - Routing
// - Controller lookup / invocation
// - Parameter binding
// - Session, flash, i18n cookies
// - Render() call magic
// - Template rendering
func BenchmarkServeAction(b *testing.B) {
	benchmarkRequest(b, showRequest)
}

// This tries to benchmark the static serving overhead when serving an "average
// size" 7k file.
func BenchmarkServeStatic(b *testing.B) {
	benchmarkRequest(b, staticRequest)
}

func benchmarkRequest(b *testing.B, req *http.Request) {
	startFakeBookingApp()
	b.ResetTimer()
	resp := httptest.NewRecorder()
	for i := 0; i < b.N; i++ {
		handle(resp, req)
	}
}

// Test that the booking app can be successfully run for a test.
func TestFakeServer(t *testing.T) {
	startFakeBookingApp()

	resp := httptest.NewRecorder()

	// First, test that the expected responses are actually generated
	handle(resp, showRequest)
	if !strings.Contains(resp.Body.String(), "300 Main St.") {
		t.Errorf("Failed to find hotel address in action response:\n%s", resp.Body)
		t.FailNow()
	}
	resp.Body.Reset()

	handle(resp, staticRequest)
	if resp.Body.Len() != 6712 {
		t.Errorf("Expected sessvars.js to have 6712 bytes, got %d:\n%s", resp.Body.Len(), resp.Body)
		t.FailNow()
	}

	resp.Body = nil
}

var (
	showRequest, _   = http.NewRequest("GET", "/hotels/3", nil)
	staticRequest, _ = http.NewRequest("GET", "/public/js/sessvars.js", nil)
)

func startFakeBookingApp() {
	Init("", "github.com/robfig/revel/samples/booking", "")

	// Disable logging.
	TRACE = log.New(ioutil.Discard, "", 0)
	INFO = TRACE
	WARN = TRACE
	ERROR = TRACE

	MainRouter = NewRouter("")
	routesFile, _ := ioutil.ReadFile(filepath.Join(BasePath, "conf", "routes"))
	MainRouter.Routes, _ = parseRoutes("", string(routesFile), false)
	MainTemplateLoader = NewTemplateLoader([]string{ViewsPath, path.Join(RevelPath, "templates")})
	MainTemplateLoader.Refresh()

	RegisterController((*Hotels)(nil),
		[]*MethodType{
			&MethodType{
				Name: "Index",
			},
			&MethodType{
				Name: "Show",
				Args: []*MethodArg{
					{"id", reflect.TypeOf((*int)(nil))},
				},
				RenderArgNames: map[int][]string{36: []string{"title", "hotel"}},
			},
			&MethodType{
				Name: "Book",
				Args: []*MethodArg{
					{"id", reflect.TypeOf((*int)(nil))},
				},
			},
		})

	RegisterController((*Static)(nil),
		[]*MethodType{
			&MethodType{
				Name: "Serve",
				Args: []*MethodArg{
					&MethodArg{Name: "prefix", Type: reflect.TypeOf((*string)(nil))},
					&MethodArg{Name: "filepath", Type: reflect.TypeOf((*string)(nil))},
				},
				RenderArgNames: map[int][]string{},
			},
		})

	plugins.OnAppStart()
}
<commit_msg>Add JSON benchmark to server_test<commit_after>package revel

import (
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"os"
	"path"
	"path/filepath"
	"reflect"
	"strings"
	"testing"
)

// A copy of the hotel struct from the sample app.
type Hotel struct {
	HotelId          int
	Name, Address    string
	City, State, Zip string
	Country          string
	Price            int
}

type Hotels struct {
	*Controller
}

type Static struct {
	*Controller
}

func (c Hotels) Show(id int) Result {
	title := "View Hotel"
	hotel := &Hotel{id, "A Hotel", "300 Main St.", "New York", "NY", "10010", "USA", 300}
	return c.Render(title, hotel)
}

func (c Hotels) Book(id int) Result {
	hotel := &Hotel{id, "A Hotel", "300 Main St.", "New York", "NY", "10010", "USA", 300}
	return c.RenderJson(hotel)
}

func (c Static) Serve(prefix, filepath string) Result {
	var basePath, dirName string

	if !path.IsAbs(dirName) {
		basePath = BasePath
	}

	fname := path.Join(basePath, prefix, filepath)
	file, err := os.Open(fname)
	if os.IsNotExist(err) {
		return c.NotFound("")
	} else if err != nil {
		WARN.Printf("Problem opening file (%s): %s ", fname, err)
		return c.NotFound("This was found but not sure why we couldn't open it.")
	}
	return c.RenderFile(file, "")
}

// This tries to benchmark the usual request-serving pipeline to get an overall
// performance metric.
//
// Each iteration runs one mock request to display a hotel's detail page by id.
//
// Contributing parts:
// - Routing
// - Controller lookup / invocation
// - Parameter binding
// - Session, flash, i18n cookies
// - Render() call magic
// - Template rendering
func BenchmarkServeAction(b *testing.B) {
	benchmarkRequest(b, showRequest)
}

func BenchmarkServeJson(b *testing.B) {
	benchmarkRequest(b, jsonRequest)
}

// This tries to benchmark the static serving overhead when serving an "average
// size" 7k file.
func BenchmarkServeStatic(b *testing.B) {
	benchmarkRequest(b, staticRequest)
}

func benchmarkRequest(b *testing.B, req *http.Request) {
	startFakeBookingApp()
	b.ResetTimer()
	resp := httptest.NewRecorder()
	for i := 0; i < b.N; i++ {
		handle(resp, req)
	}
}

// Test that the booking app can be successfully run for a test.
func TestFakeServer(t *testing.T) {
	startFakeBookingApp()

	resp := httptest.NewRecorder()

	// First, test that the expected responses are actually generated
	handle(resp, showRequest)
	if !strings.Contains(resp.Body.String(), "300 Main St.") {
		t.Errorf("Failed to find hotel address in action response:\n%s", resp.Body)
		t.FailNow()
	}
	resp.Body.Reset()

	handle(resp, staticRequest)
	if resp.Body.Len() != 6712 {
		t.Errorf("Expected sessvars.js to have 6712 bytes, got %d:\n%s", resp.Body.Len(), resp.Body)
		t.FailNow()
	}
	resp.Body.Reset()

	handle(resp, jsonRequest)
	if !strings.Contains(resp.Body.String(), `"Address":"300 Main St."`) {
		t.Errorf("Failed to find hotel address in JSON response:\n%s", resp.Body)
		t.FailNow()
	}

	resp.Body = nil
}

var (
	showRequest, _   = http.NewRequest("GET", "/hotels/3", nil)
	staticRequest, _ = http.NewRequest("GET", "/public/js/sessvars.js", nil)
	jsonRequest, _   = http.NewRequest("GET", "/hotels/3/booking", nil)
)

func startFakeBookingApp() {
	Init("", "github.com/robfig/revel/samples/booking", "")

	// Disable logging.
	TRACE = log.New(ioutil.Discard, "", 0)
	INFO = TRACE
	WARN = TRACE
	ERROR = TRACE

	MainRouter = NewRouter("")
	routesFile, _ := ioutil.ReadFile(filepath.Join(BasePath, "conf", "routes"))
	MainRouter.Routes, _ = parseRoutes("", string(routesFile), false)
	MainTemplateLoader = NewTemplateLoader([]string{ViewsPath, path.Join(RevelPath, "templates")})
	MainTemplateLoader.Refresh()

	RegisterController((*Hotels)(nil),
		[]*MethodType{
			&MethodType{
				Name: "Index",
			},
			&MethodType{
				Name: "Show",
				Args: []*MethodArg{
					{"id", reflect.TypeOf((*int)(nil))},
				},
				RenderArgNames: map[int][]string{36: []string{"title", "hotel"}},
			},
			&MethodType{
				Name: "Book",
				Args: []*MethodArg{
					{"id", reflect.TypeOf((*int)(nil))},
				},
			},
		})

	RegisterController((*Static)(nil),
		[]*MethodType{
			&MethodType{
				Name: "Serve",
				Args: []*MethodArg{
					&MethodArg{Name: "prefix", Type: reflect.TypeOf((*string)(nil))},
					&MethodArg{Name: "filepath", Type: reflect.TypeOf((*string)(nil))},
				},
				RenderArgNames: map[int][]string{},
			},
		})

	plugins.OnAppStart()
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestExpandPath(t *testing.T) {
	expected := opts.DataPath + "/foobar"
	actual := expandPath("foobar")
	if expected != actual {
		t.Errorf("Expected: '%s' Got: '%s'\n", expected, actual)
	}
}

func TestPutKeyWithoutNamespace(t *testing.T) {
	testPath := expandPath("foobar")
	testContent := "foobar"
	err := putKey(testPath, testContent)
	if err != nil {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPath); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestPutKeyWithNamespace(t *testing.T) {
	testPathDirectory := expandPath("foo/")
	testPathFile := expandPath("foo/bar")
	testContent := "foobar"
	err := putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}
	if fileInfo, err := os.Stat(testPathDirectory); err != nil || !fileInfo.IsDir() {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPathFile); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestDeleteKey(t *testing.T) {
	path := expandPath("foobar")
	content := "foobar"
	if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
		t.Errorf("Could not create key '%s'\n", path)
	}
	if err := ioutil.WriteFile(path, []byte(content), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", path, content)
	}
	deleteKey(path)
	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
		t.Error(err)
	}
}

func TestMain(m *testing.M) {
	opts.DataPath, _ = filepath.Abs("./data-test")
	exit := m.Run()
	os.RemoveAll(opts.DataPath)
	os.Exit(exit)
}
<commit_msg>add more tests<commit_after>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestExpandPath(t *testing.T) {
	expected := opts.DataPath + "/foobar"
	actual := expandPath("foobar")
	if expected != actual {
		t.Errorf("Expected: '%s' Got: '%s'\n", expected, actual)
	}
}

func TestPutKeyWithoutNamespace(t *testing.T) {
	cleanData()
	testPath := expandPath("foobar")
	testContent := "foobar"
	err := putKey(testPath, testContent)
	if err != nil {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPath); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestPutKeyWithNamespace(t *testing.T) {
	cleanData()
	testPathDirectory := expandPath("foo/")
	testPathFile := expandPath("foo/bar")
	testContent := "foobar"
	err := putKey(testPathFile, testContent)
	if err != nil {
		t.Fail()
	}
	if fileInfo, err := os.Stat(testPathDirectory); err != nil || !fileInfo.IsDir() {
		t.Fail()
	}
	if content, err := ioutil.ReadFile(testPathFile); err != nil || string(content) != testContent {
		t.Fail()
	}
}

func TestDeleteKey(t *testing.T) {
	cleanData()
	path := expandPath("foobar")
	content := "foobar"
	if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
		t.Errorf("Could not create key '%s'\n", path)
	}
	if err := ioutil.WriteFile(path, []byte(content), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", path, content)
	}
	deleteKey(path)
	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
		t.Error(err)
	}
}

func TestReadKeyWithoutNamespace(t *testing.T) {
	cleanData()
	testPath := expandPath("foobar")
	testContent := "foobar"
	if err := os.MkdirAll(filepath.Dir(testPath), os.ModePerm); err != nil {
		t.Errorf("Could not create key '%s'\n", testPath)
	}
	if err := ioutil.WriteFile(testPath, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPath, testContent)
	}

	results, isNamespace, err := readKey(testPath)
	if err != nil {
		t.Error(err)
	}
	if isNamespace {
		t.Error("Is namespaced value, but should not be.")
	}
	if len(results) != 1 || results[0] != testContent {
		t.Errorf("Too many results given (%+v) or first result has not expected content (%s).", results, testContent)
	}
}

func TestReadKeyWithNamespace(t *testing.T) {
	cleanData()
	testPathDirectory := expandPath("foo/")
	testPathFile1 := expandPath("foo/bar1")
	testPathFile2 := expandPath("foo/bar2")
	testContent := "foobar"
	if err := os.MkdirAll(testPathDirectory, os.ModePerm); err != nil {
		t.Errorf("Could not create directory '%s'\n", testPathDirectory)
	}
	if err := ioutil.WriteFile(testPathFile1, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPathFile1, testContent)
	}
	if err := ioutil.WriteFile(testPathFile2, []byte(testContent), os.ModePerm); err != nil {
		t.Errorf("Could not write file '%s' with content '%s'\n", testPathFile2, testContent)
	}

	results, isNamespace, err := readKey(testPathDirectory)
	if err != nil {
		t.Error(err)
	}
	if !isNamespace {
		t.Error("Is not namespaced value, but should be.")
	}
	if len(results) != 2 {
		t.Errorf("Too many/few results given (%+v).", results)
	}
}

func cleanData() {
	os.RemoveAll(opts.DataPath)
}

func TestMain(m *testing.M) {
	opts.DataPath, _ = filepath.Abs("./data-test")
	exit := m.Run()
	cleanData()
	os.Exit(exit)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Ben Morgan. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

package dist

type Null struct{}

func NewNull() *Null             { return &Null{} }
func (n *Null) Int63() int64     { return 0 }
func (n *Null) Float64() float64 { return 0.0 }
func (n *Null) Mean() float64    { return 0.0 }
func (n *Normal) Var() float64   { return 0.0 }
func (n *Normal) Std() float64   { return 0.0 }
func (n *Null) String() string   { return "null" }
<commit_msg>Bugfix: copy&paste error<commit_after>// Copyright (c) 2016, Ben Morgan. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

package dist

type Null struct{}

func NewNull() *Null            { return &Null{} }
func (n Null) Int63() int64     { return 0 }
func (n Null) Float64() float64 { return 0.0 }
func (n Null) Mean() float64    { return 0.0 }
func (n Null) Var() float64     { return 0.0 }
func (n Null) Std() float64     { return 0.0 }
func (n Null) String() string   { return "null" }
<|endoftext|>


<commit_before>// Package dlog provides logging functions with
// caller file and line information,
// logging levels and level and text filters.
package dlog

import (
	"bufio"
	"bytes"
	"fmt"

	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// Logging levels
const (
	NONE = iota
	ERROR
	WARN
	INFO
	VERBOSE
)

type logger func(bool, ...interface{})

var (
	byt         = bytes.NewBuffer(make([]byte, 0))
	debugLevel  = ERROR
	debugFilter = ""
	writer_p    *bufio.Writer
	logFunc     logger = dLog
)

func NOPlog(override bool, in ...interface{}) {}

// The primary function of the package,
// dLog prints out and writes to file a string
// containing the logged data seperated by spaces,
// prepended with file and line information.
// It only includes logs which pass the current filters.
func dLog(override bool, in ...interface{}) {
	//(pc uintptr, file string, line int, ok bool)
	_, f, line, ok := runtime.Caller(2)
	if ok {
		f = TruncateFileName(f)
		if !checkFilter(f, in) && !override {
			return
		}

		byt.WriteRune('[')
		byt.WriteString(f)
		byt.WriteRune(':')
		byt.WriteString(strconv.Itoa(line))
		byt.WriteString("]  ")
		for _, elem := range in {
			byt.WriteString(fmt.Sprintf("%v ", elem))
		}
		byt.WriteRune('\n')

		fmt.Print(byt.String())

		if writer_p != nil {
			writer := *writer_p
			writer.WriteString(byt.String())
			writer.Flush()
		}

		byt.Reset()
	}
}

func TruncateFileName(f string) string {
	index := strings.LastIndex(f, "/")
	lIndex := strings.LastIndex(f, ".")
	return f[index+1 : lIndex]
}

func checkFilter(f string, in ...interface{}) bool {
	ret := false
	for _, elem := range in {
		ret = ret || strings.Contains(fmt.Sprintf("%s", elem), debugFilter)
	}
	return ret || strings.Contains(f, debugFilter)
}

func SetDebugFilter(filter string) {
	debugFilter = filter
}

func SetDebugLevel(dL int) {
	if dL < NONE || dL > VERBOSE {
		Warn("Unknown debug level: ", dL)
		debugLevel = NONE
	} else {
		debugLevel = dL
	}
}

func CreateLogFile() {
	file := "../logs/dlog"
	file += time.Now().Format("_Jan_2_15-04-05_2006")
	file += ".txt"
	fHandle, _ := os.Create(file)
	writer_p = bufio.NewWriter(fHandle)
}

func Error(in ...interface{}) {
	if debugLevel > NONE {
		logFunc(true, in)
	}
}

func Warn(in ...interface{}) {
	if debugLevel > ERROR {
		logFunc(true, in)
	}
}

func Info(in ...interface{}) {
	if debugLevel > WARN {
		logFunc(false, in)
	}
}

func Verb(in ...interface{}) {
	if debugLevel > INFO {
		logFunc(false, in)
	}
}

func SetStringDebugLevel(debugL string) {

	var dLevel int
	switch debugL {
	case "INFO":
		dLevel = INFO
	case "VERBOSE":
		dLevel = VERBOSE
	case "ERROR":
		dLevel = ERROR
	case "WARN":
		dLevel = WARN
	case "NONE":
		dLevel = NONE
	default:
		dLevel = ERROR
		fmt.Println("setting dlog level to \"", debugL, "\" failed, it is now set to ERROR")
	}

	SetDebugLevel(dLevel)
}
<commit_msg>Updated to use RoomBlocks. Broke connections somehow<commit_after>// Package dlog provides logging functions with
// caller file and line information,
// logging levels and level and text filters.
package dlog

import (
	"bufio"
	"bytes"
	"fmt"

	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// Logging levels
const (
	NONE = iota
	ERROR
	WARN
	INFO
	VERBOSE
)

type logger func(bool, ...interface{})

var (
	byt         = bytes.NewBuffer(make([]byte, 0))
	debugLevel  = ERROR
	debugFilter = ""
	writer_p    *bufio.Writer
	logFunc     logger = dLog
)

func NOPlog(override bool, in ...interface{}) {}

// The primary function of the package,
// dLog prints out and writes to file a string
// containing the logged data separated by spaces,
// prepended with file and line information.
// It only includes logs which pass the current filters.
func dLog(override bool, in ...interface{}) {
	//(pc uintptr, file string, line int, ok bool)
	_, f, line, ok := runtime.Caller(2)
	if ok {
		f = TruncateFileName(f)
		if !checkFilter(f, in) && !override {
			return
		}

		byt.WriteRune('[')
		byt.WriteString(f)
		byt.WriteRune(':')
		byt.WriteString(strconv.Itoa(line))
		byt.WriteString("]  ")
		for _, elem := range in {
			byt.WriteString(fmt.Sprintf("%v ", elem))
		}
		byt.WriteRune('\n')

		fmt.Print(byt.String())

		if writer_p != nil {
			writer := *writer_p
			writer.WriteString(byt.String())
			writer.Flush()
		}

		byt.Reset()
	}
}

func TruncateFileName(f string) string {
	index := strings.LastIndex(f, "/")
	lIndex := strings.LastIndex(f, ".")
	return f[index+1 : lIndex]
}

func checkFilter(f string, in ...interface{}) bool {
	ret := false
	for _, elem := range in {
		ret = ret || strings.Contains(fmt.Sprintf("%s", elem), debugFilter)
	}
	return ret || strings.Contains(f, debugFilter)
}

func SetDebugFilter(filter string) {
	debugFilter = filter
}

func SetDebugLevel(dL int) {
	if dL < NONE || dL > VERBOSE {
		Warn("Unknown debug level: ", dL)
		debugLevel = NONE
	} else {
		debugLevel = dL
	}
}

func CreateLogFile() {
	file := "../logs/dlog"
	file += time.Now().Format("_Jan_2_15-04-05_2006")
	file += ".txt"
	fHandle, _ := os.Create(file)
	writer_p = bufio.NewWriter(fHandle)
}

func Error(in ...interface{}) {
	if debugLevel > NONE {
		logFunc(true, in)
	}
}

func Warn(in ...interface{}) {
	if debugLevel > ERROR {
		logFunc(true, in)
	}
}

func Info(in ...interface{}) {
	if debugLevel > WARN {
		logFunc(false, in)
	}
}

func Verb(in ...interface{}) {
	if debugLevel > INFO {
		logFunc(false, in)
	}
}

func SetStringDebugLevel(debugL string) {

	var dLevel int
	switch debugL {
	case "INFO":
		dLevel = INFO
	case "VERBOSE":
		dLevel = VERBOSE
	case "ERROR":
		dLevel = ERROR
	case "WARN":
		dLevel = WARN
	case "NONE":
		dLevel = NONE
	default:
		dLevel = ERROR
		fmt.Println("setting dlog level to \"", debugL, "\" failed, it is now set to ERROR")
	}

	SetDebugLevel(dLevel)
}
<|endoftext|>


<commit_before>/*
   Copyright The containerd 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 namespaces

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/containerd/containerd/cmd/ctr/commands"
	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/log"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

// Command is the cli command for managing namespaces
var Command = cli.Command{
	Name:    "namespaces",
	Aliases: []string{"namespace"},
	Usage:   "manage namespaces",
	Subcommands: cli.Commands{
		createCommand,
		listCommand,
		removeCommand,
		setLabelsCommand,
	},
}

var createCommand = cli.Command{
	Name:        "create",
	Usage:       "create a new namespace",
	ArgsUsage:   "<name> [<key>=<value]",
	Description: "create a new namespace. it must be unique",
	Action: func(context *cli.Context) error {
		namespace, labels := commands.ObjectWithLabelArgs(context)
		if namespace == "" {
			return errors.New("please specify a namespace")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		namespaces := client.NamespaceService()
		return namespaces.Create(ctx, namespace, labels)
	},
}

var setLabelsCommand = cli.Command{
	Name:        "label",
	Usage:       "set and clear labels for a namespace",
	ArgsUsage:   "<name> [<key>=<value>, ...]",
	Description: "set and clear labels for a namespace",
	Action: func(context *cli.Context) error {
		namespace, labels := commands.ObjectWithLabelArgs(context)
		if namespace == "" {
			return errors.New("please specify a namespace")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		namespaces := client.NamespaceService()
		for k, v := range labels {
			if err := namespaces.SetLabel(ctx, namespace, k, v); err != nil {
				return err
			}
		}
		return nil
	},
}

var listCommand = cli.Command{
	Name:        "list",
	Aliases:     []string{"ls"},
	Usage:       "list namespaces",
	ArgsUsage:   "[flags]",
	Description: "list namespaces",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "print only the namespace name",
		},
	},
	Action: func(context *cli.Context) error {
		quiet := context.Bool("quiet")
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		namespaces := client.NamespaceService()
		nss, err := namespaces.List(ctx)
		if err != nil {
			return err
		}

		if quiet {
			for _, ns := range nss {
				fmt.Println(ns)
			}
			return nil
		}

		tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
		fmt.Fprintln(tw, "NAME\tLABELS\t")
		for _, ns := range nss {
			labels, err := namespaces.Labels(ctx, ns)
			if err != nil {
				return err
			}

			var labelStrings []string
			for k, v := range labels {
				labelStrings = append(labelStrings, strings.Join([]string{k, v}, "="))
			}
			sort.Strings(labelStrings)

			fmt.Fprintf(tw, "%v\t%v\t\n", ns, strings.Join(labelStrings, ","))
		}
		return tw.Flush()
	},
}

var removeCommand = cli.Command{
	Name:        "remove",
	Aliases:     []string{"rm"},
	Usage:       "remove one or more namespaces",
	ArgsUsage:   "<name> [<name>, ...]",
	Description: "remove one or more namespaces. for now, the namespace must be empty",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "cgroup,c",
			Usage: "delete the namespace's cgroup",
		},
	},
	Action: func(context *cli.Context) error {
		var exitErr error
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()

		opts := deleteOpts(context)
		namespaces := client.NamespaceService()
		for _, target := range context.Args() {
			if err := namespaces.Delete(ctx, target, opts...); err != nil {
				if !errdefs.IsNotFound(err) {
					if exitErr == nil {
						exitErr = errors.Wrapf(err, "unable to delete %v", target)
					}
					log.G(ctx).WithError(err).Errorf("unable to delete %v", target)
					continue
				}

			}

			fmt.Println(target)
		}
		return exitErr
	},
}
<commit_msg>Add aliases to namespaces subcommand<commit_after>/*
   Copyright The containerd 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 namespaces

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/containerd/containerd/cmd/ctr/commands"
	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/log"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

// Command is the cli command for managing namespaces
var Command = cli.Command{
	Name:    "namespaces",
	Aliases: []string{"namespace", "ns"},
	Usage:   "manage namespaces",
	Subcommands: cli.Commands{
		createCommand,
		listCommand,
		removeCommand,
		setLabelsCommand,
	},
}

var createCommand = cli.Command{
	Name:        "create",
	Aliases:     []string{"c"},
	Usage:       "create a new namespace",
	ArgsUsage:   "<name> [<key>=<value]",
	Description: "create a new namespace. it must be unique",
	Action: func(context *cli.Context) error {
		namespace, labels := commands.ObjectWithLabelArgs(context)
		if namespace == "" {
			return errors.New("please specify a namespace")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		namespaces := client.NamespaceService()
		return namespaces.Create(ctx, namespace, labels)
	},
}

var setLabelsCommand = cli.Command{
	Name:        "label",
	Usage:       "set and clear labels for a namespace",
	ArgsUsage:   "<name> [<key>=<value>, ...]",
	Description: "set and clear labels for a namespace",
	Action: func(context *cli.Context) error {
		namespace, labels := commands.ObjectWithLabelArgs(context)
		if namespace == "" {
			return errors.New("please specify a namespace")
		}
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		namespaces := client.NamespaceService()
		for k, v := range labels {
			if err := namespaces.SetLabel(ctx, namespace, k, v); err != nil {
				return err
			}
		}
		return nil
	},
}

var listCommand = cli.Command{
	Name:        "list",
	Aliases:     []string{"ls"},
	Usage:       "list namespaces",
	ArgsUsage:   "[flags]",
	Description: "list namespaces",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "quiet, q",
			Usage: "print only the namespace name",
		},
	},
	Action: func(context *cli.Context) error {
		quiet := context.Bool("quiet")
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()
		namespaces := client.NamespaceService()
		nss, err := namespaces.List(ctx)
		if err != nil {
			return err
		}

		if quiet {
			for _, ns := range nss {
				fmt.Println(ns)
			}
			return nil
		}

		tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
		fmt.Fprintln(tw, "NAME\tLABELS\t")
		for _, ns := range nss {
			labels, err := namespaces.Labels(ctx, ns)
			if err != nil {
				return err
			}

			var labelStrings []string
			for k, v := range labels {
				labelStrings = append(labelStrings, strings.Join([]string{k, v}, "="))
			}
			sort.Strings(labelStrings)

			fmt.Fprintf(tw, "%v\t%v\t\n", ns, strings.Join(labelStrings, ","))
		}
		return tw.Flush()
	},
}

var removeCommand = cli.Command{
	Name:        "remove",
	Aliases:     []string{"rm"},
	Usage:       "remove one or more namespaces",
	ArgsUsage:   "<name> [<name>, ...]",
	Description: "remove one or more namespaces. for now, the namespace must be empty",
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "cgroup,c",
			Usage: "delete the namespace's cgroup",
		},
	},
	Action: func(context *cli.Context) error {
		var exitErr error
		client, ctx, cancel, err := commands.NewClient(context)
		if err != nil {
			return err
		}
		defer cancel()

		opts := deleteOpts(context)
		namespaces := client.NamespaceService()
		for _, target := range context.Args() {
			if err := namespaces.Delete(ctx, target, opts...); err != nil {
				if !errdefs.IsNotFound(err) {
					if exitErr == nil {
						exitErr = errors.Wrapf(err, "unable to delete %v", target)
					}
					log.G(ctx).WithError(err).Errorf("unable to delete %v", target)
					continue
				}

			}

			fmt.Println(target)
		}
		return exitErr
	},
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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 featuregate

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestRegistry(t *testing.T) {
	r := Registry{gates: map[string]Gate{}}

	gate := Gate{
		ID:          "foo",
		Description: "Test Gate",
		Enabled:     true,
	}

	assert.Empty(t, r.List())
	assert.False(t, r.IsEnabled(gate.ID))

	assert.NoError(t, r.Register(gate))
	assert.Len(t, r.List(), 1)
	assert.True(t, r.IsEnabled(gate.ID))

	assert.NoError(t, r.Apply(map[string]bool{gate.ID: false}))
	assert.False(t, r.IsEnabled(gate.ID))

	assert.Error(t, r.Register(gate))
	assert.Panics(t, func() {
		r.MustRegister(gate)
	})
}

func TestRegistryWithErrorApply(t *testing.T) {
	r := Registry{gates: map[string]Gate{}}

	assert.NoError(t, r.Register(Gate{
		ID:          "foo",
		Description: "Test Gate",
		stage:       Alpha,
	}))
	assert.NoError(t, r.Register(Gate{
		ID:             "stable-foo",
		Description:    "Test Gate",
		stage:          Stable,
		removalVersion: "next",
	}))

	tests := []struct {
		name        string
		gate        string
		enabled     bool
		shouldError bool
	}{
		{
			name:        "existing_gate",
			gate:        "foo",
			enabled:     false,
			shouldError: false,
		},
		{
			name:        "none_existing_gate",
			gate:        "bar",
			enabled:     false,
			shouldError: true,
		},
		{
			name:        "stable gate modified",
			gate:        "stable-foo",
			enabled:     false,
			shouldError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if tt.shouldError {
				assert.Error(t, r.Apply(map[string]bool{tt.gate: tt.enabled}))
				return
			}
			assert.NoError(t, r.Apply(map[string]bool{tt.gate: tt.enabled}))
			assert.Equal(t, tt.enabled, r.IsEnabled(tt.gate))
		})
	}
}

func TestRegisterGateLifecycle(t *testing.T) {
	for _, tc := range []struct {
		name      string
		id        string
		stage     Stage
		opts      []RegistryOption
		enabled   bool
		shouldErr bool
	}{
		{
			name:      "Alpha Flag",
			id:        "test-gate",
			stage:     Alpha,
			enabled:   false,
			shouldErr: false,
		},
		{
			name:  "Alpha Flag with all options",
			id:    "test-gate",
			stage: Alpha,
			opts: []RegistryOption{
				WithRegisterDescription("test-gate"),
				WithRegisterReferenceURL("http://example.com/issue/1"),
				WithRegisterRemovalVersion(""),
			},
			enabled:   false,
			shouldErr: false,
		},
		{
			name:      "Beta Flag",
			id:        "test-gate",
			stage:     Beta,
			enabled:   true,
			shouldErr: false,
		},
		{
			name:  "Stable Flag",
			id:    "test-gate",
			stage: Stable,
			opts: []RegistryOption{
				WithRegisterRemovalVersion("next"),
			},
			enabled:   true,
			shouldErr: false,
		},
		{
			name:      "Invalid stage",
			id:        "test-gate",
			stage:     Stage(-1),
			shouldErr: true,
		},
		{
			name:      "Stable gate missing removal version",
			id:        "test-gate",
			stage:     Stable,
			shouldErr: true,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			r := NewRegistry()
			if tc.shouldErr {
				assert.Error(t, r.RegisterID(tc.id, tc.stage, tc.opts...), "Must error when registering gate")
				assert.Panics(t, func() {
					r.MustRegisterID(tc.id, tc.stage, tc.opts...)
				})
				return
			}
			assert.NoError(t, r.RegisterID(tc.id, tc.stage, tc.opts...), "Must not error when registering feature gate")
			assert.Equal(t, tc.enabled, r.IsEnabled(tc.id), "Must match the expected enabled value")
		})
	}
}

func TestGateMethods(t *testing.T) {
	g := &Gate{
		ID:             "test",
		Description:    "test gate",
		Enabled:        false,
		stage:          Alpha,
		referenceURL:   "http://example.com",
		removalVersion: "v0.64.0",
	}

	assert.Equal(t, "test", g.GetID())
	assert.Equal(t, "test gate", g.GetDescription())
	assert.Equal(t, false, g.IsEnabled())
	assert.Equal(t, Alpha, g.GetStage())
	assert.Equal(t, "http://example.com", g.GetReferenceURL())
	assert.Equal(t, "v0.64.0", g.GetRemovalVersion())
}

func TestStageNames(t *testing.T) {
	for expected, s := range map[string]Stage{
		"Alpha":   Alpha,
		"Beta":    Beta,
		"Stable":  Stable,
		"unknown": Stage(-1),
	} {
		assert.Equal(t, expected, s.String())
	}
}
<commit_msg>Improving test coverage<commit_after>// Copyright The OpenTelemetry 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 featuregate

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestRegistry(t *testing.T) {
	r := Registry{gates: map[string]Gate{}}

	gate := Gate{
		ID:          "foo",
		Description: "Test Gate",
		Enabled:     true,
	}

	assert.Empty(t, r.List())
	assert.False(t, r.IsEnabled(gate.ID))

	assert.NoError(t, r.Register(gate))
	assert.Len(t, r.List(), 1)
	assert.True(t, r.IsEnabled(gate.ID))

	assert.NoError(t, r.Apply(map[string]bool{gate.ID: false}))
	assert.False(t, r.IsEnabled(gate.ID))

	assert.Error(t, r.Register(gate))
	assert.Panics(t, func() {
		r.MustRegister(gate)
	})
}

func TestRegistryWithErrorApply(t *testing.T) {
	r := Registry{gates: map[string]Gate{}}

	assert.NoError(t, r.Register(Gate{
		ID:          "foo",
		Description: "Test Gate",
		stage:       Alpha,
	}))
	assert.NoError(t, r.Register(Gate{
		ID:             "stable-foo",
		Description:    "Test Gate",
		stage:          Stable,
		removalVersion: "next",
	}))

	tests := []struct {
		name        string
		gate        string
		enabled     bool
		shouldError bool
	}{
		{
			name:        "existing_gate",
			gate:        "foo",
			enabled:     false,
			shouldError: false,
		},
		{
			name:        "none_existing_gate",
			gate:        "bar",
			enabled:     false,
			shouldError: true,
		},
		{
			name:        "stable gate modified",
			gate:        "stable-foo",
			enabled:     false,
			shouldError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if tt.shouldError {
				assert.Error(t, r.Apply(map[string]bool{tt.gate: tt.enabled}))
				return
			}
			assert.NoError(t, r.Apply(map[string]bool{tt.gate: tt.enabled}))
			assert.Equal(t, tt.enabled, r.IsEnabled(tt.gate))
		})
	}
}

func TestRegisterGateLifecycle(t *testing.T) {
	for _, tc := range []struct {
		name      string
		id        string
		stage     Stage
		opts      []RegistryOption
		enabled   bool
		shouldErr bool
	}{
		{
			name:      "Alpha Flag",
			id:        "test-gate",
			stage:     Alpha,
			enabled:   false,
			shouldErr: false,
		},
		{
			name:  "Alpha Flag with all options",
			id:    "test-gate",
			stage: Alpha,
			opts: []RegistryOption{
				WithRegisterDescription("test-gate"),
				WithRegisterReferenceURL("http://example.com/issue/1"),
				WithRegisterRemovalVersion(""),
			},
			enabled:   false,
			shouldErr: false,
		},
		{
			name:      "Beta Flag",
			id:        "test-gate",
			stage:     Beta,
			enabled:   true,
			shouldErr: false,
		},
		{
			name:  "Stable Flag",
			id:    "test-gate",
			stage: Stable,
			opts: []RegistryOption{
				WithRegisterRemovalVersion("next"),
			},
			enabled:   true,
			shouldErr: false,
		},
		{
			name:      "Invalid stage",
			id:        "test-gate",
			stage:     Stage(-1),
			shouldErr: true,
		},
		{
			name:      "Stable gate missing removal version",
			id:        "test-gate",
			stage:     Stable,
			shouldErr: true,
		},
		{
			name:      "Duplicate gate",
			id:        "existing-gate",
			stage:     Stable,
			shouldErr: true,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			r := NewRegistry()
			require.NoError(t, r.RegisterID("existing-gate", Beta))
			if tc.shouldErr {
				assert.Error(t, r.RegisterID(tc.id, tc.stage, tc.opts...), "Must error when registering gate")
				assert.Panics(t, func() {
					r.MustRegisterID(tc.id, tc.stage, tc.opts...)
				})
				return
			}
			assert.NoError(t, r.RegisterID(tc.id, tc.stage, tc.opts...), "Must not error when registering feature gate")
			assert.Equal(t, tc.enabled, r.IsEnabled(tc.id), "Must match the expected enabled value")
		})
	}
}

func TestGateMethods(t *testing.T) {
	g := &Gate{
		ID:             "test",
		Description:    "test gate",
		Enabled:        false,
		stage:          Alpha,
		referenceURL:   "http://example.com",
		removalVersion: "v0.64.0",
	}

	assert.Equal(t, "test", g.GetID())
	assert.Equal(t, "test gate", g.GetDescription())
	assert.Equal(t, false, g.IsEnabled())
	assert.Equal(t, Alpha, g.GetStage())
	assert.Equal(t, "http://example.com", g.GetReferenceURL())
	assert.Equal(t, "v0.64.0", g.GetRemovalVersion())
}

func TestStageNames(t *testing.T) {
	for expected, s := range map[string]Stage{
		"Alpha":   Alpha,
		"Beta":    Beta,
		"Stable":  Stable,
		"unknown": Stage(-1),
	} {
		assert.Equal(t, expected, s.String())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/alewmoose/show-lyrics/fetcher/azlyrics"
	"github.com/alewmoose/show-lyrics/player/cmus"
	"github.com/alewmoose/show-lyrics/player/mocp"
	"github.com/alewmoose/show-lyrics/songinfo"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"
	"syscall"
)

func main() {
	home := os.Getenv("HOME")
	if home == "" {
		log.Fatal("HOME not found")
	}

	songinfo, err := getSongInfo()
	if err != nil {
		log.Fatal(err)
	}

	artistP := replaceSlashes(songinfo.Artist)
	titleP := replaceSlashes(songinfo.Title)

	dotDir := path.Join(home, ".show-lyrics")
	cacheDir := path.Join(dotDir, "cache")
	cacheArtistDir := path.Join(cacheDir, artistP)
	songFile := path.Join(cacheArtistDir, titleP+".txt")

	_, err = os.Stat(songFile)
	if err == nil {
		err := execLess(songFile)
		if err != nil {
			log.Fatal(err)
		}
	}

	for _, dir := range []string{dotDir, cacheDir, cacheArtistDir} {
		err := mkdirUnlessExists(dir)
		if err != nil {
			log.Fatal(err)
		}
	}

	client := &http.Client{}

	lyrics, err := azlyrics.Fetch(client, songinfo)
	if err != nil {
		log.Fatal(err)
	}

	lyrics = prepareLyrics(songinfo, lyrics)

	err = ioutil.WriteFile(songFile, lyrics, 0644)
	if err != nil {
		log.Fatal(err)
	}

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

func getSongInfo() (*songinfo.SongInfo, error) {
	type songInfoResult struct {
		songinfo *songinfo.SongInfo
		err error
	}

	cmusSi, cmusErr := cmus.GetSongInfo()
	mocpSi, mocpErr := mocp.GetSongInfo()

	if cmusErr != nil && mocpErr != nil {
		return nil, errors.New("No players running")
	}
	if mocpErr != nil {
		return cmusSi, nil
	}
	return mocpSi, nil
}

func prepareLyrics(si *songinfo.SongInfo, lyrics []byte) []byte {
	title := si.PrettyTitle()
	return []byte(title + "\n\n" + string(lyrics) + "\n")
}

func replaceSlashes(s string) string {
	return strings.Replace(s, "/", "_", -1)
}

func execLess(file string) error {
	lessBin, err := exec.LookPath("less")
	if err != nil {
		return err
	}
	err = syscall.Exec(lessBin, []string{"less", "-c", file}, os.Environ())
	if err != nil {
		return err
	}
	return nil
}

func mkdirUnlessExists(dir string) error {
	_, err := os.Stat(dir)
	if err != nil {
		err = os.Mkdir(dir, 0755)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Retry without parens<commit_after>package main

import (
	"errors"
	"github.com/alewmoose/show-lyrics/fetcher/azlyrics"
	"github.com/alewmoose/show-lyrics/player/cmus"
	"github.com/alewmoose/show-lyrics/player/mocp"
	"github.com/alewmoose/show-lyrics/songinfo"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"regexp"
	"strings"
	"syscall"
)

func main() {
	home := os.Getenv("HOME")
	if home == "" {
		log.Fatal("HOME not found")
	}

	songinfo, err := getSongInfo()
	if err != nil {
		log.Fatal(err)
	}

	artistP := replaceSlashes(songinfo.Artist)
	titleP := replaceSlashes(songinfo.Title)

	dotDir := path.Join(home, ".show-lyrics")
	cacheDir := path.Join(dotDir, "cache")
	cacheArtistDir := path.Join(cacheDir, artistP)
	songFile := path.Join(cacheArtistDir, titleP+".txt")

	_, err = os.Stat(songFile)
	if err == nil {
		err := execLess(songFile)
		if err != nil {
			log.Fatal(err)
		}
	}

	for _, dir := range []string{dotDir, cacheDir, cacheArtistDir} {
		err := mkdirUnlessExists(dir)
		if err != nil {
			log.Fatal(err)
		}
	}

	client := &http.Client{}

	lyrics, err := fetchLyrics(client, songinfo)
	if err != nil {
		log.Fatal(err)
	}

	lyrics = prepareLyrics(songinfo, lyrics)

	err = ioutil.WriteFile(songFile, lyrics, 0644)
	if err != nil {
		log.Fatal(err)
	}

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

var parensRe = regexp.MustCompile(`\(.+\)$`)

func fetchLyrics(c *http.Client, si *songinfo.SongInfo) ([]byte, error) {
	lyrics, err := azlyrics.Fetch(c, si)
	if err == nil {
		return lyrics, err
	}
	if err.Error() != "404 Not Found" {
		return lyrics, err
	}
	if parensRe.MatchString(si.Title) == false {
		return lyrics, err
	}
	title := parensRe.ReplaceAllString(si.Title, "")
	if len(title) == 0 {
		return lyrics, err
	}
	newSi := songinfo.SongInfo{Artist: si.Artist, Title: title}
	return fetchLyrics(c, &newSi)
}

func getSongInfo() (*songinfo.SongInfo, error) {
	type songInfoResult struct {
		songinfo *songinfo.SongInfo
		err      error
	}

	cmusSi, cmusErr := cmus.GetSongInfo()
	mocpSi, mocpErr := mocp.GetSongInfo()

	if cmusErr != nil && mocpErr != nil {
		return nil, errors.New("No players running")
	}
	if mocpErr != nil {
		return cmusSi, nil
	}
	return mocpSi, nil
}

func prepareLyrics(si *songinfo.SongInfo, lyrics []byte) []byte {
	title := si.PrettyTitle()
	return []byte(title + "\n\n" + string(lyrics) + "\n")
}

func replaceSlashes(s string) string {
	return strings.Replace(s, "/", "_", -1)
}

func execLess(file string) error {
	lessBin, err := exec.LookPath("less")
	if err != nil {
		return err
	}
	err = syscall.Exec(lessBin, []string{"less", "-c", file}, os.Environ())
	if err != nil {
		return err
	}
	return nil
}

func mkdirUnlessExists(dir string) error {
	_, err := os.Stat(dir)
	if err != nil {
		err = os.Mkdir(dir, 0755)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package mango

import (
	"bytes"
	"template"
)

func ShowErrors(templateString string) Middleware {
	if templateString == "" {
		templateString = `

          {{.Error|html}}

    `
	}

	errorTemplate := template.Must(template.New("error").Parse(templateString))

	return func(env Env, app App) (status Status, headers Headers, body Body) {
		defer func() {
			if err := recover(); err != nil {
				buffer := bytes.NewBufferString("")
				errorTemplate.Execute(buffer, struct{ Error string }{err.(string)})
				status = 500
				headers = Headers{}
				body = Body(buffer.String())
			}
		}()

		return app(env)
	}
}
<commit_msg>making show_errors more robust<commit_after>package mango

import (
	"bytes"
	"template"
)

func ShowErrors(templateString string) Middleware {
	if templateString == "" {
		templateString = `

          {{.Error|html}}

    `
	}

	errorTemplate := template.Must(template.New("error").Parse(templateString))

	return func(env Env, app App) (status Status, headers Headers, body Body) {
		defer func() {
			if err := recover(); err != nil {
				buffer := bytes.NewBufferString("")
				errorTemplate.Execute(buffer, struct{ Error string }{fmt.Sprintf("%s", err)})
				status = 500
				headers = Headers{}
				body = Body(buffer.String())
			}
		}()

		return app(env)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"net/http"
	"runtime"
	"strconv"
	"strings"

	"github.com/inconshreveable/go-update"
)

const VERSION = "0.1.0"

var updateURL = "http://23.239.14.98/releases/" + runtime.GOOS + "_" + runtime.GOARCH + "/current/"

// returns true if version is "greater than" VERSION.
func newerVersion(version string) bool {
	// super naive; assumes same number of .s
	// TODO: make this more robust... if it's worth the effort.
	nums := strings.Split(version, ".")
	NUMS := strings.Split(VERSION, ".")
	for i := range nums {
		// inputs are trusted, so no need to check the error
		ni, _ := strconv.Atoi(nums[i])
		Ni, _ := strconv.Atoi(NUMS[i])
		if ni > Ni {
			return true
		}
	}
	return false
}

// helper function that requests and parses the update manifest. It returns a
// boolean indicating whether an update is available, and a list of urls
// pointing to files targeted by the update.
func fetchManifest() (bool, []string, error) {
	resp, err := http.Get(updateURL + "MANIFEST")
	if err != nil {
		return false, nil, err
	}
	defer resp.Body.Close()
	manifest, _ := ioutil.ReadAll(resp.Body)
	lines := strings.Split(strings.TrimSpace(string(manifest)), "\n")
	return newerVersion(lines[0]), lines[1:], nil
}

// checkForUpdate checks a centralized server for a more recent version of
// Sia, and returns true if an update is available.
func (d *daemon) checkForUpdate() (bool, error) {
	avail, _, err := fetchManifest()
	return avail, err
}

// applyUpdate downloads and applies an update. If Sia is up to date,
// applyUpdate is a no-op.
//
// TODO: lots of room for improvement here.
//   - binary diffs
//   - signed updates
//   - zipped updates
//   - ability to apply a specific update
func (d *daemon) applyUpdate() (applied bool, err error) {
	avail, files, err := fetchManifest()
	if !avail || err != nil {
		return
	}

	for _, file := range files {
		err, _ = update.New().Target(file).FromUrl(updateURL + file)
		if err != nil {
			// TODO: revert prior successful updates?
			break
		}
	}
	return
}
<commit_msg>add update docstring<commit_after>package main

import (
	"io/ioutil"
	"net/http"
	"runtime"
	"strconv"
	"strings"

	"github.com/inconshreveable/go-update"
)

const VERSION = "0.1.0"

// Updates work like this: each version is stored in a folder on a Linode
// server operated by the developers The most recent version is stored in
// current/. The folder contains the files changed by the update, as well as a
// MANIFEST file that contains the version number and a file listing. To check
// for an update, we first read the version number from current/MANIFEST. If
// the version is newer, we download and apply the files listed in the update
// manifest.
var updateURL = "http://23.239.14.98/releases/" + runtime.GOOS + "_" + runtime.GOARCH + "/current/"

// returns true if version is "greater than" VERSION.
func newerVersion(version string) bool {
	// super naive; assumes same number of .s
	// TODO: make this more robust... if it's worth the effort.
	nums := strings.Split(version, ".")
	NUMS := strings.Split(VERSION, ".")
	for i := range nums {
		// inputs are trusted, so no need to check the error
		ni, _ := strconv.Atoi(nums[i])
		Ni, _ := strconv.Atoi(NUMS[i])
		if ni > Ni {
			return true
		}
	}
	return false
}

// helper function that requests and parses the update manifest. It returns a
// boolean indicating whether an update is available, and a list of urls
// pointing to files targeted by the update.
func fetchManifest() (bool, []string, error) {
	resp, err := http.Get(updateURL + "MANIFEST")
	if err != nil {
		return false, nil, err
	}
	defer resp.Body.Close()
	manifest, _ := ioutil.ReadAll(resp.Body)
	lines := strings.Split(strings.TrimSpace(string(manifest)), "\n")
	return newerVersion(lines[0]), lines[1:], nil
}

// checkForUpdate checks a centralized server for a more recent version of
// Sia, and returns true if an update is available.
func (d *daemon) checkForUpdate() (bool, error) {
	avail, _, err := fetchManifest()
	return avail, err
}

// applyUpdate downloads and applies an update. If Sia is up to date,
// applyUpdate is a no-op.
//
// TODO: lots of room for improvement here.
//   - binary diffs
//   - signed updates
//   - zipped updates
//   - ability to apply a specific update
func (d *daemon) applyUpdate() (applied bool, err error) {
	avail, files, err := fetchManifest()
	if !avail || err != nil {
		return
	}

	for _, file := range files {
		err, _ = update.New().Target(file).FromUrl(updateURL + file)
		if err != nil {
			// TODO: revert prior successful updates?
			break
		}
	}
	return
}
<|endoftext|>


<commit_before>package sink

import (
	"time"

	log "github.com/Sirupsen/logrus"
)

// StdoutSink ...
type StdoutSink struct {
	stopCh chan interface{}
	putCh  chan []byte
}

// NewStdout ...
func NewStdout() (*StdoutSink, error) {
	return &StdoutSink{
		stopCh: make(chan interface{}),
		putCh:  make(chan []byte, 1000),
	}, nil
}

// Start ...
func (s *StdoutSink) Start() error {
	// Stop chan for all tasks to depend on
	s.stopCh = make(chan interface{})

	// wait forever for a stop signal to happen
	for {
		select {
		case <-s.stopCh:
			break
		}
		break
	}

	return nil
}

// Stop ...
func (s *StdoutSink) Stop() {
	log.Infof("[sink/stdout] ensure writer queue is empty (%d messages left)", len(s.putCh))

	for len(s.putCh) > 0 {
		log.Info("[sink/stdout] Waiting for queue to drain - (%d messages left)", len(s.putCh))
		time.Sleep(1 * time.Second)
	}

	close(s.stopCh)
}

// Put ..
func (s *StdoutSink) Put(data []byte) error {
	log.Infof("[sink/stdout] %s", string(data))
	return nil
}
<commit_msg>use fmt.Println for stdout sink<commit_after>package sink

import (
	"time"
	"fmt"
	log "github.com/Sirupsen/logrus"
)

// StdoutSink ...
type StdoutSink struct {
	stopCh chan interface{}
	putCh  chan []byte
}

// NewStdout ...
func NewStdout() (*StdoutSink, error) {
	return &StdoutSink{
		stopCh: make(chan interface{}),
		putCh:  make(chan []byte, 1000),
	}, nil
}

// Start ...
func (s *StdoutSink) Start() error {
	// Stop chan for all tasks to depend on
	s.stopCh = make(chan interface{})

	// wait forever for a stop signal to happen
	for {
		select {
		case <-s.stopCh:
			break
		}
		break
	}

	return nil
}

// Stop ...
func (s *StdoutSink) Stop() {
	log.Infof("[sink/stdout] ensure writer queue is empty (%d messages left)", len(s.putCh))

	for len(s.putCh) > 0 {
		log.Info("[sink/stdout] Waiting for queue to drain - (%d messages left)", len(s.putCh))
		time.Sleep(1 * time.Second)
	}

	close(s.stopCh)
}

// Put ..
func (s *StdoutSink) Put(data []byte) error {
	fmt.Println(string(data))
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 FullStory, Inc.
//
// 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 smutil

import (
	"errors"
	"fmt"
	"net"
	"strings"

	"github.com/samuel/go-zookeeper/zk"
)

// ParseNodeName parses a solr node identifier into an IP, a port, and a suffix.
func ParseNodeName(node string) (string, string, string, error) {
	parts := strings.SplitN(node, "_", 2)
	if len(parts) != 2 {
		return "", "", "", errors.New("malformed: no underscore present")
	}

	if ip, port, err := net.SplitHostPort(parts[0]); err != nil {
		return "", "", "", fmt.Errorf("%q is not a valid socket", parts[0])
	} else {
		return ip, port, parts[1], nil
	}
}

// GetHostname performs an address lookup on the ip portion of e.g. `127.0.0.1:8983_solr` and returns the first hostname returned.
// If the lookup fails, then ip is returned.
func GetHostname(solrNode string) string {
	ip, _, _, err := ParseNodeName(solrNode)
	if err != nil {
		return ""
	}
	if names, err := net.LookupAddr(ip); err != nil {
		return ip // fall back to just using the IP
	} else {
		// Just return the first part of the hostname
		hostname := names[0]
		i := strings.Index(hostname, ".")
		if i > -1 {
			hostname = hostname[:i]
		}
		return hostname
	}
}

// ResolveNode performs a DNS resolve on the hostname and return an IP on ip and returns the first hostname returned.
// If the lookup fails, hostName is returned.
func ResolveNode(hostName string) string {
	ip, err := net.ResolveIPAddr("tcp", hostName)
	if err != nil {
		return hostName
	}
	return ip.String()
}

// delete the specified path and its children, recursively.
func DeleteRecursive(c *zk.Conn, path string) error {
	children, _, err := c.Children(path)
	if err != nil {
		if err == zk.ErrNoNode {
			// if the node doesn't even exist, we are done!
			return nil
		}
		return err
	}

	for _, child := range children {
		p := path + "/" + child
		if err := DeleteRecursive(c, p); err != nil {
			return err
		}
	}

	return c.Delete(path, -1)
}
<commit_msg>fix solrman ip lookup (#10500)<commit_after>// Copyright 2017 FullStory, Inc.
//
// 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 smutil

import (
	"errors"
	"fmt"
	"net"
	"strings"

	"github.com/samuel/go-zookeeper/zk"
)

// ParseNodeName parses a solr node identifier into an IP, a port, and a suffix.
func ParseNodeName(node string) (string, string, string, error) {
	parts := strings.SplitN(node, "_", 2)
	if len(parts) != 2 {
		return "", "", "", errors.New("malformed: no underscore present")
	}

	if ip, port, err := net.SplitHostPort(parts[0]); err != nil {
		return "", "", "", fmt.Errorf("%q is not a valid socket", parts[0])
	} else {
		return ip, port, parts[1], nil
	}
}

// GetHostname performs an address lookup on the ip portion of e.g. `127.0.0.1:8983_solr` and returns the first hostname returned.
// If the lookup fails, then ip is returned.
func GetHostname(solrNode string) string {
	ip, _, _, err := ParseNodeName(solrNode)
	if err != nil {
		return ""
	}
	if names, err := net.LookupAddr(ip); err != nil {
		return ip // fall back to just using the IP
	} else {
		// Just return the first part of the hostname
		hostname := names[0]
		i := strings.Index(hostname, ".")
		if i > -1 {
			hostname = hostname[:i]
		}
		return hostname
	}
}

// ResolveNode performs a DNS resolve on the hostname and return an IP on ip and returns the first hostname returned.
// If the lookup fails, hostName is returned.
func ResolveNode(hostName string) string {
	ip, err := net.ResolveIPAddr("ip4", hostName)
	if err != nil {
		return hostName
	}
	return ip.String()
}

// delete the specified path and its children, recursively.
func DeleteRecursive(c *zk.Conn, path string) error {
	children, _, err := c.Children(path)
	if err != nil {
		if err == zk.ErrNoNode {
			// if the node doesn't even exist, we are done!
			return nil
		}
		return err
	}

	for _, child := range children {
		p := path + "/" + child
		if err := DeleteRecursive(c, p); err != nil {
			return err
		}
	}

	return c.Delete(path, -1)
}
<|endoftext|>


<commit_before>package config_test

import (
	. "chaos-galago/broker/Godeps/_workspace/src/github.com/onsi/ginkgo"
	. "chaos-galago/broker/Godeps/_workspace/src/github.com/onsi/gomega"
	. "chaos-galago/broker/config"
	"fmt"
)

var _ = Describe("#LoadConfig_#GetConfig", func() {
	It("Loads configuration from a file into a struct", func() {
		_, err := LoadConfig("fixtures/test_config.json")
		if err != nil {
			panic(fmt.Sprintf("Error loading config file [%s]...", err.Error()))
		}
		conf := GetConfig()
		Expect(conf.CatalogPath).To(Equal("test"))
		Expect(conf.DefaultProbability).To(Equal(0.4))
		Expect(conf.DefaultFrequency).To(Equal(10))
	})
})
<commit_msg>improve broker/config test coverage<commit_after>package config_test

import (
	. "chaos-galago/broker/Godeps/_workspace/src/github.com/onsi/ginkgo"
	. "chaos-galago/broker/Godeps/_workspace/src/github.com/onsi/gomega"
	. "chaos-galago/broker/config"
	"fmt"
)

var _ = Describe("#LoadConfig_#GetConfig", func() {
	It("Loads configuration from a file into a struct", func() {
		_, err := LoadConfig("fixtures/test_config.json")
		if err != nil {
			panic(fmt.Sprintf("Error loading config file [%s]...", err.Error()))
		}
		conf := GetConfig()
		Expect(conf.CatalogPath).To(Equal("test"))
		Expect(conf.DefaultProbability).To(Equal(0.4))
		Expect(conf.DefaultFrequency).To(Equal(10))
	})

	Context("When the file cannot be read", func() {
		It("returns an error", func() {
			_, err := LoadConfig("fixtures/no_config.json")
			Expect(err).ToNot(BeNil())
			Expect(err.Error()).To(Equal("open fixtures/no_config.json: no such file or directory"))
		})
	})

	Context("When the file is invalid json", func() {
		It("returns an error", func() {
			_, err := LoadConfig("fixtures/invalid_config.json")
			Expect(err).ToNot(BeNil())
			Expect(err.Error()).To(MatchRegexp("invalid"))
		})
	})
})
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 proxies

import (
	"encoding/xml"
	"fmt"

	proxytypes "github.com/apigee/apigeecli/bundlegen/common"
)

type proxyEndpointDef struct {
	XMLName             xml.Name               `xml:"ProxyEndpoint"`
	Name                string                 `xml:"name,attr"`
	Description         string                 `xml:"Description,omitempty"`
	FaultRules          string                 `xml:"FaultRules,omitempty"`
	PreFlow             proxytypes.PreFlowDef  `xml:"PreFlow,omitempty"`
	PostFlow            proxytypes.PostFlowDef `xml:"PostFlow,omitempty"`
	Flows               proxytypes.FlowsDef    `xml:"Flows,omitempty"`
	HTTPProxyConnection httpProxyConnectionDef `xml:"HTTPProxyConnection,omitempty"`
	RouteRule           routeRuleDef           `xml:"RouteRule,omitempty"`
}

type routeRuleDef struct {
	XMLName        xml.Name `xml:"RouteRule"`
	Name           string   `xml:"name,attr"`
	TargetEndpoint string   `xml:"TargetEndpoint"`
}

type httpProxyConnectionDef struct {
	XMLName     xml.Name `xml:"HTTPProxyConnection"`
	BasePath    string   `xml:"BasePath"`
	Properties  string   `xml:"Properties"`
	VirtualHost []string `xml:"VirtualHost"`
}

var proxyEndpoint proxyEndpointDef

func GetProxyEndpoint() (string, error) {
	proxyBody, err := xml.MarshalIndent(proxyEndpoint, "", " ")
	if err != nil {
		return "", nil
	}
	return string(proxyBody), nil
}

func NewProxyEndpoint(basePath string) {
	proxyEndpoint.Name = "default"
	proxyEndpoint.PreFlow.Name = "PreFlow"
	proxyEndpoint.PostFlow.Name = "PostFlow"
	proxyEndpoint.HTTPProxyConnection.BasePath = basePath
	proxyEndpoint.RouteRule.Name = "default"
	proxyEndpoint.RouteRule.TargetEndpoint = "default"
}

func AddFlow(operationId string, keyPath string, method string, description string) {
	flow := proxytypes.FlowDef{}
	flow.Name = operationId
	flow.Description = description
	flow.Condition.ConditionData = "(proxy.pathsuffix MatchesPath \"" + keyPath + "\") and (request.verb = \"" + method + "\")"
	proxyEndpoint.Flows.Flow = append(proxyEndpoint.Flows.Flow, flow)
}

func AddStepToPreFlowRequest(name string) {
	step := proxytypes.StepDef{}
	step.Name = name
	proxyEndpoint.PreFlow.Request.Step = append(proxyEndpoint.PreFlow.Request.Step, &step)
}

func AddStepToFlowRequest(name string, flowName string) error {
	for flowKey, flow := range proxyEndpoint.Flows.Flow {
		if flow.Name == flowName {
			step := proxytypes.StepDef{}
			step.Name = name
			proxyEndpoint.Flows.Flow[flowKey].Request.Step = append(proxyEndpoint.Flows.Flow[flowKey].Request.Step, &step)
			return nil
		}
	}
	return fmt.Errorf("flow name not found")
}
<commit_msg>Fix for issue34<commit_after>// Copyright 2020 Google LLC
//
// 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 proxies

import (
	"encoding/xml"
	"fmt"
	"strings"

	proxytypes "github.com/apigee/apigeecli/bundlegen/common"
)

type proxyEndpointDef struct {
	XMLName             xml.Name               `xml:"ProxyEndpoint"`
	Name                string                 `xml:"name,attr"`
	Description         string                 `xml:"Description,omitempty"`
	FaultRules          string                 `xml:"FaultRules,omitempty"`
	PreFlow             proxytypes.PreFlowDef  `xml:"PreFlow,omitempty"`
	PostFlow            proxytypes.PostFlowDef `xml:"PostFlow,omitempty"`
	Flows               proxytypes.FlowsDef    `xml:"Flows,omitempty"`
	HTTPProxyConnection httpProxyConnectionDef `xml:"HTTPProxyConnection,omitempty"`
	RouteRule           routeRuleDef           `xml:"RouteRule,omitempty"`
}

type routeRuleDef struct {
	XMLName        xml.Name `xml:"RouteRule"`
	Name           string   `xml:"name,attr"`
	TargetEndpoint string   `xml:"TargetEndpoint"`
}

type httpProxyConnectionDef struct {
	XMLName     xml.Name `xml:"HTTPProxyConnection"`
	BasePath    string   `xml:"BasePath"`
	Properties  string   `xml:"Properties"`
	VirtualHost []string `xml:"VirtualHost"`
}

var proxyEndpoint proxyEndpointDef

func GetProxyEndpoint() (string, error) {
	proxyBody, err := xml.MarshalIndent(proxyEndpoint, "", " ")
	if err != nil {
		return "", nil
	}
	return string(proxyBody), nil
}

func NewProxyEndpoint(basePath string) {
	proxyEndpoint.Name = "default"
	proxyEndpoint.PreFlow.Name = "PreFlow"
	proxyEndpoint.PostFlow.Name = "PostFlow"
	proxyEndpoint.HTTPProxyConnection.BasePath = basePath
	proxyEndpoint.RouteRule.Name = "default"
	proxyEndpoint.RouteRule.TargetEndpoint = "default"
}

func AddFlow(operationId string, keyPath string, method string, description string) {
	flow := proxytypes.FlowDef{}
	flow.Name = operationId
	flow.Description = description
	flow.Condition.ConditionData = "(proxy.pathsuffix MatchesPath \"" + keyPath + "\") and (request.verb = \"" + strings.ToUpper(method) + "\")"
	proxyEndpoint.Flows.Flow = append(proxyEndpoint.Flows.Flow, flow)
}

func AddStepToPreFlowRequest(name string) {
	step := proxytypes.StepDef{}
	step.Name = name
	proxyEndpoint.PreFlow.Request.Step = append(proxyEndpoint.PreFlow.Request.Step, &step)
}

func AddStepToFlowRequest(name string, flowName string) error {
	for flowKey, flow := range proxyEndpoint.Flows.Flow {
		if flow.Name == flowName {
			step := proxytypes.StepDef{}
			step.Name = name
			proxyEndpoint.Flows.Flow[flowKey].Request.Step = append(proxyEndpoint.Flows.Flow[flowKey].Request.Step, &step)
			return nil
		}
	}
	return fmt.Errorf("flow name not found")
}
<|endoftext|>


<commit_before>package cassandra

import (
	"fmt"
	"github.com/ProductHealth/gose4"
	"github.com/gocql/gocql"
)

type check struct {
	session *gocql.Session
	config  gose4.Configuration
}

func New(session *gocql.Session, config gose4.Configuration) *check {
	return &check{session: session, config: config}
}

func (hc check) Run() gose4.HealthCheckResult {
	sw := gose4.CreateStopWatch()
	valid, err := hc.checkConnection()
	if !valid {
		return gose4.Failed(sw.GetDuration(), fmt.Sprintf("encountered error while quering cassandra : %v", err))
	} else {
		return gose4.Ok(sw.GetDuration())
	}
}

func (hc check) checkConnection() (bool, error) {
	res, err := hc.session.Query("SELECT now() FROM system.local").Iter().RowData()
	return len(res.Values) == 1, err
}

func (hc check) Configuration() gose4.Configuration {
	return hc.config
}
<commit_msg>Fixed cassandra check<commit_after>package cassandra

import (
	"fmt"
	"github.com/ProductHealth/gose4"
	"github.com/gocql/gocql"
	gtime "github.com/ProductHealth/gommons/time"
)

type check struct {
	session *gocql.Session
	config  gose4.Configuration
}

func New(session *gocql.Session, config gose4.Configuration) *check {
	return &check{session: session, config: config}
}

func (hc check) Run() gose4.HealthCheckResult {
	sw := gtime.NewStopWatch()
	valid, err := hc.checkConnection()
	if !valid {
		return gose4.Failed(sw.GetDuration(), fmt.Sprintf("encountered error while quering cassandra : %v", err))
	} else {
		return gose4.Ok(sw.GetDuration())
	}
}

func (hc check) checkConnection() (bool, error) {
	res, err := hc.session.Query("SELECT now() FROM system.local").Iter().RowData()
	return len(res.Values) == 1, err
}

func (hc check) Configuration() gose4.Configuration {
	return hc.config
}
<|endoftext|>


<commit_before>package client

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"encoding/json"
	"github.com/coreos/go-semver/semver"
	"github.com/stretchr/testify/assert"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/rest"

	"github.com/coreos-inc/alm/apis/alphacatalogentry/v1alpha1"
	csvv1alpha1 "github.com/coreos-inc/alm/apis/clusterserviceversion/v1alpha1"
)

func TestUpdateEntry(t *testing.T) {

	testCSVName := "MockServiceName-v1"
	testCSVVersion := "0.2.4+alpha"

	testEntry := v1alpha1.AlphaCatalogEntry{
		TypeMeta: metav1.TypeMeta{
			Kind:       v1alpha1.AlphaCatalogEntryKind,
			APIVersion: v1alpha1.AlphaCatalogEntryCRDAPIVersion,
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:      testCSVName,
			Namespace: "alm-coreos-tests",
		},
		Spec: &v1alpha1.AlphaCatalogEntrySpec{
			ClusterServiceVersionSpec: csvv1alpha1.ClusterServiceVersionSpec{
				Version: *semver.New(testCSVVersion),
				CustomResourceDefinitions: csvv1alpha1.CustomResourceDefinitions{
					Owned:    []csvv1alpha1.CRDDescription{},
					Required: []csvv1alpha1.CRDDescription{},
				},
			},
		},
	}
	rawResp, err := json.Marshal(testEntry)
	assert.NoError(t, err)
	testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write(rawResp)
	})

	ts := httptest.NewServer(testHandler)
	defer ts.Close()
	config := rest.Config{
		Host: ts.URL,
	}

	scheme := runtime.NewScheme()
	assert.NoError(t, v1alpha1.AddToScheme(scheme))

	config.GroupVersion = &v1alpha1.SchemeGroupVersion
	config.APIPath = "/apis"
	config.ContentType = runtime.ContentTypeJSON
	config.NegotiatedSerializer = serializer.DirectCodecFactory{
		CodecFactory: serializer.NewCodecFactory(scheme),
	}

	restClient, err := rest.RESTClientFor(&config)
	assert.NoError(t, err)
	assert.NotNil(t, restClient)

	aceClient := &AlphaCatalogEntryClient{
		RESTClient: restClient,
	}
	entry, err := aceClient.UpdateEntry(&testEntry)
	assert.NoError(t, err)
	assert.NotNil(t, entry)
}
<commit_msg>test(client/alphacatalogentry): test upsert behavior<commit_after>package client

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"encoding/json"
	"github.com/coreos/go-semver/semver"
	"github.com/stretchr/testify/assert"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/rest"

	"github.com/coreos-inc/alm/apis/alphacatalogentry/v1alpha1"
	csvv1alpha1 "github.com/coreos-inc/alm/apis/clusterserviceversion/v1alpha1"
)

func mockClient(t *testing.T, ts *httptest.Server) *AlphaCatalogEntryClient {
	config := rest.Config{
		Host: ts.URL,
	}

	scheme := runtime.NewScheme()
	assert.NoError(t, v1alpha1.AddToScheme(scheme))

	config.GroupVersion = &v1alpha1.SchemeGroupVersion
	config.APIPath = "/apis"
	config.ContentType = runtime.ContentTypeJSON
	config.NegotiatedSerializer = serializer.DirectCodecFactory{
		CodecFactory: serializer.NewCodecFactory(scheme),
	}

	restClient, err := rest.RESTClientFor(&config)
	assert.NoError(t, err)
	assert.NotNil(t, restClient)

	return &AlphaCatalogEntryClient{
		RESTClient: restClient,
	}
}

func TestUpdateEntry(t *testing.T) {

	testCSVName := "MockServiceName-v1"
	testCSVVersion := "0.2.4+alpha"

	testEntry := v1alpha1.AlphaCatalogEntry{
		TypeMeta: metav1.TypeMeta{
			Kind:       v1alpha1.AlphaCatalogEntryKind,
			APIVersion: v1alpha1.AlphaCatalogEntryCRDAPIVersion,
		},
		ObjectMeta: metav1.ObjectMeta{
			Name:      testCSVName,
			Namespace: "alm-coreos-tests",
		},
		Spec: &v1alpha1.AlphaCatalogEntrySpec{
			ClusterServiceVersionSpec: csvv1alpha1.ClusterServiceVersionSpec{
				Version: *semver.New(testCSVVersion),
				CustomResourceDefinitions: csvv1alpha1.CustomResourceDefinitions{
					Owned:    []csvv1alpha1.CRDDescription{},
					Required: []csvv1alpha1.CRDDescription{},
				},
			},
		},
	}

	rawResp, err := json.Marshal(testEntry)
	assert.NoError(t, err)
	testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.Write(rawResp)
	})
	ts := httptest.NewServer(testHandler)
	defer ts.Close()

	entry, err := mockClient(t, ts).UpdateEntry(&testEntry)
	assert.NoError(t, err)
	assert.NotNil(t, entry)

	testHandler2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodPost:
			w.WriteHeader(http.StatusConflict)
		case http.MethodGet:
			w.Header().Set("Content-Type", "application/json")
			w.Write(rawResp)
		case http.MethodPut:
			w.Header().Set("Content-Type", "application/json")
			w.Write(rawResp)
		}
	})
	ts2 := httptest.NewServer(testHandler2)
	defer ts2.Close()

	entry2, err := mockClient(t, ts2).UpdateEntry(&testEntry)
	assert.NoError(t, err)
	assert.NotNil(t, entry2)
}
<|endoftext|>