<commit_before>// package rest contains functions for sending http requests to a REST API, which
// can be used to create, read, update, and delete models from a server.
//
// TODO: add a really detailed package doc comment describing:
//   - The methods and urls that are used for each function
//   - The format in which models are encoded and what field types are supported
//   - What responses from the server should look like
//   - What happens if there is a non-200 response status code
package rest

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"
)

// Model must be satisfied by all models. Satisfying this interface allows you to
// use the helper methods which send http requests to a REST API. They are used
// for e.g., creating a new model or getting an existing model from the server.
// Because of the way reflection is used to encode the data, a Model must have an
// underlying type of either a struct or a pointer to a struct.
type Model interface {
	// GetId returns a unique identifier for the model. It is used for determining
	// which URL to send a request to.
	GetId() string
	// RootURL returns the url for the REST resource corresponding to this model.
	// Typically it should look something like "http://examle.com/todos". Note that
	// the trailing slash should not be included.
	RootURL() string
}

// Create sends an http request to create the given model. It uses reflection to
// convert the fields of model to url-encoded data. Then it sends a POST request to
// model.RootURL() with the encoded data in the body and the Content-Type header set to
// application/x-www-form-urlencoded. It expects a JSON response containing the created
// object from the server if the request was successful, in which case it will mutate model
// by setting the fields to the values in the JSON response. Since model may be mutated,
// it should be a poitner.
func Create(model Model) error {
	fullURL := model.RootURL()
	encodedModelData, err := encodeModelFields(model)
	if err != nil {
		return err
	}
	return sendRequestAndUnmarshal("POST", fullURL, encodedModelData, model)
}

// Read sends an http request to read (or fetch) the model with the given id
// from the server. It sends a GET request to model.RootURL() + "/" + model.GetId().
// Read expects a JSON response containing the data for the requested model if the
// request was successful, in which case it will mutate model by setting the fields
// to the values in the JSON response. Since model may be mutated, it should be
// a pointer.
func Read(id string, model Model) error {
	fullURL := model.RootURL() + "/" + id
	return sendRequestAndUnmarshal("GET", fullURL, "", model)
}

// ReadAll sends an http request to read (or fetch) all the models of a particular
// type from the server (e.g. get all the todos). It sends a GET request to
// model.RootURL(). ReadAll expects a JSON response containing an array of objects,
// where each object contains data for one model. models must be a pointer to a slice
// of some type which implements Model. ReadAll will mutate models by growing or shrinking
// the slice as needed, and by setting the fields of each element to the values in the JSON
// response.
func ReadAll(models interface{}) error {
	rootURL, err := getURLFromModels(models)
	if err != nil {
		return err
	}
	return sendRequestAndUnmarshal("GET", rootURL, "", models)
}

// Update sends an http request to update the given model, i.e. to change some or all
// of the fields. It uses reflection to convert the fields of model to url-encoded data.
// Then it sends a PUT request to model.RootURL() with the encoded data in the body and
// the Content-Type header set to application/x-www-form-urlencoded. Update expects a
// JSON response containing the data for the updated model if the request was successful,
// in which case it will mutate model by setting the fields to the values in the JSON
// response. Since model may be mutated, it should be a pointer.
func Update(model Model) error {
	fullURL := model.RootURL() + "/" + model.GetId()
	encodedModelData, err := encodeModelFields(model)
	if err != nil {
		return err
	}
	return sendRequestAndUnmarshal("PUT", fullURL, encodedModelData, model)
}

// Delete sends an http request to delete the given model. It sends a DELETE request
// to model.RootURL() + "/" + model.GetId(). DELETE expects an empty JSON response
// if the request was successful, and it will not mutate model.
func Delete(model Model) error {
	fullURL := model.RootURL() + "/" + model.GetId()
	req, err := http.NewRequest("DELETE", fullURL, nil)
	if err != nil {
		return fmt.Errorf("Something went wrong building DELETE request to %s: %s", fullURL, err.Error())
	}
	if _, err := http.DefaultClient.Do(req); err != nil {
		return fmt.Errorf("Something went wrong with DELETE request to %s: %s", fullURL, err.Error())
	}
	return nil
}

// getURLFromModels returns the url that should be used for the type that corresponds
// to models. It does this by instantiating a new model of the correct type and then
// calling RootURL on it. models should be a pointer to a slice of models.
func getURLFromModels(models interface{}) (string, error) {
	// Check the type of models
	typ := reflect.TypeOf(models)
	switch {
	// Make sure its a pointer
	case typ.Kind() != reflect.Ptr:
		return "", fmt.Errorf("models must be a pointer to a slice of models. %T is not a pointer.", models)
	// Make sure its a pointer to a slice
	case typ.Elem().Kind() != reflect.Slice:
		return "", fmt.Errorf("models must be a pointer to a slice of models. %T is not a pointer to a slice", models)
	// Make sure the type of the elements of the slice implement Model
	case !typ.Elem().Elem().Implements(reflect.TypeOf([]Model{}).Elem()):
		return "", fmt.Errorf("models must be a pointer to a slice of models. The elem type %T does not implement model", typ.Elem().Elem())
	}
	// modelType is the type of the elements of models
	modelType := typ.Elem().Elem()
	// Ultimately, we need to be able to instantiate a new object of a type that
	// implements Model so that we can call RootURL on it. The trouble is that
	// reflect.New only works for things that are not pointers, and the type of
	// the elements of models could be pointers. To solve for this, we are going
	// to get the Elem of modelType if it is a pointer and keep track of the number
	// of times we get the Elem. So if modelType is *Todo, we'll call Elem once to
	// get the type Todo.
	numDeref := 0
	for modelType.Kind() == reflect.Ptr {
		modelType = modelType.Elem()
		numDeref += 1
	}
	// Now that we have the underlying type that is not a pointer, we can instantiate
	// a new object with reflect.New.
	newModelVal := reflect.New(modelType).Elem()
	// Now we need to iteratively get the address of the object we created exactly
	// numDeref times to get to a type that implements Model. Note that Addr is the
	// inverse of Elem.
	for i := 0; i < numDeref; i++ {
		newModelVal = newModelVal.Addr()
	}
	// Now we can use a type assertion to convert the object we instantiated to a Model
	newModel := newModelVal.Interface().(Model)
	// Finally, once we have a Model we can get what we wanted by calling RootURL
	return newModel.RootURL(), nil
}

// sendRequestAndUnmarshal constructs a request with the given method, url, and
// data. If data is an empty string, it will construct a request without any
// data in the body. If data is a non-empty string, it will send it as the body
// of the request and set the Content-Type header to
// application/x-www-form-urlencoded. Then sendRequestAndUnmarshal sends the
// request using http.DefaultClient and marshals the response into v using the json
// package.
// TODO: do something if the response status code is non-200.
func sendRequestAndUnmarshal(method string, url string, data string, v interface{}) error {
	// Build the request
	req, err := http.NewRequest(method, url, strings.NewReader(data))
	if err != nil {
		return fmt.Errorf("Something went wrong building %s request to %s: %s", method, url, err.Error())
	}
	// Set the Content-Type header only if data was provided
	if data != "" {
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}
	// Send the request using the default client
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return fmt.Errorf("Something went wrong with %s request to %s: %s", req.Method, req.URL.String(), err.Error())
	}
	// Unmarshal the response into v
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return fmt.Errorf("Couldn't read response to %s: %s", res.Request.URL.String(), err.Error())
	}
	return json.Unmarshal(body, v)
}

// encodeModelFields returns the fields of model represented as a url-encoded string.
// Suitable for POST requests with a content type of application/x-www-form-urlencoded.
// It returns an error if model is a nil pointer or if it is not a struct or a pointer
// to a struct. Any fields that are nil will not be added to the url-encoded string.
func encodeModelFields(model Model) (string, error) {
	modelVal := reflect.ValueOf(model)
	// dereference the pointer until we reach the underlying struct value.
	for modelVal.Kind() == reflect.Ptr {
		if modelVal.IsNil() {
			return "", errors.New("Error encoding model as url-encoded data: model was a nil pointer.")
		}
		modelVal = modelVal.Elem()
	}
	// Make sure the type of model after dereferencing is a struct.
	if modelVal.Kind() != reflect.Struct {
		return "", fmt.Errorf("Error encoding model as url-encoded data: model must be a struct or a pointer to a struct.")
	}
	encodedFields := []string{}
	for i := 0; i < modelVal.Type().NumField(); i++ {
		field := modelVal.Type().Field(i)
		fieldValue := modelVal.FieldByName(field.Name)
		encodedField, err := encodeField(field, fieldValue)
		if err != nil {
			if _, ok := err.(nilFieldError); ok {
				// If there was a nil field, continue without adding the field
				// to the encoded data.
				continue
			}
			// We should return any other kind of error
			return "", err
		}
		encodedFields = append(encodedFields, field.Name+"="+encodedField)
	}
	return strings.Join(encodedFields, "&"), nil
}

type nilFieldError struct{}

func (nilFieldError) Error() string {
	return "field was nil"
}

// encodeField converts a field with the given value to a string. It returns an error
// if field has a type which is unsupported. It returns a special error (nilFieldError)
// if a field has a value of nil. The supported types are int and its variants (int64,
// int32, etc.), uint and its variants (uint64, uint32, etc.), bool, string, and []byte.
func encodeField(field reflect.StructField, value reflect.Value) (string, error) {
	for value.Kind() == reflect.Ptr {
		if value.IsNil() {
			// Skip nil fields
			return "", nilFieldError{}
		}
		value = value.Elem()
	}
	switch v := value.Interface().(type) {
	case int, int64, int32, int16, int8, uint, uint64, uint32, uint16, uint8, bool:
		return fmt.Sprint(v), nil
	case string:
		return url.QueryEscape(v), nil
	case []byte:
		return url.QueryEscape(string(v)), nil
	default:
		return "", fmt.Errorf("Error encoding model as url-encoded data: Don't know how to convert %v of type %T to a string.", v, v)
	}
}
<commit_msg>Improve an error message in rest.go when the type of models is incorrect.<commit_after>// package rest contains functions for sending http requests to a REST API, which
// can be used to create, read, update, and delete models from a server.
//
// TODO: add a really detailed package doc comment describing:
//   - The methods and urls that are used for each function
//   - The format in which models are encoded and what field types are supported
//   - What responses from the server should look like
//   - What happens if there is a non-200 response status code
package rest

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"
)

// Model must be satisfied by all models. Satisfying this interface allows you to
// use the helper methods which send http requests to a REST API. They are used
// for e.g., creating a new model or getting an existing model from the server.
// Because of the way reflection is used to encode the data, a Model must have an
// underlying type of either a struct or a pointer to a struct.
type Model interface {
	// GetId returns a unique identifier for the model. It is used for determining
	// which URL to send a request to.
	GetId() string
	// RootURL returns the url for the REST resource corresponding to this model.
	// Typically it should look something like "http://examle.com/todos". Note that
	// the trailing slash should not be included.
	RootURL() string
}

// Create sends an http request to create the given model. It uses reflection to
// convert the fields of model to url-encoded data. Then it sends a POST request to
// model.RootURL() with the encoded data in the body and the Content-Type header set to
// application/x-www-form-urlencoded. It expects a JSON response containing the created
// object from the server if the request was successful, in which case it will mutate model
// by setting the fields to the values in the JSON response. Since model may be mutated,
// it should be a poitner.
func Create(model Model) error {
	fullURL := model.RootURL()
	encodedModelData, err := encodeModelFields(model)
	if err != nil {
		return err
	}
	return sendRequestAndUnmarshal("POST", fullURL, encodedModelData, model)
}

// Read sends an http request to read (or fetch) the model with the given id
// from the server. It sends a GET request to model.RootURL() + "/" + model.GetId().
// Read expects a JSON response containing the data for the requested model if the
// request was successful, in which case it will mutate model by setting the fields
// to the values in the JSON response. Since model may be mutated, it should be
// a pointer.
func Read(id string, model Model) error {
	fullURL := model.RootURL() + "/" + id
	return sendRequestAndUnmarshal("GET", fullURL, "", model)
}

// ReadAll sends an http request to read (or fetch) all the models of a particular
// type from the server (e.g. get all the todos). It sends a GET request to
// model.RootURL(). ReadAll expects a JSON response containing an array of objects,
// where each object contains data for one model. models must be a pointer to a slice
// of some type which implements Model. ReadAll will mutate models by growing or shrinking
// the slice as needed, and by setting the fields of each element to the values in the JSON
// response.
func ReadAll(models interface{}) error {
	rootURL, err := getURLFromModels(models)
	if err != nil {
		return err
	}
	return sendRequestAndUnmarshal("GET", rootURL, "", models)
}

// Update sends an http request to update the given model, i.e. to change some or all
// of the fields. It uses reflection to convert the fields of model to url-encoded data.
// Then it sends a PUT request to model.RootURL() with the encoded data in the body and
// the Content-Type header set to application/x-www-form-urlencoded. Update expects a
// JSON response containing the data for the updated model if the request was successful,
// in which case it will mutate model by setting the fields to the values in the JSON
// response. Since model may be mutated, it should be a pointer.
func Update(model Model) error {
	fullURL := model.RootURL() + "/" + model.GetId()
	encodedModelData, err := encodeModelFields(model)
	if err != nil {
		return err
	}
	return sendRequestAndUnmarshal("PUT", fullURL, encodedModelData, model)
}

// Delete sends an http request to delete the given model. It sends a DELETE request
// to model.RootURL() + "/" + model.GetId(). DELETE expects an empty JSON response
// if the request was successful, and it will not mutate model.
func Delete(model Model) error {
	fullURL := model.RootURL() + "/" + model.GetId()
	req, err := http.NewRequest("DELETE", fullURL, nil)
	if err != nil {
		return fmt.Errorf("Something went wrong building DELETE request to %s: %s", fullURL, err.Error())
	}
	if _, err := http.DefaultClient.Do(req); err != nil {
		return fmt.Errorf("Something went wrong with DELETE request to %s: %s", fullURL, err.Error())
	}
	return nil
}

// getURLFromModels returns the url that should be used for the type that corresponds
// to models. It does this by instantiating a new model of the correct type and then
// calling RootURL on it. models should be a pointer to a slice of models.
func getURLFromModels(models interface{}) (string, error) {
	// Check the type of models
	typ := reflect.TypeOf(models)
	switch {
	// Make sure its a pointer
	case typ.Kind() != reflect.Ptr:
		return "", fmt.Errorf("models must be a pointer to a slice of models. %T is not a pointer.", models)
	// Make sure its a pointer to a slice
	case typ.Elem().Kind() != reflect.Slice:
		return "", fmt.Errorf("models must be a pointer to a slice of models. %T is not a pointer to a slice", models)
	// Make sure the type of the elements of the slice implement Model
	case !typ.Elem().Elem().Implements(reflect.TypeOf([]Model{}).Elem()):
		return "", fmt.Errorf("models must be a pointer to a slice of models. The elem type %s does not implement model", typ.Elem().Elem().String())
	}
	// modelType is the type of the elements of models
	modelType := typ.Elem().Elem()
	// Ultimately, we need to be able to instantiate a new object of a type that
	// implements Model so that we can call RootURL on it. The trouble is that
	// reflect.New only works for things that are not pointers, and the type of
	// the elements of models could be pointers. To solve for this, we are going
	// to get the Elem of modelType if it is a pointer and keep track of the number
	// of times we get the Elem. So if modelType is *Todo, we'll call Elem once to
	// get the type Todo.
	numDeref := 0
	for modelType.Kind() == reflect.Ptr {
		modelType = modelType.Elem()
		numDeref += 1
	}
	// Now that we have the underlying type that is not a pointer, we can instantiate
	// a new object with reflect.New.
	newModelVal := reflect.New(modelType).Elem()
	// Now we need to iteratively get the address of the object we created exactly
	// numDeref times to get to a type that implements Model. Note that Addr is the
	// inverse of Elem.
	for i := 0; i < numDeref; i++ {
		newModelVal = newModelVal.Addr()
	}
	// Now we can use a type assertion to convert the object we instantiated to a Model
	newModel := newModelVal.Interface().(Model)
	// Finally, once we have a Model we can get what we wanted by calling RootURL
	return newModel.RootURL(), nil
}

// sendRequestAndUnmarshal constructs a request with the given method, url, and
// data. If data is an empty string, it will construct a request without any
// data in the body. If data is a non-empty string, it will send it as the body
// of the request and set the Content-Type header to
// application/x-www-form-urlencoded. Then sendRequestAndUnmarshal sends the
// request using http.DefaultClient and marshals the response into v using the json
// package.
// TODO: do something if the response status code is non-200.
func sendRequestAndUnmarshal(method string, url string, data string, v interface{}) error {
	// Build the request
	req, err := http.NewRequest(method, url, strings.NewReader(data))
	if err != nil {
		return fmt.Errorf("Something went wrong building %s request to %s: %s", method, url, err.Error())
	}
	// Set the Content-Type header only if data was provided
	if data != "" {
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}
	// Send the request using the default client
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return fmt.Errorf("Something went wrong with %s request to %s: %s", req.Method, req.URL.String(), err.Error())
	}
	// Unmarshal the response into v
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return fmt.Errorf("Couldn't read response to %s: %s", res.Request.URL.String(), err.Error())
	}
	return json.Unmarshal(body, v)
}

// encodeModelFields returns the fields of model represented as a url-encoded string.
// Suitable for POST requests with a content type of application/x-www-form-urlencoded.
// It returns an error if model is a nil pointer or if it is not a struct or a pointer
// to a struct. Any fields that are nil will not be added to the url-encoded string.
func encodeModelFields(model Model) (string, error) {
	modelVal := reflect.ValueOf(model)
	// dereference the pointer until we reach the underlying struct value.
	for modelVal.Kind() == reflect.Ptr {
		if modelVal.IsNil() {
			return "", errors.New("Error encoding model as url-encoded data: model was a nil pointer.")
		}
		modelVal = modelVal.Elem()
	}
	// Make sure the type of model after dereferencing is a struct.
	if modelVal.Kind() != reflect.Struct {
		return "", fmt.Errorf("Error encoding model as url-encoded data: model must be a struct or a pointer to a struct.")
	}
	encodedFields := []string{}
	for i := 0; i < modelVal.Type().NumField(); i++ {
		field := modelVal.Type().Field(i)
		fieldValue := modelVal.FieldByName(field.Name)
		encodedField, err := encodeField(field, fieldValue)
		if err != nil {
			if _, ok := err.(nilFieldError); ok {
				// If there was a nil field, continue without adding the field
				// to the encoded data.
				continue
			}
			// We should return any other kind of error
			return "", err
		}
		encodedFields = append(encodedFields, field.Name+"="+encodedField)
	}
	return strings.Join(encodedFields, "&"), nil
}

type nilFieldError struct{}

func (nilFieldError) Error() string {
	return "field was nil"
}

// encodeField converts a field with the given value to a string. It returns an error
// if field has a type which is unsupported. It returns a special error (nilFieldError)
// if a field has a value of nil. The supported types are int and its variants (int64,
// int32, etc.), uint and its variants (uint64, uint32, etc.), bool, string, and []byte.
func encodeField(field reflect.StructField, value reflect.Value) (string, error) {
	for value.Kind() == reflect.Ptr {
		if value.IsNil() {
			// Skip nil fields
			return "", nilFieldError{}
		}
		value = value.Elem()
	}
	switch v := value.Interface().(type) {
	case int, int64, int32, int16, int8, uint, uint64, uint32, uint16, uint8, bool:
		return fmt.Sprint(v), nil
	case string:
		return url.QueryEscape(v), nil
	case []byte:
		return url.QueryEscape(string(v)), nil
	default:
		return "", fmt.Errorf("Error encoding model as url-encoded data: Don't know how to convert %v of type %T to a string.", v, v)
	}
}
<|endoftext|>


<commit_before>package healthcheck

import (
	"errors"
	"fmt"
	"testing"
)

func TestHealthcheckDefault(t *testing.T) {
	h := Healthcheck{
		Type: "ping",
	}
	h.Default()
	if h.Rise != 2 {
		t.Fail()
	}
	if h.Fall != 3 {
		t.Fail()
	}
}

func TestHealthcheckValidate(t *testing.T) {
	h := Healthcheck{
		Type:        "ping",
		Destination: "127.0.0.1",
	}
	h.Default()
	err := h.Validate("foo")
	if err != nil {
		t.Log(err)
		t.Fail()
	}
}

func TestHealthcheckValidateFailNoDestination(t *testing.T) {
	h := Healthcheck{
		Type: "notping",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Healthcheck foo has no destination set" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckValidateFailDestination(t *testing.T) {
	h := Healthcheck{
		Type:        "notping",
		Destination: "www.google.com",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Healthcheck foo destination 'www.google.com' does not parse as an IP address" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckValidateFailType(t *testing.T) {
	h := Healthcheck{
		Type:        "notping",
		Destination: "127.0.0.1",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Unknown healthcheck type 'notping' in foo" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckValidateFailRise(t *testing.T) {
	h := Healthcheck{
		Type:        "ping",
		Fall:        1,
		Destination: "127.0.0.1",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "rise must be > 0 in foo" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckValidateFailFall(t *testing.T) {
	h := Healthcheck{
		Type:        "ping",
		Rise:        1,
		Destination: "127.0.0.1",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "fall must be > 0 in foo" {
		t.Log(err.Error())
		t.Fail()
	}
}

func myHealthCheckConstructorFail(h Healthcheck) (HealthChecker, error) {
	return nil, errors.New("Test")
}

func TestHealthcheckRegisterNew(t *testing.T) {
	registerHealthcheck("testconstructorfail", myHealthCheckConstructorFail)
	h := Healthcheck{
		Type:        "testconstructorfail",
		Destination: "127.0.0.1",
	}
	_, err := h.GetHealthChecker()
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Test" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckGetHealthcheckNotExist(t *testing.T) {
	h := Healthcheck{
		Type:        "test_this_healthcheck_does_not_exist",
		Destination: "127.0.0.1",
	}
	_, err := h.GetHealthChecker()
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Healthcheck type 'test_this_healthcheck_does_not_exist' not found in the healthcheck registry" {
		t.Log(err.Error())
		t.Fail()
	}
}

type MyFakeHealthCheck struct {
	Healthy bool
}

func (h MyFakeHealthCheck) Healthcheck() bool {
	return h.Healthy
}

func MyFakeHealthConstructorOk(h Healthcheck) (HealthChecker, error) {
	return MyFakeHealthCheck{Healthy: true}, nil
}

func MyFakeHealthConstructorFail(h Healthcheck) (HealthChecker, error) {
	return MyFakeHealthCheck{Healthy: false}, nil
}

func TestPerformHealthcheckNotSetup(t *testing.T) {
	h := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 1}
	defer func() {
		// recover from panic if one occured. Set err to nil otherwise.
		err := recover()
		if err == nil {
			t.Fail()
		}
		if err.(string) != "Setup() never called for healthcheck before Run" {
			t.Fail()
		}
	}()
	h.PerformHealthcheck()
}

func TestHealthcheckRunSimple(t *testing.T) {
	registerHealthcheck("test_ok", MyFakeHealthConstructorOk)
	registerHealthcheck("test_fail", MyFakeHealthConstructorFail)
	h_ok := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 1}
	ok, err := h_ok.GetHealthChecker()
	if err != nil {
		t.Fail()
	}
	h_fail := Healthcheck{Type: "test_fail", Destination: "127.0.0.1"}
	fail, err := h_fail.GetHealthChecker()
	if err != nil {
		t.Fail()
	}
	if !ok.Healthcheck() {
		t.Fail()
	}
	if fail.Healthcheck() {
		t.Fail()
	}
	h_ok.Default()
	h_ok.Setup()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
}

func TestHealthcheckRise(t *testing.T) {
	registerHealthcheck("test_ok", MyFakeHealthConstructorOk)
	h_ok := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 2}
	h_ok.Default()
	h_ok.Setup()
	if h_ok.IsHealthy() {
		t.Log("Started healthy")
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Log("Became healthy after 1")
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Log("Never became healthy")
		t.Fail()
	}
	h_ok.PerformHealthcheck() // 3
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck() // 10
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	for i, v := range h_ok.History {
		if !v {
			t.Log(fmt.Printf("Index %d was unhealthy", i))
			t.Fail()
		}
	}
}

func TestHealthcheckFall(t *testing.T) {
	registerHealthcheck("test_fail", MyFakeHealthConstructorFail)
	h_ok := Healthcheck{Type: "test_fail", Destination: "127.0.0.1", Fall: 2}
	h_ok.Default()
	h_ok.Setup()
	h_ok.History = []bool{true, true, true, true, true, true, true, true, true, true}
	h_ok.isHealthy = true
	if !h_ok.IsHealthy() {
		t.Log("Started unhealthy")
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Log("Became unhealthy after 1 (expected 2)")
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Log("Never became unhealthy")
		t.Fail()
	}
	h_ok.PerformHealthcheck() // 3
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck() // 10
	if h_ok.IsHealthy() {
		t.Fail()
	}
	for i, v := range h_ok.History {
		if v {
			t.Log(fmt.Printf("Index %d was healthy", i))
			t.Fail()
		}
	}
}

func TestHealthcheckRun(t *testing.T) {
	registerHealthcheck("test_ok", MyFakeHealthConstructorOk)
	h_ok := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 2}
	h_ok.Default()
	h_ok.Setup()
	h_ok.Run(true)
	if !h_ok.IsRunning() {
		t.Fail()
	}
	h_ok.Run(true)
	if !h_ok.IsRunning() {
		t.Fail()
	}
}

func TestHealthcheckStop(t *testing.T) {
	registerHealthcheck("test_ok", MyFakeHealthConstructorOk)
	h_ok := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 2}
	h_ok.Default()
	h_ok.Setup()
	if h_ok.IsRunning() {
		t.Fail()
	}
	h_ok.Stop()
	if h_ok.IsRunning() {
		t.Fail()
	}
	h_ok.Run(false)
	if !h_ok.IsRunning() {
		t.Fail()
	}
	h_ok.Stop()
	if h_ok.IsRunning() {
		t.Fail()
	}
}
<commit_msg>Test Setup on a healthcheck that does not exist<commit_after>package healthcheck

import (
	"errors"
	"fmt"
	"testing"
)

func TestHealthcheckDefault(t *testing.T) {
	h := Healthcheck{
		Type: "ping",
	}
	h.Default()
	if h.Rise != 2 {
		t.Fail()
	}
	if h.Fall != 3 {
		t.Fail()
	}
}

func TestHealthcheckValidate(t *testing.T) {
	h := Healthcheck{
		Type:        "ping",
		Destination: "127.0.0.1",
	}
	h.Default()
	err := h.Validate("foo")
	if err != nil {
		t.Log(err)
		t.Fail()
	}
}

func TestHealthcheckValidateFailNoDestination(t *testing.T) {
	h := Healthcheck{
		Type: "notping",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Healthcheck foo has no destination set" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckValidateFailDestination(t *testing.T) {
	h := Healthcheck{
		Type:        "notping",
		Destination: "www.google.com",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Healthcheck foo destination 'www.google.com' does not parse as an IP address" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckValidateFailType(t *testing.T) {
	h := Healthcheck{
		Type:        "notping",
		Destination: "127.0.0.1",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Unknown healthcheck type 'notping' in foo" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckValidateFailRise(t *testing.T) {
	h := Healthcheck{
		Type:        "ping",
		Fall:        1,
		Destination: "127.0.0.1",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "rise must be > 0 in foo" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckValidateFailFall(t *testing.T) {
	h := Healthcheck{
		Type:        "ping",
		Rise:        1,
		Destination: "127.0.0.1",
	}
	err := h.Validate("foo")
	if err == nil {
		t.Fail()
	}
	if err.Error() != "fall must be > 0 in foo" {
		t.Log(err.Error())
		t.Fail()
	}
}

func myHealthCheckConstructorFail(h Healthcheck) (HealthChecker, error) {
	return nil, errors.New("Test")
}

func TestHealthcheckRegisterNew(t *testing.T) {
	registerHealthcheck("testconstructorfail", myHealthCheckConstructorFail)
	h := Healthcheck{
		Type:        "testconstructorfail",
		Destination: "127.0.0.1",
	}
	_, err := h.GetHealthChecker()
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Test" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckGetHealthcheckNotExist(t *testing.T) {
	h := Healthcheck{
		Type:        "test_this_healthcheck_does_not_exist",
		Destination: "127.0.0.1",
	}
	_, err := h.GetHealthChecker()
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Healthcheck type 'test_this_healthcheck_does_not_exist' not found in the healthcheck registry" {
		t.Log(err.Error())
		t.Fail()
	}
}

func TestHealthcheckGetHealthcheckNotExistSetup(t *testing.T) {
	h := Healthcheck{
		Type:        "test_this_healthcheck_does_not_exist",
		Destination: "127.0.0.1",
	}
	err := h.Setup()
	if err == nil {
		t.Fail()
	}
	if err.Error() != "Healthcheck type 'test_this_healthcheck_does_not_exist' not found in the healthcheck registry" {
		t.Log(err.Error())
		t.Fail()
	}
}

type MyFakeHealthCheck struct {
	Healthy bool
}

func (h MyFakeHealthCheck) Healthcheck() bool {
	return h.Healthy
}

func MyFakeHealthConstructorOk(h Healthcheck) (HealthChecker, error) {
	return MyFakeHealthCheck{Healthy: true}, nil
}

func MyFakeHealthConstructorFail(h Healthcheck) (HealthChecker, error) {
	return MyFakeHealthCheck{Healthy: false}, nil
}

func TestPerformHealthcheckNotSetup(t *testing.T) {
	h := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 1}
	defer func() {
		// recover from panic if one occured. Set err to nil otherwise.
		err := recover()
		if err == nil {
			t.Fail()
		}
		if err.(string) != "Setup() never called for healthcheck before Run" {
			t.Fail()
		}
	}()
	h.PerformHealthcheck()
}

func TestHealthcheckRunSimple(t *testing.T) {
	registerHealthcheck("test_ok", MyFakeHealthConstructorOk)
	registerHealthcheck("test_fail", MyFakeHealthConstructorFail)
	h_ok := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 1}
	ok, err := h_ok.GetHealthChecker()
	if err != nil {
		t.Fail()
	}
	h_fail := Healthcheck{Type: "test_fail", Destination: "127.0.0.1"}
	fail, err := h_fail.GetHealthChecker()
	if err != nil {
		t.Fail()
	}
	if !ok.Healthcheck() {
		t.Fail()
	}
	if fail.Healthcheck() {
		t.Fail()
	}
	h_ok.Default()
	h_ok.Setup()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
}

func TestHealthcheckRise(t *testing.T) {
	registerHealthcheck("test_ok", MyFakeHealthConstructorOk)
	h_ok := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 2}
	h_ok.Default()
	h_ok.Setup()
	if h_ok.IsHealthy() {
		t.Log("Started healthy")
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Log("Became healthy after 1")
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Log("Never became healthy")
		t.Fail()
	}
	h_ok.PerformHealthcheck() // 3
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck() // 10
	if !h_ok.IsHealthy() {
		t.Fail()
	}
	for i, v := range h_ok.History {
		if !v {
			t.Log(fmt.Printf("Index %d was unhealthy", i))
			t.Fail()
		}
	}
}

func TestHealthcheckFall(t *testing.T) {
	registerHealthcheck("test_fail", MyFakeHealthConstructorFail)
	h_ok := Healthcheck{Type: "test_fail", Destination: "127.0.0.1", Fall: 2}
	h_ok.Default()
	h_ok.Setup()
	h_ok.History = []bool{true, true, true, true, true, true, true, true, true, true}
	h_ok.isHealthy = true
	if !h_ok.IsHealthy() {
		t.Log("Started unhealthy")
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if !h_ok.IsHealthy() {
		t.Log("Became unhealthy after 1 (expected 2)")
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Log("Never became unhealthy")
		t.Fail()
	}
	h_ok.PerformHealthcheck() // 3
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck()
	if h_ok.IsHealthy() {
		t.Fail()
	}
	h_ok.PerformHealthcheck() // 10
	if h_ok.IsHealthy() {
		t.Fail()
	}
	for i, v := range h_ok.History {
		if v {
			t.Log(fmt.Printf("Index %d was healthy", i))
			t.Fail()
		}
	}
}

func TestHealthcheckRun(t *testing.T) {
	registerHealthcheck("test_ok", MyFakeHealthConstructorOk)
	h_ok := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 2}
	h_ok.Default()
	h_ok.Setup()
	h_ok.Run(true)
	if !h_ok.IsRunning() {
		t.Fail()
	}
	h_ok.Run(true)
	if !h_ok.IsRunning() {
		t.Fail()
	}
}

func TestHealthcheckStop(t *testing.T) {
	registerHealthcheck("test_ok", MyFakeHealthConstructorOk)
	h_ok := Healthcheck{Type: "test_ok", Destination: "127.0.0.1", Rise: 2}
	h_ok.Default()
	h_ok.Setup()
	if h_ok.IsRunning() {
		t.Fail()
	}
	h_ok.Stop()
	if h_ok.IsRunning() {
		t.Fail()
	}
	h_ok.Run(false)
	if !h_ok.IsRunning() {
		t.Fail()
	}
	h_ok.Stop()
	if h_ok.IsRunning() {
		t.Fail()
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Serviced 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.

// +build integration

package facade

import (
	"fmt"

	"github.com/control-center/serviced/domain/service"
	. "gopkg.in/check.v1"
)

func (ft *FacadeIntegrationTest) Test_PublicEndpoint_PortAdd(c *C) {
	fmt.Println(" ##### Test_PublicEndpoint_PortAdd: starting")

	// Add a service so we can test our public endpoint.
	svcA := service.Service{
		ID:           "validate-service-tenant-A",
		Name:         "TestFacade_validateServiceTenantA",
		DeploymentID: "deployment-id",
		PoolID:       "pool-id",
		Launch:       "auto",
		DesiredState: int(service.SVCStop),
		Endpoints: []service.ServiceEndpoint{
			service.ServiceEndpoint{
				Application: "zproxy",
				Name:        "zproxy",
				PortNumber:  8080,
				Protocol:    "tcp",
				Purpose:     "export",
			},
		},
	}
	// Add a service so we can test our public endpoint.
	svcB := service.Service{
		ID:           "validate-service-tenant-B",
		Name:         "TestFacade_validateServiceTenantB",
		DeploymentID: "deployment-id",
		PoolID:       "pool-id",
		Launch:       "auto",
		DesiredState: int(service.SVCStop),
		Endpoints: []service.ServiceEndpoint{
			service.ServiceEndpoint{
				Application: "service2",
				Name:        "service2",
				PortNumber:  9090,
				Protocol:    "tcp",
				Purpose:     "export",
			},
		},
	}
	c.Assert(ft.Facade.AddService(ft.CTX, svcA), IsNil)
	c.Assert(ft.Facade.AddService(ft.CTX, svcB), IsNil)

	endpointName := "zproxy"
	portAddr := ":22222"
	usetls := true
	protocol := "http"
	isEnabled := true
	restart := false

	// Add a valid port.
	port, err := ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	c.Assert(err, IsNil)
	if port == nil {
		c.Errorf("Adding a valid public endpoint port returned a nil port")
	}

	// Add a duplicate port.
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding a duplicate port")
	}

	// Add a port with an invalid port range.
	portAddr = ":70000"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding an invalid port address %s", portAddr)
	}

	portAddr = ":0"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding an invalid port address %s", portAddr)
	}

	portAddr = ":-1"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding an invalid port address %s", portAddr)
	}

	// Add a port for an invalid service.
	portAddr = ":22223"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, "invalid", endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding a port to an invalid service", portAddr)
	}

	// Add a port to a service that's defined in another service.
	// Add a port for an invalid service.
	portAddr = ":22222"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcB.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding a port that already exists in another service", portAddr)
	}

	fmt.Println(" ##### Test_PublicEndpoint_PortAdd: PASSED")
}
<commit_msg>Fix integration tests<commit_after>// Copyright 2016 The Serviced 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.

// +build integration

package facade

import (
	"fmt"

	"github.com/control-center/serviced/domain/service"
	"github.com/control-center/serviced/zzk/registry"
	. "gopkg.in/check.v1"
)

func (ft *FacadeIntegrationTest) Test_PublicEndpoint_PortAdd(c *C) {
	fmt.Println(" ##### Test_PublicEndpoint_PortAdd: starting")

	// Add a service so we can test our public endpoint.
	svcA := service.Service{
		ID:           "validate-service-tenant-A",
		Name:         "TestFacade_validateServiceTenantA",
		DeploymentID: "deployment-id",
		PoolID:       "pool-id",
		Launch:       "auto",
		DesiredState: int(service.SVCStop),
		Endpoints: []service.ServiceEndpoint{
			service.ServiceEndpoint{
				Application: "zproxy",
				Name:        "zproxy",
				PortNumber:  8080,
				Protocol:    "tcp",
				Purpose:     "export",
			},
		},
	}
	// Add a service so we can test our public endpoint.
	svcB := service.Service{
		ID:           "validate-service-tenant-B",
		Name:         "TestFacade_validateServiceTenantB",
		DeploymentID: "deployment-id",
		PoolID:       "pool-id",
		Launch:       "auto",
		DesiredState: int(service.SVCStop),
		Endpoints: []service.ServiceEndpoint{
			service.ServiceEndpoint{
				Application: "service2",
				Name:        "service2",
				PortNumber:  9090,
				Protocol:    "tcp",
				Purpose:     "export",
			},
		},
	}
	c.Assert(ft.Facade.AddService(ft.CTX, svcA), IsNil)
	c.Assert(ft.Facade.AddService(ft.CTX, svcB), IsNil)

	endpointName := "zproxy"
	portAddr := ":22222"
	usetls := true
	protocol := "http"
	isEnabled := true
	restart := false

	// Add a valid port.
	ft.zzk.On("CheckRunningPublicEndpoint", registry.PublicEndpointKey(":22222-1"), svcA.ID).Return(nil)
	port, err := ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	c.Assert(err, IsNil)
	if port == nil {
		c.Errorf("Adding a valid public endpoint port returned a nil port")
	}

	// Add a duplicate port.
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding a duplicate port")
	}

	// Add a port with an invalid port range.
	portAddr = ":70000"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding an invalid port address %s", portAddr)
	}

	portAddr = ":0"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding an invalid port address %s", portAddr)
	}

	portAddr = ":-1"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcA.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding an invalid port address %s", portAddr)
	}

	// Add a port for an invalid service.
	portAddr = ":22223"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, "invalid", endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding a port to an invalid service", portAddr)
	}

	// Add a port to a service that's defined in another service.
	// Add a port for an invalid service.
	portAddr = ":22222"
	port, err = ft.Facade.AddPublicEndpointPort(ft.CTX, svcB.ID, endpointName, portAddr,
		usetls, protocol, isEnabled, restart)
	if err == nil {
		c.Errorf("Expected failure adding a port that already exists in another service", portAddr)
	}

	fmt.Println(" ##### Test_PublicEndpoint_PortAdd: PASSED")
}
<|endoftext|>


<commit_before>package main
// @author Robin Verlangen

// Imports
import (
	"log"
	"flag"
)

// Config through flags
var seedNodes string
func init() {
	flag.StringVar(&seedNodes, "seeds", "", "Seed nodes, comma separated host:port tuples (e.g. 12.34.56.78,23.34.45.56:8080")
	flag.Parse()
}

// Main function of dispenso
func main() {
	log.Println("Starting dispenso")
}<commit_msg>Cleanup<commit_after>package main
// @author Robin Verlangen

// Imports
import (
	"log"
	"flag"
	"fmt"
)

// Constants
const defaultPort int = 8011

// Configuration
var seedNodes string
var serverPort int

// Set configuration from flags
func init() {
	flag.StringVar(&seedNodes, "seeds", "", "Seed nodes, comma separated host:port tuples (e.g. 12.34.56.78,23.34.45.56:8080")
	flag.IntVar(&serverPort, "port", defaultPort, fmt.Sprintf("Port to bind on (defaults to %d)", defaultPort))
	flag.Parse()
}

// Main function of dispenso
func main() {
	log.Println("Starting dispenso")
}<|endoftext|>


<commit_before>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE.txt file.

// This program is an example of how you can use the gohg library.

package main

import (
	. "bitbucket.org/gohg/gohg"
	"fmt"
	"log"
)

func main() {
	// Set var hgexe to whatever is appropriate for your situation.
	// You can also change it to test with different versions of Mercurial.
	hgexe := "hg"
	repo := "."

	fmt.Println("========== Begin of example1 ==========")

	var err error
	fmt.Printf("Using Mercurial repo at: %s\n", repo)
	fmt.Println("--------------------")

	hc := NewHgClient()
	var cfg []string
	if err = hc.Connect(hgexe, repo, cfg); err != nil {
		log.Fatal(err)
	}
	defer hc.Disconnect()
	defer func() { fmt.Println("========== End of example1 ==========") }()

	var v string
	if v, err = hc.Version(); err != nil {
		log.Println(err)
	}
	fmt.Printf("[[version]]: %s\n", v)

	fmt.Println("--------------------")

	var s []byte
	if s, err = hc.Summary(); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("[[summary]]:\n%s", s)

	fmt.Println("--------------------")

	var l []byte
	if l, err = hc.Log([]string{"branches_test.go"}, Limit(2), Verbose(true)); err != nil {
		fmt.Println(err)
		return
	}
	// use 'go run example1.go | less' (or more) to view big results (such as a full log)
	fmt.Printf("[[log -v -l 2 branches_test.go]]:\n%s", l)

	// give time to see the Hg CS session live and die from Process Explorer
	// fmt.Print("waiting...")
	// time.Sleep(3 * time.Second)
}
<commit_msg>example1: added call to Identify<commit_after>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE.txt file.

// This program is an example of how you can use the gohg library.

package main

import (
	. "bitbucket.org/gohg/gohg"
	"fmt"
	"log"
)

func main() {
	// Set var hgexe to whatever is appropriate for your situation.
	// You can also change it to test with different versions of Mercurial.
	hgexe := "hg"
	repo := "."

	fmt.Println("========== Begin of example1 ==========")

	var err error
	fmt.Printf("Using Mercurial repo at: %s\n", repo)
	fmt.Println("--------------------")

	hc := NewHgClient()
	var cfg []string
	if err = hc.Connect(hgexe, repo, cfg); err != nil {
		log.Fatal(err)
	}
	defer hc.Disconnect()
	defer func() { fmt.Println("========== End of example1 ==========") }()

	var v string
	if v, err = hc.Version(); err != nil {
		log.Println(err)
	}
	fmt.Printf("[[version]]: %s\n", v)

	fmt.Println("--------------------")

	var i []byte
	if i, err = hc.Identify(""); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("[[identify]]:\n%s", i)

	fmt.Println("--------------------")

	var s []byte
	if s, err = hc.Summary(); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("[[summary]]:\n%s", s)

	fmt.Println("--------------------")

	var l []byte
	if l, err = hc.Log([]string{"branches_test.go"}, Limit(2), Verbose(true)); err != nil {
		fmt.Println(err)
		return
	}
	// use 'go run example1.go | less' (or more) to view big results (such as a full log)
	fmt.Printf("[[log -v -l 2 branches_test.go]]:\n%s", l)

	// give time to see the Hg CS session live and die from Process Explorer
	// fmt.Print("waiting...")
	// time.Sleep(3 * time.Second)
}
<|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
//
// 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.

package metric

import (
	"context"
	"log"
	"net"
	"os"
	"strings"
	"testing"

	"github.com/golang/protobuf/ptypes/empty"
	"github.com/googleinterns/cloud-operations-api-mock/validation"
	"google.golang.org/genproto/googleapis/api/metric"
	"google.golang.org/genproto/googleapis/api/monitoredres"
	"google.golang.org/genproto/googleapis/monitoring/v3"
	"google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/test/bufconn"
	"google.golang.org/protobuf/proto"
)

const bufSize = 1024 * 1024

var (
	client     monitoring.MetricServiceClient
	conn       *grpc.ClientConn
	ctx        context.Context
	grpcServer *grpc.Server
	lis        *bufconn.Listener
)

func setup() {
	// Setup the in-memory server.
	lis = bufconn.Listen(bufSize)
	grpcServer = grpc.NewServer()
	monitoring.RegisterMetricServiceServer(grpcServer, &MockMetricServer{})
	go func() {
		if err := grpcServer.Serve(lis); err != nil {
			log.Fatalf("server exited with error: %v", err)
		}
	}()

	// Setup the connection and client.
	ctx = context.Background()
	var err error
	conn, err = grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("failed to dial bufnet: %v", err)
	}
	client = monitoring.NewMetricServiceClient(conn)
}

func tearDown() {
	conn.Close()
	grpcServer.GracefulStop()
}

func TestMain(m *testing.M) {
	setup()
	retCode := m.Run()
	tearDown()
	os.Exit(retCode)
}

func bufDialer(context.Context, string) (net.Conn, error) {
	return lis.Dial()
}

func TestMockMetricServer_CreateTimeSeries(t *testing.T) {
	in := &monitoring.CreateTimeSeriesRequest{
		Name:       "test create time series request",
		TimeSeries: []*monitoring.TimeSeries{&monitoring.TimeSeries{}},
	}
	want := &empty.Empty{}
	response, err := client.CreateTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListTimeSeries(t *testing.T) {
	in := &monitoring.ListTimeSeriesRequest{
		Name: "test list time series request",
	}
	want := &monitoring.ListTimeSeriesResponse{
		TimeSeries:      []*monitoring.TimeSeries{},
		NextPageToken:   "",
		ExecutionErrors: []*status.Status{},
	}

	response, err := client.ListTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMonitoredResourceDescriptor(t *testing.T) {
	in := &monitoring.GetMonitoredResourceDescriptorRequest{
		Name: "test get metric monitored resource descriptor",
	}
	want := &monitoredres.MonitoredResourceDescriptor{}
	response, err := client.GetMonitoredResourceDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMonitoredResourceDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMonitoredResourceDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMonitoredResourceDescriptors(t *testing.T) {
	in := &monitoring.ListMonitoredResourceDescriptorsRequest{
		Name: "test list monitored resource descriptors",
	}
	want := &monitoring.ListMonitoredResourceDescriptorsResponse{
		ResourceDescriptors: []*monitoredres.MonitoredResourceDescriptor{},
	}
	response, err := client.ListMonitoredResourceDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMonitoredResourceDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMonitoredResourceDescriptors(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMetricDescriptor(t *testing.T) {
	in := &monitoring.GetMetricDescriptorRequest{
		Name: "test get metric descriptor",
	}
	want := &metric.MetricDescriptor{}
	response, err := client.GetMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMetricDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMetricDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_CreateMetricDescriptor(t *testing.T) {
	in := &monitoring.CreateMetricDescriptorRequest{
		Name:             "test create metric descriptor",
		MetricDescriptor: &metric.MetricDescriptor{},
	}
	want := &metric.MetricDescriptor{}
	response, err := client.CreateMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_DeleteMetricDescriptor(t *testing.T) {
	in := &monitoring.DeleteMetricDescriptorRequest{
		Name: "test create metric descriptor",
	}
	want := &empty.Empty{}

	response, err := client.DeleteMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call DeleteMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("DeleteMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMetricDescriptors(t *testing.T) {
	in := &monitoring.ListMetricDescriptorsRequest{
		Name: "test list metric decriptors request",
	}
	want := &monitoring.ListMetricDescriptorsResponse{
		MetricDescriptors: []*metric.MetricDescriptor{},
	}
	response, err := client.ListMetricDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMetricDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMetricDescriptors(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMetricDescriptorError(t *testing.T) {
	in := &monitoring.GetMetricDescriptorRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.GetMetricDescriptor(ctx, in)
	if err == nil {
		t.Errorf("GetMetricDescriptor(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("GetMetricDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_GetMonitoredResourceDescriptorError(t *testing.T) {
	in := &monitoring.GetMonitoredResourceDescriptorRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.GetMonitoredResourceDescriptor(ctx, in)
	if err == nil {
		t.Errorf("GetMonitoredResourceDescriptor(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("GetMonitoredResourceDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_DeleteMetricDescriptorError(t *testing.T) {
	in := &monitoring.DeleteMetricDescriptorRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.DeleteMetricDescriptor(ctx, in)
	if err == nil {
		t.Errorf("DeleteMetricDescriptor(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("DeleteMetricDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_ListMetricDescriptorError(t *testing.T) {
	in := &monitoring.ListMetricDescriptorsRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.ListMetricDescriptors(ctx, in)
	if err == nil {
		t.Errorf("ListMetricDescriptors(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("ListMetricDescriptors(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_CreateMetricDescriptorError(t *testing.T) {
	in := &monitoring.CreateMetricDescriptorRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}, "MetricDescriptor": {}}
	response, err := client.CreateMetricDescriptor(ctx, in)
	if err == nil {
		t.Errorf("CreateMetricDescriptor(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("CreateMetricDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_ListMonitoredResourceDescriptorsError(t *testing.T) {
	in := &monitoring.ListMonitoredResourceDescriptorsRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.ListMonitoredResourceDescriptors(ctx, in)
	if err == nil {
		t.Errorf("ListMonitoredResourceDescriptors(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("ListMonitoredResourceDescriptors(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_ListTimeSeriesError(t *testing.T) {
	in := &monitoring.ListTimeSeriesRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}, "Filter": {}}
	response, err := client.ListTimeSeries(ctx, in)
	if err == nil {
		t.Errorf("ListTimeSeries(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("ListTimeSeries(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_CreateTimeSeriesError(t *testing.T) {
	in := &monitoring.CreateTimeSeriesRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}, "TimeSeries": {}}
	response, err := client.CreateTimeSeries(ctx, in)
	if err == nil {
		t.Errorf("CreateTimeSeries(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("CreateTimeSeries(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}
<commit_msg>add missing required fields for ListTimeSeriesRequest validation<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
//
// 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.

package metric

import (
	"context"
	"log"
	"net"
	"os"
	"strings"
	"testing"

	"github.com/golang/protobuf/ptypes/empty"
	"github.com/googleinterns/cloud-operations-api-mock/validation"
	"google.golang.org/genproto/googleapis/api/metric"
	"google.golang.org/genproto/googleapis/api/monitoredres"
	"google.golang.org/genproto/googleapis/monitoring/v3"
	"google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/test/bufconn"
	"google.golang.org/protobuf/proto"
)

const bufSize = 1024 * 1024

var (
	client     monitoring.MetricServiceClient
	conn       *grpc.ClientConn
	ctx        context.Context
	grpcServer *grpc.Server
	lis        *bufconn.Listener
)

func setup() {
	// Setup the in-memory server.
	lis = bufconn.Listen(bufSize)
	grpcServer = grpc.NewServer()
	monitoring.RegisterMetricServiceServer(grpcServer, &MockMetricServer{})
	go func() {
		if err := grpcServer.Serve(lis); err != nil {
			log.Fatalf("server exited with error: %v", err)
		}
	}()

	// Setup the connection and client.
	ctx = context.Background()
	var err error
	conn, err = grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithInsecure())
	if err != nil {
		log.Fatalf("failed to dial bufnet: %v", err)
	}
	client = monitoring.NewMetricServiceClient(conn)
}

func tearDown() {
	conn.Close()
	grpcServer.GracefulStop()
}

func TestMain(m *testing.M) {
	setup()
	retCode := m.Run()
	tearDown()
	os.Exit(retCode)
}

func bufDialer(context.Context, string) (net.Conn, error) {
	return lis.Dial()
}

func TestMockMetricServer_CreateTimeSeries(t *testing.T) {
	in := &monitoring.CreateTimeSeriesRequest{
		Name:       "test create time series request",
		TimeSeries: []*monitoring.TimeSeries{&monitoring.TimeSeries{}},
	}
	want := &empty.Empty{}
	response, err := client.CreateTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListTimeSeries(t *testing.T) {
	in := &monitoring.ListTimeSeriesRequest{
		Name:     "test list time series request",
		Filter:   "test filter",
		Interval: &monitoring.TimeInterval{},
		View:     monitoring.ListTimeSeriesRequest_HEADERS,
	}
	want := &monitoring.ListTimeSeriesResponse{
		TimeSeries:      []*monitoring.TimeSeries{},
		NextPageToken:   "",
		ExecutionErrors: []*status.Status{},
	}

	response, err := client.ListTimeSeries(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListTimeSeries %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListTimeSeries(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMonitoredResourceDescriptor(t *testing.T) {
	in := &monitoring.GetMonitoredResourceDescriptorRequest{
		Name: "test get metric monitored resource descriptor",
	}
	want := &monitoredres.MonitoredResourceDescriptor{}
	response, err := client.GetMonitoredResourceDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMonitoredResourceDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMonitoredResourceDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMonitoredResourceDescriptors(t *testing.T) {
	in := &monitoring.ListMonitoredResourceDescriptorsRequest{
		Name: "test list monitored resource descriptors",
	}
	want := &monitoring.ListMonitoredResourceDescriptorsResponse{
		ResourceDescriptors: []*monitoredres.MonitoredResourceDescriptor{},
	}
	response, err := client.ListMonitoredResourceDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMonitoredResourceDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMonitoredResourceDescriptors(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMetricDescriptor(t *testing.T) {
	in := &monitoring.GetMetricDescriptorRequest{
		Name: "test get metric descriptor",
	}
	want := &metric.MetricDescriptor{}
	response, err := client.GetMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call GetMetricDescriptor %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("GetMetricDescriptor(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_CreateMetricDescriptor(t *testing.T) {
	in := &monitoring.CreateMetricDescriptorRequest{
		Name:             "test create metric descriptor",
		MetricDescriptor: &metric.MetricDescriptor{},
	}
	want := &metric.MetricDescriptor{}
	response, err := client.CreateMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call CreateMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("CreateMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_DeleteMetricDescriptor(t *testing.T) {
	in := &monitoring.DeleteMetricDescriptorRequest{
		Name: "test create metric descriptor",
	}
	want := &empty.Empty{}

	response, err := client.DeleteMetricDescriptor(ctx, in)
	if err != nil {
		t.Fatalf("failed to call DeleteMetricDescriptorRequest: %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("DeleteMetricDescriptorRequest(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_ListMetricDescriptors(t *testing.T) {
	in := &monitoring.ListMetricDescriptorsRequest{
		Name: "test list metric decriptors request",
	}
	want := &monitoring.ListMetricDescriptorsResponse{
		MetricDescriptors: []*metric.MetricDescriptor{},
	}
	response, err := client.ListMetricDescriptors(ctx, in)
	if err != nil {
		t.Fatalf("failed to call ListMetricDescriptors %v", err)
	}

	if !proto.Equal(response, want) {
		t.Errorf("ListMetricDescriptors(%q) == %q, want %q", in, response, want)
	}
}

func TestMockMetricServer_GetMetricDescriptorError(t *testing.T) {
	in := &monitoring.GetMetricDescriptorRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.GetMetricDescriptor(ctx, in)
	if err == nil {
		t.Errorf("GetMetricDescriptor(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("GetMetricDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_GetMonitoredResourceDescriptorError(t *testing.T) {
	in := &monitoring.GetMonitoredResourceDescriptorRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.GetMonitoredResourceDescriptor(ctx, in)
	if err == nil {
		t.Errorf("GetMonitoredResourceDescriptor(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("GetMonitoredResourceDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_DeleteMetricDescriptorError(t *testing.T) {
	in := &monitoring.DeleteMetricDescriptorRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.DeleteMetricDescriptor(ctx, in)
	if err == nil {
		t.Errorf("DeleteMetricDescriptor(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("DeleteMetricDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_ListMetricDescriptorError(t *testing.T) {
	in := &monitoring.ListMetricDescriptorsRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.ListMetricDescriptors(ctx, in)
	if err == nil {
		t.Errorf("ListMetricDescriptors(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("ListMetricDescriptors(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_CreateMetricDescriptorError(t *testing.T) {
	in := &monitoring.CreateMetricDescriptorRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}, "MetricDescriptor": {}}
	response, err := client.CreateMetricDescriptor(ctx, in)
	if err == nil {
		t.Errorf("CreateMetricDescriptor(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("CreateMetricDescriptor(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_ListMonitoredResourceDescriptorsError(t *testing.T) {
	in := &monitoring.ListMonitoredResourceDescriptorsRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}}
	response, err := client.ListMonitoredResourceDescriptors(ctx, in)
	if err == nil {
		t.Errorf("ListMonitoredResourceDescriptors(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("ListMonitoredResourceDescriptors(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_ListTimeSeriesError(t *testing.T) {
	in := &monitoring.ListTimeSeriesRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}, "Filter": {}, "View": {}, "Interval": {}}
	response, err := client.ListTimeSeries(ctx, in)
	if err == nil {
		t.Errorf("ListTimeSeries(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("ListTimeSeries(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}

func TestMockMetricServer_CreateTimeSeriesError(t *testing.T) {
	in := &monitoring.CreateTimeSeriesRequest{}
	want := validation.ErrMissingField.Err()
	missingFields := map[string]struct{}{"Name": {}, "TimeSeries": {}}
	response, err := client.CreateTimeSeries(ctx, in)
	if err == nil {
		t.Errorf("CreateTimeSeries(%q) == %q, expected error %q", in, response, want)
	}

	if !strings.Contains(err.Error(), want.Error()) {
		t.Errorf("CreateTimeSeries(%q) returned error %q, expected error %q",
			in, err.Error(), want)
	}

	if valid := validation.ValidateErrDetails(err, missingFields); !valid {
		t.Errorf("Expected missing fields %q", missingFields)
	}
}
<|endoftext|>


<commit_before>package gocoding

import (
	"errors"
	"fmt"
	"reflect"

	"encoding"
	"encoding/json"
	"encoding/xml"
)

var nv = reflect.ValueOf(nil)

type Field struct {
	Name string
	Value reflect.Value
	Type reflect.Type
}

func MakeField(name string, value interface{}, fType reflect.Type) Field {
	return Field{name, reflect.ValueOf(value), fType}
}

type Marshaller interface {
	MarshallableFields() []Field
}

func getValue(field Field) (interface{}, error) {
	if field.Value.Kind() == reflect.Func {
		fvType := field.Value.Type()

		if fvType.NumIn() != 0 {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 " should take no arguments but takes ", fvType.NumIn()))
		}

		if fvType.NumOut() < 1 {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 " should return at least one value but returns ", fvType.NumOut()))
		}

		if field.Type != nil && !fvType.Out(0).ConvertibleTo(field.Type) {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 "'s first return value should be of type ", field.Type,
											 " but is of type ", fvType.Out(0)))
		}

		if fvType.NumOut() > 2 {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 " should return at most two values but returns ", fvType.NumOut()))
		}

		if fvType.NumOut() == 2 && fvType.Out(1) != reflect.TypeOf(errors.New("")) {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 "'s second return value should be of type error but is of type ", fvType.Out(1)))
		}

		rValue := field.Value.Call([]reflect.Value{})

		if len(rValue) > 1 && !rValue[1].IsNil() {
			return nil, rValue[1].Interface().(error)
		}

		field.Value = rValue[0]
	}

	if field.Value.IsValid() && field.Type != nil {
		field.Value = field.Value.Convert(field.Type)
	}

	if field.Value.IsValid() {
		return field.Value.Interface(), nil
	} else {
		return nil, nil
	}
}

func Marshal(marshalFunc func(interface{}) ([]byte, error), value interface{}) ([]byte, error) {
	rValue := reflect.ValueOf(value)

	if rValue.Kind() == reflect.Array || rValue.Kind() == reflect.Slice {
		count := rValue.Len()
		array := make([]string, count)

		for i := 0; i < count; i++ {
			data, err := Marshal(marshalFunc, rValue.Index(i).Interface())
			if err != nil { return nil, err }
			array[i] = string(data)
		}

		return marshalFunc(array)
	}

	if _, ok := value.(Marshaller); !ok { return marshalFunc(value) }

	strMap := make(map[string]string)
	for _, field := range value.(Marshaller).MarshallableFields() {
		obj, err := getValue(field)
		if err != nil { return nil, err }

		data, err := Marshal(marshalFunc, obj)
		if err != nil { return nil, err }
		strMap[field.Name] = string(data)
	}

	return marshalFunc(strMap)
}

func MarshalJSON(value interface{}) ([]byte, error) {
	marshalFunc := json.Marshal

	if _, ok := value.(json.Marshaler); ok { return marshalFunc(value) }
	if _, ok := value.(encoding.TextMarshaler); ok { return marshalFunc(value) }

	return Marshal(marshalFunc, value)
}

func MarshalXML(value interface{}) ([]byte, error) {
	marshalFunc := xml.Marshal

	if _, ok := value.(xml.Marshaler); ok { return marshalFunc(value) }
	if _, ok := value.(encoding.TextMarshaler); ok { return marshalFunc(value) }

	return Marshal(marshalFunc, value)
}

type Unmarshaller interface {
	UnmarshallableFields() []Field
}

func setField(field Field, value interface{}) error {
	rValue := reflect.ValueOf(value)

	if field.Type != nil {
		if !rValue.Type().ConvertibleTo(field.Type) {
			return errors.New(fmt.Sprint("Unmarshallable field is of type ", field.Type,
										 " but value is of type ", rValue.Type()))
		}
		rValue = rValue.Convert(field.Type)
	}

	if field.Value.Kind() == reflect.Func {
		fvType := field.Value.Type()

		if fvType.NumIn() != 1 {
			return errors.New(fmt.Sprint("Function valued unmarshallable field ", field.Name,
										 " should take one arguments but takes ", fvType.NumIn()))
		}

		if !rValue.Type().ConvertibleTo(fvType.In(0)) {
			return errors.New(fmt.Sprint("Function valued unmarshallable field ", field.Name,
										 "'s first argument is of type ", fvType.In(0),
										 " but value is of type ", rValue.Type()))
		}

		if fvType.NumOut() > 1 {
			return errors.New(fmt.Sprint("Function valued unmarshallable field ", field.Name,
										 " should return at most one value but returns ", fvType.NumOut()))
		}

		if fvType.NumOut() == 1 && fvType.Out(0).ConvertibleTo(reflect.TypeOf(errors.New(""))) {
			return errors.New(fmt.Sprint("Function valued unmarshallable field ", field.Name,
										 "'s first return value should be of type error but is of type ", fvType.Out(0)))
		}

		//r = rValue.Convert(t.In(0))
		ret := field.Value.Call([]reflect.Value{rValue})

		if len(ret) > 0 && !ret[0].IsNil() {
			return ret[0].Interface().(error)
		}

		return nil
	}

	if field.Value.Kind() == reflect.Ptr {
		field.Value = field.Value.Elem()

		if !field.Value.CanSet() {
			return errors.New(fmt.Sprint("Pointer valued unmarshallable field ", field.Name,
										 " should be settable but is not"))
		}

		if !rValue.Type().ConvertibleTo(field.Value.Type()) {
			return errors.New(fmt.Sprint("Pointer valued unmarshallable field ", field.Name,
										 " is of type ", field.Value.Type(),
										 " but value is of type ", rValue.Type()))
		}

		field.Value.Set(rValue)

		return nil
	}

	return errors.New(fmt.Sprint("Unmarshallable field is of kind ", field.Value.Kind(),
								 " but should be of kind Func or Ptr"))
}

func getSubclass(field Field) (interface{}, error) {
	if field.Value.Kind() == reflect.Func {
		fvType := field.Value.Type()

		if fvType.NumIn() > 0 {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  " should take no arguments but takes ", fvType.NumIn()))
		}

		if fvType.NumOut() < 1 {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  " should return at least one value but returns ", fvType.NumOut()))
		}

		if field.Type != nil && !fvType.Out(0).ConvertibleTo(field.Type) {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  "'s first return value should be of type ", field.Type,
											  " but is of type ", fvType.Out(0)))
		}

		if fvType.NumOut() > 2 {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  " should return at most two values but returns ", fvType.NumOut()))
		}

		if fvType.NumOut() == 2 && fvType.Out(1) != reflect.TypeOf(errors.New("")) {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  "'s second return value should be of type error but is of type ", fvType.Out(1)))
		}

		ret := field.Value.Call([]reflect.Value{})

		if len(ret) > 1 && !ret[1].IsNil() {
			return nil, ret[1].Interface().(error)
		}

		field.Value = ret[0]

		if field.Value.IsValid() {
			if field.Type != nil {
				field.Value = field.Value.Convert(field.Type)
			}
			return field.Value.Interface(), nil
		} else {
			return reflect.Zero(field.Type), nil
		}
	}

	return nil, errors.New(fmt.Sprint("Subclass field is of kind ", field.Value.Kind(),
									  " but should be of kind Func"))
}

func Unmarshal(unmarshalFunc func([]byte, interface{}) error, data []byte, value interface{}) error {
	rValue := reflect.ValueOf(value)

	if rValue.Kind() == reflect.Array || rValue.Kind() == reflect.Slice {
		eType := rValue.Type().Elem()
		array := []string{}

		err := unmarshalFunc(data, array)
		if err != nil { return err }

		for index, str := range array {
			eValue := reflect.New(eType)

			err := Unmarshal(unmarshalFunc, []byte(str), eValue.Interface())
			if err != nil { return err }

			rValue.Index(index).Set(eValue)
		}

		return nil
	}

	if _, ok := value.(Unmarshaller); !ok { return unmarshalFunc(data, value) }

	strMap := make(map[string]string)
	if err := unmarshalFunc(data, strMap); err != nil { return err }

loop:
	for _, field := range value.(Unmarshaller).UnmarshallableFields() {
		if field.Name == "" {
			subclass, err := getSubclass(field)
			if err != nil { return err }

			if _, ok := subclass.(Unmarshaller); !ok {
				return errors.New(fmt.Sprint("Subclass field does not implement gocoding.Unmarshaller"))
			}

			value = subclass

			goto loop
		}

		obj := reflect.New(field.Type).Interface()
		data := []byte(strMap[field.Name])
		if err := Unmarshal(unmarshalFunc, data, obj); err != nil { return err }
		if err := setField(field, obj); err != nil { return err }
	}

	return nil
}

func UnmarshalJSON(data []byte, value interface{}) error {
	unmarshalFunc := json.Unmarshal

	if _, ok := value.(json.Unmarshaler); ok { return unmarshalFunc(data, value) }
	if _, ok := value.(encoding.TextUnmarshaler); ok { return unmarshalFunc(data, value) }

	return Unmarshal(unmarshalFunc, data, value)
}

func UnmarshalXML(data []byte, value interface{}) error {
	unmarshalFunc := xml.Unmarshal

	if _, ok := value.(xml.Unmarshaler); ok { return unmarshalFunc(data, value) }
	if _, ok := value.(encoding.TextUnmarshaler); ok { return unmarshalFunc(data, value) }

	return Unmarshal(unmarshalFunc, data, value)
}<commit_msg>Saving work<commit_after>package gocoding

import (
	"errors"
	"fmt"
	"reflect"

	"encoding/json"
)

var nv = reflect.ValueOf(nil)

type Field struct {
	Name string
	Value reflect.Value
	Type reflect.Type
}

func MakeField(name string, value interface{}, fType reflect.Type) Field {
	return Field{name, reflect.ValueOf(value), fType}
}

type Marshaller interface {
	MarshallableFields() []Field
}

func getValue(field Field) (interface{}, error) {
	if field.Value.Kind() == reflect.Func {
		fvType := field.Value.Type()

		if fvType.NumIn() != 0 {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 " should take no arguments but takes ", fvType.NumIn()))
		}

		if fvType.NumOut() < 1 {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 " should return at least one value but returns ", fvType.NumOut()))
		}

		if field.Type != nil && !fvType.Out(0).ConvertibleTo(field.Type) {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 "'s first return value should be of type ", field.Type,
											 " but is of type ", fvType.Out(0)))
		}

		if fvType.NumOut() > 2 {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 " should return at most two values but returns ", fvType.NumOut()))
		}

		if fvType.NumOut() == 2 && fvType.Out(1) != reflect.TypeOf(errors.New("")) {
			return nil, errors.New(fmt.Sprint("Function valued marshallable field ", field.Name,
											 "'s second return value should be of type error but is of type ", fvType.Out(1)))
		}

		rValue := field.Value.Call([]reflect.Value{})

		if len(rValue) > 1 && !rValue[1].IsNil() {
			return nil, rValue[1].Interface().(error)
		}

		field.Value = rValue[0]
	}

	if field.Value.IsValid() && field.Type != nil {
		field.Value = field.Value.Convert(field.Type)
	}

	if field.Value.IsValid() {
		return field.Value.Interface(), nil
	} else {
		return nil, nil
	}
}

func Marshal(value interface{}) ([]byte, error) {
	rValue := reflect.ValueOf(value)

	switch rValue.Kind() {
	case reflect.Slice, reflect.Array:
		count := rValue.Len()
		array := make([]*Raw, count)

		for i := 0; i < count; i++ {
			data, err := Marshal(rValue.Index(i).Interface())
			if err != nil { return nil, err }
			array[i] = mkraw(data)
		}

		return json.Marshal(array)

	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface:
		if rValue.IsNil() {
			return json.Marshal(nil)
		}
	}

	if _, ok := value.(Marshaller); !ok { return json.Marshal(value) }

	strMap := make(map[string]string)
	for _, field := range value.(Marshaller).MarshallableFields() {
		obj, err := getValue(field)
		if err != nil { return nil, err }

		data, err := Marshal(obj)
		if err != nil { return nil, err }
		strMap[field.Name] = string(data)
	}

	return json.Marshal(strMap)
}

type Unmarshaller interface {
	UnmarshallableFields() []Field
}

func setField(field Field, value interface{}) error {
	rValue := reflect.ValueOf(value)

	if field.Type != nil {
		if !rValue.Type().ConvertibleTo(field.Type) {
			return errors.New(fmt.Sprint("Unmarshallable field is of type ", field.Type,
										 " but value is of type ", rValue.Type()))
		}
		rValue = rValue.Convert(field.Type)
	}

	if field.Value.Kind() == reflect.Func {
		fvType := field.Value.Type()

		if fvType.NumIn() != 1 {
			return errors.New(fmt.Sprint("Function valued unmarshallable field ", field.Name,
										 " should take one arguments but takes ", fvType.NumIn()))
		}

		if !rValue.Type().ConvertibleTo(fvType.In(0)) {
			return errors.New(fmt.Sprint("Function valued unmarshallable field ", field.Name,
										 "'s first argument is of type ", fvType.In(0),
										 " but value is of type ", rValue.Type()))
		}

		if fvType.NumOut() > 1 {
			return errors.New(fmt.Sprint("Function valued unmarshallable field ", field.Name,
										 " should return at most one value but returns ", fvType.NumOut()))
		}

		if fvType.NumOut() == 1 && fvType.Out(0).ConvertibleTo(reflect.TypeOf(errors.New(""))) {
			return errors.New(fmt.Sprint("Function valued unmarshallable field ", field.Name,
										 "'s first return value should be of type error but is of type ", fvType.Out(0)))
		}

		//r = rValue.Convert(t.In(0))
		ret := field.Value.Call([]reflect.Value{rValue})

		if len(ret) > 0 && !ret[0].IsNil() {
			return ret[0].Interface().(error)
		}

		return nil
	}

	if field.Value.Kind() == reflect.Ptr {
		field.Value = field.Value.Elem()

		if !field.Value.CanSet() {
			return errors.New(fmt.Sprint("Pointer valued unmarshallable field ", field.Name,
										 " should be settable but is not"))
		}

		if !rValue.Type().ConvertibleTo(field.Value.Type()) {
			return errors.New(fmt.Sprint("Pointer valued unmarshallable field ", field.Name,
										 " is of type ", field.Value.Type(),
										 " but value is of type ", rValue.Type()))
		}

		field.Value.Set(rValue)

		return nil
	}

	return errors.New(fmt.Sprint("Unmarshallable field is of kind ", field.Value.Kind(),
								 " but should be of kind Func or Ptr"))
}

func getSubclass(field Field) (interface{}, error) {
	if field.Value.Kind() == reflect.Func {
		fvType := field.Value.Type()

		if fvType.NumIn() > 0 {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  " should take no arguments but takes ", fvType.NumIn()))
		}

		if fvType.NumOut() < 1 {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  " should return at least one value but returns ", fvType.NumOut()))
		}

		if field.Type != nil && !fvType.Out(0).ConvertibleTo(field.Type) {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  "'s first return value should be of type ", field.Type,
											  " but is of type ", fvType.Out(0)))
		}

		if fvType.NumOut() > 2 {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  " should return at most two values but returns ", fvType.NumOut()))
		}

		if fvType.NumOut() == 2 && fvType.Out(1) != reflect.TypeOf(errors.New("")) {
			return nil, errors.New(fmt.Sprint("Function valued subclass field ", field.Name,
											  "'s second return value should be of type error but is of type ", fvType.Out(1)))
		}

		ret := field.Value.Call([]reflect.Value{})

		if len(ret) > 1 && !ret[1].IsNil() {
			return nil, ret[1].Interface().(error)
		}

		field.Value = ret[0]

		if field.Value.IsValid() {
			if field.Type != nil {
				field.Value = field.Value.Convert(field.Type)
			}
			return field.Value.Interface(), nil
		} else {
			return reflect.Zero(field.Type), nil
		}
	}

	return nil, errors.New(fmt.Sprint("Subclass field is of kind ", field.Value.Kind(),
									  " but should be of kind Func"))
}

func Unmarshal(data []byte, value interface{}) error {
	rValue := reflect.ValueOf(value)

	if rValue.Kind() == reflect.Array || rValue.Kind() == reflect.Slice {
		eType := rValue.Type().Elem()
		array := []string{}

		err := json.Unmarshal(data, array)
		if err != nil { return err }

		for index, str := range array {
			eValue := reflect.New(eType)

			err := Unmarshal([]byte(str), eValue.Interface())
			if err != nil { return err }

			rValue.Index(index).Set(eValue)
		}

		return nil
	}

	if _, ok := value.(Unmarshaller); !ok { return json.Unmarshal(data, value) }

	strMap := make(map[string]string)
	if err := json.Unmarshal(data, strMap); err != nil { return err }

loop:
	for _, field := range value.(Unmarshaller).UnmarshallableFields() {
		if field.Name == "" {
			subclass, err := getSubclass(field)
			if err != nil { return err }

			if _, ok := subclass.(Unmarshaller); !ok {
				return errors.New(fmt.Sprint("Subclass field does not implement gocoding.Unmarshaller"))
			}

			value = subclass

			goto loop
		}

		obj := reflect.New(field.Type).Interface()
		data := []byte(strMap[field.Name])
		if err := Unmarshal(data, obj); err != nil { return err }
		if err := setField(field, obj); err != nil { return err }
	}

	return nil
}<|endoftext|>


<commit_before>// Copyright © 2017 Ricardo Aravena <raravena@branch.io>
//
// 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 exec

import (
	"bytes"
	"fmt"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
	"io/ioutil"
	"net"
	"os"
	"time"
)

type Options struct {
	machines []string
	port     string
	user     string
	cmd      string
	key      string
	useAgent bool
}

type executeResult struct {
	result string
	err    error
}

func User(u string) func(*Options) {
	return func(e *Options) {
		e.user = u
	}
}

func Port(p string) func(*Options) {
	return func(e *Options) {
		e.port = p
	}
}

func Cmd(c string) func(*Options) {
	return func(e *Options) {
		e.cmd = c
	}
}

func Machines(m []string) func(*Options) {
	return func(e *Options) {
		e.machines = m
	}
}

func Key(k string) func(*Options) {
	return func(e *Options) {
		e.key = k
	}
}

func UseAgent(u bool) func(*Options) {
	return func(e *Options) {
		e.useAgent = u
	}
}

func makeSigner(keyname string) (signer ssh.Signer, err error) {
	fp, err := os.Open(keyname)
	if err != nil {
		return
	}
	defer fp.Close()

	buf, _ := ioutil.ReadAll(fp)
	signer, _ = ssh.ParsePrivateKey(buf)
	return
}

func makeKeyring(key string, useAgent bool) ssh.AuthMethod {
	signers := []ssh.Signer{}

	if useAgent == true {
		aConn, _ := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
		sshAgent := agent.NewClient(aConn)
		aSigners, _ := sshAgent.Signers()
		for _, signer := range aSigners {
			signers = append(signers, signer)
		}
	}

	keys := []string{key}

	for _, keyname := range keys {
		signer, err := makeSigner(keyname)
		if err == nil {
			signers = append(signers, signer)
		}
	}
	return ssh.PublicKeys(signers...)
}

func executeCmd(opt Options, hostname string, config *ssh.ClientConfig) executeResult {

	conn, err := ssh.Dial("tcp", hostname+":"+opt.port, config)

	if err != nil {
		return executeResult{result: "",
			err: err}
	}

	session, _ := conn.NewSession()
	defer session.Close()

	var stdoutBuf bytes.Buffer
	session.Stdout = &stdoutBuf
	err = session.Run(opt.cmd)

	return executeResult{result: hostname + ":\n" + stdoutBuf.String(),
		err: err}
}

func Run(options ...func(*Options)) bool {
	opt := Options{}
	for _, option := range options {
		option(&opt)
	}

	// in 20 seconds the message will come to timeout channel
	timeout := time.After(20 * time.Second)
	results := make(chan executeResult, len(opt.machines)+1)

	config := &ssh.ClientConfig{
		User: opt.user,
		Auth: []ssh.AuthMethod{
			makeKeyring(opt.key, opt.useAgent),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	for _, m := range opt.machines {
		go func(hostname string) {
			// we’ll write results into the buffered channel of strings
			results <- executeCmd(opt, hostname, config)
		}(m)
	}

	retval := true

	for i := 0; i < len(opt.machines); i++ {
		select {
		case res := <-results:
			if res.err == nil {
				fmt.Print(res.result)
			} else {
				fmt.Println(res.err)
				retval = false
			}
		case <-timeout:
			fmt.Println(fmt.Sprintf("%v:", opt.machines[i]))
			fmt.Println("Server timed out!")
			retval = false
		}
	}
	return retval
}
<commit_msg>Changes to the output in case we see an exit code other than 0 (#21)<commit_after>// Copyright © 2017 Ricardo Aravena <raravena@branch.io>
//
// 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 exec

import (
	"bytes"
	"fmt"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
	"io/ioutil"
	"net"
	"os"
	"time"
)

type Options struct {
	machines []string
	port     string
	user     string
	cmd      string
	key      string
	useAgent bool
}

type executeResult struct {
	result string
	err    error
}

func User(u string) func(*Options) {
	return func(e *Options) {
		e.user = u
	}
}

func Port(p string) func(*Options) {
	return func(e *Options) {
		e.port = p
	}
}

func Cmd(c string) func(*Options) {
	return func(e *Options) {
		e.cmd = c
	}
}

func Machines(m []string) func(*Options) {
	return func(e *Options) {
		e.machines = m
	}
}

func Key(k string) func(*Options) {
	return func(e *Options) {
		e.key = k
	}
}

func UseAgent(u bool) func(*Options) {
	return func(e *Options) {
		e.useAgent = u
	}
}

func makeSigner(keyname string) (signer ssh.Signer, err error) {
	fp, err := os.Open(keyname)
	if err != nil {
		return
	}
	defer fp.Close()

	buf, _ := ioutil.ReadAll(fp)
	signer, _ = ssh.ParsePrivateKey(buf)
	return
}

func makeKeyring(key string, useAgent bool) ssh.AuthMethod {
	signers := []ssh.Signer{}

	if useAgent == true {
		aConn, _ := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
		sshAgent := agent.NewClient(aConn)
		aSigners, _ := sshAgent.Signers()
		for _, signer := range aSigners {
			signers = append(signers, signer)
		}
	}

	keys := []string{key}

	for _, keyname := range keys {
		signer, err := makeSigner(keyname)
		if err == nil {
			signers = append(signers, signer)
		}
	}
	return ssh.PublicKeys(signers...)
}

func executeCmd(opt Options, hostname string, config *ssh.ClientConfig) executeResult {

	conn, err := ssh.Dial("tcp", hostname+":"+opt.port, config)

	if err != nil {
		return executeResult{result: "Connection refused",
			err: err}
	}

	session, _ := conn.NewSession()
	defer session.Close()

	var stdoutBuf bytes.Buffer
	session.Stdout = &stdoutBuf
	err = session.Run(opt.cmd)

	return executeResult{result: hostname + ":\n" + stdoutBuf.String(),
		err: err}
}

func Run(options ...func(*Options)) bool {
	opt := Options{}
	for _, option := range options {
		option(&opt)
	}

	// in 20 seconds the message will come to timeout channel
	timeout := time.After(20 * time.Second)
	results := make(chan executeResult, len(opt.machines)+1)

	config := &ssh.ClientConfig{
		User: opt.user,
		Auth: []ssh.AuthMethod{
			makeKeyring(opt.key, opt.useAgent),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	for _, m := range opt.machines {
		go func(hostname string) {
			// we’ll write results into the buffered channel of strings
			results <- executeCmd(opt, hostname, config)
		}(m)
	}

	retval := true

	for i := 0; i < len(opt.machines); i++ {
		select {
		case res := <-results:
			if res.err == nil {
				fmt.Print(res.result)
			} else {
				fmt.Println(res.result, "\n", res.err)
				retval = false
			}
		case <-timeout:
			fmt.Println(fmt.Sprintf("%v:", opt.machines[i]))
			fmt.Println("Server timed out!")
			retval = false
		}
	}
	return retval
}
<|endoftext|>