<commit_before>// +build appengine

package endpoints

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
)

var (
	// Pre-defined API errors.
	// Use NewAPIError() method to create your own.

	// InternalServerError is default error with http.StatusInternalServerError (500)
	InternalServerError = NewInternalServerError("")
	// BadRequestError is default error with http.StatusBadRequest (400)
	BadRequestError = NewBadRequestError("")
	// UnauthorizedError is default error with http.StatusUnauthorized (401)
	UnauthorizedError = NewUnauthorizedError("")
	// ForbiddenError is default error with http.StatusForbidden (403)
	ForbiddenError = NewForbiddenError("")
	// NotFoundError is default error with http.StatusNotFound (404)
	NotFoundError = NewNotFoundError("")
	// ConflictError is default error with http.StatusConflict (409)
	ConflictError = NewConflictError("")

	// errorNames is a map of known error names (or better, their prefixes).
	// See newErrorResponse method for details.
	errorNames = map[int]string{
		http.StatusInternalServerError: "Internal Server Error",
		http.StatusBadRequest:          "Bad Request",
		http.StatusUnauthorized:        "Unauthorized",
		http.StatusForbidden:           "Forbidden",
		http.StatusNotFound:            "Not Found",
		http.StatusConflict:            "Conflict",
	}
)

// APIError is a user custom API's error
type APIError struct {
	Name string
	Msg  string
	Code int
}

// APIError is an error
func (a *APIError) Error() string {
	return a.Msg
}

// NewAPIError Create a new APIError for custom error
func NewAPIError(name string, msg string, code int) error {
	return &APIError{Name: name, Msg: msg, Code: code}
}

// errorf creates a new APIError given its status code, a format string and its arguments.
func errorf(code int, format string, args ...interface{}) error {
	return &APIError{Name: errorNames[code], Msg: fmt.Sprintf(format, args...), Code: code}
}

// NewInternalServerError creates a new APIError with Internal Server Error status (500)
func NewInternalServerError(format string, args ...interface{}) error {
	return errorf(http.StatusInternalServerError, format, args...)
}

// NewBadRequestError creates a new APIError with Bad Request status (400)
func NewBadRequestError(format string, args ...interface{}) error {
	return errorf(http.StatusBadRequest, format, args...)
}

// NewUnauthorizedError creates a new APIError with Unauthorized status (401)
func NewUnauthorizedError(format string, args ...interface{}) error {
	return errorf(http.StatusUnauthorized, format, args...)
}

// NewNotFoundError creates a new APIError with Not Found status (404)
func NewNotFoundError(format string, args ...interface{}) error {
	return errorf(http.StatusNotFound, format, args...)
}

// NewForbiddenError creates a new APIError with Forbidden status (403)
func NewForbiddenError(format string, args ...interface{}) error {
	return errorf(http.StatusForbidden, format, args...)
}

// NewConflictError creates a new APIError with Conflict status (409)
func NewConflictError(format string, args ...interface{}) error {
	return errorf(http.StatusConflict, format, args...)
}

// errorResponse is SPI-compatible error response
type errorResponse struct {
	// Currently always "APPLICATION_ERROR"
	State string `json:"state"`
	Name  string `json:"error_name"`
	Msg   string `json:"error_message,omitempty"`
	Code  int    `json:"-"`
}

// Creates and initializes a new errorResponse.
// If msg contains any of errorNames then errorResponse.Name will be set
// to that name and the rest of the msg becomes errorResponse.Msg.
// Otherwise, a default error name is used and msg argument
// is errorResponse.Msg.
func newErrorResponse(err error) *errorResponse {
	if e, ok := err.(*APIError); ok {
		return &errorResponse{"APPLICATION_ERROR", e.Name, e.Msg, e.Code}
	}
	msg := err.Error()
	for code, name := range errorNames {
		if strings.HasPrefix(msg, name) {
			return &errorResponse{"APPLICATION_ERROR", name, strings.Trim(msg[len(name):], " :"), code}
		}
	}
	//for compatibility, Before behavior, always return 400 HTTP Status Code.
	// TODO(alex): where is 400 coming from?
	return &errorResponse{"APPLICATION_ERROR", errorNames[http.StatusInternalServerError], msg, http.StatusBadRequest}
}

// writeError writes SPI-compatible error response.
func writeError(w http.ResponseWriter, err error) {
	errResp := newErrorResponse(err)
	w.WriteHeader(errResp.Code)
	json.NewEncoder(w).Encode(errResp)
}
<commit_msg>use http.StatusText<commit_after>// +build appengine

package endpoints

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
)

var (
	// Pre-defined API errors.
	// Use NewAPIError() method to create your own.

	// InternalServerError is default error with http.StatusInternalServerError (500)
	InternalServerError = NewInternalServerError("")
	// BadRequestError is default error with http.StatusBadRequest (400)
	BadRequestError = NewBadRequestError("")
	// UnauthorizedError is default error with http.StatusUnauthorized (401)
	UnauthorizedError = NewUnauthorizedError("")
	// ForbiddenError is default error with http.StatusForbidden (403)
	ForbiddenError = NewForbiddenError("")
	// NotFoundError is default error with http.StatusNotFound (404)
	NotFoundError = NewNotFoundError("")
	// ConflictError is default error with http.StatusConflict (409)
	ConflictError = NewConflictError("")

	// knownErrors is a list of all known errors.
	knownErrors = [...]int{
		http.StatusInternalServerError,
		http.StatusBadRequest,
		http.StatusUnauthorized,
		http.StatusForbidden,
		http.StatusNotFound,
		http.StatusConflict,
	}
)

// APIError is a user custom API's error
type APIError struct {
	Name string
	Msg  string
	Code int
}

// APIError is an error
func (a *APIError) Error() string {
	return a.Msg
}

// NewAPIError Create a new APIError for custom error
func NewAPIError(name string, msg string, code int) error {
	return &APIError{name, msg, code}
}

// errorf creates a new APIError given its status code, a format string and its arguments.
func errorf(code int, format string, args ...interface{}) error {
	return &APIError{http.StatusText(code), fmt.Sprintf(format, args...), code}
}

// NewInternalServerError creates a new APIError with Internal Server Error status (500)
func NewInternalServerError(format string, args ...interface{}) error {
	return errorf(http.StatusInternalServerError, format, args...)
}

// NewBadRequestError creates a new APIError with Bad Request status (400)
func NewBadRequestError(format string, args ...interface{}) error {
	return errorf(http.StatusBadRequest, format, args...)
}

// NewUnauthorizedError creates a new APIError with Unauthorized status (401)
func NewUnauthorizedError(format string, args ...interface{}) error {
	return errorf(http.StatusUnauthorized, format, args...)
}

// NewNotFoundError creates a new APIError with Not Found status (404)
func NewNotFoundError(format string, args ...interface{}) error {
	return errorf(http.StatusNotFound, format, args...)
}

// NewForbiddenError creates a new APIError with Forbidden status (403)
func NewForbiddenError(format string, args ...interface{}) error {
	return errorf(http.StatusForbidden, format, args...)
}

// NewConflictError creates a new APIError with Conflict status (409)
func NewConflictError(format string, args ...interface{}) error {
	return errorf(http.StatusConflict, format, args...)
}

// errorResponse is SPI-compatible error response
type errorResponse struct {
	// Currently always "APPLICATION_ERROR"
	State string `json:"state"`
	Name  string `json:"error_name"`
	Msg   string `json:"error_message,omitempty"`
	Code  int    `json:"-"`
}

// Creates and initializes a new errorResponse.
// If msg contains any of knownErrors then errorResponse.Name will be set
// to that name and the rest of the msg becomes errorResponse.Msg.
// Otherwise, a default error name is used and msg argument
// is errorResponse.Msg.
func newErrorResponse(err error) *errorResponse {
	if e, ok := err.(*APIError); ok {
		return &errorResponse{"APPLICATION_ERROR", e.Name, e.Msg, e.Code}
	}
	msg := err.Error()
	for _, code := range knownErrors {
		if name := http.StatusText(code); strings.HasPrefix(msg, name) {
			return &errorResponse{"APPLICATION_ERROR", name, strings.Trim(msg[len(name):], " :"), code}
		}
	}
	//for compatibility, Before behavior, always return 400 HTTP Status Code.
	// TODO(alex): where is 400 coming from?
	return &errorResponse{"APPLICATION_ERROR", http.StatusText(http.StatusInternalServerError), msg, http.StatusBadRequest}
}

// writeError writes SPI-compatible error response.
func writeError(w http.ResponseWriter, err error) {
	errResp := newErrorResponse(err)
	w.WriteHeader(errResp.Code)
	json.NewEncoder(w).Encode(errResp)
}
<|endoftext|>


<commit_before>package engine

import (
	"fmt"
	"testing"

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

func Test_Rect_Location(t *testing.T) {
	rect := Rect{
		x: 0,
		y: 0,
		w: 1,
		h: 5,
	}

	require.Equal(t, Location{
		{0, 0},
		{0, 1},
		{0, 2},
		{0, 3},
		{0, 4},
	}, rect.Location())
}

func Test_Rect_Dot_HorizontalRect(t *testing.T) {
	rect := Rect{
		x: 0,
		y: 0,
		w: 1,
		h: 5,
	}

	require.Equal(t, Dot{0, 0}, rect.Dot(0))
	require.Equal(t, Dot{0, 1}, rect.Dot(1))
	require.Equal(t, Dot{0, 2}, rect.Dot(2))
	require.Equal(t, Dot{0, 3}, rect.Dot(3))
	require.Equal(t, Dot{0, 4}, rect.Dot(4))
}

func Test_Rect_Dot_VerticalRect(t *testing.T) {
	rect := Rect{
		x: 0,
		y: 0,
		w: 5,
		h: 1,
	}

	require.Equal(t, Dot{0, 0}, rect.Dot(0))
	require.Equal(t, Dot{1, 0}, rect.Dot(1))
	require.Equal(t, Dot{2, 0}, rect.Dot(2))
	require.Equal(t, Dot{3, 0}, rect.Dot(3))
	require.Equal(t, Dot{4, 0}, rect.Dot(4))
}

func Test_Rect_Dot_VerticalRectWithXY(t *testing.T) {
	rect := Rect{
		x: 5,
		y: 5,
		w: 5,
		h: 1,
	}

	require.Equal(t, Dot{5, 5}, rect.Dot(0))
	require.Equal(t, Dot{6, 5}, rect.Dot(1))
	require.Equal(t, Dot{7, 5}, rect.Dot(2))
	require.Equal(t, Dot{8, 5}, rect.Dot(3))
	require.Equal(t, Dot{9, 5}, rect.Dot(4))
}

func Test_Rect_Dot_HorizontalRectWithXY(t *testing.T) {
	rect := Rect{
		x: 5,
		y: 5,
		w: 1,
		h: 5,
	}

	require.Equal(t, Dot{5, 5}, rect.Dot(0))
	require.Equal(t, Dot{5, 6}, rect.Dot(1))
	require.Equal(t, Dot{5, 7}, rect.Dot(2))
	require.Equal(t, Dot{5, 8}, rect.Dot(3))
	require.Equal(t, Dot{5, 9}, rect.Dot(4))
}

func Test_Rect_Dot_SquareRectWithXY(t *testing.T) {
	rect := Rect{
		x: 5,
		y: 5,
		w: 3,
		h: 3,
	}

	require.Equal(t, Dot{5, 5}, rect.Dot(0))
	require.Equal(t, Dot{6, 5}, rect.Dot(1))
	require.Equal(t, Dot{7, 5}, rect.Dot(2))
	require.Equal(t, Dot{5, 6}, rect.Dot(3))
	require.Equal(t, Dot{6, 6}, rect.Dot(4))
	require.Equal(t, Dot{7, 6}, rect.Dot(5))
	require.Equal(t, Dot{5, 7}, rect.Dot(6))
	require.Equal(t, Dot{6, 7}, rect.Dot(7))
	require.Equal(t, Dot{7, 7}, rect.Dot(8))
}

func Test_Rect_MarshalJSON(t *testing.T) {
	tests := []struct {
		rect Rect
		json []byte
	}{
		{
			Rect{},
			[]byte("[0,0,0,0]"),
		},
		{
			Rect{1, 2, 3, 4},
			[]byte("[1,2,3,4]"),
		},
		{
			Rect{4, 3, 2, 1},
			[]byte("[4,3,2,1]"),
		},
		{
			Rect{255, 200, 160, 100},
			[]byte("[255,200,160,100]"),
		},
		{
			Rect{255, 200, 160, 255},
			[]byte("[255,200,160,255]"),
		},
	}

	for i, test := range tests {
		actualJSON, err := test.rect.MarshalJSON()
		require.Nil(t, err, "test %d", i)
		require.Equal(t, test.json, actualJSON, "test %d", i)
	}
}

func Test_Rect_Width_ReturnsRectWidth(t *testing.T) {
	tests := []struct {
		rect Rect
	}{
		{Rect{0, 0, 10, 3}},
		{Rect{0, 0, 22, 4}},
		{Rect{0, 0, 123, 5}},
		{Rect{0, 0, 0, 233}},
	}

	for i, test := range tests {
		require.Equal(t, test.rect.w, test.rect.Width(), fmt.Sprintf("number: %d", i))
	}
}

func Test_Rect_Height_ReturnsRectHeight(t *testing.T) {
	tests := []struct {
		rect Rect
	}{
		{Rect{0, 0, 10, 3}},
		{Rect{0, 0, 22, 4}},
		{Rect{0, 0, 123, 5}},
		{Rect{0, 0, 0, 233}},
	}

	for i, test := range tests {
		require.Equal(t, test.rect.h, test.rect.Height(), fmt.Sprintf("number: %d", i))
	}
}

func Test_Rect_X_ReturnsRectX(t *testing.T) {
	tests := []struct {
		rect Rect
	}{
		{Rect{3, 23, 10, 3}},
		{Rect{32, 1, 22, 4}},
		{Rect{1, 32, 123, 5}},
		{Rect{42, 231, 0, 233}},
	}

	for i, test := range tests {
		require.Equal(t, test.rect.x, test.rect.X(), fmt.Sprintf("number: %d", i))
	}
}

func Test_Rect_Y_ReturnsRectY(t *testing.T) {
	tests := []struct {
		rect Rect
	}{
		{Rect{213, 231, 10, 3}},
		{Rect{23, 32, 22, 4}},
		{Rect{123, 132, 123, 5}},
		{Rect{22, 3, 0, 233}},
	}

	for i, test := range tests {
		require.Equal(t, test.rect.y, test.rect.Y(), fmt.Sprintf("number: %d", i))
	}
}
<commit_msg>Create tests for engine.Rect Dots()<commit_after>package engine

import (
	"fmt"
	"testing"

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

func Test_Rect_Location(t *testing.T) {
	rect := Rect{
		x: 0,
		y: 0,
		w: 1,
		h: 5,
	}

	require.Equal(t, Location{
		{0, 0},
		{0, 1},
		{0, 2},
		{0, 3},
		{0, 4},
	}, rect.Location())
}

func Test_Rect_Dot_HorizontalRect(t *testing.T) {
	rect := Rect{
		x: 0,
		y: 0,
		w: 1,
		h: 5,
	}

	require.Equal(t, Dot{0, 0}, rect.Dot(0))
	require.Equal(t, Dot{0, 1}, rect.Dot(1))
	require.Equal(t, Dot{0, 2}, rect.Dot(2))
	require.Equal(t, Dot{0, 3}, rect.Dot(3))
	require.Equal(t, Dot{0, 4}, rect.Dot(4))
}

func Test_Rect_Dot_VerticalRect(t *testing.T) {
	rect := Rect{
		x: 0,
		y: 0,
		w: 5,
		h: 1,
	}

	require.Equal(t, Dot{0, 0}, rect.Dot(0))
	require.Equal(t, Dot{1, 0}, rect.Dot(1))
	require.Equal(t, Dot{2, 0}, rect.Dot(2))
	require.Equal(t, Dot{3, 0}, rect.Dot(3))
	require.Equal(t, Dot{4, 0}, rect.Dot(4))
}

func Test_Rect_Dot_VerticalRectWithXY(t *testing.T) {
	rect := Rect{
		x: 5,
		y: 5,
		w: 5,
		h: 1,
	}

	require.Equal(t, Dot{5, 5}, rect.Dot(0))
	require.Equal(t, Dot{6, 5}, rect.Dot(1))
	require.Equal(t, Dot{7, 5}, rect.Dot(2))
	require.Equal(t, Dot{8, 5}, rect.Dot(3))
	require.Equal(t, Dot{9, 5}, rect.Dot(4))
}

func Test_Rect_Dot_HorizontalRectWithXY(t *testing.T) {
	rect := Rect{
		x: 5,
		y: 5,
		w: 1,
		h: 5,
	}

	require.Equal(t, Dot{5, 5}, rect.Dot(0))
	require.Equal(t, Dot{5, 6}, rect.Dot(1))
	require.Equal(t, Dot{5, 7}, rect.Dot(2))
	require.Equal(t, Dot{5, 8}, rect.Dot(3))
	require.Equal(t, Dot{5, 9}, rect.Dot(4))
}

func Test_Rect_Dot_SquareRectWithXY(t *testing.T) {
	rect := Rect{
		x: 5,
		y: 5,
		w: 3,
		h: 3,
	}

	require.Equal(t, Dot{5, 5}, rect.Dot(0))
	require.Equal(t, Dot{6, 5}, rect.Dot(1))
	require.Equal(t, Dot{7, 5}, rect.Dot(2))
	require.Equal(t, Dot{5, 6}, rect.Dot(3))
	require.Equal(t, Dot{6, 6}, rect.Dot(4))
	require.Equal(t, Dot{7, 6}, rect.Dot(5))
	require.Equal(t, Dot{5, 7}, rect.Dot(6))
	require.Equal(t, Dot{6, 7}, rect.Dot(7))
	require.Equal(t, Dot{7, 7}, rect.Dot(8))
}

func Test_Rect_MarshalJSON(t *testing.T) {
	tests := []struct {
		rect Rect
		json []byte
	}{
		{
			Rect{},
			[]byte("[0,0,0,0]"),
		},
		{
			Rect{1, 2, 3, 4},
			[]byte("[1,2,3,4]"),
		},
		{
			Rect{4, 3, 2, 1},
			[]byte("[4,3,2,1]"),
		},
		{
			Rect{255, 200, 160, 100},
			[]byte("[255,200,160,100]"),
		},
		{
			Rect{255, 200, 160, 255},
			[]byte("[255,200,160,255]"),
		},
	}

	for i, test := range tests {
		actualJSON, err := test.rect.MarshalJSON()
		require.Nil(t, err, "test %d", i)
		require.Equal(t, test.json, actualJSON, "test %d", i)
	}
}

func Test_Rect_Width_ReturnsRectWidth(t *testing.T) {
	tests := []struct {
		rect Rect
	}{
		{Rect{0, 0, 10, 3}},
		{Rect{0, 0, 22, 4}},
		{Rect{0, 0, 123, 5}},
		{Rect{0, 0, 0, 233}},
	}

	for i, test := range tests {
		require.Equal(t, test.rect.w, test.rect.Width(), fmt.Sprintf("number: %d", i))
	}
}

func Test_Rect_Height_ReturnsRectHeight(t *testing.T) {
	tests := []struct {
		rect Rect
	}{
		{Rect{0, 0, 10, 3}},
		{Rect{0, 0, 22, 4}},
		{Rect{0, 0, 123, 5}},
		{Rect{0, 0, 0, 233}},
	}

	for i, test := range tests {
		require.Equal(t, test.rect.h, test.rect.Height(), fmt.Sprintf("number: %d", i))
	}
}

func Test_Rect_X_ReturnsRectX(t *testing.T) {
	tests := []struct {
		rect Rect
	}{
		{Rect{3, 23, 10, 3}},
		{Rect{32, 1, 22, 4}},
		{Rect{1, 32, 123, 5}},
		{Rect{42, 231, 0, 233}},
	}

	for i, test := range tests {
		require.Equal(t, test.rect.x, test.rect.X(), fmt.Sprintf("number: %d", i))
	}
}

func Test_Rect_Y_ReturnsRectY(t *testing.T) {
	tests := []struct {
		rect Rect
	}{
		{Rect{213, 231, 10, 3}},
		{Rect{23, 32, 22, 4}},
		{Rect{123, 132, 123, 5}},
		{Rect{22, 3, 0, 233}},
	}

	for i, test := range tests {
		require.Equal(t, test.rect.y, test.rect.Y(), fmt.Sprintf("number: %d", i))
	}
}

func Test_Rect_Dots_ReturnsDotList(t *testing.T) {
	tests := []struct {
		rect Rect
		dots []Dot
	}{
		{Rect{213, 231, 10, 3}, []Dot{
			// 0
			{213, 231}, {214, 231}, {215, 231}, {216, 231}, {217, 231},
			{218, 231}, {219, 231}, {220, 231}, {221, 231}, {222, 231},
			// 1
			{213, 232}, {214, 232}, {215, 232}, {216, 232}, {217, 232},
			{218, 232}, {219, 232}, {220, 232}, {221, 232}, {222, 232},
			// 2
			{213, 233}, {214, 233}, {215, 233}, {216, 233}, {217, 233},
			{218, 233}, {219, 233}, {220, 233}, {221, 233}, {222, 233},
		}},
		{Rect{23, 32, 3, 3}, []Dot{
			{23, 32}, {24, 32}, {25, 32},
			{23, 33}, {24, 33}, {25, 33},
			{23, 34}, {24, 34}, {25, 34},
		}},
		{Rect{123, 132, 1, 1}, []Dot{
			{123, 132},
		}},
		{Rect{22, 3, 0, 233}, []Dot{}},
		{Rect{22, 3, 123, 0}, []Dot{}},
		{Rect{22, 3, 0, 0}, []Dot{}},
	}

	for i, test := range tests {
		require.Equal(t, test.dots, test.rect.Dots(), fmt.Sprintf("number: %d", i))
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 CoreOS, 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 engine

import (
	"errors"
	"strings"
	"time"

	"github.com/coreos/fleet/log"
	"github.com/coreos/fleet/machine"
	"github.com/coreos/fleet/pkg/lease"
	"github.com/coreos/fleet/registry"
)

// IsGrpcLeader checks if the current leader has gRPC capabilities enabled or error
// if there is not a elected leader yet.
func (e *Engine) IsGrpcLeader() (bool, error) {
	leader, err := e.lManager.GetLease(engineLeaseName)
	if err != nil {
		log.Errorf("Unable to determine current lease: %v", err)
		return false, err
	}
	// It can happen that the leader is not yet stored in etcd and nor error (line 122 pkg/lease/etcd.go)
	if leader == nil {
		return false, errors.New("Unable to get the current leader")
	}

	leaderState, err := e.getMachineState(leader.MachineID())
	if err != nil {
		log.Errorf("Unable to determine current lease: %v", err)
		return false, err
	}

	if leaderState.Capabilities != nil && leaderState.Capabilities.Has(machine.CapGRPC) {
		return true, nil
	}

	log.Info("Engine leader has no gRPC capabilities enabled!")

	return false, nil
}

func (e *Engine) rpcLeadership(leaseTTL time.Duration, machID string) lease.Lease {
	var previousEngine string
	if e.lease != nil {
		previousEngine = e.lease.MachineID()
	}

	var l lease.Lease
	if isLeader(e.lease, machID) {
		l = rpcRenewLeadership(e.lManager, e.lease, engineVersion, leaseTTL)
	} else {
		l = rpcAcquireLeadership(e.registry, e.lManager, machID, engineVersion, leaseTTL)
	}

	// log all leadership changes
	if l != nil && e.lease == nil && l.MachineID() != machID {
		log.Infof("Engine leader is %s", l.MachineID())
	} else if l != nil && e.lease != nil && l.MachineID() != e.lease.MachineID() {
		log.Infof("Engine leadership changed from %s to %s", e.lease.MachineID(), l.MachineID())
	}

	e.lease = l
	if e.lease != nil && previousEngine != e.lease.MachineID() {
		engineState, err := e.getMachineState(e.lease.MachineID())
		if err != nil {
			log.Errorf("Failed to get machine state for machine %s %v", e.lease.MachineID(), err)
		}
		if engineState != nil {
			log.Infof("Updating engine state... engineState: %v previous: %s lease: %v", engineState, previousEngine, e.lease)
			go e.updateEngineState(*engineState)
		}
	}

	return e.lease
}

func rpcAcquireLeadership(reg registry.Registry, lManager lease.Manager, machID string, ver int, ttl time.Duration) lease.Lease {
	existing, err := lManager.GetLease(engineLeaseName)
	if err != nil {
		log.Errorf("Unable to determine current lease: %v", err)
		return nil
	}

	var l lease.Lease
	if (existing == nil && reg.UseEtcdRegistry()) || (existing == nil && !reg.IsRegistryReady()) {
		l, err = lManager.AcquireLease(engineLeaseName, machID, ver, ttl)
		if err != nil {
			log.Errorf("Engine leadership acquisition failed: %v", err)
			return nil
		} else if l == nil {
			log.Infof("Unable to acquire engine leadership")
			return nil
		}
		log.Infof("Engine leadership acquired")
		return l
	}

	if existing != nil && existing.Version() >= ver {
		log.Debugf("Lease already held by Machine(%s) operating at acceptable version %d", existing.MachineID(), existing.Version())
		return existing
	}

	// TODO(hector): Here we could add a possible SLA to determine when the leader
	// is too busy. In such a case, we can trigger a new leader election
	if (existing != nil && reg.UseEtcdRegistry()) || (existing != nil && !reg.IsRegistryReady()) {
		rem := existing.TimeRemaining()
		l, err = lManager.StealLease(engineLeaseName, machID, ver, ttl+rem, existing.Index())
		if err != nil {
			log.Errorf("Engine leadership steal failed: %v", err)
			return nil
		} else if l == nil {
			log.Infof("Unable to steal engine leadership")
			return nil
		}

		log.Infof("Stole engine leadership from Machine(%s)", existing.MachineID())

		if rem > 0 {
			log.Infof("Waiting %v for previous lease to expire before continuing reconciliation", rem)
			<-time.After(rem)
		}

		return l
	}

	log.Infof("Engine leader is BUSY!")

	return existing

}

func rpcRenewLeadership(lManager lease.Manager, l lease.Lease, ver int, ttl time.Duration) lease.Lease {
	err := l.Renew(ttl)
	if err != nil && strings.Contains(err.Error(), "Key not found") {
		log.Errorf("Retry renew etcd operation that failed due to %v", err)
		l, err = lManager.AcquireLease(engineLeaseName, l.MachineID(), ver, ttl)
		if err != nil {
			log.Errorf("Engine leadership re-acquisition failed: %v", err)
			return nil
		} else if l == nil {
			log.Infof("Unable to re-acquire engine leadership")
			return nil
		}
		log.Infof("Engine leadership re-acquired")
		return l

	} else if err != nil {
		log.Errorf("Engine leadership lost, renewal failed: %v", err)
		return nil
	}

	log.Debugf("Engine leadership renewed")
	return l
}

func (e *Engine) getMachineState(machID string) (*machine.MachineState, error) {
	machines, err := e.registry.Machines()
	if err != nil {
		log.Errorf("Unable to get the list of machines from the registry: %v", err)
		return nil, err
	}

	for _, s := range machines {
		if s.ID == machID {
			return &s, nil
		}
	}
	return nil, nil
}
<commit_msg>engine: check for an exact error code from etcd<commit_after>// Copyright 2016 The fleet 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 engine

import (
	"errors"
	"time"

	etcdErr "github.com/coreos/etcd/error"

	"github.com/coreos/fleet/log"
	"github.com/coreos/fleet/machine"
	"github.com/coreos/fleet/pkg/lease"
	"github.com/coreos/fleet/registry"
)

// IsGrpcLeader checks if the current leader has gRPC capabilities enabled or error
// if there is not a elected leader yet.
func (e *Engine) IsGrpcLeader() (bool, error) {
	leader, err := e.lManager.GetLease(engineLeaseName)
	if err != nil {
		log.Errorf("Unable to determine current lease: %v", err)
		return false, err
	}
	// It can happen that the leader is not yet stored in etcd and nor error (line 122 pkg/lease/etcd.go)
	if leader == nil {
		return false, errors.New("Unable to get the current leader")
	}

	leaderState, err := e.getMachineState(leader.MachineID())
	if err != nil {
		log.Errorf("Unable to determine current lease: %v", err)
		return false, err
	}

	if leaderState.Capabilities != nil && leaderState.Capabilities.Has(machine.CapGRPC) {
		return true, nil
	}

	log.Info("Engine leader has no gRPC capabilities enabled!")

	return false, nil
}

func (e *Engine) rpcLeadership(leaseTTL time.Duration, machID string) lease.Lease {
	var previousEngine string
	if e.lease != nil {
		previousEngine = e.lease.MachineID()
	}

	var l lease.Lease
	if isLeader(e.lease, machID) {
		l = rpcRenewLeadership(e.lManager, e.lease, engineVersion, leaseTTL)
	} else {
		l = rpcAcquireLeadership(e.registry, e.lManager, machID, engineVersion, leaseTTL)
	}

	// log all leadership changes
	if l != nil && e.lease == nil && l.MachineID() != machID {
		log.Infof("Engine leader is %s", l.MachineID())
	} else if l != nil && e.lease != nil && l.MachineID() != e.lease.MachineID() {
		log.Infof("Engine leadership changed from %s to %s", e.lease.MachineID(), l.MachineID())
	}

	e.lease = l
	if e.lease != nil && previousEngine != e.lease.MachineID() {
		engineState, err := e.getMachineState(e.lease.MachineID())
		if err != nil {
			log.Errorf("Failed to get machine state for machine %s %v", e.lease.MachineID(), err)
		}
		if engineState != nil {
			log.Infof("Updating engine state... engineState: %v previous: %s lease: %v", engineState, previousEngine, e.lease)
			go e.updateEngineState(*engineState)
		}
	}

	return e.lease
}

func rpcAcquireLeadership(reg registry.Registry, lManager lease.Manager, machID string, ver int, ttl time.Duration) lease.Lease {
	existing, err := lManager.GetLease(engineLeaseName)
	if err != nil {
		log.Errorf("Unable to determine current lease: %v", err)
		return nil
	}

	var l lease.Lease
	if (existing == nil && reg.UseEtcdRegistry()) || (existing == nil && !reg.IsRegistryReady()) {
		l, err = lManager.AcquireLease(engineLeaseName, machID, ver, ttl)
		if err != nil {
			log.Errorf("Engine leadership acquisition failed: %v", err)
			return nil
		} else if l == nil {
			log.Infof("Unable to acquire engine leadership")
			return nil
		}
		log.Infof("Engine leadership acquired")
		return l
	}

	if existing != nil && existing.Version() >= ver {
		log.Debugf("Lease already held by Machine(%s) operating at acceptable version %d", existing.MachineID(), existing.Version())
		return existing
	}

	// TODO(hector): Here we could add a possible SLA to determine when the leader
	// is too busy. In such a case, we can trigger a new leader election
	if (existing != nil && reg.UseEtcdRegistry()) || (existing != nil && !reg.IsRegistryReady()) {
		rem := existing.TimeRemaining()
		l, err = lManager.StealLease(engineLeaseName, machID, ver, ttl+rem, existing.Index())
		if err != nil {
			log.Errorf("Engine leadership steal failed: %v", err)
			return nil
		} else if l == nil {
			log.Infof("Unable to steal engine leadership")
			return nil
		}

		log.Infof("Stole engine leadership from Machine(%s)", existing.MachineID())

		if rem > 0 {
			log.Infof("Waiting %v for previous lease to expire before continuing reconciliation", rem)
			<-time.After(rem)
		}

		return l
	}

	log.Infof("Engine leader is BUSY!")

	return existing

}

func rpcRenewLeadership(lManager lease.Manager, l lease.Lease, ver int, ttl time.Duration) lease.Lease {
	err := l.Renew(ttl)
	if err != nil {
		if eerr, ok := err.(*etcdErr.Error); ok && eerr.ErrorCode == etcdErr.EcodeKeyNotFound {
			log.Errorf("Retry renew etcd operation that failed due to %v", err)
			l, err = lManager.AcquireLease(engineLeaseName, l.MachineID(), ver, ttl)
			if err != nil {
				log.Errorf("Engine leadership re-acquisition failed: %v", err)
				return nil
			} else if l == nil {
				log.Infof("Unable to re-acquire engine leadership")
				return nil
			}
			log.Infof("Engine leadership re-acquired")
			return l
		} else {
			log.Errorf("Engine leadership lost, renewal failed: %v", err)
			return nil
		}
	}

	log.Debugf("Engine leadership renewed")
	return l
}

func (e *Engine) getMachineState(machID string) (*machine.MachineState, error) {
	machines, err := e.registry.Machines()
	if err != nil {
		log.Errorf("Unable to get the list of machines from the registry: %v", err)
		return nil, err
	}

	for _, s := range machines {
		if s.ID == machID {
			return &s, nil
		}
	}
	return nil, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"testing"
)

// TestMain prepares database for testing and then performs a cleanup
func TestMain(m *testing.M) {

	setup()

	retCode := m.Run()

	// your func
	teardown()

	// call with result of m.Run()
	os.Exit(retCode)
}

// TestCaptureHeader tests whether request gets new header assigned
func TestCaptureHeader(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	req, err := http.NewRequest("GET", "http://example.com", nil)
	expect(t, err, nil)

	response, err := dbClient.captureRequest(req)

	expect(t, response.Header.Get("hoverfly"), "Was-Here")
}

// TestRequestBodyCaptured tests whether request body is recorded
func TestRequestBodyCaptured(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	requestBody := []byte("fizz=buzz")

	body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	req, err := http.NewRequest("POST", "http://capture_body.com", body)
	expect(t, err, nil)

	_, err = dbClient.captureRequest(req)
	expect(t, err, nil)

	fp := getRequestFingerprint(req, requestBody)

	payloadBts, err := dbClient.cache.Get([]byte(fp))
	expect(t, err, nil)

	payload, err := decodePayload(payloadBts)
	expect(t, err, nil)
	expect(t, payload.Request.Body, "fizz=buzz")
}

func TestMatchOnRequestBody(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	// preparing and saving requests/responses with unique bodies
	for i := 0; i < 5; i++ {
		requestBody := []byte(fmt.Sprintf("fizz=buzz, number=%d", i))
		body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

		request, err := http.NewRequest("POST", "http://capture_body.com", body)
		expect(t, err, nil)

		resp := response{
			Status: 200,
			Body:   fmt.Sprintf("body here, number=%d", i),
		}
		payload := Payload{Response: resp}

		// creating response
		c := NewConstructor(request, payload)
		response := c.reconstructResponse()

		dbClient.save(request, requestBody, response, []byte(resp.Body))
	}

	// now getting responses
	for i := 0; i < 5; i++ {
		requestBody := []byte(fmt.Sprintf("fizz=buzz, number=%d", i))
		body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

		request, _ := http.NewRequest("POST", "http://capture_body.com", body)

		response := dbClient.getResponse(request)

		responseBody, err := ioutil.ReadAll(response.Body)
		response.Body.Close()

		expect(t, err, nil)
		expect(t, string(responseBody), fmt.Sprintf("body here, number=%d", i))

	}

}

func TestGetNotRecordedRequest(t *testing.T) {
	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	request, _ := http.NewRequest("POST", "http://capture_body.com", nil)

	response := dbClient.getResponse(request)

	expect(t, response.StatusCode, http.StatusPreconditionFailed)
}

// TestRequestFingerprint tests whether we get correct request ID
func TestRequestFingerprint(t *testing.T) {

	req, err := http.NewRequest("GET", "http://example.com", nil)
	expect(t, err, nil)

	fp := getRequestFingerprint(req, []byte(""))

	expect(t, fp, "92a65ed4ca2b7100037a4cba9afd15ea")
}

// TestRequestFingerprintBody tests where request body is also used to create unique request ID
func TestRequestFingerprintBody(t *testing.T) {
	req, err := http.NewRequest("GET", "http://example.com", nil)
	expect(t, err, nil)

	fp := getRequestFingerprint(req, []byte("some huge XML or JSON here"))

	expect(t, fp, "b3918a54eb6e42652e29e14c21ba8f81")
}

func TestScheme(t *testing.T) {
	req, err := http.NewRequest("GET", "http://example.com", nil)
	expect(t, err, nil)

	originalFp := getRequestFingerprint(req, []byte(""))

	httpsReq, err := http.NewRequest("GET", "https://example.com", nil)
	expect(t, err, nil)

	newFp := getRequestFingerprint(httpsReq, []byte(""))

	// fingerprint should be the same
	expect(t, originalFp, newFp)
}

func TestDeleteAllRecords(t *testing.T) {

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	// inserting some payloads
	for i := 0; i < 5; i++ {
		req, err := http.NewRequest("GET", fmt.Sprintf("http://delete_all_records.com/q=%d", i), nil)
		expect(t, err, nil)
		dbClient.captureRequest(req)
	}
	err := dbClient.cache.DeleteBucket(dbClient.cache.requestsBucket)
	expect(t, err, nil)
}

func TestPayloadEncodeDecode(t *testing.T) {
	resp := response{
		Status: 200,
		Body:   "body here",
	}

	payload := Payload{Response: resp}

	bts, err := payload.encode()
	expect(t, err, nil)

	pl, err := decodePayload(bts)
	expect(t, err, nil)
	expect(t, pl.Response.Body, resp.Body)
	expect(t, pl.Response.Status, resp.Status)

}

func TestPayloadEncodeEmpty(t *testing.T) {
	payload := Payload{}

	bts, err := payload.encode()
	expect(t, err, nil)

	_, err = decodePayload(bts)
	expect(t, err, nil)
}

func TestDecodeRandomBytes(t *testing.T) {
	bts := []byte("some random stuff here")
	_, err := decodePayload(bts)
	refute(t, err, nil)
}

func TestModifyRequest(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	dbClient.cfg.middleware = "./examples/middleware/modify_request/modify_request.py"

	req, err := http.NewRequest("GET", "http://very-interesting-website.com/q=123", nil)
	expect(t, err, nil)

	response, err := dbClient.modifyRequestResponse(req, dbClient.cfg.middleware)
	expect(t, err, nil)

	// response should be changed to 202
	expect(t, response.StatusCode, 202)

}

func TestModifyRequestNoMiddleware(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	dbClient.cfg.middleware = ""

	req, err := http.NewRequest("GET", "http://very-interesting-website.com/q=123", nil)
	expect(t, err, nil)

	_, err = dbClient.modifyRequestResponse(req, dbClient.cfg.middleware)
	refute(t, err, nil)
}

func TestGetResponseCorruptedPayload(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	requestBody := []byte("fizz=buzz")

	body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	req, err := http.NewRequest("POST", "http://capture_body.com", body)
	expect(t, err, nil)

	_, err = dbClient.captureRequest(req)
	expect(t, err, nil)

	fp := getRequestFingerprint(req, requestBody)

	dbClient.cache.Set([]byte(fp), []byte("you shall not decode me!"))

	// repeating process
	bodyNew := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	reqNew, err := http.NewRequest("POST", "http://capture_body.com", bodyNew)
	expect(t, err, nil)
	response := dbClient.getResponse(reqNew)

	expect(t, response.StatusCode, http.StatusInternalServerError)

}

func TestDoRequestWFailedMiddleware(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	// adding middleware which doesn't exist, doRequest should return error
	dbClient.cfg.middleware = "./should/not/exist.go"

	requestBody := []byte("fizz=buzz")

	body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	req, err := http.NewRequest("POST", "http://capture_body.com", body)
	expect(t, err, nil)

	_, err = dbClient.doRequest(req)
	refute(t, err, nil)
}

func TestDoRequestFailedHTTP(t *testing.T) {
	server, dbClient := testTools(200, `{'message': 'here'}`)
	// stopping server
	server.Close()

	requestBody := []byte("fizz=buzz")

	body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	req, err := http.NewRequest("POST", "http://capture_body.com", body)
	expect(t, err, nil)

	_, err = dbClient.doRequest(req)
	refute(t, err, nil)

}
<commit_msg>test to verify that middleware gets request details and is able to reconstruct it<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"testing"
)

// TestMain prepares database for testing and then performs a cleanup
func TestMain(m *testing.M) {

	setup()

	retCode := m.Run()

	// your func
	teardown()

	// call with result of m.Run()
	os.Exit(retCode)
}

// TestCaptureHeader tests whether request gets new header assigned
func TestCaptureHeader(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	req, err := http.NewRequest("GET", "http://example.com", nil)
	expect(t, err, nil)

	response, err := dbClient.captureRequest(req)

	expect(t, response.Header.Get("hoverfly"), "Was-Here")
}

// TestRequestBodyCaptured tests whether request body is recorded
func TestRequestBodyCaptured(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	requestBody := []byte("fizz=buzz")

	body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	req, err := http.NewRequest("POST", "http://capture_body.com", body)
	expect(t, err, nil)

	_, err = dbClient.captureRequest(req)
	expect(t, err, nil)

	fp := getRequestFingerprint(req, requestBody)

	payloadBts, err := dbClient.cache.Get([]byte(fp))
	expect(t, err, nil)

	payload, err := decodePayload(payloadBts)
	expect(t, err, nil)
	expect(t, payload.Request.Body, "fizz=buzz")
}

func TestMatchOnRequestBody(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	// preparing and saving requests/responses with unique bodies
	for i := 0; i < 5; i++ {
		requestBody := []byte(fmt.Sprintf("fizz=buzz, number=%d", i))
		body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

		request, err := http.NewRequest("POST", "http://capture_body.com", body)
		expect(t, err, nil)

		resp := response{
			Status: 200,
			Body:   fmt.Sprintf("body here, number=%d", i),
		}
		payload := Payload{Response: resp}

		// creating response
		c := NewConstructor(request, payload)
		response := c.reconstructResponse()

		dbClient.save(request, requestBody, response, []byte(resp.Body))
	}

	// now getting responses
	for i := 0; i < 5; i++ {
		requestBody := []byte(fmt.Sprintf("fizz=buzz, number=%d", i))
		body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

		request, _ := http.NewRequest("POST", "http://capture_body.com", body)

		response := dbClient.getResponse(request)

		responseBody, err := ioutil.ReadAll(response.Body)
		response.Body.Close()

		expect(t, err, nil)
		expect(t, string(responseBody), fmt.Sprintf("body here, number=%d", i))

	}

}

func TestGetNotRecordedRequest(t *testing.T) {
	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	request, _ := http.NewRequest("POST", "http://capture_body.com", nil)

	response := dbClient.getResponse(request)

	expect(t, response.StatusCode, http.StatusPreconditionFailed)
}

// TestRequestFingerprint tests whether we get correct request ID
func TestRequestFingerprint(t *testing.T) {

	req, err := http.NewRequest("GET", "http://example.com", nil)
	expect(t, err, nil)

	fp := getRequestFingerprint(req, []byte(""))

	expect(t, fp, "92a65ed4ca2b7100037a4cba9afd15ea")
}

// TestRequestFingerprintBody tests where request body is also used to create unique request ID
func TestRequestFingerprintBody(t *testing.T) {
	req, err := http.NewRequest("GET", "http://example.com", nil)
	expect(t, err, nil)

	fp := getRequestFingerprint(req, []byte("some huge XML or JSON here"))

	expect(t, fp, "b3918a54eb6e42652e29e14c21ba8f81")
}

func TestScheme(t *testing.T) {
	req, err := http.NewRequest("GET", "http://example.com", nil)
	expect(t, err, nil)

	originalFp := getRequestFingerprint(req, []byte(""))

	httpsReq, err := http.NewRequest("GET", "https://example.com", nil)
	expect(t, err, nil)

	newFp := getRequestFingerprint(httpsReq, []byte(""))

	// fingerprint should be the same
	expect(t, originalFp, newFp)
}

func TestDeleteAllRecords(t *testing.T) {

	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	// inserting some payloads
	for i := 0; i < 5; i++ {
		req, err := http.NewRequest("GET", fmt.Sprintf("http://delete_all_records.com/q=%d", i), nil)
		expect(t, err, nil)
		dbClient.captureRequest(req)
	}
	err := dbClient.cache.DeleteBucket(dbClient.cache.requestsBucket)
	expect(t, err, nil)
}

func TestPayloadEncodeDecode(t *testing.T) {
	resp := response{
		Status: 200,
		Body:   "body here",
	}

	payload := Payload{Response: resp}

	bts, err := payload.encode()
	expect(t, err, nil)

	pl, err := decodePayload(bts)
	expect(t, err, nil)
	expect(t, pl.Response.Body, resp.Body)
	expect(t, pl.Response.Status, resp.Status)

}

func TestPayloadEncodeEmpty(t *testing.T) {
	payload := Payload{}

	bts, err := payload.encode()
	expect(t, err, nil)

	_, err = decodePayload(bts)
	expect(t, err, nil)
}

func TestDecodeRandomBytes(t *testing.T) {
	bts := []byte("some random stuff here")
	_, err := decodePayload(bts)
	refute(t, err, nil)
}

func TestModifyRequest(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	dbClient.cfg.middleware = "./examples/middleware/modify_request/modify_request.py"

	req, err := http.NewRequest("GET", "http://very-interesting-website.com/q=123", nil)
	expect(t, err, nil)

	response, err := dbClient.modifyRequestResponse(req, dbClient.cfg.middleware)
	expect(t, err, nil)

	// response should be changed to 202
	expect(t, response.StatusCode, 202)

}

func TestModifyRequestWODestination(t *testing.T) {
	// tests modify mode but uses different middleware to not supply destination
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	dbClient.cfg.middleware = "./examples/middleware/modify_response/modify_response.py"

	req, err := http.NewRequest("GET", "http://very-interesting-website.com/q=123", nil)
	expect(t, err, nil)

	response, err := dbClient.modifyRequestResponse(req, dbClient.cfg.middleware)
	expect(t, err, nil)

	// response should be changed to 201
	expect(t, response.StatusCode, 201)

}

func TestModifyRequestNoMiddleware(t *testing.T) {
	server, dbClient := testTools(201, `{'message': 'here'}`)
	defer server.Close()

	dbClient.cfg.middleware = ""

	req, err := http.NewRequest("GET", "http://very-interesting-website.com/q=123", nil)
	expect(t, err, nil)

	_, err = dbClient.modifyRequestResponse(req, dbClient.cfg.middleware)
	refute(t, err, nil)
}

func TestGetResponseCorruptedPayload(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	requestBody := []byte("fizz=buzz")

	body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	req, err := http.NewRequest("POST", "http://capture_body.com", body)
	expect(t, err, nil)

	_, err = dbClient.captureRequest(req)
	expect(t, err, nil)

	fp := getRequestFingerprint(req, requestBody)

	dbClient.cache.Set([]byte(fp), []byte("you shall not decode me!"))

	// repeating process
	bodyNew := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	reqNew, err := http.NewRequest("POST", "http://capture_body.com", bodyNew)
	expect(t, err, nil)
	response := dbClient.getResponse(reqNew)

	expect(t, response.StatusCode, http.StatusInternalServerError)

}

func TestDoRequestWFailedMiddleware(t *testing.T) {

	server, dbClient := testTools(200, `{'message': 'here'}`)
	defer server.Close()

	// adding middleware which doesn't exist, doRequest should return error
	dbClient.cfg.middleware = "./should/not/exist.go"

	requestBody := []byte("fizz=buzz")

	body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	req, err := http.NewRequest("POST", "http://capture_body.com", body)
	expect(t, err, nil)

	_, err = dbClient.doRequest(req)
	refute(t, err, nil)
}

func TestDoRequestFailedHTTP(t *testing.T) {
	server, dbClient := testTools(200, `{'message': 'here'}`)
	// stopping server
	server.Close()

	requestBody := []byte("fizz=buzz")

	body := ioutil.NopCloser(bytes.NewBuffer(requestBody))

	req, err := http.NewRequest("POST", "http://capture_body.com", body)
	expect(t, err, nil)

	_, err = dbClient.doRequest(req)
	refute(t, err, nil)

}
<|endoftext|>


<commit_before>package ps

import (
	"bytes"
	"testing"

	"github.com/docker/docker/api/types"
)

func TestFormat(t *testing.T) {
	contexts := []struct {
		context  Context
		expected string
	}{
		// Errors
		{
			Context{
				Format: "{{InvalidFunction}}",
			},
			`Template parsing error: template: :1: function "InvalidFunction" not defined
`,
		},
		{
			Context{
				Format: "{{nil}}",
			},
			`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
`,
		},
		// Table Format
		{
			Context{
				Format: "table",
			},
			`CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
containerID1        ubuntu              ""                  45 years ago                                                foobar_baz
containerID2        ubuntu              ""                  45 years ago                                                foobar_bar
`,
		},
		{
			Context{
				Format: "table {{.Image}}",
			},
			"IMAGE\nubuntu\nubuntu\n",
		},
		{
			Context{
				Format: "table {{.Image}}",
				Size:   true,
			},
			"IMAGE               SIZE\nubuntu              0 B\nubuntu              0 B\n",
		},
		{
			Context{
				Format: "table {{.Image}}",
				Quiet:  true,
			},
			"IMAGE\nubuntu\nubuntu\n",
		},
		{
			Context{
				Format: "table",
				Quiet:  true,
			},
			"containerID1\ncontainerID2\n",
		},
		// Raw Format
		{
			Context{
				Format: "raw",
			},
			`container_id: containerID1
image: ubuntu
command: ""
created_at: 1970-01-01 00:00:00 +0000 UTC
status:
names: foobar_baz
labels:
ports:

container_id: containerID2
image: ubuntu
command: ""
created_at: 1970-01-01 00:00:00 +0000 UTC
status:
names: foobar_bar
labels:
ports:

`,
		},
		{
			Context{
				Format: "raw",
				Size:   true,
			},
			`container_id: containerID1
image: ubuntu
command: ""
created_at: 1970-01-01 00:00:00 +0000 UTC
status:
names: foobar_baz
labels:
ports:
size: 0 B

container_id: containerID2
image: ubuntu
command: ""
created_at: 1970-01-01 00:00:00 +0000 UTC
status:
names: foobar_bar
labels:
ports:
size: 0 B

`,
		},
		{
			Context{
				Format: "raw",
				Quiet:  true,
			},
			"container_id: containerID1\ncontainer_id: containerID2\n",
		},
		// Custom Format
		{
			Context{
				Format: "{{.Image}}",
			},
			"ubuntu\nubuntu\n",
		},
		{
			Context{
				Format: "{{.Image}}",
				Size:   true,
			},
			"ubuntu\nubuntu\n",
		},
	}

	for _, context := range contexts {
		containers := []types.Container{
			{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu"},
			{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu"},
		}
		out := bytes.NewBufferString("")
		context.context.Output = out
		Format(context.context, containers)
		actual := out.String()
		if actual != context.expected {
			t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
		}
		// Clean buffer
		out.Reset()
	}
}

func TestCustomFormatNoContainers(t *testing.T) {
	out := bytes.NewBufferString("")
	containers := []types.Container{}

	contexts := []struct {
		context  Context
		expected string
	}{
		{
			Context{
				Format: "{{.Image}}",
				Output: out,
			},
			"",
		},
		{
			Context{
				Format: "table {{.Image}}",
				Output: out,
			},
			"IMAGE\n",
		},
		{
			Context{
				Format: "{{.Image}}",
				Output: out,
				Size:   true,
			},
			"",
		},
		{
			Context{
				Format: "table {{.Image}}",
				Output: out,
				Size:   true,
			},
			"IMAGE               SIZE\n",
		},
	}

	for _, context := range contexts {
		customFormat(context.context, containers)
		actual := out.String()
		if actual != context.expected {
			t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
		}
		// Clean buffer
		out.Reset()
	}
}
<commit_msg>Fix the api/client/ps unit tests.<commit_after>package ps

import (
	"bytes"
	"fmt"
	"testing"
	"time"

	"github.com/docker/docker/api/types"
)

func TestFormat(t *testing.T) {
	unixTime := time.Now().Add(-50 * time.Hour).Unix()
	expectedTime := time.Unix(unixTime, 0).String()

	contexts := []struct {
		context  Context
		expected string
	}{
		// Errors
		{
			Context{
				Format: "{{InvalidFunction}}",
			},
			`Template parsing error: template: :1: function "InvalidFunction" not defined
`,
		},
		{
			Context{
				Format: "{{nil}}",
			},
			`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
`,
		},
		// Table Format
		{
			Context{
				Format: "table",
			},
			`CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
containerID1        ubuntu              ""                  2 days ago                                                  foobar_baz
containerID2        ubuntu              ""                  2 days ago                                                  foobar_bar
`,
		},
		{
			Context{
				Format: "table {{.Image}}",
			},
			"IMAGE\nubuntu\nubuntu\n",
		},
		{
			Context{
				Format: "table {{.Image}}",
				Size:   true,
			},
			"IMAGE               SIZE\nubuntu              0 B\nubuntu              0 B\n",
		},
		{
			Context{
				Format: "table {{.Image}}",
				Quiet:  true,
			},
			"IMAGE\nubuntu\nubuntu\n",
		},
		{
			Context{
				Format: "table",
				Quiet:  true,
			},
			"containerID1\ncontainerID2\n",
		},
		// Raw Format
		{
			Context{
				Format: "raw",
			},
			fmt.Sprintf(`container_id: containerID1
image: ubuntu
command: ""
created_at: %s
status:
names: foobar_baz
labels:
ports:

container_id: containerID2
image: ubuntu
command: ""
created_at: %s
status:
names: foobar_bar
labels:
ports:

`, expectedTime, expectedTime),
		},
		{
			Context{
				Format: "raw",
				Size:   true,
			},
			fmt.Sprintf(`container_id: containerID1
image: ubuntu
command: ""
created_at: %s
status:
names: foobar_baz
labels:
ports:
size: 0 B

container_id: containerID2
image: ubuntu
command: ""
created_at: %s
status:
names: foobar_bar
labels:
ports:
size: 0 B

`, expectedTime, expectedTime),
		},
		{
			Context{
				Format: "raw",
				Quiet:  true,
			},
			"container_id: containerID1\ncontainer_id: containerID2\n",
		},
		// Custom Format
		{
			Context{
				Format: "{{.Image}}",
			},
			"ubuntu\nubuntu\n",
		},
		{
			Context{
				Format: "{{.Image}}",
				Size:   true,
			},
			"ubuntu\nubuntu\n",
		},
	}

	for _, context := range contexts {
		containers := []types.Container{
			{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime},
			{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unixTime},
		}
		out := bytes.NewBufferString("")
		context.context.Output = out
		Format(context.context, containers)
		actual := out.String()
		if actual != context.expected {
			t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
		}
		// Clean buffer
		out.Reset()
	}
}

func TestCustomFormatNoContainers(t *testing.T) {
	out := bytes.NewBufferString("")
	containers := []types.Container{}

	contexts := []struct {
		context  Context
		expected string
	}{
		{
			Context{
				Format: "{{.Image}}",
				Output: out,
			},
			"",
		},
		{
			Context{
				Format: "table {{.Image}}",
				Output: out,
			},
			"IMAGE\n",
		},
		{
			Context{
				Format: "{{.Image}}",
				Output: out,
				Size:   true,
			},
			"",
		},
		{
			Context{
				Format: "table {{.Image}}",
				Output: out,
				Size:   true,
			},
			"IMAGE               SIZE\n",
		},
	}

	for _, context := range contexts {
		customFormat(context.context, containers)
		actual := out.String()
		if actual != context.expected {
			t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
		}
		// Clean buffer
		out.Reset()
	}
}
<|endoftext|>


<commit_before>// Copyright 2021 The Ebiten 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 go2cpp

import (
	"io"
	"runtime"
	"sync"
	"syscall/js"
)

type Context struct {
	v js.Value
}

func NewContext(sampleRate int) *Context {
	v := js.Global().Get("go2cpp").Call("createAudio", sampleRate, 2, 2, 8192)
	return &Context{
		v: v,
	}
}

func (c *Context) NewPlayer(r io.Reader) *Player {
	cond := sync.NewCond(&sync.Mutex{})
	onwritten := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		cond.Signal()
		return nil
	})
	v := c.v.Call("createPlayer", onwritten)
	p := &Player{
		src:       r,
		v:         v,
		cond:      cond,
		onWritten: onwritten,
	}
	runtime.SetFinalizer(p, (*Player).Close)

	go p.loop()
	return p
}

func (c *Context) Close() error {
	return nil
}

type playerState int

const (
	playerStatePaused playerState = iota
	playerStatePlaying
	playerStateClosed
	playerStateError
)

type Player struct {
	src   io.Reader
	v     js.Value
	state playerState
	cond  *sync.Cond
	err   error

	onWritten js.Func
}

func (p *Player) Pause() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateClosed {
		return
	}
	p.v.Call("pause")
	p.state = playerStatePaused
	p.cond.Signal()
}

func (p *Player) Play() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateClosed {
		return
	}
	p.v.Call("play")
	p.state = playerStatePlaying
	p.cond.Signal()
}

func (p *Player) Reset() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateClosed {
		return
	}

	p.v.Call("reset")
	p.cond.Signal()
}

func (p *Player) Volume() float64 {
	return p.v.Get("volume").Float()
}

func (p *Player) SetVolume(volume float64) {
	p.v.Set("volume", volume)
}

func (p *Player) Close() error {
	runtime.SetFinalizer(p, nil)

	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateError {
		return p.err
	}

	p.v.Call("close")
	p.state = playerStateClosed
	p.cond.Signal()
	p.onWritten.Release()
	return nil
}

func (p *Player) setError(err error) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateError {
		return
	}

	p.v.Call("close")
	p.err = err
	p.state = playerStateClosed
	p.cond.Signal()
}

func (p *Player) waitUntilUnpaused() bool {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	for p.state == playerStatePaused || (p.state == playerStatePlaying && !p.v.Call("isWritable").Bool()) {
		p.cond.Wait()
	}
	return p.state == playerStatePlaying
}

func (p *Player) loop() {
	const size = 4096

	buf := make([]byte, size)
	dst := js.Global().Get("Uint8Array").New(size)

	for {
		if !p.waitUntilUnpaused() {
			return
		}

		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setError(err)
			return
		}
		if n > 0 {
			js.CopyBytesToJS(dst, buf[:n])
			p.v.Call("write", dst, n)
		}

		if err == io.EOF {
			// TODO: This should be Pause instead of Close for Rewind
			p.Close()
			return
		}
	}
}
<commit_msg>audio/internal/go2cpp: Recreate the underlying audio player when resetting<commit_after>// Copyright 2021 The Ebiten 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 go2cpp

import (
	"io"
	"runtime"
	"sync"
	"syscall/js"
)

type Context struct {
	v js.Value
}

func NewContext(sampleRate int) *Context {
	v := js.Global().Get("go2cpp").Call("createAudio", sampleRate, 2, 2, 8192)
	return &Context{
		v: v,
	}
}

func (c *Context) NewPlayer(r io.Reader) *Player {
	cond := sync.NewCond(&sync.Mutex{})
	onwritten := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		cond.Signal()
		return nil
	})
	p := &Player{
		context:   c,
		src:       r,
		volume:    1,
		cond:      cond,
		onWritten: onwritten,
	}
	runtime.SetFinalizer(p, (*Player).Close)
	return p
}

func (c *Context) Close() error {
	return nil
}

type playerState int

const (
	playerStatePaused playerState = iota
	playerStatePlaying
	playerStateClosed
)

type Player struct {
	context *Context
	src     io.Reader
	v       js.Value
	state   playerState
	volume  float64
	cond    *sync.Cond
	err     error

	onWritten js.Func
}

func (p *Player) Pause() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateClosed {
		return
	}
	if !p.v.Truthy() {
		return
	}

	p.v.Call("pause")
	p.state = playerStatePaused
	p.cond.Signal()
}

func (p *Player) Play() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateClosed {
		return
	}
	if !p.v.Truthy() {
		p.v = p.context.v.Call("createPlayer", p.onWritten)
		p.v.Set("volume", p.volume)
		go p.loop()
	}

	p.v.Call("play")
	p.state = playerStatePlaying
	p.cond.Signal()
}

func (p *Player) Reset() {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateClosed {
		return
	}
	if !p.v.Truthy() {
		return
	}

	p.v.Call("close", true)
	p.v = js.Undefined()
	p.cond.Signal()
}

func (p *Player) Volume() float64 {
	if !p.v.Truthy() {
		return p.volume
	}
	return p.v.Get("volume").Float()
}

func (p *Player) SetVolume(volume float64) {
	if !p.v.Truthy() {
		return
	}
	p.v.Set("volume", volume)
	p.volume = volume
}

func (p *Player) Close() error {
	runtime.SetFinalizer(p, nil)
	return p.close(true)
}

func (p *Player) close(remove bool) error {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state == playerStateClosed {
		return p.err
	}

	p.v.Call("close", false)
	p.v = js.Undefined()
	if remove {
		p.state = playerStateClosed
		p.onWritten.Release()
	} else {
		p.state = playerStatePaused
	}
	p.cond.Signal()
	return p.err
}

func (p *Player) setError(err error) {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	if p.state != playerStateClosed && p.v.Truthy() {
		p.v.Call("close", true)
		p.v = js.Undefined()
	}
	p.err = err
	p.state = playerStateClosed
	p.cond.Signal()
}

func (p *Player) waitUntilUnpaused() bool {
	p.cond.L.Lock()
	defer p.cond.L.Unlock()

	for p.v.Truthy() && (p.state == playerStatePaused || (p.state == playerStatePlaying && !p.v.Call("isWritable").Bool())) {
		p.cond.Wait()
	}
	return p.v.Truthy() && p.state == playerStatePlaying
}

func (p *Player) loop() {
	const size = 4096

	buf := make([]byte, size)
	dst := js.Global().Get("Uint8Array").New(size)

	for {
		if !p.waitUntilUnpaused() {
			return
		}

		n, err := p.src.Read(buf)
		if err != nil && err != io.EOF {
			p.setError(err)
			return
		}
		if n > 0 {
			js.CopyBytesToJS(dst, buf[:n])
			p.v.Call("write", dst, n)
		}

		if err == io.EOF {
			p.close(false)
			return
		}
	}
}
<|endoftext|>


<commit_before>package runner

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/iron-io/functions/api/models"
	"github.com/iron-io/functions/api/mqs"
)

func getMockTask() models.Task {
	priority := int32(0)
	image := fmt.Sprintf("Image-%d", rand.Int31()%1000)
	task := &models.Task{}
	task.Image = &image
	task.ID = fmt.Sprintf("ID-%d", rand.Int31()%1000)
	task.RouteName = fmt.Sprintf("RouteName-%d", rand.Int31()%1000)
	task.Priority = &priority
	return *task
}

func getTestServer(mockTasks []*models.Task) *httptest.Server {
	mq, err := mqs.New("memory://test")
	if err != nil {
		panic(err)
	}

	for _, mt := range mockTasks {
		mq.Push(mt)
	}

	getHandler := func(c *gin.Context) {
		task, err := mq.Reserve()
		if err != nil {
			logrus.WithError(err)
			c.JSON(http.StatusInternalServerError, err)
			return
		}
		c.JSON(http.StatusAccepted, task)
	}

	delHandler := func(c *gin.Context) {
		body, err := ioutil.ReadAll(c.Request.Body)
		if err != nil {
			logrus.WithError(err)
			c.JSON(http.StatusInternalServerError, err.Error())
			return
		}
		var task models.Task
		if err = json.Unmarshal(body, &task); err != nil {
			logrus.WithError(err)
			c.JSON(http.StatusInternalServerError, err.Error())
			return
		}

		if err := mq.Delete(&task); err != nil {
			logrus.WithError(err)
			c.JSON(http.StatusInternalServerError, err.Error())
			return
		}
		c.JSON(http.StatusAccepted, task)
	}

	r := gin.Default()
	r.GET("/tasks", getHandler)
	r.DELETE("/tasks", delHandler)
	return httptest.NewServer(r)
}

func TestGetTask(t *testing.T) {
	mockTask := getMockTask()

	ts := getTestServer([]*models.Task{&mockTask})
	defer ts.Close()

	url := ts.URL + "/tasks"
	task, err := getTask(url)
	if err != nil {
		t.Error("expected no error, got", err)
	}
	if task.ID != mockTask.ID {
		t.Errorf("expected task ID '%s', got '%s'", task.ID, mockTask.ID)
	}
}

func TestGetTaskError(t *testing.T) {
	tests := []map[string]interface{}{
		map[string]interface{}{
			"url":   "/invalid",
			"task":  getMockTask(),
			"error": "invalid character 'p' after top-level value",
		},
	}

	var tasks []*models.Task
	for _, v := range tests {
		task := v["task"].(models.Task)
		tasks = append(tasks, &task)
	}

	ts := getTestServer(tasks)
	defer ts.Close()

	for i, test := range tests {
		url := ts.URL + test["url"].(string)
		_, err := getTask(url)
		if err == nil {
			t.Errorf("expected error '%s'", test["error"].(string))
		}
		if err.Error() != test["error"].(string) {
			t.Errorf("test %d: expected error '%s', got '%s'", i, test["error"].(string), err)
		}
	}
}

func TestDeleteTask(t *testing.T) {
	mockTask := getMockTask()

	ts := getTestServer([]*models.Task{&mockTask})
	defer ts.Close()

	url := ts.URL + "/tasks"
	err := deleteTask(url, &mockTask)
	if err == nil {
		t.Error("expected error 'Not reserver', got", err)
	}

	_, err = getTask(url)
	if err != nil {
		t.Error("expected no error, got", err)
	}

	err = deleteTask(url, &mockTask)
	if err != nil {
		t.Error("expected no error, got", err)
	}
}
<commit_msg>update tests with new mq interface<commit_after>package runner

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/iron-io/functions/api/models"
	"github.com/iron-io/functions/api/mqs"
)

func getMockTask() models.Task {
	priority := int32(0)
	image := fmt.Sprintf("Image-%d", rand.Int31()%1000)
	task := &models.Task{}
	task.Image = &image
	task.ID = fmt.Sprintf("ID-%d", rand.Int31()%1000)
	task.RouteName = fmt.Sprintf("RouteName-%d", rand.Int31()%1000)
	task.Priority = &priority
	return *task
}

func getTestServer(mockTasks []*models.Task) *httptest.Server {
	ctx := context.TODO()

	mq, err := mqs.New("memory://test")
	if err != nil {
		panic(err)
	}

	for _, mt := range mockTasks {
		mq.Push(ctx, mt)
	}

	getHandler := func(c *gin.Context) {
		task, err := mq.Reserve(ctx)
		if err != nil {
			logrus.WithError(err)
			c.JSON(http.StatusInternalServerError, err)
			return
		}
		c.JSON(http.StatusAccepted, task)
	}

	delHandler := func(c *gin.Context) {
		body, err := ioutil.ReadAll(c.Request.Body)
		if err != nil {
			logrus.WithError(err)
			c.JSON(http.StatusInternalServerError, err.Error())
			return
		}
		var task models.Task
		if err = json.Unmarshal(body, &task); err != nil {
			logrus.WithError(err)
			c.JSON(http.StatusInternalServerError, err.Error())
			return
		}

		if err := mq.Delete(ctx, &task); err != nil {
			logrus.WithError(err)
			c.JSON(http.StatusInternalServerError, err.Error())
			return
		}
		c.JSON(http.StatusAccepted, task)
	}

	r := gin.Default()
	r.GET("/tasks", getHandler)
	r.DELETE("/tasks", delHandler)
	return httptest.NewServer(r)
}

func TestGetTask(t *testing.T) {
	mockTask := getMockTask()

	ts := getTestServer([]*models.Task{&mockTask})
	defer ts.Close()

	url := ts.URL + "/tasks"
	task, err := getTask(url)
	if err != nil {
		t.Error("expected no error, got", err)
	}
	if task.ID != mockTask.ID {
		t.Errorf("expected task ID '%s', got '%s'", task.ID, mockTask.ID)
	}
}

func TestGetTaskError(t *testing.T) {
	tests := []map[string]interface{}{
		map[string]interface{}{
			"url":   "/invalid",
			"task":  getMockTask(),
			"error": "invalid character 'p' after top-level value",
		},
	}

	var tasks []*models.Task
	for _, v := range tests {
		task := v["task"].(models.Task)
		tasks = append(tasks, &task)
	}

	ts := getTestServer(tasks)
	defer ts.Close()

	for i, test := range tests {
		url := ts.URL + test["url"].(string)
		_, err := getTask(url)
		if err == nil {
			t.Errorf("expected error '%s'", test["error"].(string))
		}
		if err.Error() != test["error"].(string) {
			t.Errorf("test %d: expected error '%s', got '%s'", i, test["error"].(string), err)
		}
	}
}

func TestDeleteTask(t *testing.T) {
	mockTask := getMockTask()

	ts := getTestServer([]*models.Task{&mockTask})
	defer ts.Close()

	url := ts.URL + "/tasks"
	err := deleteTask(url, &mockTask)
	if err == nil {
		t.Error("expected error 'Not reserver', got", err)
	}

	_, err = getTask(url)
	if err != nil {
		t.Error("expected no error, got", err)
	}

	err = deleteTask(url, &mockTask)
	if err != nil {
		t.Error("expected no error, got", err)
	}
}
<|endoftext|>


<commit_before>package apiGatewayDeploy

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/30x/apid"
	"github.com/30x/apid/factory"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

var (
	tmpDir     string
	testServer *httptest.Server
)

var _ = BeforeSuite(func() {
	apid.Initialize(factory.DefaultServicesFactory())

	config := apid.Config()

	config.SetDefault("apigeesync_proxy_server_base", "X")
	config.SetDefault("apigeesync_consumer_key", "X")
	config.SetDefault("apigeesync_consumer_secret", "X")
	config.SetDefault("apigeesync_snapshot_server_base", "X")
	config.SetDefault("apigeesync_change_server_base", "X")
	config.SetDefault("apigeesync_log_level", "info")

	var err error
	tmpDir, err = ioutil.TempDir("", "api_test")
	Expect(err).NotTo(HaveOccurred())

	config.Set("data_path", tmpDir)
	config.Set(configBundleDir, tmpDir)

	// init() will create the tables
	apid.InitializePlugins()

	router := apid.API().Router()
	// fake bundle repo
	router.HandleFunc("/bundle", func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte("bundle stuff"))
	})
	testServer = httptest.NewServer(router)
})

var _ = AfterSuite(func() {
	apid.Events().Close()
	if testServer != nil {
		testServer.Close()
	}
	os.RemoveAll(tmpDir)
})

func TestApidGatewayDeploy(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "ApidGatewayDeploy Suite")
}
<commit_msg>Cleanup<commit_after>package apiGatewayDeploy

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/30x/apid"
	"github.com/30x/apid/factory"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
)

var (
	tmpDir     string
	testServer *httptest.Server
)

var _ = BeforeSuite(func() {
	apid.Initialize(factory.DefaultServicesFactory())

	config := apid.Config()

	var err error
	tmpDir, err = ioutil.TempDir("", "api_test")
	Expect(err).NotTo(HaveOccurred())

	config.Set("data_path", tmpDir)
	config.Set(configBundleDir, tmpDir)

	// init() will create the tables
	apid.InitializePlugins()

	router := apid.API().Router()
	// fake bundle repo
	router.HandleFunc("/bundle", func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte("bundle stuff"))
	})
	testServer = httptest.NewServer(router)
})

var _ = AfterSuite(func() {
	apid.Events().Close()
	if testServer != nil {
		testServer.Close()
	}
	os.RemoveAll(tmpDir)
})

func TestApidGatewayDeploy(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "ApidGatewayDeploy Suite")
}
<|endoftext|>


<commit_before>package obj

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io"

	"golang.org/x/sync/errgroup"

	"github.com/Azure/azure-sdk-for-go/storage"
	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
)

const (
	maxBlockSize = 100 * 1024 * 1024 // 100MB (according to: https://docs.microsoft.com/en-us/rest/api/storageservices/understanding-block-blobs--append-blobs--and-page-blobs#about-block-blobs)
)

var (
	bufPool = grpcutil.NewBufPool(maxBlockSize)
)

type microsoftClient struct {
	blobClient storage.BlobStorageClient
	container  string
}

func newMicrosoftClient(container string, accountName string, accountKey string) (*microsoftClient, error) {
	client, err := storage.NewBasicClient(
		accountName,
		accountKey,
	)
	if err != nil {
		return nil, err
	}

	return &microsoftClient{
		blobClient: client.GetBlobService(),
		container:  container,
	}, nil
}

func (c *microsoftClient) Writer(name string) (io.WriteCloser, error) {
	writer, err := newMicrosoftWriter(c, name)
	if err != nil {
		return nil, err
	}
	return newBackoffWriteCloser(c, writer), nil
}

func (c *microsoftClient) Reader(name string, offset uint64, size uint64) (io.ReadCloser, error) {
	byteRange := byteRange(offset, size)
	var reader io.ReadCloser
	var err error
	if byteRange == "" {
		reader, err = c.blobClient.GetBlob(c.container, name)
	} else {
		reader, err = c.blobClient.GetBlobRange(c.container, name, byteRange, nil)
	}

	if err != nil {
		return nil, err
	}
	return newBackoffReadCloser(c, reader), nil
}

func (c *microsoftClient) Delete(name string) error {
	return c.blobClient.DeleteBlob(c.container, name, nil)
}

func (c *microsoftClient) Walk(name string, fn func(name string) error) error {
	// See Azure docs for what `marker` does:
	// https://docs.microsoft.com/en-us/rest/api/storageservices/List-Blobs?redirectedfrom=MSDN
	var marker string
	for {
		blobList, err := c.blobClient.ListBlobs(c.container, storage.ListBlobsParameters{
			Prefix: name,
			Marker: marker,
		})
		if err != nil {
			return err
		}

		for _, file := range blobList.Blobs {
			if err := fn(file.Name); err != nil {
				return err
			}
		}

		// NextMarker is empty when all results have been returned
		if blobList.NextMarker == "" {
			break
		}
		marker = blobList.NextMarker
	}
	return nil
}

func (c *microsoftClient) Exists(name string) bool {
	exists, _ := c.blobClient.BlobExists(c.container, name)
	return exists
}

func (c *microsoftClient) IsRetryable(err error) (ret bool) {
	microsoftErr, ok := err.(storage.AzureStorageServiceError)
	if !ok {
		return false
	}
	return microsoftErr.StatusCode >= 500
}

func (c *microsoftClient) IsNotExist(err error) bool {
	microsoftErr, ok := err.(storage.AzureStorageServiceError)
	if !ok {
		return false
	}
	return microsoftErr.StatusCode == 404
}

func (c *microsoftClient) IsIgnorable(err error) bool {
	return false
}

type microsoftWriter struct {
	container  string
	blob       string
	blobClient storage.BlobStorageClient
	buf        *bytes.Buffer
	nBlocks    int
	eg         errgroup.Group
	err        error
}

func newMicrosoftWriter(client *microsoftClient, name string) (*microsoftWriter, error) {
	if _, err := client.blobClient.CreateContainerIfNotExists(client.container, storage.ContainerAccessTypePrivate); err != nil {
		return nil, err
	}
	if err := client.blobClient.CreateBlockBlob(client.container, name); err != nil {
		return nil, err
	}
	return &microsoftWriter{
		container:  client.container,
		blob:       name,
		blobClient: client.blobClient,
		buf:        bytes.NewBuffer(bufPool.GetBuffer()[:0]),
	}, nil
}

func (w *microsoftWriter) Write(b []byte) (int, error) {
	if w.err != nil {
		// w.err wasn't generated by putting this block but a previous block,
		// we return it here though because PutBlock is called async so we
		// can't return it from the correct call but we also don't want to wait
		// until the end to handle errors.
		return 0, w.err
	}
	nBytes := 0
	for {
		if w.buf.Len()+len(b) >= maxBlockSize {
			offset := maxBlockSize - w.buf.Len()
			w.buf.Write(b[:offset])
			w.writeBlock(w.buf.Bytes())
			nBytes += offset
			w.buf = bytes.NewBuffer(bufPool.GetBuffer()[:0])
			b = b[offset:]
		} else {
			w.buf.Write(b)
			nBytes += len(b)
			break
		}
	}
	return nBytes, nil
}

func blockID(n int) string {
	return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%011d\n", n)))
}

func (w *microsoftWriter) writeBlock(b []byte) {
	block := w.nBlocks
	w.nBlocks++
	w.eg.Go(func() error {
		defer bufPool.PutBuffer(b)
		if err := w.blobClient.PutBlock(w.container, w.blob, blockID(block), b); err != nil {
			w.err = err
			return err
		}
		return nil
	})
}

func (w *microsoftWriter) Close() error {
	if w.buf.Len() > 0 {
		w.writeBlock(w.buf.Bytes())
	}
	if err := w.eg.Wait(); err != nil {
		return err
	}
	blocks := make([]storage.Block, w.nBlocks)
	for i := range blocks {
		blocks[i] = storage.Block{ID: blockID(i), Status: storage.BlockStatusUncommitted}
	}
	return w.blobClient.PutBlockList(w.container, w.blob, blocks)
}
<commit_msg>Add clarifying comment.<commit_after>package obj

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"io"

	"golang.org/x/sync/errgroup"

	"github.com/Azure/azure-sdk-for-go/storage"
	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
)

const (
	maxBlockSize = 100 * 1024 * 1024 // 100MB (according to: https://docs.microsoft.com/en-us/rest/api/storageservices/understanding-block-blobs--append-blobs--and-page-blobs#about-block-blobs)
)

var (
	bufPool = grpcutil.NewBufPool(maxBlockSize)
)

type microsoftClient struct {
	blobClient storage.BlobStorageClient
	container  string
}

func newMicrosoftClient(container string, accountName string, accountKey string) (*microsoftClient, error) {
	client, err := storage.NewBasicClient(
		accountName,
		accountKey,
	)
	if err != nil {
		return nil, err
	}

	return &microsoftClient{
		blobClient: client.GetBlobService(),
		container:  container,
	}, nil
}

func (c *microsoftClient) Writer(name string) (io.WriteCloser, error) {
	writer, err := newMicrosoftWriter(c, name)
	if err != nil {
		return nil, err
	}
	return newBackoffWriteCloser(c, writer), nil
}

func (c *microsoftClient) Reader(name string, offset uint64, size uint64) (io.ReadCloser, error) {
	byteRange := byteRange(offset, size)
	var reader io.ReadCloser
	var err error
	if byteRange == "" {
		reader, err = c.blobClient.GetBlob(c.container, name)
	} else {
		reader, err = c.blobClient.GetBlobRange(c.container, name, byteRange, nil)
	}

	if err != nil {
		return nil, err
	}
	return newBackoffReadCloser(c, reader), nil
}

func (c *microsoftClient) Delete(name string) error {
	return c.blobClient.DeleteBlob(c.container, name, nil)
}

func (c *microsoftClient) Walk(name string, fn func(name string) error) error {
	// See Azure docs for what `marker` does:
	// https://docs.microsoft.com/en-us/rest/api/storageservices/List-Blobs?redirectedfrom=MSDN
	var marker string
	for {
		blobList, err := c.blobClient.ListBlobs(c.container, storage.ListBlobsParameters{
			Prefix: name,
			Marker: marker,
		})
		if err != nil {
			return err
		}

		for _, file := range blobList.Blobs {
			if err := fn(file.Name); err != nil {
				return err
			}
		}

		// NextMarker is empty when all results have been returned
		if blobList.NextMarker == "" {
			break
		}
		marker = blobList.NextMarker
	}
	return nil
}

func (c *microsoftClient) Exists(name string) bool {
	exists, _ := c.blobClient.BlobExists(c.container, name)
	return exists
}

func (c *microsoftClient) IsRetryable(err error) (ret bool) {
	microsoftErr, ok := err.(storage.AzureStorageServiceError)
	if !ok {
		return false
	}
	return microsoftErr.StatusCode >= 500
}

func (c *microsoftClient) IsNotExist(err error) bool {
	microsoftErr, ok := err.(storage.AzureStorageServiceError)
	if !ok {
		return false
	}
	return microsoftErr.StatusCode == 404
}

func (c *microsoftClient) IsIgnorable(err error) bool {
	return false
}

type microsoftWriter struct {
	container  string
	blob       string
	blobClient storage.BlobStorageClient
	buf        *bytes.Buffer
	nBlocks    int
	eg         errgroup.Group
	err        error // used for fast exit from Write below
}

func newMicrosoftWriter(client *microsoftClient, name string) (*microsoftWriter, error) {
	if _, err := client.blobClient.CreateContainerIfNotExists(client.container, storage.ContainerAccessTypePrivate); err != nil {
		return nil, err
	}
	if err := client.blobClient.CreateBlockBlob(client.container, name); err != nil {
		return nil, err
	}
	return &microsoftWriter{
		container:  client.container,
		blob:       name,
		blobClient: client.blobClient,
		buf:        bytes.NewBuffer(bufPool.GetBuffer()[:0]),
	}, nil
}

func (w *microsoftWriter) Write(b []byte) (int, error) {
	if w.err != nil {
		// w.err wasn't generated by putting this block but a previous block,
		// we return it here though because PutBlock is called async so we
		// can't return it from the correct call but we also don't want to wait
		// until the end to handle errors.
		return 0, w.err
	}
	nBytes := 0
	for {
		if w.buf.Len()+len(b) >= maxBlockSize {
			offset := maxBlockSize - w.buf.Len()
			w.buf.Write(b[:offset])
			w.writeBlock(w.buf.Bytes())
			nBytes += offset
			w.buf = bytes.NewBuffer(bufPool.GetBuffer()[:0])
			b = b[offset:]
		} else {
			w.buf.Write(b)
			nBytes += len(b)
			break
		}
	}
	return nBytes, nil
}

func blockID(n int) string {
	return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%011d\n", n)))
}

func (w *microsoftWriter) writeBlock(b []byte) {
	block := w.nBlocks
	w.nBlocks++
	w.eg.Go(func() error {
		defer bufPool.PutBuffer(b)
		if err := w.blobClient.PutBlock(w.container, w.blob, blockID(block), b); err != nil {
			w.err = err
			return err
		}
		return nil
	})
}

func (w *microsoftWriter) Close() error {
	if w.buf.Len() > 0 {
		w.writeBlock(w.buf.Bytes())
	}
	if err := w.eg.Wait(); err != nil {
		return err
	}
	blocks := make([]storage.Block, w.nBlocks)
	for i := range blocks {
		blocks[i] = storage.Block{ID: blockID(i), Status: storage.BlockStatusUncommitted}
	}
	return w.blobClient.PutBlockList(w.container, w.blob, blocks)
}
<|endoftext|>


<commit_before>/*
Copyright 2018 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 naming

import "testing"

func TestGetNameFromCallsite(t *testing.T) {
	tests := []struct {
		name            string
		ignoredPackages []string
		expected        string
	}{
		{
			name:     "simple",
			expected: "k8s.io/apimachinery/pkg/util/naming/from_stack_test.go:50",
		},
		{
			name:            "ignore-package",
			ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming"},
			expected:        "testing/testing.go:827",
		},
		{
			name:            "ignore-file",
			ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go"},
			expected:        "testing/testing.go:827",
		},
		{
			name:            "ignore-multiple",
			ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go", "testing/testing.go"},
			expected:        "????",
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			actual := GetNameFromCallsite(tc.ignoredPackages...)
			if tc.expected != actual {
				t.Fatalf("expected %q, got %q", tc.expected, actual)
			}
		})
	}
}
<commit_msg>UPSTREAM: <drop>: apimachinery tests<commit_after>/*
Copyright 2018 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 naming

import "testing"

func TestGetNameFromCallsite(t *testing.T) {
	tests := []struct {
		name            string
		ignoredPackages []string
		expected        string
	}{
		{
			name:     "simple",
			expected: "k8s.io/apimachinery/pkg/util/naming/from_stack_test.go:50",
		},
		{
			name:            "ignore-package",
			ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming"},
			expected:        "testing/testing.go:777",
		},
		{
			name:            "ignore-file",
			ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go"},
			expected:        "testing/testing.go:777",
		},
		{
			name:            "ignore-multiple",
			ignoredPackages: []string{"k8s.io/apimachinery/pkg/util/naming/from_stack_test.go", "testing/testing.go"},
			expected:        "????",
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			actual := GetNameFromCallsite(tc.ignoredPackages...)
			if tc.expected != actual {
				t.Fatalf("expected %q, got %q", tc.expected, actual)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 The Go Cloud Development Kit 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
//
//     https://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.

// Summarizes the output of go test.
// Run like so:
//    go test  -json ./... | test-summary
package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"time"
)

// From running "go doc test2json".
type TestEvent struct {
	Time    time.Time // encodes as an RFC3339-format string
	Action  string
	Package string
	Test    string
	Elapsed float64 // seconds
	Output  string
}

func main() {
	s, fails, err := run(os.Stdin)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(s)
	if fails {
		os.Exit(1)
	}
}

func run(r io.Reader) (msg string, failures bool, err error) {
	counts := map[string]int{}
	scanner := bufio.NewScanner(bufio.NewReader(r))
	for scanner.Scan() {
		var event TestEvent
		if err := json.Unmarshal(scanner.Bytes(), &event); err != nil {
			return "", false, fmt.Errorf("%q: %v", scanner.Text(), err)
		}
		counts[event.Action]++
	}
	if err := scanner.Err(); err != nil {
		return "", false, err
	}
	p := counts["pass"]
	f := counts["fail"]
	s := counts["skip"]
	return fmt.Sprintf("ran %d; passed %d; failed %d; skipped %d", p+f+s, p, f, s), f > 0, nil
}
<commit_msg>test-summary: produce more output (#2121)<commit_after>// Copyright 2019 The Go Cloud Development Kit 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
//
//     https://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.

// Summarizes the output of go test.
// Run like so:
//    go test  -json ./... | test-summary
package main

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"time"
)

var (
	progress = flag.Bool("progress", false, "display test progress")
	verbose  = flag.Bool("verbose", false, "display all test output")
)

// From running "go doc test2json".
type TestEvent struct {
	Time    time.Time // encodes as an RFC3339-format string
	Action  string
	Package string
	Test    string
	Elapsed float64 // seconds
	Output  string
}

func main() {
	flag.Parse()
	s, fails, err := run(os.Stdin)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(s)
	if fails {
		os.Exit(1)
	}
}

func run(r io.Reader) (msg string, failures bool, err error) {
	counts := map[string]int{}
	scanner := bufio.NewScanner(bufio.NewReader(r))
	prevPkg := "" // In progress mode, the package we previously wrote, to avoid repeating it.
	for scanner.Scan() {
		var event TestEvent
		if err := json.Unmarshal(scanner.Bytes(), &event); err != nil {
			return "", false, fmt.Errorf("%q: %v", scanner.Text(), err)
		}
		if *verbose && event.Action == "output" {
			fmt.Print(event.Output)
		}
		// Ignore pass or fail events that don't have a Test; they refer to the
		// package as a whole, and we would be over-counting if we included them.
		// However, skips of an entire package are not duplicated with individual
		// test skips.
		if event.Test == "" && (event.Action == "pass" || event.Action == "fail") {
			continue
		}
		counts[event.Action]++
		if *progress && (event.Action == "pass" || event.Action == "fail" || event.Action == "skip") {
			if event.Package == prevPkg {
				fmt.Printf("%s     %s (%.2fs)\n", event.Action, event.Test, event.Elapsed)
			} else {
				path := event.Package
				if event.Test != "" {
					path += "/" + event.Test
				}
				fmt.Printf("%s %s (%.2fs)\n", event.Action, path, event.Elapsed)
				prevPkg = event.Package
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return "", false, err
	}
	p := counts["pass"]
	f := counts["fail"]
	s := counts["skip"]
	return fmt.Sprintf("ran %d; passed %d; failed %d; skipped %d", p+f+s, p, f, s), f > 0, nil
}
<|endoftext|>