<commit_before>// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package git

import (
	"bytes"
	"container/list"
	"strconv"
	"strings"
)

// getRefCommitID returns the last commit ID string of given reference (branch or tag).
func (repo *Repository) getRefCommitID(name string) (string, error) {
	stdout, err := NewCommand("show-ref", "--verify", name).RunInDir(repo.Path)
	if err != nil {
		if strings.Contains(err.Error(), "not a valid ref") {
			return "", ErrNotExist{name, ""}
		}
		return "", err
	}
	return strings.Split(stdout, " ")[0], nil
}

// GetBranchCommitID returns last commit ID string of given branch.
func (repo *Repository) GetBranchCommitID(name string) (string, error) {
	return repo.getRefCommitID(BranchPrefix + name)
}

// GetTagCommitID returns last commit ID string of given tag.
func (repo *Repository) GetTagCommitID(name string) (string, error) {
	return repo.getRefCommitID(TagPrefix + name)
}

// parseCommitData parses commit information from the (uncompressed) raw
// data from the commit object.
// \n\n separate headers from message
func parseCommitData(data []byte) (*Commit, error) {
	commit := new(Commit)
	commit.parents = make([]SHA1, 0, 1)
	// we now have the contents of the commit object. Let's investigate...
	nextline := 0
l:
	for {
		eol := bytes.IndexByte(data[nextline:], '\n')
		switch {
		case eol > 0:
			line := data[nextline : nextline+eol]
			spacepos := bytes.IndexByte(line, ' ')
			reftype := line[:spacepos]
			switch string(reftype) {
			case "tree", "object":
				id, err := NewIDFromString(string(line[spacepos+1:]))
				if err != nil {
					return nil, err
				}
				commit.Tree.ID = id
			case "parent":
				// A commit can have one or more parents
				oid, err := NewIDFromString(string(line[spacepos+1:]))
				if err != nil {
					return nil, err
				}
				commit.parents = append(commit.parents, oid)
			case "author", "tagger":
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
				if err != nil {
					return nil, err
				}
				commit.Author = sig
			case "committer":
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
				if err != nil {
					return nil, err
				}
				commit.Committer = sig
			case "gpgsig":
				sig, err := newGPGSignatureFromCommitline(data, nextline+spacepos+1)
				if err != nil {
					return nil, err
				}
				commit.Signature = sig
			}
			nextline += eol + 1
		case eol == 0:
			commit.CommitMessage = string(data[nextline+1:])
			break l
		default:
			break l
		}
	}
	return commit, nil
}

func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
	c, ok := repo.commitCache.Get(id.String())
	if ok {
		log("Hit cache: %s", id)
		return c.(*Commit), nil
	}

	data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path)
	if err != nil {
		if strings.Contains(err.Error(), "fatal: Not a valid object name") {
			return nil, ErrNotExist{id.String(), ""}
		}
		return nil, err
	}

	commit, err := parseCommitData(data)
	if err != nil {
		return nil, err
	}
	commit.repo = repo
	commit.ID = id

	repo.commitCache.Set(id.String(), commit)
	return commit, nil
}

// GetCommit returns commit object of by ID string.
func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
	if len(commitID) != 40 {
		var err error
		commitID, err = NewCommand("rev-parse", commitID).RunInDir(repo.Path)
		if err != nil {
			return nil, err
		}
	}
	id, err := NewIDFromString(commitID)
	if err != nil {
		return nil, err
	}

	return repo.getCommit(id)
}

// GetBranchCommit returns the last commit of given branch.
func (repo *Repository) GetBranchCommit(name string) (*Commit, error) {
	commitID, err := repo.GetBranchCommitID(name)
	if err != nil {
		return nil, err
	}
	return repo.GetCommit(commitID)
}

// GetTagCommit get the commit of the specific tag via name
func (repo *Repository) GetTagCommit(name string) (*Commit, error) {
	commitID, err := repo.GetTagCommitID(name)
	if err != nil {
		return nil, err
	}
	return repo.GetCommit(commitID)
}

func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit, error) {
	// File name starts with ':' must be escaped.
	if relpath[0] == ':' {
		relpath = `\` + relpath
	}

	stdout, err := NewCommand("log", "-1", prettyLogFormat, id.String(), "--", relpath).RunInDir(repo.Path)
	if err != nil {
		return nil, err
	}

	id, err = NewIDFromString(stdout)
	if err != nil {
		return nil, err
	}

	return repo.getCommit(id)
}

// GetCommitByPath returns the last commit of relative path.
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
	stdout, err := NewCommand("log", "-1", prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}

	commits, err := repo.parsePrettyFormatLogToList(stdout)
	if err != nil {
		return nil, err
	}
	return commits.Front().Value.(*Commit), nil
}

// CommitsRangeSize the default commits range size
var CommitsRangeSize = 50

func (repo *Repository) commitsByRange(id SHA1, page int) (*list.List, error) {
	stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*CommitsRangeSize),
		"--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return repo.parsePrettyFormatLogToList(stdout)
}

func (repo *Repository) searchCommits(id SHA1, keyword string, all bool) (*list.List, error) {
	cmd := NewCommand("log", id.String(), "-100", "-i", "--grep="+keyword, prettyLogFormat)
	if all {
		cmd.AddArguments("--all")
	}
	stdout, err := cmd.RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return repo.parsePrettyFormatLogToList(stdout)
}

func (repo *Repository) getFilesChanged(id1 string, id2 string) ([]string, error) {
	stdout, err := NewCommand("diff", "--name-only", id1, id2).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return strings.Split(string(stdout), "\n"), nil
}

// FileCommitsCount return the number of files at a revison
func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
	return commitsCount(repo.Path, revision, file)
}

// CommitsByFileAndRange return the commits accroding revison file and the page
func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) {
	stdout, err := NewCommand("log", revision, "--follow", "--skip="+strconv.Itoa((page-1)*50),
		"--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return repo.parsePrettyFormatLogToList(stdout)
}

// FilesCountBetween return the number of files changed between two commits
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
	stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
	if err != nil {
		return 0, err
	}
	return len(strings.Split(stdout, "\n")) - 1, nil
}

// CommitsBetween returns a list that contains commits between [last, before).
func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) {
	stdout, err := NewCommand("rev-list", before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
}

// CommitsBetweenIDs return commits between twoe commits
func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, error) {
	lastCommit, err := repo.GetCommit(last)
	if err != nil {
		return nil, err
	}
	beforeCommit, err := repo.GetCommit(before)
	if err != nil {
		return nil, err
	}
	return repo.CommitsBetween(lastCommit, beforeCommit)
}

// CommitsCountBetween return numbers of commits between two commits
func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
	return commitsCount(repo.Path, start+"..."+end, "")
}

// commitsBefore the limit is depth, not total number of returned commits.
func (repo *Repository) commitsBefore(id SHA1, limit int) (*list.List, error) {
	cmd := NewCommand("log")
	if limit > 0 {
		cmd.AddArguments("-"+ strconv.Itoa(limit), prettyLogFormat, id.String())
	} else {
		cmd.AddArguments(prettyLogFormat, id.String())
	}

	stdout, err := cmd.RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}

	formattedLog, err := repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
	if err != nil {
		return nil, err
	}

	commits := list.New()
	for logEntry := formattedLog.Front(); logEntry != nil; logEntry = logEntry.Next() {
		commit := logEntry.Value.(*Commit)
		branches, err := repo.getBranches(commit, 2)
		if err != nil {
			return nil, err
		}

		if len(branches) > 1 {
			break
		}

		commits.PushBack(commit)
	}

	return commits, nil
}

func (repo *Repository) getCommitsBefore(id SHA1) (*list.List, error) {
	return repo.commitsBefore(id, 0)
}

func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) (*list.List, error) {
	return repo.commitsBefore(id, num)
}

func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) {
	stdout, err := NewCommand("for-each-ref", "--count="+ strconv.Itoa(limit), "--format=%(refname)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path)
	if err != nil {
		return nil, err
	}

	refs := strings.Split(stdout, "\n")
	branches := make([]string, len(refs)-1)
	for i, ref := range refs[:len(refs)-1] {
		branches[i] = strings.TrimPrefix(ref, BranchPrefix)
	}
	return branches, nil
}
<commit_msg>Make GetRefCommitID exported (#107)<commit_after>// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package git

import (
	"bytes"
	"container/list"
	"strconv"
	"strings"
)

// GetRefCommitID returns the last commit ID string of given reference (branch or tag).
func (repo *Repository) GetRefCommitID(name string) (string, error) {
	stdout, err := NewCommand("show-ref", "--verify", name).RunInDir(repo.Path)
	if err != nil {
		if strings.Contains(err.Error(), "not a valid ref") {
			return "", ErrNotExist{name, ""}
		}
		return "", err
	}
	return strings.Split(stdout, " ")[0], nil
}

// GetBranchCommitID returns last commit ID string of given branch.
func (repo *Repository) GetBranchCommitID(name string) (string, error) {
	return repo.GetRefCommitID(BranchPrefix + name)
}

// GetTagCommitID returns last commit ID string of given tag.
func (repo *Repository) GetTagCommitID(name string) (string, error) {
	return repo.GetRefCommitID(TagPrefix + name)
}

// parseCommitData parses commit information from the (uncompressed) raw
// data from the commit object.
// \n\n separate headers from message
func parseCommitData(data []byte) (*Commit, error) {
	commit := new(Commit)
	commit.parents = make([]SHA1, 0, 1)
	// we now have the contents of the commit object. Let's investigate...
	nextline := 0
l:
	for {
		eol := bytes.IndexByte(data[nextline:], '\n')
		switch {
		case eol > 0:
			line := data[nextline : nextline+eol]
			spacepos := bytes.IndexByte(line, ' ')
			reftype := line[:spacepos]
			switch string(reftype) {
			case "tree", "object":
				id, err := NewIDFromString(string(line[spacepos+1:]))
				if err != nil {
					return nil, err
				}
				commit.Tree.ID = id
			case "parent":
				// A commit can have one or more parents
				oid, err := NewIDFromString(string(line[spacepos+1:]))
				if err != nil {
					return nil, err
				}
				commit.parents = append(commit.parents, oid)
			case "author", "tagger":
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
				if err != nil {
					return nil, err
				}
				commit.Author = sig
			case "committer":
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
				if err != nil {
					return nil, err
				}
				commit.Committer = sig
			case "gpgsig":
				sig, err := newGPGSignatureFromCommitline(data, nextline+spacepos+1)
				if err != nil {
					return nil, err
				}
				commit.Signature = sig
			}
			nextline += eol + 1
		case eol == 0:
			commit.CommitMessage = string(data[nextline+1:])
			break l
		default:
			break l
		}
	}
	return commit, nil
}

func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
	c, ok := repo.commitCache.Get(id.String())
	if ok {
		log("Hit cache: %s", id)
		return c.(*Commit), nil
	}

	data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path)
	if err != nil {
		if strings.Contains(err.Error(), "fatal: Not a valid object name") {
			return nil, ErrNotExist{id.String(), ""}
		}
		return nil, err
	}

	commit, err := parseCommitData(data)
	if err != nil {
		return nil, err
	}
	commit.repo = repo
	commit.ID = id

	repo.commitCache.Set(id.String(), commit)
	return commit, nil
}

// GetCommit returns commit object of by ID string.
func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
	if len(commitID) != 40 {
		var err error
		commitID, err = NewCommand("rev-parse", commitID).RunInDir(repo.Path)
		if err != nil {
			return nil, err
		}
	}
	id, err := NewIDFromString(commitID)
	if err != nil {
		return nil, err
	}

	return repo.getCommit(id)
}

// GetBranchCommit returns the last commit of given branch.
func (repo *Repository) GetBranchCommit(name string) (*Commit, error) {
	commitID, err := repo.GetBranchCommitID(name)
	if err != nil {
		return nil, err
	}
	return repo.GetCommit(commitID)
}

// GetTagCommit get the commit of the specific tag via name
func (repo *Repository) GetTagCommit(name string) (*Commit, error) {
	commitID, err := repo.GetTagCommitID(name)
	if err != nil {
		return nil, err
	}
	return repo.GetCommit(commitID)
}

func (repo *Repository) getCommitByPathWithID(id SHA1, relpath string) (*Commit, error) {
	// File name starts with ':' must be escaped.
	if relpath[0] == ':' {
		relpath = `\` + relpath
	}

	stdout, err := NewCommand("log", "-1", prettyLogFormat, id.String(), "--", relpath).RunInDir(repo.Path)
	if err != nil {
		return nil, err
	}

	id, err = NewIDFromString(stdout)
	if err != nil {
		return nil, err
	}

	return repo.getCommit(id)
}

// GetCommitByPath returns the last commit of relative path.
func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
	stdout, err := NewCommand("log", "-1", prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}

	commits, err := repo.parsePrettyFormatLogToList(stdout)
	if err != nil {
		return nil, err
	}
	return commits.Front().Value.(*Commit), nil
}

// CommitsRangeSize the default commits range size
var CommitsRangeSize = 50

func (repo *Repository) commitsByRange(id SHA1, page int) (*list.List, error) {
	stdout, err := NewCommand("log", id.String(), "--skip="+strconv.Itoa((page-1)*CommitsRangeSize),
		"--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return repo.parsePrettyFormatLogToList(stdout)
}

func (repo *Repository) searchCommits(id SHA1, keyword string, all bool) (*list.List, error) {
	cmd := NewCommand("log", id.String(), "-100", "-i", "--grep="+keyword, prettyLogFormat)
	if all {
		cmd.AddArguments("--all")
	}
	stdout, err := cmd.RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return repo.parsePrettyFormatLogToList(stdout)
}

func (repo *Repository) getFilesChanged(id1 string, id2 string) ([]string, error) {
	stdout, err := NewCommand("diff", "--name-only", id1, id2).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return strings.Split(string(stdout), "\n"), nil
}

// FileCommitsCount return the number of files at a revison
func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
	return commitsCount(repo.Path, revision, file)
}

// CommitsByFileAndRange return the commits accroding revison file and the page
func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) {
	stdout, err := NewCommand("log", revision, "--follow", "--skip="+strconv.Itoa((page-1)*50),
		"--max-count="+strconv.Itoa(CommitsRangeSize), prettyLogFormat, "--", file).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return repo.parsePrettyFormatLogToList(stdout)
}

// FilesCountBetween return the number of files changed between two commits
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
	stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
	if err != nil {
		return 0, err
	}
	return len(strings.Split(stdout, "\n")) - 1, nil
}

// CommitsBetween returns a list that contains commits between [last, before).
func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) {
	stdout, err := NewCommand("rev-list", before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}
	return repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
}

// CommitsBetweenIDs return commits between twoe commits
func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, error) {
	lastCommit, err := repo.GetCommit(last)
	if err != nil {
		return nil, err
	}
	beforeCommit, err := repo.GetCommit(before)
	if err != nil {
		return nil, err
	}
	return repo.CommitsBetween(lastCommit, beforeCommit)
}

// CommitsCountBetween return numbers of commits between two commits
func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
	return commitsCount(repo.Path, start+"..."+end, "")
}

// commitsBefore the limit is depth, not total number of returned commits.
func (repo *Repository) commitsBefore(id SHA1, limit int) (*list.List, error) {
	cmd := NewCommand("log")
	if limit > 0 {
		cmd.AddArguments("-"+ strconv.Itoa(limit), prettyLogFormat, id.String())
	} else {
		cmd.AddArguments(prettyLogFormat, id.String())
	}

	stdout, err := cmd.RunInDirBytes(repo.Path)
	if err != nil {
		return nil, err
	}

	formattedLog, err := repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
	if err != nil {
		return nil, err
	}

	commits := list.New()
	for logEntry := formattedLog.Front(); logEntry != nil; logEntry = logEntry.Next() {
		commit := logEntry.Value.(*Commit)
		branches, err := repo.getBranches(commit, 2)
		if err != nil {
			return nil, err
		}

		if len(branches) > 1 {
			break
		}

		commits.PushBack(commit)
	}

	return commits, nil
}

func (repo *Repository) getCommitsBefore(id SHA1) (*list.List, error) {
	return repo.commitsBefore(id, 0)
}

func (repo *Repository) getCommitsBeforeLimit(id SHA1, num int) (*list.List, error) {
	return repo.commitsBefore(id, num)
}

func (repo *Repository) getBranches(commit *Commit, limit int) ([]string, error) {
	stdout, err := NewCommand("for-each-ref", "--count="+ strconv.Itoa(limit), "--format=%(refname)", "--contains", commit.ID.String(), BranchPrefix).RunInDir(repo.Path)
	if err != nil {
		return nil, err
	}

	refs := strings.Split(stdout, "\n")
	branches := make([]string, len(refs)-1)
	for i, ref := range refs[:len(refs)-1] {
		branches[i] = strings.TrimPrefix(ref, BranchPrefix)
	}
	return branches, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/amfranz/go-xen-api-client"
	"github.com/hashicorp/terraform/helper/schema"
)

const (
	vmSchemaNameLabel        = "name_label"
	vmSchemaBaseTemplateName = "base_template_name"
	vmSchemaXenstoreData     = "xenstore_data"
)

func resourceVM() *schema.Resource {
	return &schema.Resource{
		Create: resourceVMCreate,
		Read:   resourceVMRead,
		Update: resourceVMUpdate,
		Delete: resourceVMDelete,
		Exists: resourceVMExists,

		Schema: map[string]*schema.Schema{
			vmSchemaNameLabel: &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			vmSchemaBaseTemplateName: &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			vmSchemaXenstoreData: &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
			},
		},
	}
}

func filterVMTemplates(c *Connection, vms []xenAPI.VMRef) ([]xenAPI.VMRef, error) {
	var templates []xenAPI.VMRef
	for _, vm := range vms {
		isATemplate, err := c.client.VM().GetIsATemplate(c.session, vm)
		if err != nil {
			return templates, err
		}
		if isATemplate {
			templates = append(templates, vm)
		}
	}
	return templates, nil
}

func resourceVMCreate(d *schema.ResourceData, m interface{}) error {
	c := m.(*Connection)

	dBaseTemplateName := d.Get(vmSchemaBaseTemplateName).(string)

	xenBaseTemplates, err := c.client.VM().GetByNameLabel(c.session, dBaseTemplateName)
	if err != nil {
		return err
	}

	xenBaseTemplates, err = filterVMTemplates(c, xenBaseTemplates)
	if err != nil {
		return err
	}

	if len(xenBaseTemplates) == 0 {
		return fmt.Errorf("No VM template with label %q has been found", dBaseTemplateName)
	}

	if len(xenBaseTemplates) > 1 {
		return fmt.Errorf("More than one VM template with label %q has been found", dBaseTemplateName)
	}

	xenBaseTemplate := xenBaseTemplates[0]

	dNameLabel := d.Get(vmSchemaNameLabel).(string)

	xenVM, err := c.client.VM().Clone(c.session, xenBaseTemplate, dNameLabel)
	if err != nil {
		return err
	}

	xenUUID, err := c.client.VM().GetUUID(c.session, xenVM)
	if err != nil {
		return err
	}

	d.SetId(xenUUID)

	dXenstoreDataRaw, ok := d.GetOk(vmSchemaXenstoreData)
	if ok {
		dXenstoreData := make(map[string]string)
		for key, value := range dXenstoreDataRaw.(map[string]interface{}) {
			dXenstoreData[key] = value.(string)
		}

		err = c.client.VM().SetXenstoreData(c.session, xenVM, dXenstoreData)
		if err != nil {
			return err
		}
	}

	err = c.client.VM().Provision(c.session, xenVM)
	if err != nil {
		return err
	}

	return nil
}

func resourceVMRead(d *schema.ResourceData, m interface{}) error {
	c := m.(*Connection)

	xenVM, err := c.client.VM().GetByUUID(c.session, d.Id())
	if err != nil {
		if xenErr, ok := err.(*xenAPI.Error); ok {
			if xenErr.Code() == xenAPI.ERR_UUID_INVALID {
				d.SetId("")
				return nil
			}
		}

		return err
	}

	vmRecord, err := c.client.VM().GetRecord(c.session, xenVM)
	if err != nil {
		return err
	}

	err = d.Set(vmSchemaNameLabel, vmRecord.NameLabel)
	if err != nil {
		return err
	}

	vmBaseTemplateName, ok := vmRecord.OtherConfig["base_template_name"]
	if ok {
		err = d.Set(vmSchemaBaseTemplateName, vmBaseTemplateName)
		if err != nil {
			return err
		}
	}

	err = d.Set(vmSchemaXenstoreData, vmRecord.XenstoreData)
	if err != nil {
		return err
	}

	return nil
}

func resourceVMUpdate(d *schema.ResourceData, m interface{}) error {
	c := m.(*Connection)

	xenVM, err := c.client.VM().GetByUUID(c.session, d.Id())
	if err != nil {
		if xenErr, ok := err.(*xenAPI.Error); ok {
			if xenErr.Code() == xenAPI.ERR_UUID_INVALID {
				d.SetId("")
				return nil
			}
		}

		return err
	}

	vmRecord, err := c.client.VM().GetRecord(c.session, xenVM)
	if err != nil {
		return err
	}

	d.Partial(true)

	dNameLabel := d.Get(vmSchemaNameLabel).(string)
	if vmRecord.NameLabel != dNameLabel {
		err := c.client.VM().SetNameLabel(c.session, xenVM, dNameLabel)
		if err != nil {
			return err
		}

		d.SetPartial(vmSchemaNameLabel)
	}

	dXenstoreDataRaw, ok := d.GetOk(vmSchemaXenstoreData)
	if ok {
		dXenstoreData := make(map[string]string)
		for key, value := range dXenstoreDataRaw.(map[string]interface{}) {
			dXenstoreData[key] = value.(string)
		}

		err = c.client.VM().SetXenstoreData(c.session, xenVM, dXenstoreData)
		if err != nil {
			return err
		}

		d.SetPartial(vmSchemaXenstoreData)
	}

	d.Partial(false)

	return resourceVMRead(d, m)
}

func resourceVMDelete(d *schema.ResourceData, m interface{}) error {
	c := m.(*Connection)

	xenVM, err := c.client.VM().GetByUUID(c.session, d.Id())
	if err != nil {
		if xenErr, ok := err.(*xenAPI.Error); ok {
			if xenErr.Code() == xenAPI.ERR_UUID_INVALID {
				d.SetId("")
				return nil
			}
		}

		return err
	}

	err = c.client.VM().Destroy(c.session, xenVM)
	if err != nil {
		return err
	}

	d.SetId("")
	return nil
}

func resourceVMExists(d *schema.ResourceData, m interface{}) (bool, error) {
	c := m.(*Connection)

	_, err := c.client.VM().GetByUUID(c.session, d.Id())
	if err != nil {
		if xenErr, ok := err.(*xenAPI.Error); ok {
			if xenErr.Code() == xenAPI.ERR_UUID_INVALID {
				return false, nil
			}
		}

		return false, err
	}

	return true, nil
}
<commit_msg>Fix destroy VM if it is running.<commit_after>package main

import (
	"fmt"
	"github.com/amfranz/go-xen-api-client"
	"github.com/hashicorp/terraform/helper/schema"
)

const (
	vmSchemaNameLabel        = "name_label"
	vmSchemaBaseTemplateName = "base_template_name"
	vmSchemaXenstoreData     = "xenstore_data"
)

func resourceVM() *schema.Resource {
	return &schema.Resource{
		Create: resourceVMCreate,
		Read:   resourceVMRead,
		Update: resourceVMUpdate,
		Delete: resourceVMDelete,
		Exists: resourceVMExists,

		Schema: map[string]*schema.Schema{
			vmSchemaNameLabel: &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			vmSchemaBaseTemplateName: &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			vmSchemaXenstoreData: &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
			},
		},
	}
}

func filterVMTemplates(c *Connection, vms []xenAPI.VMRef) ([]xenAPI.VMRef, error) {
	var templates []xenAPI.VMRef
	for _, vm := range vms {
		isATemplate, err := c.client.VM().GetIsATemplate(c.session, vm)
		if err != nil {
			return templates, err
		}
		if isATemplate {
			templates = append(templates, vm)
		}
	}
	return templates, nil
}

func resourceVMCreate(d *schema.ResourceData, m interface{}) error {
	c := m.(*Connection)

	dBaseTemplateName := d.Get(vmSchemaBaseTemplateName).(string)

	xenBaseTemplates, err := c.client.VM().GetByNameLabel(c.session, dBaseTemplateName)
	if err != nil {
		return err
	}

	xenBaseTemplates, err = filterVMTemplates(c, xenBaseTemplates)
	if err != nil {
		return err
	}

	if len(xenBaseTemplates) == 0 {
		return fmt.Errorf("No VM template with label %q has been found", dBaseTemplateName)
	}

	if len(xenBaseTemplates) > 1 {
		return fmt.Errorf("More than one VM template with label %q has been found", dBaseTemplateName)
	}

	xenBaseTemplate := xenBaseTemplates[0]

	dNameLabel := d.Get(vmSchemaNameLabel).(string)

	xenVM, err := c.client.VM().Clone(c.session, xenBaseTemplate, dNameLabel)
	if err != nil {
		return err
	}

	xenUUID, err := c.client.VM().GetUUID(c.session, xenVM)
	if err != nil {
		return err
	}

	d.SetId(xenUUID)

	dXenstoreDataRaw, ok := d.GetOk(vmSchemaXenstoreData)
	if ok {
		dXenstoreData := make(map[string]string)
		for key, value := range dXenstoreDataRaw.(map[string]interface{}) {
			dXenstoreData[key] = value.(string)
		}

		err = c.client.VM().SetXenstoreData(c.session, xenVM, dXenstoreData)
		if err != nil {
			return err
		}
	}

	err = c.client.VM().Provision(c.session, xenVM)
	if err != nil {
		return err
	}

	return nil
}

func resourceVMRead(d *schema.ResourceData, m interface{}) error {
	c := m.(*Connection)

	xenVM, err := c.client.VM().GetByUUID(c.session, d.Id())
	if err != nil {
		if xenErr, ok := err.(*xenAPI.Error); ok {
			if xenErr.Code() == xenAPI.ERR_UUID_INVALID {
				d.SetId("")
				return nil
			}
		}

		return err
	}

	vmRecord, err := c.client.VM().GetRecord(c.session, xenVM)
	if err != nil {
		return err
	}

	err = d.Set(vmSchemaNameLabel, vmRecord.NameLabel)
	if err != nil {
		return err
	}

	vmBaseTemplateName, ok := vmRecord.OtherConfig["base_template_name"]
	if ok {
		err = d.Set(vmSchemaBaseTemplateName, vmBaseTemplateName)
		if err != nil {
			return err
		}
	}

	err = d.Set(vmSchemaXenstoreData, vmRecord.XenstoreData)
	if err != nil {
		return err
	}

	return nil
}

func resourceVMUpdate(d *schema.ResourceData, m interface{}) error {
	c := m.(*Connection)

	xenVM, err := c.client.VM().GetByUUID(c.session, d.Id())
	if err != nil {
		if xenErr, ok := err.(*xenAPI.Error); ok {
			if xenErr.Code() == xenAPI.ERR_UUID_INVALID {
				d.SetId("")
				return nil
			}
		}

		return err
	}

	vmRecord, err := c.client.VM().GetRecord(c.session, xenVM)
	if err != nil {
		return err
	}

	d.Partial(true)

	dNameLabel := d.Get(vmSchemaNameLabel).(string)
	if vmRecord.NameLabel != dNameLabel {
		err := c.client.VM().SetNameLabel(c.session, xenVM, dNameLabel)
		if err != nil {
			return err
		}

		d.SetPartial(vmSchemaNameLabel)
	}

	dXenstoreDataRaw, ok := d.GetOk(vmSchemaXenstoreData)
	if ok {
		dXenstoreData := make(map[string]string)
		for key, value := range dXenstoreDataRaw.(map[string]interface{}) {
			dXenstoreData[key] = value.(string)
		}

		err = c.client.VM().SetXenstoreData(c.session, xenVM, dXenstoreData)
		if err != nil {
			return err
		}

		d.SetPartial(vmSchemaXenstoreData)
	}

	d.Partial(false)

	return resourceVMRead(d, m)
}

func resourceVMDelete(d *schema.ResourceData, m interface{}) error {
	c := m.(*Connection)

	xenVM, err := c.client.VM().GetByUUID(c.session, d.Id())
	if err != nil {
		if xenErr, ok := err.(*xenAPI.Error); ok {
			if xenErr.Code() == xenAPI.ERR_UUID_INVALID {
				d.SetId("")
				return nil
			}
		}

		return err
	}

	powerState, err := c.client.VM().GetPowerState(c.session, xenVM)
	if err != nil {
		return err
	}

	if powerState == xenAPI.VMPowerStateRunning {
		err = c.client.VM().HardShutdown(c.session, xenVM)
		if err != nil {
			return err
		}
	}

	err = c.client.VM().Destroy(c.session, xenVM)
	if err != nil {
		return err
	}

	d.SetId("")
	return nil
}

func resourceVMExists(d *schema.ResourceData, m interface{}) (bool, error) {
	c := m.(*Connection)

	_, err := c.client.VM().GetByUUID(c.session, d.Id())
	if err != nil {
		if xenErr, ok := err.(*xenAPI.Error); ok {
			if xenErr.Code() == xenAPI.ERR_UUID_INVALID {
				return false, nil
			}
		}

		return false, err
	}

	return true, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Davin Hills. All rights reserved.
// MIT license. License details can be found in the LICENSE file.

package goauto

import (
	"errors"
	"fmt"
	"os/exec"
)

// A RestartTask represents a task to launch or relaunch an executable file
type RestartTask struct {
	ecmd *exec.Cmd
	Cmd  string
	Args []string
}

// NewRestartTask returns a ReloadTask
func NewRestartTask(cmd string, args ...string) *RestartTask {
	return &RestartTask{Cmd: cmd, Args: args}
}

// Reload will launch or relaunch the application
func (r *RestartTask) Restart(t *TaskInfo) (err error) {
	if r.Cmd == "" {
		return errors.New("Cmd not set, Nothing to run")
	}

	err = r.Kill(t)
	if err != nil {
		return
	}

	r.ecmd = exec.Command(r.Cmd, r.Args...)
	r.ecmd.Stdout = t.Tout
	r.ecmd.Stderr = t.Terr

	err = r.ecmd.Start()
	go r.ecmd.Wait()
	if t.Verbose {
		fmt.Fprintf(t.Tout, "Process %v started\n", r.Cmd)
	}
	return
}

// Kill will stop the running task
func (r *RestartTask) Kill(t *TaskInfo) (err error) {
	defer func() { r.ecmd = nil }()
	if r.ecmd == nil || r.ecmd.Process == nil {
		return
	}
	if r.ecmd.ProcessState != nil && r.ecmd.ProcessState.Exited() {
		if t.Verbose {
			fmt.Fprintf(t.Tout, "Process %v already exited\n", r.Cmd)
		}
		return
	}

	if err = r.ecmd.Process.Kill(); err != nil {
		return
	}

	err = r.ecmd.Process.Release()
	if t.Verbose {
		fmt.Fprintf(t.Tout, "Process %v killed\n", r.Cmd)
	}
	return
}

// Run will restart the application in Cmd
func (r *RestartTask) Run(t *TaskInfo) (err error) {
	return r.Restart(t)
}
<commit_msg>Updated comment<commit_after>// Copyright 2015 Davin Hills. All rights reserved.
// MIT license. License details can be found in the LICENSE file.

package goauto

import (
	"errors"
	"fmt"
	"os/exec"
)

// A RestartTask represents a task to launch or relaunch an executable file
type RestartTask struct {
	ecmd *exec.Cmd
	Cmd  string
	Args []string
}

// NewRestartTask returns a ReloadTask
func NewRestartTask(cmd string, args ...string) *RestartTask {
	return &RestartTask{Cmd: cmd, Args: args}
}

// Restart will launch or relaunch the application
func (r *RestartTask) Restart(t *TaskInfo) (err error) {
	if r.Cmd == "" {
		return errors.New("Cmd not set, Nothing to run")
	}

	err = r.Kill(t)
	if err != nil {
		return
	}

	r.ecmd = exec.Command(r.Cmd, r.Args...)
	r.ecmd.Stdout = t.Tout
	r.ecmd.Stderr = t.Terr

	err = r.ecmd.Start()
	go r.ecmd.Wait()
	if t.Verbose {
		fmt.Fprintf(t.Tout, "Process %v started\n", r.Cmd)
	}
	return
}

// Kill will stop the running task
func (r *RestartTask) Kill(t *TaskInfo) (err error) {
	defer func() { r.ecmd = nil }()
	if r.ecmd == nil || r.ecmd.Process == nil {
		return
	}
	if r.ecmd.ProcessState != nil && r.ecmd.ProcessState.Exited() {
		if t.Verbose {
			fmt.Fprintf(t.Tout, "Process %v already exited\n", r.Cmd)
		}
		return
	}

	if err = r.ecmd.Process.Kill(); err != nil {
		return
	}

	err = r.ecmd.Process.Release()
	if t.Verbose {
		fmt.Fprintf(t.Tout, "Process %v killed\n", r.Cmd)
	}
	return
}

// Run will restart the application in Cmd
func (r *RestartTask) Run(t *TaskInfo) (err error) {
	return r.Restart(t)
}
<|endoftext|>


<commit_before>// Copyright 2016 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.

package grpc_retry

import (
	"context"
	"fmt"
	"io"
	"sync"
	"time"

	"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
	"golang.org/x/net/trace"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
)

const (
	AttemptMetadataKey = "x-retry-attempty"
)

// UnaryClientInterceptor returns a new retrying unary client interceptor.
//
// The default configuration of the interceptor is to not retry *at all*. This behaviour can be
// changed through options (e.g. WithMax) on creation of the interceptor or on call (through grpc.CallOptions).
func UnaryClientInterceptor(optFuncs ...CallOption) grpc.UnaryClientInterceptor {
	intOpts := reuseOrNewWithCallOptions(defaultOptions, optFuncs)
	return func(parentCtx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
		grpcOpts, retryOpts := filterCallOptions(opts)
		callOpts := reuseOrNewWithCallOptions(intOpts, retryOpts)
		// short circuit for simplicity, and avoiding allocations.
		if callOpts.max == 0 {
			return invoker(parentCtx, method, req, reply, cc, grpcOpts...)
		}
		var lastErr error
		for attempt := uint(0); attempt < callOpts.max; attempt++ {
			if err := waitRetryBackoff(attempt, parentCtx, callOpts); err != nil {
				return err
			}
			callCtx := perCallContext(parentCtx, callOpts, attempt)
			lastErr = invoker(callCtx, method, req, reply, cc, grpcOpts...)
			// TODO(mwitkow): Maybe dial and transport errors should be retriable?
			if lastErr == nil {
				return nil
			}
			logTrace(parentCtx, "grpc_retry attempt: %d, got err: %v", attempt, lastErr)
			if isContextError(lastErr) {
				if parentCtx.Err() != nil {
					logTrace(parentCtx, "grpc_retry attempt: %d, parent context error: %v", attempt, parentCtx.Err())
					// its the parent context deadline or cancellation.
					return lastErr
				} else if callOpts.perCallTimeout != 0 {
					// We have set a perCallTimeout in the retry middleware, which would result in a context error if
					// the deadline was exceeded, in which case try again.
					logTrace(parentCtx, "grpc_retry attempt: %d, context error from retry call", attempt)
					continue
				}
			}
			if !isRetriable(lastErr, callOpts) {
				return lastErr
			}
		}
		return lastErr
	}
}

// StreamClientInterceptor returns a new retrying stream client interceptor for server side streaming calls.
//
// The default configuration of the interceptor is to not retry *at all*. This behaviour can be
// changed through options (e.g. WithMax) on creation of the interceptor or on call (through grpc.CallOptions).
//
// Retry logic is available *only for ServerStreams*, i.e. 1:n streams, as the internal logic needs
// to buffer the messages sent by the client. If retry is enabled on any other streams (ClientStreams,
// BidiStreams), the retry interceptor will fail the call.
func StreamClientInterceptor(optFuncs ...CallOption) grpc.StreamClientInterceptor {
	intOpts := reuseOrNewWithCallOptions(defaultOptions, optFuncs)
	return func(parentCtx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
		grpcOpts, retryOpts := filterCallOptions(opts)
		callOpts := reuseOrNewWithCallOptions(intOpts, retryOpts)
		// short circuit for simplicity, and avoiding allocations.
		if callOpts.max == 0 {
			return streamer(parentCtx, desc, cc, method, grpcOpts...)
		}
		if desc.ClientStreams {
			return nil, status.Errorf(codes.Unimplemented, "grpc_retry: cannot retry on ClientStreams, set grpc_retry.Disable()")
		}

		var lastErr error
		for attempt := uint(0); attempt < callOpts.max; attempt++ {
			if err := waitRetryBackoff(attempt, parentCtx, callOpts); err != nil {
				return nil, err
			}
			callCtx := perCallContext(parentCtx, callOpts, 0)

			var newStreamer grpc.ClientStream
			newStreamer, lastErr = streamer(callCtx, desc, cc, method, grpcOpts...)
			if lastErr == nil {
				retryingStreamer := &serverStreamingRetryingStream{
					ClientStream: newStreamer,
					callOpts:     callOpts,
					parentCtx:    parentCtx,
					streamerCall: func(ctx context.Context) (grpc.ClientStream, error) {
						return streamer(ctx, desc, cc, method, grpcOpts...)
					},
				}
				return retryingStreamer, nil
			}

			logTrace(parentCtx, "grpc_retry attempt: %d, got err: %v", attempt, lastErr)
			if isContextError(lastErr) {
				if parentCtx.Err() != nil {
					logTrace(parentCtx, "grpc_retry attempt: %d, parent context error: %v", attempt, parentCtx.Err())
					// its the parent context deadline or cancellation.
					return nil, lastErr
				} else if callOpts.perCallTimeout != 0 {
					// We have set a perCallTimeout in the retry middleware, which would result in a context error if
					// the deadline was exceeded, in which case try again.
					logTrace(parentCtx, "grpc_retry attempt: %d, context error from retry call", attempt)
					continue
				}
			}
			if !isRetriable(lastErr, callOpts) {
				return nil, lastErr
			}
		}
		return nil, lastErr
	}
}

// type serverStreamingRetryingStream is the implementation of grpc.ClientStream that acts as a
// proxy to the underlying call. If any of the RecvMsg() calls fail, it will try to reestablish
// a new ClientStream according to the retry policy.
type serverStreamingRetryingStream struct {
	grpc.ClientStream
	bufferedSends []interface{} // single message that the client can sen
	receivedGood  bool          // indicates whether any prior receives were successful
	wasClosedSend bool          // indicates that CloseSend was closed
	parentCtx     context.Context
	callOpts      *options
	streamerCall  func(ctx context.Context) (grpc.ClientStream, error)
	mu            sync.RWMutex
}

func (s *serverStreamingRetryingStream) setStream(clientStream grpc.ClientStream) {
	s.mu.Lock()
	s.ClientStream = clientStream
	s.mu.Unlock()
}

func (s *serverStreamingRetryingStream) getStream() grpc.ClientStream {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.ClientStream
}

func (s *serverStreamingRetryingStream) SendMsg(m interface{}) error {
	s.mu.Lock()
	s.bufferedSends = append(s.bufferedSends, m)
	s.mu.Unlock()
	return s.getStream().SendMsg(m)
}

func (s *serverStreamingRetryingStream) CloseSend() error {
	s.mu.Lock()
	s.wasClosedSend = true
	s.mu.Unlock()
	return s.getStream().CloseSend()
}

func (s *serverStreamingRetryingStream) Header() (metadata.MD, error) {
	return s.getStream().Header()
}

func (s *serverStreamingRetryingStream) Trailer() metadata.MD {
	return s.getStream().Trailer()
}

func (s *serverStreamingRetryingStream) RecvMsg(m interface{}) error {
	attemptRetry, lastErr := s.receiveMsgAndIndicateRetry(m)
	if !attemptRetry {
		return lastErr // success or hard failure
	}
	// We start off from attempt 1, because zeroth was already made on normal SendMsg().
	for attempt := uint(1); attempt < s.callOpts.max; attempt++ {
		if err := waitRetryBackoff(attempt, s.parentCtx, s.callOpts); err != nil {
			return err
		}
		callCtx := perCallContext(s.parentCtx, s.callOpts, attempt)
		newStream, err := s.reestablishStreamAndResendBuffer(callCtx)
		if err != nil {
			// Retry dial and transport errors of establishing stream as grpc doesn't retry.
			if isRetriable(err, s.callOpts) {
				continue
			}
			return err
		}

		s.setStream(newStream)
		attemptRetry, lastErr = s.receiveMsgAndIndicateRetry(m)
		//fmt.Printf("Received message and indicate: %v  %v\n", attemptRetry, lastErr)
		if !attemptRetry {
			return lastErr
		}
	}
	return lastErr
}

func (s *serverStreamingRetryingStream) receiveMsgAndIndicateRetry(m interface{}) (bool, error) {
	s.mu.RLock()
	wasGood := s.receivedGood
	s.mu.RUnlock()
	err := s.getStream().RecvMsg(m)
	if err == nil || err == io.EOF {
		s.mu.Lock()
		s.receivedGood = true
		s.mu.Unlock()
		return false, err
	} else if wasGood {
		// previous RecvMsg in the stream succeeded, no retry logic should interfere
		return false, err
	}
	if isContextError(err) {
		if s.parentCtx.Err() != nil {
			logTrace(s.parentCtx, "grpc_retry parent context error: %v", s.parentCtx.Err())
			return false, err
		} else if s.callOpts.perCallTimeout != 0 {
			// We have set a perCallTimeout in the retry middleware, which would result in a context error if
			// the deadline was exceeded, in which case try again.
			logTrace(s.parentCtx, "grpc_retry context error from retry call")
			return true, err
		}
	}
	return isRetriable(err, s.callOpts), err
}

func (s *serverStreamingRetryingStream) reestablishStreamAndResendBuffer(
	callCtx context.Context,
) (grpc.ClientStream, error) {
	s.mu.RLock()
	bufferedSends := s.bufferedSends
	s.mu.RUnlock()
	newStream, err := s.streamerCall(callCtx)
	if err != nil {
		logTrace(callCtx, "grpc_retry failed redialing new stream: %v", err)
		return nil, err
	}
	for _, msg := range bufferedSends {
		if err := newStream.SendMsg(msg); err != nil {
			logTrace(callCtx, "grpc_retry failed resending message: %v", err)
			return nil, err
		}
	}
	if err := newStream.CloseSend(); err != nil {
		logTrace(callCtx, "grpc_retry failed CloseSend on new stream %v", err)
		return nil, err
	}
	return newStream, nil
}

func waitRetryBackoff(attempt uint, parentCtx context.Context, callOpts *options) error {
	var waitTime time.Duration = 0
	if attempt > 0 {
		waitTime = callOpts.backoffFunc(parentCtx, attempt)
	}
	if waitTime > 0 {
		logTrace(parentCtx, "grpc_retry attempt: %d, backoff for %v", attempt, waitTime)
		timer := time.NewTimer(waitTime)
		select {
		case <-parentCtx.Done():
			timer.Stop()
			return contextErrToGrpcErr(parentCtx.Err())
		case <-timer.C:
		}
	}
	return nil
}

func isRetriable(err error, callOpts *options) bool {
	errCode := status.Code(err)
	if isContextError(err) {
		// context errors are not retriable based on user settings.
		return false
	}
	for _, code := range callOpts.codes {
		if code == errCode {
			return true
		}
	}
	return false
}

func isContextError(err error) bool {
	code := status.Code(err)
	return code == codes.DeadlineExceeded || code == codes.Canceled
}

func perCallContext(parentCtx context.Context, callOpts *options, attempt uint) context.Context {
	ctx := parentCtx
	if callOpts.perCallTimeout != 0 {
		ctx, _ = context.WithTimeout(ctx, callOpts.perCallTimeout)
	}
	if attempt > 0 && callOpts.includeHeader {
		mdClone := metautils.ExtractOutgoing(ctx).Clone().Set(AttemptMetadataKey, fmt.Sprintf("%d", attempt))
		ctx = mdClone.ToOutgoing(ctx)
	}
	return ctx
}

func contextErrToGrpcErr(err error) error {
	switch err {
	case context.DeadlineExceeded:
		return status.Error(codes.DeadlineExceeded, err.Error())
	case context.Canceled:
		return status.Error(codes.Canceled, err.Error())
	default:
		return status.Error(codes.Unknown, err.Error())
	}
}

func logTrace(ctx context.Context, format string, a ...interface{}) {
	tr, ok := trace.FromContext(ctx)
	if !ok {
		return
	}
	tr.LazyPrintf(format, a...)
}
<commit_msg>Do not stop retrying based on earlier good message from the stream (#313)<commit_after>// Copyright 2016 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.

package grpc_retry

import (
	"context"
	"fmt"
	"io"
	"sync"
	"time"

	"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
	"golang.org/x/net/trace"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
)

const (
	AttemptMetadataKey = "x-retry-attempty"
)

// UnaryClientInterceptor returns a new retrying unary client interceptor.
//
// The default configuration of the interceptor is to not retry *at all*. This behaviour can be
// changed through options (e.g. WithMax) on creation of the interceptor or on call (through grpc.CallOptions).
func UnaryClientInterceptor(optFuncs ...CallOption) grpc.UnaryClientInterceptor {
	intOpts := reuseOrNewWithCallOptions(defaultOptions, optFuncs)
	return func(parentCtx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
		grpcOpts, retryOpts := filterCallOptions(opts)
		callOpts := reuseOrNewWithCallOptions(intOpts, retryOpts)
		// short circuit for simplicity, and avoiding allocations.
		if callOpts.max == 0 {
			return invoker(parentCtx, method, req, reply, cc, grpcOpts...)
		}
		var lastErr error
		for attempt := uint(0); attempt < callOpts.max; attempt++ {
			if err := waitRetryBackoff(attempt, parentCtx, callOpts); err != nil {
				return err
			}
			callCtx := perCallContext(parentCtx, callOpts, attempt)
			lastErr = invoker(callCtx, method, req, reply, cc, grpcOpts...)
			// TODO(mwitkow): Maybe dial and transport errors should be retriable?
			if lastErr == nil {
				return nil
			}
			logTrace(parentCtx, "grpc_retry attempt: %d, got err: %v", attempt, lastErr)
			if isContextError(lastErr) {
				if parentCtx.Err() != nil {
					logTrace(parentCtx, "grpc_retry attempt: %d, parent context error: %v", attempt, parentCtx.Err())
					// its the parent context deadline or cancellation.
					return lastErr
				} else if callOpts.perCallTimeout != 0 {
					// We have set a perCallTimeout in the retry middleware, which would result in a context error if
					// the deadline was exceeded, in which case try again.
					logTrace(parentCtx, "grpc_retry attempt: %d, context error from retry call", attempt)
					continue
				}
			}
			if !isRetriable(lastErr, callOpts) {
				return lastErr
			}
		}
		return lastErr
	}
}

// StreamClientInterceptor returns a new retrying stream client interceptor for server side streaming calls.
//
// The default configuration of the interceptor is to not retry *at all*. This behaviour can be
// changed through options (e.g. WithMax) on creation of the interceptor or on call (through grpc.CallOptions).
//
// Retry logic is available *only for ServerStreams*, i.e. 1:n streams, as the internal logic needs
// to buffer the messages sent by the client. If retry is enabled on any other streams (ClientStreams,
// BidiStreams), the retry interceptor will fail the call.
func StreamClientInterceptor(optFuncs ...CallOption) grpc.StreamClientInterceptor {
	intOpts := reuseOrNewWithCallOptions(defaultOptions, optFuncs)
	return func(parentCtx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
		grpcOpts, retryOpts := filterCallOptions(opts)
		callOpts := reuseOrNewWithCallOptions(intOpts, retryOpts)
		// short circuit for simplicity, and avoiding allocations.
		if callOpts.max == 0 {
			return streamer(parentCtx, desc, cc, method, grpcOpts...)
		}
		if desc.ClientStreams {
			return nil, status.Errorf(codes.Unimplemented, "grpc_retry: cannot retry on ClientStreams, set grpc_retry.Disable()")
		}

		var lastErr error
		for attempt := uint(0); attempt < callOpts.max; attempt++ {
			if err := waitRetryBackoff(attempt, parentCtx, callOpts); err != nil {
				return nil, err
			}
			callCtx := perCallContext(parentCtx, callOpts, 0)

			var newStreamer grpc.ClientStream
			newStreamer, lastErr = streamer(callCtx, desc, cc, method, grpcOpts...)
			if lastErr == nil {
				retryingStreamer := &serverStreamingRetryingStream{
					ClientStream: newStreamer,
					callOpts:     callOpts,
					parentCtx:    parentCtx,
					streamerCall: func(ctx context.Context) (grpc.ClientStream, error) {
						return streamer(ctx, desc, cc, method, grpcOpts...)
					},
				}
				return retryingStreamer, nil
			}

			logTrace(parentCtx, "grpc_retry attempt: %d, got err: %v", attempt, lastErr)
			if isContextError(lastErr) {
				if parentCtx.Err() != nil {
					logTrace(parentCtx, "grpc_retry attempt: %d, parent context error: %v", attempt, parentCtx.Err())
					// its the parent context deadline or cancellation.
					return nil, lastErr
				} else if callOpts.perCallTimeout != 0 {
					// We have set a perCallTimeout in the retry middleware, which would result in a context error if
					// the deadline was exceeded, in which case try again.
					logTrace(parentCtx, "grpc_retry attempt: %d, context error from retry call", attempt)
					continue
				}
			}
			if !isRetriable(lastErr, callOpts) {
				return nil, lastErr
			}
		}
		return nil, lastErr
	}
}

// type serverStreamingRetryingStream is the implementation of grpc.ClientStream that acts as a
// proxy to the underlying call. If any of the RecvMsg() calls fail, it will try to reestablish
// a new ClientStream according to the retry policy.
type serverStreamingRetryingStream struct {
	grpc.ClientStream
	bufferedSends []interface{} // single message that the client can sen
	wasClosedSend bool          // indicates that CloseSend was closed
	parentCtx     context.Context
	callOpts      *options
	streamerCall  func(ctx context.Context) (grpc.ClientStream, error)
	mu            sync.RWMutex
}

func (s *serverStreamingRetryingStream) setStream(clientStream grpc.ClientStream) {
	s.mu.Lock()
	s.ClientStream = clientStream
	s.mu.Unlock()
}

func (s *serverStreamingRetryingStream) getStream() grpc.ClientStream {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.ClientStream
}

func (s *serverStreamingRetryingStream) SendMsg(m interface{}) error {
	s.mu.Lock()
	s.bufferedSends = append(s.bufferedSends, m)
	s.mu.Unlock()
	return s.getStream().SendMsg(m)
}

func (s *serverStreamingRetryingStream) CloseSend() error {
	s.mu.Lock()
	s.wasClosedSend = true
	s.mu.Unlock()
	return s.getStream().CloseSend()
}

func (s *serverStreamingRetryingStream) Header() (metadata.MD, error) {
	return s.getStream().Header()
}

func (s *serverStreamingRetryingStream) Trailer() metadata.MD {
	return s.getStream().Trailer()
}

func (s *serverStreamingRetryingStream) RecvMsg(m interface{}) error {
	attemptRetry, lastErr := s.receiveMsgAndIndicateRetry(m)
	if !attemptRetry {
		return lastErr // success or hard failure
	}
	// We start off from attempt 1, because zeroth was already made on normal SendMsg().
	for attempt := uint(1); attempt < s.callOpts.max; attempt++ {
		if err := waitRetryBackoff(attempt, s.parentCtx, s.callOpts); err != nil {
			return err
		}
		callCtx := perCallContext(s.parentCtx, s.callOpts, attempt)
		newStream, err := s.reestablishStreamAndResendBuffer(callCtx)
		if err != nil {
			// Retry dial and transport errors of establishing stream as grpc doesn't retry.
			if isRetriable(err, s.callOpts) {
				continue
			}
			return err
		}

		s.setStream(newStream)
		attemptRetry, lastErr = s.receiveMsgAndIndicateRetry(m)
		//fmt.Printf("Received message and indicate: %v  %v\n", attemptRetry, lastErr)
		if !attemptRetry {
			return lastErr
		}
	}
	return lastErr
}

func (s *serverStreamingRetryingStream) receiveMsgAndIndicateRetry(m interface{}) (bool, error) {
	err := s.getStream().RecvMsg(m)
	if err == nil || err == io.EOF {
		return false, err
	}
	if isContextError(err) {
		if s.parentCtx.Err() != nil {
			logTrace(s.parentCtx, "grpc_retry parent context error: %v", s.parentCtx.Err())
			return false, err
		} else if s.callOpts.perCallTimeout != 0 {
			// We have set a perCallTimeout in the retry middleware, which would result in a context error if
			// the deadline was exceeded, in which case try again.
			logTrace(s.parentCtx, "grpc_retry context error from retry call")
			return true, err
		}
	}
	return isRetriable(err, s.callOpts), err
}

func (s *serverStreamingRetryingStream) reestablishStreamAndResendBuffer(
	callCtx context.Context,
) (grpc.ClientStream, error) {
	s.mu.RLock()
	bufferedSends := s.bufferedSends
	s.mu.RUnlock()
	newStream, err := s.streamerCall(callCtx)
	if err != nil {
		logTrace(callCtx, "grpc_retry failed redialing new stream: %v", err)
		return nil, err
	}
	for _, msg := range bufferedSends {
		if err := newStream.SendMsg(msg); err != nil {
			logTrace(callCtx, "grpc_retry failed resending message: %v", err)
			return nil, err
		}
	}
	if err := newStream.CloseSend(); err != nil {
		logTrace(callCtx, "grpc_retry failed CloseSend on new stream %v", err)
		return nil, err
	}
	return newStream, nil
}

func waitRetryBackoff(attempt uint, parentCtx context.Context, callOpts *options) error {
	var waitTime time.Duration = 0
	if attempt > 0 {
		waitTime = callOpts.backoffFunc(parentCtx, attempt)
	}
	if waitTime > 0 {
		logTrace(parentCtx, "grpc_retry attempt: %d, backoff for %v", attempt, waitTime)
		timer := time.NewTimer(waitTime)
		select {
		case <-parentCtx.Done():
			timer.Stop()
			return contextErrToGrpcErr(parentCtx.Err())
		case <-timer.C:
		}
	}
	return nil
}

func isRetriable(err error, callOpts *options) bool {
	errCode := status.Code(err)
	if isContextError(err) {
		// context errors are not retriable based on user settings.
		return false
	}
	for _, code := range callOpts.codes {
		if code == errCode {
			return true
		}
	}
	return false
}

func isContextError(err error) bool {
	code := status.Code(err)
	return code == codes.DeadlineExceeded || code == codes.Canceled
}

func perCallContext(parentCtx context.Context, callOpts *options, attempt uint) context.Context {
	ctx := parentCtx
	if callOpts.perCallTimeout != 0 {
		ctx, _ = context.WithTimeout(ctx, callOpts.perCallTimeout)
	}
	if attempt > 0 && callOpts.includeHeader {
		mdClone := metautils.ExtractOutgoing(ctx).Clone().Set(AttemptMetadataKey, fmt.Sprintf("%d", attempt))
		ctx = mdClone.ToOutgoing(ctx)
	}
	return ctx
}

func contextErrToGrpcErr(err error) error {
	switch err {
	case context.DeadlineExceeded:
		return status.Error(codes.DeadlineExceeded, err.Error())
	case context.Canceled:
		return status.Error(codes.Canceled, err.Error())
	default:
		return status.Error(codes.Unknown, err.Error())
	}
}

func logTrace(ctx context.Context, format string, a ...interface{}) {
	tr, ok := trace.FromContext(ctx)
	if !ok {
		return
	}
	tr.LazyPrintf(format, a...)
}
<|endoftext|>


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

package main

import (
	"fmt"

	"github.com/coreos/rocket/version"
)

var cmdVersion = &Command{
	Name:        "version",
	Description: "Print the version and exit",
	Summary:     "Print the version and exit",
	Run:         runVersion,
}

func init() {
	commands = append(commands, cmdVersion)
}

func runVersion(args []string) (exit int) {
	fmt.Printf("rkt version %s\n", version.Version)
	return
}
<commit_msg>rkt: add appc spec version information<commit_after>// Copyright 2014 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"

	"github.com/appc/spec/schema"
	"github.com/coreos/rocket/version"
)

var cmdVersion = &Command{
	Name:        "version",
	Description: "Print the version and exit",
	Summary:     "Print the version and exit",
	Run:         runVersion,
}

func init() {
	commands = append(commands, cmdVersion)
}

func runVersion(args []string) (exit int) {
	fmt.Printf("rkt version %s\n", version.Version)
	fmt.Printf("appc version %s\n", schema.AppContainerVersion)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"path/filepath"
	"strings"

	"github.com/jmartin82/mmock/console"
	"github.com/jmartin82/mmock/definition"
	"github.com/jmartin82/mmock/match"
	"github.com/jmartin82/mmock/route"
	"github.com/jmartin82/mmock/scenario"
	"github.com/jmartin82/mmock/server"
	"github.com/jmartin82/mmock/translate"
	"github.com/jmartin82/mmock/vars"
	"github.com/jmartin82/mmock/vars/fakedata"
)

//ErrNotFoundDefaultPath if we can't resolve the current path
var ErrNotFoundDefaultPath = errors.New("We can't determinate the current path")

//ErrNotFoundAnyMock when we don't found any valid mock definition to load
var ErrNotFoundAnyMock = errors.New("No valid mock definition found")

func banner() {
	fmt.Println("MMock v 2.0.1")
	fmt.Println("")

	fmt.Print(
		`		.---. .---.
               :     : o   :    me want request!
           _..-:   o :     :-.._    /
       .-''  '  ` + "`" + `---' ` + "`" + `---' "   ` + "`" + `` + "`" + `-.
     .'   "   '  "  .    "  . '  "  ` + "`" + `.
    :   '.---.,,.,...,.,.,.,..---.  ' ;
    ` + "`" + `. " ` + "`" + `.                     .' " .'
     ` + "`" + `.  '` + "`" + `.                   .' ' .'
      ` + "`" + `.    ` + "`" + `-._           _.-' "  .'  .----.
        ` + "`" + `. "    '"--...--"'  . ' .'  .'  o   ` + "`" + `.
        .'` + "`" + `-._'    " .     " _.-'` + "`" + `. :       o  :
      .'      ` + "`" + `` + "`" + `` + "`" + `--.....--'''    ' ` + "`" + `:_ o       :
    .'    "     '         "     "   ; ` + "`" + `.;";";";'
   ;         '       "       '     . ; .' ; ; ;
  ;     '         '       '   "    .'      .-'
  '  "     "   '      "           "    _.-'
 `)
	fmt.Println("")
}

// Get preferred outbound ip of this machine
func getOutboundIP() string {
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		return "127.0.0.1"
	}
	defer conn.Close()

	log.Println("Getting external IP")
	localAddr := conn.LocalAddr().String()
	idx := strings.LastIndex(localAddr, ":")

	return localAddr[0:idx]
}

func getRouter(mocks []definition.Mock, scenario scenario.ScenarioManager, dUpdates chan []definition.Mock) *route.RequestRouter {
	log.Printf("Loding router with %d definitions\n", len(mocks))
	router := route.NewRouter(mocks, match.MockMatch{Scenario: scenario}, dUpdates)
	router.MockChangeWatch()
	return router
}

func getVarsProcessor() vars.VarsProcessor {

	return vars.VarsProcessor{FillerFactory: vars.MockFillerFactory{FakeAdapter: fakedata.FakeAdapter{}}}
}

func startServer(ip string, port int, done chan bool, router route.Router, mLog chan definition.Match, scenario scenario.ScenarioManager, varsProcessor vars.VarsProcessor) {
	dispatcher := server.Dispatcher{IP: ip,
		Port:          port,
		Router:        router,
		Translator:    translate.HTTPTranslator{},
		VarsProcessor: varsProcessor,
		Scenario:      scenario,
		Mlog:          mLog,
	}
	dispatcher.Start()
	done <- true
}
func startConsole(ip string, port int, done chan bool, mLog chan definition.Match) {
	dispatcher := console.Dispatcher{IP: ip, Port: port, Mlog: mLog}
	dispatcher.Start()
	done <- true
}

func getMocks(path string, updateCh chan []definition.Mock) []definition.Mock {
	log.Printf("Reading Mock definition from: %s\n", path)

	definitionReader := definition.NewFileDefinition(path, updateCh)

	definitionReader.AddConfigReader(definition.JSONReader{})
	definitionReader.AddConfigReader(definition.YAMLReader{})

	mocks := definitionReader.ReadMocksDefinition()
	if len(mocks) == 0 {
		log.Fatalln(ErrNotFoundAnyMock.Error())
	}
	definitionReader.WatchDir()
	return mocks
}

func main() {
	banner()
	outIP := getOutboundIP()
	path, err := filepath.Abs("./config")
	if err != nil {
		panic(ErrNotFoundDefaultPath)
	}

	sIP := flag.String("server-ip", outIP, "Mock server IP")
	sPort := flag.Int("server-port", 8083, "Mock Server Port")
	cIP := flag.String("console-ip", outIP, "Console Server IP")
	cPort := flag.Int("cconsole-port", 8082, "Console server Port")
	console := flag.Bool("console", true, "Console enabled  (true/false)")
	cPath := flag.String("config-path", path, "Mocks definition folder")

	flag.Parse()
	path, _ = filepath.Abs(*cPath)

	//chanels
	mLog := make(chan definition.Match)
	dUpdates := make(chan []definition.Mock)
	done := make(chan bool)

	scenario := scenario.NewInMemmoryScenarion()
	mocks := getMocks(path, dUpdates)
	router := getRouter(mocks, scenario, dUpdates)
	varsProcessor := getVarsProcessor()

	go startServer(*sIP, *sPort, done, router, mLog, scenario, varsProcessor)
	log.Printf("HTTP Server running at %s:%d\n", *sIP, *sPort)
	if *console {
		go startConsole(*cIP, *cPort, done, mLog)
		log.Printf("Console running at %s:%d\n", *cIP, *cPort)
	}

	<-done

}
<commit_msg>Fixed some typos (#21)<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"path/filepath"
	"strings"

	"github.com/jmartin82/mmock/console"
	"github.com/jmartin82/mmock/definition"
	"github.com/jmartin82/mmock/match"
	"github.com/jmartin82/mmock/route"
	"github.com/jmartin82/mmock/scenario"
	"github.com/jmartin82/mmock/server"
	"github.com/jmartin82/mmock/translate"
	"github.com/jmartin82/mmock/vars"
	"github.com/jmartin82/mmock/vars/fakedata"
)

//ErrNotFoundDefaultPath if we can't resolve the current path
var ErrNotFoundDefaultPath = errors.New("We can't determinate the current path")

//ErrNotFoundAnyMock when we don't found any valid mock definition to load
var ErrNotFoundAnyMock = errors.New("No valid mock definition found")

func banner() {
	fmt.Println("MMock v 2.0.1")
	fmt.Println("")

	fmt.Print(
		`		.---. .---.
               :     : o   :    me want request!
           _..-:   o :     :-.._    /
       .-''  '  ` + "`" + `---' ` + "`" + `---' "   ` + "`" + `` + "`" + `-.
     .'   "   '  "  .    "  . '  "  ` + "`" + `.
    :   '.---.,,.,...,.,.,.,..---.  ' ;
    ` + "`" + `. " ` + "`" + `.                     .' " .'
     ` + "`" + `.  '` + "`" + `.                   .' ' .'
      ` + "`" + `.    ` + "`" + `-._           _.-' "  .'  .----.
        ` + "`" + `. "    '"--...--"'  . ' .'  .'  o   ` + "`" + `.
        .'` + "`" + `-._'    " .     " _.-'` + "`" + `. :       o  :
      .'      ` + "`" + `` + "`" + `` + "`" + `--.....--'''    ' ` + "`" + `:_ o       :
    .'    "     '         "     "   ; ` + "`" + `.;";";";'
   ;         '       "       '     . ; .' ; ; ;
  ;     '         '       '   "    .'      .-'
  '  "     "   '      "           "    _.-'
 `)
	fmt.Println("")
}

// Get preferred outbound ip of this machine
func getOutboundIP() string {
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		return "127.0.0.1"
	}
	defer conn.Close()

	log.Println("Getting external IP")
	localAddr := conn.LocalAddr().String()
	idx := strings.LastIndex(localAddr, ":")

	return localAddr[0:idx]
}

func getRouter(mocks []definition.Mock, scenario scenario.ScenarioManager, dUpdates chan []definition.Mock) *route.RequestRouter {
	log.Printf("Loding router with %d definitions\n", len(mocks))
	router := route.NewRouter(mocks, match.MockMatch{Scenario: scenario}, dUpdates)
	router.MockChangeWatch()
	return router
}

func getVarsProcessor() vars.VarsProcessor {

	return vars.VarsProcessor{FillerFactory: vars.MockFillerFactory{FakeAdapter: fakedata.FakeAdapter{}}}
}

func startServer(ip string, port int, done chan bool, router route.Router, mLog chan definition.Match, scenario scenario.ScenarioManager, varsProcessor vars.VarsProcessor) {
	dispatcher := server.Dispatcher{IP: ip,
		Port:          port,
		Router:        router,
		Translator:    translate.HTTPTranslator{},
		VarsProcessor: varsProcessor,
		Scenario:      scenario,
		Mlog:          mLog,
	}
	dispatcher.Start()
	done <- true
}
func startConsole(ip string, port int, done chan bool, mLog chan definition.Match) {
	dispatcher := console.Dispatcher{IP: ip, Port: port, Mlog: mLog}
	dispatcher.Start()
	done <- true
}

func getMocks(path string, updateCh chan []definition.Mock) []definition.Mock {
	log.Printf("Reading Mock definition from: %s\n", path)

	definitionReader := definition.NewFileDefinition(path, updateCh)

	definitionReader.AddConfigReader(definition.JSONReader{})
	definitionReader.AddConfigReader(definition.YAMLReader{})

	mocks := definitionReader.ReadMocksDefinition()
	if len(mocks) == 0 {
		log.Fatalln(ErrNotFoundAnyMock.Error())
	}
	definitionReader.WatchDir()
	return mocks
}

func main() {
	banner()
	outIP := getOutboundIP()
	path, err := filepath.Abs("./config")
	if err != nil {
		panic(ErrNotFoundDefaultPath)
	}

	sIP := flag.String("server-ip", outIP, "Mock server IP")
	sPort := flag.Int("server-port", 8083, "Mock server Port")
	cIP := flag.String("console-ip", outIP, "Console server IP")
	cPort := flag.Int("console-port", 8082, "Console server Port")
	console := flag.Bool("console", true, "Console enabled  (true/false)")
	cPath := flag.String("config-path", path, "Mocks definition folder")

	flag.Parse()
	path, _ = filepath.Abs(*cPath)

	//chanels
	mLog := make(chan definition.Match)
	dUpdates := make(chan []definition.Mock)
	done := make(chan bool)

	scenario := scenario.NewInMemmoryScenarion()
	mocks := getMocks(path, dUpdates)
	router := getRouter(mocks, scenario, dUpdates)
	varsProcessor := getVarsProcessor()

	go startServer(*sIP, *sPort, done, router, mLog, scenario, varsProcessor)
	log.Printf("HTTP Server running at %s:%d\n", *sIP, *sPort)
	if *console {
		go startConsole(*cIP, *cPort, done, mLog)
		log.Printf("Console running at %s:%d\n", *cIP, *cPort)
	}

	<-done

}
<|endoftext|>


<commit_before>package main

import (
	goconf "goconf.googlecode.com/hg"
	"strconv"
	"log"
)

type Model struct {
	cmdchan       <-chan TwitterCommand
	newtweetchan  chan<- []*Tweet
	newtweets_int chan []*Tweet
	users         []UserTwitterAPITuple
	cur_user      uint
	tweets        []*Tweet
	tweet_map     map[int64]*Tweet
	lookupchan    chan TweetRequest
	uiactionchan  chan UserInterfaceAction
	last_id       int64
}

type TweetRequest struct {
	Status_id int64
	Reply     chan *Tweet
}

type CmdId int

const (
	UPDATE CmdId = iota
	RETWEET
	DELETE
	FAVORITE
	FOLLOW
	UNFOLLOW
	SET_CURUSER
)

type TwitterCommand struct {
	Cmd CmdId
	Data Tweet
	Pos uint // for SET_CURUSER
}

func NewModel(users []UserTwitterAPITuple, cc chan TwitterCommand, ntc chan<- []*Tweet, lc chan TweetRequest, uac chan UserInterfaceAction, cfg *goconf.ConfigFile) *Model {
	model := &Model{
		cmdchan:       cc,
		newtweetchan:  ntc,
		newtweets_int: make(chan []*Tweet, 10),
		users:         users,
		cur_user:      0,
		lookupchan:    lc,
		tweet_map:     map[int64]*Tweet{},
		uiactionchan:  uac,
	}

	if cfg != nil {
		if default_user, err := cfg.GetString("default", "default_user"); err == nil {
			for idx, _ := range model.users {
				if model.users[idx].User == default_user {
					model.cur_user = uint(idx)
					break
				}
			}
		}
	}

	userlist := []string{ strconv.Uitoa(model.cur_user) }
	for _, u := range model.users {
		userlist = append(userlist, u.User)
	}
	model.uiactionchan <- UserInterfaceAction{SET_USERLIST, userlist}

	return model
}

func (m *Model) Run() {
	m.last_id = int64(0)

	new_tweets := make(chan []*Tweet, 10)

	// pre-fill with 50 latest items from home timeline
	// TODO: move this to StartUserStreams, including merge, sort and deduplication
	/*
	if home_tl, err := m.users[m.cur_user].Tapi.HomeTimeline(50, 0); err == nil {
		if len(home_tl.Tweets) > 0 {
			new_tweets <-home_tl.Tweets
		}
	}
	*/

	// then start userstream
	StartUserStreams(m.users, new_tweets, m.uiactionchan)

	for {
		select {
		case cmd := <-m.cmdchan:
			m.HandleCommand(cmd)
		case req := <-m.lookupchan:
			tweet := m.tweet_map[req.Status_id]
			req.Reply <- tweet
			close(req.Reply)
		case tweets := <-m.newtweets_int:
			for _, t := range tweets {
				m.tweet_map[*t.Id] = t
			}
			m.tweets = append(tweets, m.tweets...)
		case tweets := <-new_tweets:
			log.Printf("received %d tweets", len(tweets))
			unique_tweets := []*Tweet{}
			for _, t := range tweets {
				if _, contained := m.tweet_map[*t.Id]; !contained {
					m.tweet_map[*t.Id] = t
					unique_tweets = append(unique_tweets, t)
				}
				m.tweets = append(unique_tweets, m.tweets...)
			}
			m.newtweetchan <- unique_tweets
		}
	}
}

func (m *Model) HandleCommand(cmd TwitterCommand) {
	switch cmd.Cmd {
	case UPDATE:
		go func(cur_user uint) {
			if newtweet, err := m.users[cur_user].Tapi.Update(cmd.Data); err == nil {
				m.newtweets_int <- []*Tweet{newtweet}
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Posting tweet failed: " + err.String()}}
			}
		}(m.cur_user)
	case RETWEET:
		go func(cur_user uint) {
			if newtweet, err := m.users[cur_user].Tapi.Retweet(cmd.Data); err == nil {
				m.newtweets_int <- []*Tweet{newtweet}
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Retweeting failed:" + err.String()}}
			}
		}(m.cur_user)
	case FAVORITE:
		go func(cur_user uint) {
			if err := m.users[cur_user].Tapi.Favorite(cmd.Data); err == nil {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Favoriting tweet failed: " + err.String()}}
			}
		}(m.cur_user)
	case FOLLOW:
		go func(cur_user uint) {
			if err := m.users[cur_user].Tapi.Follow(*cmd.Data.User.Screen_name); err == nil {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Following " + *cmd.Data.User.Screen_name + " failed: " + err.String()}}
			}
		}(m.cur_user)
	case UNFOLLOW:
		go func(cur_user uint) {
			if err := m.users[cur_user].Tapi.Unfollow(*cmd.Data.User); err == nil {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Unfollowing " + *cmd.Data.User.Screen_name + " failed: " + err.String()}}
			}
		}(m.cur_user)
	case SET_CURUSER:
		m.cur_user = cmd.Pos
	}
}

func StartUserStreams(users []UserTwitterAPITuple, new_tweets chan<- []*Tweet, uiactions chan<- UserInterfaceAction) {
	for _, u := range users {
		go u.Tapi.UserStream(new_tweets, uiactions)
	}
}
<commit_msg>display up to 50 of the latest tweets from the home timeline at startup.<commit_after>package main

import (
	goconf "goconf.googlecode.com/hg"
	"strconv"
	"log"
	"sort"
)

type Model struct {
	cmdchan       <-chan TwitterCommand
	newtweetchan  chan<- []*Tweet
	newtweets_int chan []*Tweet
	users         []UserTwitterAPITuple
	cur_user      uint
	tweets        []*Tweet
	tweet_map     map[int64]*Tweet
	lookupchan    chan TweetRequest
	uiactionchan  chan UserInterfaceAction
	last_id       int64
}

type TweetRequest struct {
	Status_id int64
	Reply     chan *Tweet
}

type CmdId int

const (
	UPDATE CmdId = iota
	RETWEET
	DELETE
	FAVORITE
	FOLLOW
	UNFOLLOW
	SET_CURUSER
)

type TwitterCommand struct {
	Cmd CmdId
	Data Tweet
	Pos uint // for SET_CURUSER
}

func NewModel(users []UserTwitterAPITuple, cc chan TwitterCommand, ntc chan<- []*Tweet, lc chan TweetRequest, uac chan UserInterfaceAction, cfg *goconf.ConfigFile) *Model {
	model := &Model{
		cmdchan:       cc,
		newtweetchan:  ntc,
		newtweets_int: make(chan []*Tweet, 10),
		users:         users,
		cur_user:      0,
		lookupchan:    lc,
		tweet_map:     map[int64]*Tweet{},
		uiactionchan:  uac,
	}

	if cfg != nil {
		if default_user, err := cfg.GetString("default", "default_user"); err == nil {
			for idx, _ := range model.users {
				if model.users[idx].User == default_user {
					model.cur_user = uint(idx)
					break
				}
			}
		}
	}

	userlist := []string{ strconv.Uitoa(model.cur_user) }
	for _, u := range model.users {
		userlist = append(userlist, u.User)
	}
	model.uiactionchan <- UserInterfaceAction{SET_USERLIST, userlist}

	return model
}

func (m *Model) Run() {
	m.last_id = int64(0)

	new_tweets := make(chan []*Tweet, 10)

	go StartUserStreams(m.users, new_tweets, m.uiactionchan)

	for {
		select {
		case cmd := <-m.cmdchan:
			m.HandleCommand(cmd)
		case req := <-m.lookupchan:
			tweet := m.tweet_map[req.Status_id]
			req.Reply <- tweet
			close(req.Reply)
		case tweets := <-m.newtweets_int:
			for _, t := range tweets {
				m.tweet_map[*t.Id] = t
			}
			m.tweets = append(tweets, m.tweets...)
		case tweets := <-new_tweets:
			log.Printf("received %d tweets", len(tweets))
			unique_tweets := []*Tweet{}
			for _, t := range tweets {
				if _, contained := m.tweet_map[*t.Id]; !contained {
					m.tweet_map[*t.Id] = t
					unique_tweets = append(unique_tweets, t)
				}
				m.tweets = append(unique_tweets, m.tweets...)
			}
			m.newtweetchan <- unique_tweets
		}
	}
}

func (m *Model) HandleCommand(cmd TwitterCommand) {
	switch cmd.Cmd {
	case UPDATE:
		go func(cur_user uint) {
			if newtweet, err := m.users[cur_user].Tapi.Update(cmd.Data); err == nil {
				m.newtweets_int <- []*Tweet{newtweet}
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Posting tweet failed: " + err.String()}}
			}
		}(m.cur_user)
	case RETWEET:
		go func(cur_user uint) {
			if newtweet, err := m.users[cur_user].Tapi.Retweet(cmd.Data); err == nil {
				m.newtweets_int <- []*Tweet{newtweet}
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Retweeting failed:" + err.String()}}
			}
		}(m.cur_user)
	case FAVORITE:
		go func(cur_user uint) {
			if err := m.users[cur_user].Tapi.Favorite(cmd.Data); err == nil {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Favoriting tweet failed: " + err.String()}}
			}
		}(m.cur_user)
	case FOLLOW:
		go func(cur_user uint) {
			if err := m.users[cur_user].Tapi.Follow(*cmd.Data.User.Screen_name); err == nil {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Following " + *cmd.Data.User.Screen_name + " failed: " + err.String()}}
			}
		}(m.cur_user)
	case UNFOLLOW:
		go func(cur_user uint) {
			if err := m.users[cur_user].Tapi.Unfollow(*cmd.Data.User); err == nil {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{""}}
			} else {
				m.uiactionchan <- UserInterfaceAction{SHOW_MSG, []string{"Unfollowing " + *cmd.Data.User.Screen_name + " failed: " + err.String()}}
			}
		}(m.cur_user)
	case SET_CURUSER:
		m.cur_user = cmd.Pos
	}
}

type TweetPtrSlice []*Tweet

func (s TweetPtrSlice) Len() int {
	return len(s)
}

func (s TweetPtrSlice) Less(i, j int) bool {
	return *s[j].Id <= *s[i].Id
}

func (s TweetPtrSlice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func StartUserStreams(users []UserTwitterAPITuple, new_tweets chan<- []*Tweet, uiactions chan<- UserInterfaceAction) {
	initial_tweets := []*Tweet{}
	hometl_tweets := make(chan []*Tweet, len(users))

	for i, _ := range users {
		go func(i int) {
			if home_tl, err := users[i].Tapi.HomeTimeline(20, 0); err == nil {
				hometl_tweets <-home_tl.Tweets
			} else {
				hometl_tweets <-[]*Tweet{}
			}
		}(i)
	}

	for i:=0;i<len(users);i++ {
		tweets := <-hometl_tweets
		initial_tweets = append(initial_tweets, tweets...)
	}

	sort.Sort(TweetPtrSlice(initial_tweets))

	ids := make(map[string]bool, len(initial_tweets))
	unique_tweets := []*Tweet{}
	for _, t := range initial_tweets {
		if _, present := ids[*t.Id_str]; !present {
			ids[*t.Id_str] = true
			unique_tweets = append(unique_tweets, t)
		}
	}

	log.Printf("got %d tweets upfront", len(unique_tweets))
	if len(unique_tweets) > 50 {
		unique_tweets = unique_tweets[0:50]
	}

	new_tweets <- unique_tweets

	for _, u := range users {
		go u.Tapi.UserStream(new_tweets, uiactions)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Eric Barkie. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.

package main

import (
	"fmt"
	"math"
	"time"

	"github.com/ebarkie/weatherlink/packet"
	"github.com/ebarkie/weatherlink/units"
)

// metar generates a report string for a given Loop struct.
func metar(l loop) string {
	// Type
	s := "METAR"

	// Date/Time
	s += fmt.Sprintf(" %sZ", l.Timestamp.In(time.UTC).Format("021504"))

	// Report Modifier
	s += " AUTO" // Indicates a fully automated report with no human intervention

	// Wind
	s += fmt.Sprintf(" %03d%02.f", l.Wind.Cur.Dir, units.Kn(float64(l.Wind.Cur.Speed)))
	if units.Kn(l.Wind.Gust.Last10MinSpeed) >= 0.50 {
		s += fmt.Sprintf("G%02.f", units.Kn(l.Wind.Gust.Last10MinSpeed))
	}
	s += "KT"

	// Weather Phenomena
	if l.Rain.Rate >= 1.0 { // Heavy
		s += " +RA"
	} else if l.Rain.Rate >= 0.5 { // Moderate
		s += " RA"
	} else if l.Rain.Rate > 0.0 { // Light
		s += " -RA"
	}

	// Temperature/Dew Point
	if t := units.C(l.OutTemp); t < 0.0 {
		s += fmt.Sprintf(" M%02.f", t*-1)
	} else {
		s += fmt.Sprintf(" %02.f", t)
	}
	if t := units.C(l.DewPoint); t < 0.0 {
		s += fmt.Sprintf("/M%02.f", t*-1)
	} else {
		s += fmt.Sprintf("/%02.f", t)
	}

	// Altimeter (in inches)
	s += fmt.Sprintf(" A%04.f", l.Bar.Altimeter*100)

	// Remarks
	s += " RMK AO1" // Automated station without a precipitation descriminator

	// Pressure Rising or Falling Rapidly
	if l.Bar.Trend == packet.RisingRapid {
		s += " PRESRR"
	} else if l.Bar.Trend == packet.FallingRapid {
		s += " PRESFR"
	}

	// Sea Level Pressure
	_, d := math.Modf(l.Bar.SeaLevel * 33.8637526 / 100)
	s += fmt.Sprintf(" SLP%03.f", d*1000)

	// Hourly Precipitation Amount
	if l.Rain.Accum.LastHour > 0.0 {
		s += fmt.Sprintf(" P%04.f", l.Rain.Accum.LastHour*100)
	}

	// 24-Hour Precipitation Amount
	if l.Rain.Accum.Last24Hours > 0.0 {
		s += fmt.Sprintf(" 7%04.f", l.Rain.Accum.Last24Hours*100)
	}

	// Hourly Temperature and Dew Point
	if t := units.C(l.OutTemp); t < 0.0 {
		s += fmt.Sprintf(" T1%03.f", t*-10)
	} else {
		s += fmt.Sprintf(" T0%03.f", t*10)
	}
	if t := units.C(l.DewPoint); t < 0.0 {
		s += fmt.Sprintf("1%03.f", t*-10)
	} else {
		s += fmt.Sprintf("0%03.f", t*10)
	}

	return s
}
<commit_msg>Use weatherlink/units for altimeter conversion<commit_after>// Copyright (c) 2016-2017 Eric Barkie. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.

package main

import (
	"fmt"
	"math"
	"time"

	"github.com/ebarkie/weatherlink/packet"
	"github.com/ebarkie/weatherlink/units"
)

// metar generates a report string for a given Loop struct.
func metar(l loop) string {
	// Type
	s := "METAR"

	// Date/Time
	s += fmt.Sprintf(" %sZ", l.Timestamp.In(time.UTC).Format("021504"))

	// Report Modifier
	s += " AUTO" // Indicates a fully automated report with no human intervention

	// Wind
	s += fmt.Sprintf(" %03d%02.f", l.Wind.Cur.Dir, units.Kn(float64(l.Wind.Cur.Speed)))
	if units.Kn(l.Wind.Gust.Last10MinSpeed) >= 0.50 {
		s += fmt.Sprintf("G%02.f", units.Kn(l.Wind.Gust.Last10MinSpeed))
	}
	s += "KT"

	// Weather Phenomena
	if l.Rain.Rate >= 1.0 { // Heavy
		s += " +RA"
	} else if l.Rain.Rate >= 0.5 { // Moderate
		s += " RA"
	} else if l.Rain.Rate > 0.0 { // Light
		s += " -RA"
	}

	// Temperature/Dew Point
	if t := units.C(l.OutTemp); t < 0.0 {
		s += fmt.Sprintf(" M%02.f", t*-1)
	} else {
		s += fmt.Sprintf(" %02.f", t)
	}
	if t := units.C(l.DewPoint); t < 0.0 {
		s += fmt.Sprintf("/M%02.f", t*-1)
	} else {
		s += fmt.Sprintf("/%02.f", t)
	}

	// Altimeter (in inches)
	s += fmt.Sprintf(" A%04.f", l.Bar.Altimeter*100)

	// Remarks
	s += " RMK AO1" // Automated station without a precipitation descriminator

	// Pressure Rising or Falling Rapidly
	if l.Bar.Trend == packet.RisingRapid {
		s += " PRESRR"
	} else if l.Bar.Trend == packet.FallingRapid {
		s += " PRESFR"
	}

	// Sea Level Pressure
	_, d := math.Modf(units.Mb(l.Bar.SeaLevel) / 100)
	s += fmt.Sprintf(" SLP%03.f", d*1000)

	// Hourly Precipitation Amount
	if l.Rain.Accum.LastHour > 0.0 {
		s += fmt.Sprintf(" P%04.f", l.Rain.Accum.LastHour*100)
	}

	// 24-Hour Precipitation Amount
	if l.Rain.Accum.Last24Hours > 0.0 {
		s += fmt.Sprintf(" 7%04.f", l.Rain.Accum.Last24Hours*100)
	}

	// Hourly Temperature and Dew Point
	if t := units.C(l.OutTemp); t < 0.0 {
		s += fmt.Sprintf(" T1%03.f", t*-10)
	} else {
		s += fmt.Sprintf(" T0%03.f", t*10)
	}
	if t := units.C(l.DewPoint); t < 0.0 {
		s += fmt.Sprintf("1%03.f", t*-10)
	} else {
		s += fmt.Sprintf("0%03.f", t*10)
	}

	return s
}
<|endoftext|>


<commit_before>// Copyright 2018 Axel Etcheverry. All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package server

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

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

func TestRouterEnableMetrics(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/metrics", nil)
	w := httptest.NewRecorder()

	router := NewRouter()

	router.EnableMetrics()

	router.ServeHTTP(w, req)

	assert.Equal(t, 200, w.Code)
}

func TestRouterEnableHealthCheck(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/health", nil)
	w := httptest.NewRecorder()

	router := NewRouter()

	router.EnableHealthCheck()

	router.ServeHTTP(w, req)

	assert.Equal(t, 200, w.Code)
}

func TestRouterEnableCors(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
	req.Header.Add("Origin", "http://localhost")

	w := httptest.NewRecorder()

	router := NewRouter()

	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}).Methods(http.MethodGet)

	router.EnableCors()

	router.ServeHTTP(w, req)

	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "*", w.Header().Get("Access-Control-Allow-Origin"))
}

func TestRouterEnableProxy(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
	req.Header.Add("X-Forwarded-For", "127.0.0.1")

	w := httptest.NewRecorder()

	router := NewRouter()

	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, "127.0.0.1", r.RemoteAddr)
		w.WriteHeader(http.StatusOK)
	}).Methods(http.MethodGet)

	router.EnableProxy()

	router.ServeHTTP(w, req)

	assert.Equal(t, 200, w.Code)
}

func TestRouterEnableProfiling(t *testing.T) {
	router := NewRouter()

	router.EnableProfiling()

	for _, item := range []struct {
		status   int
		endpoint string
		method   string
	}{
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/cmdline",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/symbol",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/profile",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/heap",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/goroutine",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/block",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/threadcreate",
			method:   http.MethodGet,
		},
	} {
		req := httptest.NewRequest(item.method, "http://example.com/"+item.endpoint, nil)

		w := httptest.NewRecorder()

		router.ServeHTTP(w, req)

		assert.Equal(t, item.status, w.Code)
	}
}
<commit_msg>test(router): added more tests for router<commit_after>// Copyright 2018 Axel Etcheverry. All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

package server

import (
	"context"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

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

func TestRouterEnableMetrics(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/metrics", nil)
	w := httptest.NewRecorder()

	router := NewRouter()

	router.EnableMetrics()

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestRouterEnableHealthCheck(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/health", nil)
	w := httptest.NewRecorder()

	router := NewRouter()

	router.EnableHealthCheck()

	err := router.AddHealthCheck("redis", func(ctx context.Context) bool {
		return true
	})
	assert.NoError(t, err)

	err = router.AddHealthCheck("redis", func(ctx context.Context) bool {
		return true
	})
	assert.Error(t, err)

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	b, err := ioutil.ReadAll(w.Body)
	assert.NoError(t, err)
	assert.Contains(t, string(b), "redis")
}

func TestRouterHealthCheckFailed(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/health", nil)
	w := httptest.NewRecorder()

	router := NewRouter()

	router.EnableHealthCheck()

	err := router.AddHealthCheck("redis", func(ctx context.Context) bool {
		return false
	})
	assert.NoError(t, err)

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusServiceUnavailable, w.Code)
	b, err := ioutil.ReadAll(w.Body)
	assert.NoError(t, err)
	assert.Contains(t, string(b), "redis")
}

func TestRouterEnableCors(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
	req.Header.Add("Origin", "http://localhost")

	w := httptest.NewRecorder()

	router := NewRouter()

	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}).Methods(http.MethodGet)

	router.EnableCors()

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
	assert.Equal(t, "*", w.Header().Get("Access-Control-Allow-Origin"))
}

func TestRouterEnableProxy(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
	req.Header.Add("X-Forwarded-For", "127.0.0.1")

	w := httptest.NewRecorder()

	router := NewRouter()

	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		assert.Equal(t, "127.0.0.1", r.RemoteAddr)
		w.WriteHeader(http.StatusOK)
	}).Methods(http.MethodGet)

	router.EnableProxy()

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)
}

func TestRouterEnableProfiling(t *testing.T) {
	router := NewRouter()

	router.EnableProfiling()

	for _, item := range []struct {
		status   int
		endpoint string
		method   string
	}{
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/cmdline",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/symbol",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/profile",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/heap",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/goroutine",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/block",
			method:   http.MethodGet,
		},
		{
			status:   http.StatusMovedPermanently,
			endpoint: "/debug/pprof/threadcreate",
			method:   http.MethodGet,
		},
	} {
		req := httptest.NewRequest(item.method, "http://example.com/"+item.endpoint, nil)

		w := httptest.NewRecorder()

		router.ServeHTTP(w, req)

		assert.Equal(t, item.status, w.Code)
	}
}

func TestRouterEnableRecovery(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/", nil)
	req.Header.Add("X-Forwarded-For", "127.0.0.1")

	w := httptest.NewRecorder()

	router := NewRouter()

	router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		panic("test")
	}).Methods(http.MethodGet)

	router.EnableRecovery()

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusInternalServerError, w.Code)
}

type testController struct {
}

func (c testController) Mount(r *Router) {
	r.HandleFunc("/controller", c.handler).Methods(http.MethodGet)
}

func (c testController) handler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNoContent)
}

func TestRouterAddController(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/controller", nil)

	w := httptest.NewRecorder()

	router := NewRouter()

	router.AddController(&testController{})

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNoContent, w.Code)
}

type testRoute struct {
}

func (testRoute) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNoContent)
}

func TestRouterAddRoute(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/route", nil)

	w := httptest.NewRecorder()

	router := NewRouter()

	router.AddRoute("/route", &testRoute{})

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNoContent, w.Code)
}

func TestRouterAddRouteFunc(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/route-func", nil)

	w := httptest.NewRecorder()

	router := NewRouter()

	router.AddRouteFunc("/route-func", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
	})

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNoContent, w.Code)
}

func TestRouterAddPrefixRoute(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/route/foo", nil)

	w := httptest.NewRecorder()

	router := NewRouter()

	router.AddPrefixRoute("/route/", &testRoute{})

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNoContent, w.Code)
}

func TestRouterAddPrefixRouteFunc(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/route-func/foo", nil)

	w := httptest.NewRecorder()

	router := NewRouter()

	router.AddPrefixRouteFunc("/route-func/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNoContent)
	})

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNoContent, w.Code)
}

type testNotFound struct {
}

func (testNotFound) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	w.Write([]byte("true"))
}

func TestRouterSetNotFound(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/route-func/foo", nil)

	w := httptest.NewRecorder()

	router := NewRouter()
	router.SetNotFound(&testNotFound{})

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
	b, err := ioutil.ReadAll(w.Body)
	assert.NoError(t, err)
	assert.Equal(t, "true", string(b))
}

func TestRouterSetNotFoundFunc(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "http://example.com/route-func/foo", nil)

	w := httptest.NewRecorder()

	router := NewRouter()
	router.SetNotFoundFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("true"))
	})

	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusNotFound, w.Code)
	b, err := ioutil.ReadAll(w.Body)
	assert.NoError(t, err)
	assert.Equal(t, "true", string(b))
}
<|endoftext|>


<commit_before>package goserver

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

func TestRouter(t *testing.T) {
	fn := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.Write([]byte("4"))
	})

	m1 := mockMiddlewareWithBody("1")
	m2 := mockMiddlewareWithBody("2")
	m3 := mockMiddlewareWithBody("3")

	r := newRoute(fn)
	r.addMiddleware(newMiddleware(m1, m2, m3))

	h := r.handler()

	w := httptest.NewRecorder()
	req, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatal(err)
	}

	h.ServeHTTP(w, req)

	if w.Body.String() != "1234" {
		t.Errorf("The router doesn't work correctly. Expected 1234, Actual: %s", w.Body.String())
	}
}
<commit_msg>Add params test<commit_after>package goserver

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

func TestRouter(t *testing.T) {
	fn := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.Write([]byte("4"))
	})

	m1 := mockMiddlewareWithBody("1")
	m2 := mockMiddlewareWithBody("2")
	m3 := mockMiddlewareWithBody("3")

	r := newRoute(fn)
	r.addMiddleware(newMiddleware(m1, m2, m3))

	h := r.handler()

	w := httptest.NewRecorder()
	req, err := http.NewRequest("GET", "/", nil)
	if err != nil {
		t.Fatal(err)
	}

	h.ServeHTTP(w, req)

	if w.Body.String() != "1234" {
		t.Errorf("The router doesn't work correctly. Expected 1234, Actual: %s", w.Body.String())
	}
}

func TestParams(t *testing.T) {
	param := Param{"key", "value"}
	params := Params{param}

	if params[0].Value("key") != "value" {
		t.Error("Invalid params value")
	}
}
<|endoftext|>