<commit_before>package tricorder

import (
	"fmt"
	"github.com/Symantec/tricorder/go/tricorder/types"
	"github.com/Symantec/tricorder/go/tricorder/units"
	"html/template"
	"io"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

const (
	htmlUrl         = "/metrics"
	htmlTemplateStr = ` \
	\ {{define "METRIC"}} \
	  \ {{with $top := .}} \
            \ {{if .IsDistribution}} \
	      {{.Metric.AbsPath}} (distribution: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	      \ {{with .Metric.AsDistribution.Snapshot}} \

	        \ {{range .Breakdown}} \
	          \ {{if .Count}} \

                    \ {{if .First}} \
	              <{{$top.ToFloat32 .End}}:	{{.Count}}
	            \ {{else if .Last}} \
	              >={{$top.ToFloat32 .Start}}:	 {{.Count}}
	            \ {{else}} \
	              {{$top.ToFloat32 .Start}}-{{$top.ToFloat32 .End}}:	 {{.Count}}
	            \ {{end}} \

		  \ {{end}} \
		\ {{end}} \

	        \ {{if .Count}} \
		 min: {{$top.ToFloat32 .Min}} max: {{$top.ToFloat32 .Max}} avg: {{$top.ToFloat32 .Average}} ~median: {{$top.ToFloat32 .Median}} sum: {{$top.ToFloat32 .Sum}} count: {{.Count}}

	        \ {{end}} \
	      \ {{end}} \
	    \ {{else if .IsList}} \
	      {{.Metric.AbsPath}} (list of {{$top.HtmlType .Metric.SubType}}: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	      \ {{range .HtmlStrings}} \

{{.}}

	      \ {{end}} \

	    \ {{else}} \
	      {{.Metric.AbsPath}} {{.AsHtmlString}} ({{$top.HtmlType .Metric.Type}}: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	    \ {{end}} \
	  \ {{end}} \
	\ {{end}} \

	  <link rel="stylesheet" type="text/css" href="/metricsstatic/theme.css">

	\ {{with $top := .}} \
	  \ {{if .Directory}} \
	    \ {{range .Directory.List}} \
	      \ {{if .Directory}} \
	        {{.Directory.AbsPath}}

              \ {{else}} \
	        \ {{template "METRIC" $top.AsMetricView .Metric}} \
	      \ {{end}} \
	    \ {{end}} \
	  \ {{else}} \
	    \ {{template "METRIC" .}} \
	  \ {{end}} \
	\ {{end}} \

	  `

	hasTricorderUrl = "/has-tricorder-metrics"

	themeCss = `
	.summary {color:#999999; font-style: italic;}
	.parens {color:#999999;}
	  `
)

var (
	leadingWhitespace = regexp.MustCompile(`\n\s*\\ `)
	htmlTemplate      = template.Must(
		template.New("browser").Parse(
			strings.Replace(
				leadingWhitespace.ReplaceAllString(
					strings.Replace(
						htmlTemplateStr,
						"\n\t",
						"\n",
						-1),
					"\n"),
				" \\\n",
				"",
				-1)))

	hasTricorderBody []byte = []byte("true")
)

type htmlView struct {
	Directory *directory
	Metric    *metric
	Session   *session
}

func (v *htmlView) AsMetricView(m *metric) *htmlView {
	return &htmlView{Metric: m, Session: v.Session}
}

func (v *htmlView) AsHtmlString() string {
	return v.Metric.AsHtmlString(v.Session)
}

func (v *htmlView) HtmlStrings() interface{} {
	return v.Metric.AsList().HtmlStrings(v.Metric.Unit())
}

func (v *htmlView) IsDistribution() bool {
	return v.Metric.Type() == types.Dist
}

func (v *htmlView) IsList() bool {
	return v.Metric.Type() == types.List
}

func (v *htmlView) HtmlType(t types.Type) types.Type {
	switch t {
	case types.GoTime:
		return types.Time
	case types.GoDuration:
		return types.Duration
	default:
		return t
	}
}

func (v *htmlView) HasUnit() bool {
	return v.Metric.Unit() != units.None
}

func (v *htmlView) Link(d *directory) string {
	return htmlUrl + d.AbsPath()
}

func (v *htmlView) ToFloat32(f float64) float32 {
	return float32(f)
}

func htmlEmitMetric(m *metric, s *session, w io.Writer) error {
	v := &htmlView{Metric: m, Session: s}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func htmlEmitDirectory(d *directory, s *session, w io.Writer) error {
	v := &htmlView{Directory: d, Session: s}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func htmlEmitDirectoryOrMetric(
	path string, w http.ResponseWriter) error {
	d, m := root.GetDirectoryOrMetric(path)
	if d == nil && m == nil {
		fmt.Fprintf(w, "Path does not exist.")
		return nil
	}
	s := newSession()
	defer s.Close()
	if m == nil {
		return htmlEmitDirectory(d, s, w)
	}
	return htmlEmitMetric(m, s, w)
}

type textCollector struct {
	W io.Writer
}

func (c *textCollector) Collect(m *metric, s *session) (err error) {
	if _, err = fmt.Fprintf(c.W, "%s ", m.AbsPath()); err != nil {
		return
	}
	return textEmitMetric(m, s, c.W)
}

func textEmitDistribution(s *snapshot, w io.Writer) error {
	_, err := fmt.Fprintf(
		w,
		"{min:%s;max:%s;avg:%s;median:%s;sum:%s;count:%d",
		strconv.FormatFloat(s.Min, 'f', -1, 32),
		strconv.FormatFloat(s.Max, 'f', -1, 32),
		strconv.FormatFloat(s.Average, 'f', -1, 32),
		strconv.FormatFloat(s.Median, 'f', -1, 32),
		strconv.FormatFloat(s.Sum, 'f', -1, 32),
		s.Count)
	if err != nil {
		return err
	}
	for _, piece := range s.Breakdown {
		if piece.Count == 0 {
			continue
		}
		if piece.First {
			_, err := fmt.Fprintf(
				w,
				";[-inf,%s):%d",
				strconv.FormatFloat(piece.End, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		} else if piece.Last {
			_, err := fmt.Fprintf(
				w,
				";[%s,inf):%d",
				strconv.FormatFloat(piece.Start, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		} else {
			_, err := fmt.Fprintf(
				w,
				";[%s,%s):%d",
				strconv.FormatFloat(piece.Start, 'f', -1, 32),
				strconv.FormatFloat(piece.End, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		}
	}
	_, err = fmt.Fprintf(w, "}\n")
	return err
}

func textEmitMetric(m *metric, s *session, w io.Writer) error {
	if m.Type() == types.Dist {
		return textEmitDistribution(m.AsDistribution().Snapshot(), w)
	}
	if m.Type() == types.List {
		_, err := fmt.Fprintf(
			w,
			"%s\n",
			strings.Join(m.AsList().TextStrings(m.Unit()), "|"))
		return err
	}
	_, err := fmt.Fprintf(w, "%s\n", m.AsTextString(s))
	return err
}

func textEmitDirectoryOrMetric(
	path string, w http.ResponseWriter) error {
	d, m := root.GetDirectoryOrMetric(path)
	if d == nil && m == nil {
		fmt.Fprintf(w, "*Path does not exist.*")
		return nil
	}
	if m == nil {
		return d.GetAllMetrics(&textCollector{W: w}, nil)
	}
	return textEmitMetric(m, nil, w)
}

func htmlAndTextHandlerFunc(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	path := r.URL.Path
	var err error
	if r.Form.Get("format") == "text" {
		err = textEmitDirectoryOrMetric(path, w)
	} else {
		err = htmlEmitDirectoryOrMetric(path, w)
	}
	if err != nil {
		handleError(w, err)
	}
}

func hasTricorderHandler(w http.ResponseWriter, r *http.Request) {
	w.Write(hasTricorderBody)
}

func newStatic() http.Handler {
	result := http.NewServeMux()
	addStatic(result, "/theme.css", themeCss)
	return result
}

func initHtmlHandlers() {
	http.Handle(
		htmlUrl+"/",
		http.StripPrefix(
			htmlUrl, http.HandlerFunc(htmlAndTextHandlerFunc)))
	http.HandleFunc(hasTricorderUrl, hasTricorderHandler)
	http.Handle(
		"/metricsstatic/",
		http.StripPrefix("/metricsstatic", newStatic()))
}
<commit_msg>Added security header and content type for XSS protection<commit_after>package tricorder

import (
	"fmt"
	"github.com/Symantec/tricorder/go/tricorder/types"
	"github.com/Symantec/tricorder/go/tricorder/units"
	"html/template"
	"io"
	"net/http"
	"regexp"
	"strconv"
	"strings"
)

const (
	htmlUrl         = "/metrics"
	htmlTemplateStr = ` \
	\ {{define "METRIC"}} \
	  \ {{with $top := .}} \
            \ {{if .IsDistribution}} \
	      {{.Metric.AbsPath}} (distribution: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	      \ {{with .Metric.AsDistribution.Snapshot}} \

	        \ {{range .Breakdown}} \
	          \ {{if .Count}} \

                    \ {{if .First}} \
	              <{{$top.ToFloat32 .End}}:	{{.Count}}
	            \ {{else if .Last}} \
	              >={{$top.ToFloat32 .Start}}:	 {{.Count}}
	            \ {{else}} \
	              {{$top.ToFloat32 .Start}}-{{$top.ToFloat32 .End}}:	 {{.Count}}
	            \ {{end}} \

		  \ {{end}} \
		\ {{end}} \

	        \ {{if .Count}} \
		 min: {{$top.ToFloat32 .Min}} max: {{$top.ToFloat32 .Max}} avg: {{$top.ToFloat32 .Average}} ~median: {{$top.ToFloat32 .Median}} sum: {{$top.ToFloat32 .Sum}} count: {{.Count}}

	        \ {{end}} \
	      \ {{end}} \
	    \ {{else if .IsList}} \
	      {{.Metric.AbsPath}} (list of {{$top.HtmlType .Metric.SubType}}: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	      \ {{range .HtmlStrings}} \

{{.}}

	      \ {{end}} \

	    \ {{else}} \
	      {{.Metric.AbsPath}} {{.AsHtmlString}} ({{$top.HtmlType .Metric.Type}}: {{.Metric.Description}}{{if .HasUnit}}; unit: {{.Metric.Unit}}{{end}})

	    \ {{end}} \
	  \ {{end}} \
	\ {{end}} \

	  <link rel="stylesheet" type="text/css" href="/metricsstatic/theme.css">

	\ {{with $top := .}} \
	  \ {{if .Directory}} \
	    \ {{range .Directory.List}} \
	      \ {{if .Directory}} \
	        {{.Directory.AbsPath}}

              \ {{else}} \
	        \ {{template "METRIC" $top.AsMetricView .Metric}} \
	      \ {{end}} \
	    \ {{end}} \
	  \ {{else}} \
	    \ {{template "METRIC" .}} \
	  \ {{end}} \
	\ {{end}} \

	  `

	hasTricorderUrl = "/has-tricorder-metrics"

	themeCss = `
	.summary {color:#999999; font-style: italic;}
	.parens {color:#999999;}
	  `
)

var (
	leadingWhitespace = regexp.MustCompile(`\n\s*\\ `)
	htmlTemplate      = template.Must(
		template.New("browser").Parse(
			strings.Replace(
				leadingWhitespace.ReplaceAllString(
					strings.Replace(
						htmlTemplateStr,
						"\n\t",
						"\n",
						-1),
					"\n"),
				" \\\n",
				"",
				-1)))

	hasTricorderBody []byte = []byte("true")
)

type htmlView struct {
	Directory *directory
	Metric    *metric
	Session   *session
}

func (v *htmlView) AsMetricView(m *metric) *htmlView {
	return &htmlView{Metric: m, Session: v.Session}
}

func (v *htmlView) AsHtmlString() string {
	return v.Metric.AsHtmlString(v.Session)
}

func (v *htmlView) HtmlStrings() interface{} {
	return v.Metric.AsList().HtmlStrings(v.Metric.Unit())
}

func (v *htmlView) IsDistribution() bool {
	return v.Metric.Type() == types.Dist
}

func (v *htmlView) IsList() bool {
	return v.Metric.Type() == types.List
}

func (v *htmlView) HtmlType(t types.Type) types.Type {
	switch t {
	case types.GoTime:
		return types.Time
	case types.GoDuration:
		return types.Duration
	default:
		return t
	}
}

func (v *htmlView) HasUnit() bool {
	return v.Metric.Unit() != units.None
}

func (v *htmlView) Link(d *directory) string {
	return htmlUrl + d.AbsPath()
}

func (v *htmlView) ToFloat32(f float64) float32 {
	return float32(f)
}

func htmlEmitMetric(m *metric, s *session, w io.Writer) error {
	v := &htmlView{Metric: m, Session: s}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func htmlEmitDirectory(d *directory, s *session, w io.Writer) error {
	v := &htmlView{Directory: d, Session: s}
	if err := htmlTemplate.Execute(w, v); err != nil {
		return err
	}
	return nil
}

func htmlEmitDirectoryOrMetric(
	path string, w http.ResponseWriter) error {
	d, m := root.GetDirectoryOrMetric(path)
	if d == nil && m == nil {
		fmt.Fprintf(w, "Path does not exist.")
		return nil
	}
	s := newSession()
	defer s.Close()
	if m == nil {
		return htmlEmitDirectory(d, s, w)
	}
	return htmlEmitMetric(m, s, w)
}

type textCollector struct {
	W io.Writer
}

func (c *textCollector) Collect(m *metric, s *session) (err error) {
	if _, err = fmt.Fprintf(c.W, "%s ", m.AbsPath()); err != nil {
		return
	}
	return textEmitMetric(m, s, c.W)
}

func textEmitDistribution(s *snapshot, w io.Writer) error {
	_, err := fmt.Fprintf(
		w,
		"{min:%s;max:%s;avg:%s;median:%s;sum:%s;count:%d",
		strconv.FormatFloat(s.Min, 'f', -1, 32),
		strconv.FormatFloat(s.Max, 'f', -1, 32),
		strconv.FormatFloat(s.Average, 'f', -1, 32),
		strconv.FormatFloat(s.Median, 'f', -1, 32),
		strconv.FormatFloat(s.Sum, 'f', -1, 32),
		s.Count)
	if err != nil {
		return err
	}
	for _, piece := range s.Breakdown {
		if piece.Count == 0 {
			continue
		}
		if piece.First {
			_, err := fmt.Fprintf(
				w,
				";[-inf,%s):%d",
				strconv.FormatFloat(piece.End, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		} else if piece.Last {
			_, err := fmt.Fprintf(
				w,
				";[%s,inf):%d",
				strconv.FormatFloat(piece.Start, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		} else {
			_, err := fmt.Fprintf(
				w,
				";[%s,%s):%d",
				strconv.FormatFloat(piece.Start, 'f', -1, 32),
				strconv.FormatFloat(piece.End, 'f', -1, 32),
				piece.Count)
			if err != nil {
				return err
			}
		}
	}
	_, err = fmt.Fprintf(w, "}\n")
	return err
}

func textEmitMetric(m *metric, s *session, w io.Writer) error {
	if m.Type() == types.Dist {
		return textEmitDistribution(m.AsDistribution().Snapshot(), w)
	}
	if m.Type() == types.List {
		_, err := fmt.Fprintf(
			w,
			"%s\n",
			strings.Join(m.AsList().TextStrings(m.Unit()), "|"))
		return err
	}
	_, err := fmt.Fprintf(w, "%s\n", m.AsTextString(s))
	return err
}

func textEmitDirectoryOrMetric(
	path string, w http.ResponseWriter) error {
	d, m := root.GetDirectoryOrMetric(path)
	if d == nil && m == nil {
		fmt.Fprintf(w, "*Path does not exist.*")
		return nil
	}
	if m == nil {
		return d.GetAllMetrics(&textCollector{W: w}, nil)
	}
	return textEmitMetric(m, nil, w)
}

func setSecurityHeaders(w http.ResponseWriter) {
	w.Header().Set("X-Frame-Options", "DENY")
	w.Header().Set("X-XSS-Protection", "1")
	w.Header().Set("Content-Security-Policy", "default-src 'self' ;style-src 'self' 'unsafe-inline'")
}

func htmlAndTextHandlerFunc(w http.ResponseWriter, r *http.Request) {
	setSecurityHeaders(w)
	r.ParseForm()
	path := r.URL.Path
	var err error
	if r.Form.Get("format") == "text" {
		w.Header().Set("Content-Type", "text/plain")
		err = textEmitDirectoryOrMetric(path, w)
	} else {
		err = htmlEmitDirectoryOrMetric(path, w)
	}
	if err != nil {
		handleError(w, err)
	}
}

func hasTricorderHandler(w http.ResponseWriter, r *http.Request) {
	setSecurityHeaders(w)
	w.Write(hasTricorderBody)
}

func newStatic() http.Handler {
	result := http.NewServeMux()
	addStatic(result, "/theme.css", themeCss)
	return result
}

func initHtmlHandlers() {
	http.Handle(
		htmlUrl+"/",
		http.StripPrefix(
			htmlUrl, http.HandlerFunc(htmlAndTextHandlerFunc)))
	http.HandleFunc(hasTricorderUrl, hasTricorderHandler)
	http.Handle(
		"/metricsstatic/",
		http.StripPrefix("/metricsstatic", newStatic()))
}
<|endoftext|>


<commit_before>// Extensions to the go-check unittest framework.
//
// NOTE: see https://github.com/go-check/check/pull/6 for reasons why these
// checkers live here.
package gocheck2

import (
	"bytes"
	"fmt"
	"reflect"
	"regexp"

	. "gopkg.in/check.v1"
)

// -----------------------------------------------------------------------
// IsTrue / IsFalse checker.

type isBoolValueChecker struct {
	*CheckerInfo
	expected bool
}

func (checker *isBoolValueChecker) Check(
	params []interface{},
	names []string) (
	result bool,
	error string) {

	obtained, ok := params[0].(bool)
	if !ok {
		return false, "Argument to " + checker.Name + " must be bool"
	}

	return obtained == checker.expected, ""
}

// The IsTrue checker verifies that the obtained value is true.
//
// For example:
//
//     c.Assert(value, IsTrue)
//
var IsTrue Checker = &isBoolValueChecker{
	&CheckerInfo{Name: "IsTrue", Params: []string{"obtained"}},
	true,
}

// The IsFalse checker verifies that the obtained value is false.
//
// For example:
//
//     c.Assert(value, IsFalse)
//
var IsFalse Checker = &isBoolValueChecker{
	&CheckerInfo{Name: "IsFalse", Params: []string{"obtained"}},
	false,
}

// -----------------------------------------------------------------------
// BytesEquals checker.

type bytesEquals struct{}

func (b *bytesEquals) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "BytesEqual takes 2 bytestring arguments"
	}
	b1, ok1 := params[0].([]byte)
	b2, ok2 := params[1].([]byte)

	if !(ok1 && ok2) {
		return false, "Arguments to BytesEqual must both be bytestrings"
	}

	if bytes.Equal(b1, b2) {
		return true, ""
	}
	return false, "Byte arrays were different"
}

func (b *bytesEquals) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "BytesEquals",
		Params: []string{"bytes_one", "bytes_two"},
	}
}

// BytesEquals checker compares two bytes sequence using bytes.Equal.
//
// For example:
//
//     c.Assert(b, BytesEquals, []byte("bar"))
//
// Main difference between DeepEquals and BytesEquals is that BytesEquals treats
// `nil` as empty byte sequence while DeepEquals doesn't.
//
//     c.Assert(nil, BytesEquals, []byte("")) // succeeds
//     c.Assert(nil, DeepEquals, []byte("")) // fails
var BytesEquals = &bytesEquals{}

// -----------------------------------------------------------------------
// AlmostEqual checker.
// Meant to compare floats with some margin of error which might arrise
// from rounding errors.

type almostEqualChecker struct{}

func (ae *almostEqualChecker) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "AlmostEqual",
		Params: []string{"obtained", "expected", "margin"},
	}
}

func (ae *almostEqualChecker) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 3 {
		return false, "AlmostEqual takes exactly 3 arguments"
	}
	obtained, ok1 := params[0].(float64)
	expected, ok2 := params[1].(float64)
	margin, ok3 := params[2].(float64)

	if !(ok1 && ok2 && ok3) {
		return false, "All arguments to AlmostEqual must be float64"
	}

	if margin < 0 {
		return false, "Margin must be non-negative"
	}

	if obtained < (expected-margin) || obtained > (expected+margin) {
		return false, fmt.Sprintf("Obtained %f different from expected %f by more than %f margin",
			obtained, expected, margin)
	}
	return true, ""
}

var AlmostEqual = &almostEqualChecker{}

// -----------------------------------------------------------------------
// HasKey checker.

type hasKey struct{}

func (h *hasKey) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "HasKey takes 2 arguments: a map and a key"
	}

	mapValue := reflect.ValueOf(params[0])
	if mapValue.Kind() != reflect.Map {
		return false, "First argument to HasKey must be a map"
	}

	keyValue := reflect.ValueOf(params[1])
	if !keyValue.Type().AssignableTo(mapValue.Type().Key()) {
		return false, "Second argument must be assignable to the map key type"
	}

	return mapValue.MapIndex(keyValue).IsValid(), ""
}

func (h *hasKey) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "HasKey",
		Params: []string{"obtained", "key"},
	}
}

// The HasKey checker verifies that the obtained map contains the given key.
//
// For example:
//
//     c.Assert(myMap, HasKey, "foo")
//
var HasKey = &hasKey{}

// -----------------------------------------------------------------------
// NoErr checker.

type noErr struct{}

// This exists to implement fmt.GoStringer and force the `%#v` format to show
// the string unescaped, newlines and all.
type rawString string

func (r rawString) GoString() string {
	return string(r)
}

func (c noErr) Check(params []interface{}, names []string) (bool, string) {
	err, ok := params[0].(error)
	if !ok {
		return true, ""
	}
	params[0] = rawString("\n" + err.Error())
	return false, ""
}

func (c noErr) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "NoErr",
		Params: []string{"error"},
	}
}

// The NoErr checker tests that the obtained value is nil.  On failure,
// the checker adjusts the output so that a multi-line error message will
// be printed in a readable fashion.
//
// For example:
//
//     c.Assert(err, NoErr)
var NoErr = &noErr{}

// -----------------------------------------------------------------------
// MultilineErrorMatches: Multiline ErrorMatches
// The standard gocheck ErrorMatches brackets the regular expression that
// the error must match in ^ and $, so that it can only match single-line
// errors messages. Most dropbox errors are created using godropbox.errors,
// which produce error objects that have multiline message, which means
// that our standard errors will never be matched by ErrorMatches.
//
// This is a variant of the normal ErrorMatches which avoids that problem,
// and works with dropbox errors.
// It takes two parameters:
// 1: An error object, and
// 2: a string containing a regular expression.
// The check succeeds if the error's message contains a match for the regular expression
// at any position.
type multilineErrorMatches struct{}

func (e multilineErrorMatches) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "MultilineErrorMatches take 2 arguments: an error, and a regular expression"
	}
	errValue, errIsError := params[0].(error)
	if !errIsError {
		return false, "the first parameter value must be an error!"
	}
	regexpStr, reIsStr := params[1].(string)
	if !reIsStr {
		return false, "the second parameter value must be a string containing a regular expression"
	}
	matches, err := regexp.MatchString(regexpStr, errValue.Error())
	if err != nil {
		return false, fmt.Sprintf("Error in regular expression: %v", err.Error())
	}
	return matches, ""
}

func (h multilineErrorMatches) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "MultilineErrorMatches",
		Params: []string{"error", "pattern"},
	}
}

var MultilineErrorMatches multilineErrorMatches = multilineErrorMatches{}
<commit_msg>Syncing gocheck2/ to top of repo<commit_after>// Extensions to the go-check unittest framework.
//
// NOTE: see https://github.com/go-check/check/pull/6 for reasons why these
// checkers live here.
package gocheck2

import (
	"bytes"
	"fmt"
	"reflect"
	"regexp"

	. "gopkg.in/check.v1"
)

// -----------------------------------------------------------------------
// IsTrue / IsFalse checker.

type isBoolValueChecker struct {
	*CheckerInfo
	expected bool
}

func (checker *isBoolValueChecker) Check(
	params []interface{},
	names []string) (
	result bool,
	error string) {

	obtained, ok := params[0].(bool)
	if !ok {
		return false, "Argument to " + checker.Name + " must be bool"
	}

	return obtained == checker.expected, ""
}

// The IsTrue checker verifies that the obtained value is true.
//
// For example:
//
//     c.Assert(value, IsTrue)
//
var IsTrue Checker = &isBoolValueChecker{
	&CheckerInfo{Name: "IsTrue", Params: []string{"obtained"}},
	true,
}

// The IsFalse checker verifies that the obtained value is false.
//
// For example:
//
//     c.Assert(value, IsFalse)
//
var IsFalse Checker = &isBoolValueChecker{
	&CheckerInfo{Name: "IsFalse", Params: []string{"obtained"}},
	false,
}

// -----------------------------------------------------------------------
// BytesEquals checker.

type bytesEquals struct{}

func (b *bytesEquals) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "BytesEqual takes 2 bytestring arguments"
	}
	b1, ok1 := params[0].([]byte)
	b2, ok2 := params[1].([]byte)

	if !(ok1 && ok2) {
		return false, "Arguments to BytesEqual must both be bytestrings"
	}

	if bytes.Equal(b1, b2) {
		return true, ""
	}
	return false, "Byte arrays were different"
}

func (b *bytesEquals) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "BytesEquals",
		Params: []string{"bytes_one", "bytes_two"},
	}
}

// BytesEquals checker compares two bytes sequence using bytes.Equal.
//
// For example:
//
//     c.Assert(b, BytesEquals, []byte("bar"))
//
// Main difference between DeepEquals and BytesEquals is that BytesEquals treats
// `nil` as empty byte sequence while DeepEquals doesn't.
//
//     c.Assert(nil, BytesEquals, []byte("")) // succeeds
//     c.Assert(nil, DeepEquals, []byte("")) // fails
var BytesEquals = &bytesEquals{}

// -----------------------------------------------------------------------
// AlmostEqual checker.
// Meant to compare floats with some margin of error which might arrise
// from rounding errors.

type almostEqualChecker struct{}

func (ae *almostEqualChecker) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "AlmostEqual",
		Params: []string{"obtained", "expected", "margin"},
	}
}

func (ae *almostEqualChecker) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 3 {
		return false, "AlmostEqual takes exactly 3 arguments"
	}
	obtained, ok1 := params[0].(float64)
	expected, ok2 := params[1].(float64)
	margin, ok3 := params[2].(float64)

	if !(ok1 && ok2 && ok3) {
		return false, "All arguments to AlmostEqual must be float64"
	}

	if margin < 0 {
		return false, "Margin must be non-negative"
	}

	if obtained < (expected-margin) || obtained > (expected+margin) {
		return false, fmt.Sprintf("Obtained %f different from expected %f by more than %f margin",
			obtained, expected, margin)
	}
	return true, ""
}

var AlmostEqual = &almostEqualChecker{}

// -----------------------------------------------------------------------
// HasKey checker.

type hasKey struct{}

func (h *hasKey) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "HasKey takes 2 arguments: a map and a key"
	}

	mapValue := reflect.ValueOf(params[0])
	if mapValue.Kind() != reflect.Map {
		return false, "First argument to HasKey must be a map"
	}

	keyValue := reflect.ValueOf(params[1])
	if !keyValue.Type().AssignableTo(mapValue.Type().Key()) {
		return false, "Second argument must be assignable to the map key type"
	}

	return mapValue.MapIndex(keyValue).IsValid(), ""
}

func (h *hasKey) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "HasKey",
		Params: []string{"obtained", "key"},
	}
}

// The HasKey checker verifies that the obtained map contains the given key.
//
// For example:
//
//     c.Assert(myMap, HasKey, "foo")
//
var HasKey = &hasKey{}

// -----------------------------------------------------------------------
// NoErr checker.

type noErr struct{}

// This exists to implement fmt.GoStringer and force the `%#v` format to show
// the string unescaped, newlines and all.
type rawString string

func (r rawString) GoString() string {
	return string(r)
}

func (c noErr) Check(params []interface{}, names []string) (bool, string) {
	err, ok := params[0].(error)
	if !ok {
		return true, ""
	}
	params[0] = rawString("\n" + err.Error())
	return false, ""
}

func (c noErr) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "NoErr",
		Params: []string{"error"},
	}
}

// The NoErr checker tests that the obtained value is nil.  On failure,
// the checker adjusts the output so that a multi-line error message will
// be printed in a readable fashion.
//
// For example:
//
//     c.Assert(err, NoErr)
var NoErr = &noErr{}

// -----------------------------------------------------------------------
// MultilineErrorMatches: Multiline ErrorMatches
// The standard gocheck ErrorMatches brackets the regular expression that
// the error must match in ^ and $, so that it can only match single-line
// errors messages. Most dropbox errors are created using godropbox.errors,
// which produce error objects that have multiline message, which means
// that our standard errors will never be matched by ErrorMatches.
//
// This is a variant of the normal ErrorMatches which avoids that problem,
// and works with dropbox errors.
// It takes two parameters:
// 1: An error object, and
// 2: a string containing a regular expression.
// The check succeeds if the error's message contains a match for the regular expression
// at any position.
type multilineErrorMatches struct{}

func (e multilineErrorMatches) Check(params []interface{}, names []string) (bool, string) {
	if len(params) != 2 {
		return false, "MultilineErrorMatches take 2 arguments: an error, and a regular expression"
	}
	errValue, errIsError := params[0].(error)
	if !errIsError {
		return false, "the first parameter value must be an error!"
	}
	regexpStr, reIsStr := params[1].(string)
	if !reIsStr {
		return false, "the second parameter value must be a string containing a regular expression"
	}
	matches, err := regexp.MatchString(regexpStr, errValue.Error())
	if err != nil {
		return false, fmt.Sprintf("Error in regular expression: %v", err.Error())
	}
	return matches, ""
}

func (h multilineErrorMatches) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "MultilineErrorMatches",
		Params: []string{"error", "pattern"},
	}
}

var MultilineErrorMatches multilineErrorMatches = multilineErrorMatches{}

type greaterThan struct{}

func (c greaterThan) Check(params []interface{}, names []string) (bool, string) {
	obtained, ok := params[0].(int)
	if !ok {
		return false, "obtained is not int"
	}
	expected, ok := params[1].(int)
	if !ok {
		return false, "expected is not int"
	}

	if obtained > expected {
		return true, ""
	}
	return false, fmt.Sprintf("%d is less than or equal to %d", obtained, expected)
}
func (c greaterThan) Info() *CheckerInfo {
	return &CheckerInfo{
		Name:   "GreaterThan",
		Params: []string{"obtained", "expected"},
	}
}

var GreaterThan = &greaterThan{}
<|endoftext|>


<commit_before>// Copyright 2010 Google 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.

// GoMock - a mock framework for Go.
//
// Standard usage:
//   (1) Define an interface that you wish to mock.
//         type MyInterface interface {
//           SomeMethod(x int64, y string)
//         }
//   (2) Use mockgen to generate a mock from the interface.
//   (3) Use the mock in a test:
//         func TestMyThing(t *testing.T) {
//           mockCtrl := gomock.NewController(t)
//           defer mockCtrl.Finish()
//
//           mockObj := something.NewMockMyInterface(mockCtrl)
//           mockObj.EXPECT().SomeMethod(4, "blah")
//           // pass mockObj to a real object and play with it.
//         }
//
// By default, expected calls are not enforced to run in any particular order.
// Call order dependency can be enforced by use of InOrder and/or Call.After.
// Call.After can create more varied call order dependencies, but InOrder is
// often more convenient.
//
// The following examples create equivalent call order dependencies.
//
// Example of using Call.After to chain expected call order:
//
//     firstCall := mockObj.EXPECT().SomeMethod(1, "first")
//     secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall)
//     mockObj.EXPECT().SomeMethod(3, "third").After(secondCall)
//
// Example of using InOrder to declare expected call order:
//
//     gomock.InOrder(
//         mockObj.EXPECT().SomeMethod(1, "first"),
//         mockObj.EXPECT().SomeMethod(2, "second"),
//         mockObj.EXPECT().SomeMethod(3, "third"),
//     )
//
// TODO:
//	- Handle different argument/return types (e.g. ..., chan, map, interface).
package gomock

import (
	"context"
	"fmt"
	"reflect"
	"runtime"
	"sync"
)

// A TestReporter is something that can be used to report test failures.
// It is satisfied by the standard library's *testing.T.
type TestReporter interface {
	Errorf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})
}

// A Controller represents the top-level control of a mock ecosystem.
// It defines the scope and lifetime of mock objects, as well as their expectations.
// It is safe to call Controller's methods from multiple goroutines.
type Controller struct {
	mu            sync.Mutex
	t             TestReporter
	expectedCalls callSet
}

func NewController(t TestReporter) *Controller {
	return &Controller{
		t:             t,
		expectedCalls: make(callSet),
	}
}

type cancelReporter struct {
	t      TestReporter
	cancel func()
}

func (r *cancelReporter) Errorf(format string, args ...interface{}) { r.t.Errorf(format, args...) }
func (r *cancelReporter) Fatalf(format string, args ...interface{}) {
	defer r.cancel()
	r.t.Fatalf(format, args...)
}

// WithContext returns a new Controller and a Context, which is cancelled on any
// fatal failure.
func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) {
	ctx, cancel := context.WithCancel(ctx)
	return NewController(&cancelReporter{t, cancel}), ctx
}

func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call {
	if h, ok := ctrl.t.(testHelper); ok {
		h.Helper()
	}

	recv := reflect.ValueOf(receiver)
	for i := 0; i < recv.Type().NumMethod(); i++ {
		if recv.Type().Method(i).Name == method {
			return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...)
		}
	}
	ctrl.t.Fatalf("gomock: failed finding method %s on %T", method, receiver)
	// In case t.Fatalf does not panic.
	panic(fmt.Sprintf("gomock: failed finding method %s on %T", method, receiver))
}

func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call {
	// TODO: check arity, types.
	margs := make([]Matcher, len(args))
	for i, arg := range args {
		if m, ok := arg.(Matcher); ok {
			margs[i] = m
		} else if arg == nil {
			// Handle nil specially so that passing a nil interface value
			// will match the typed nils of concrete args.
			margs[i] = Nil()
		} else {
			margs[i] = Eq(arg)
		}
	}

	ctrl.mu.Lock()
	defer ctrl.mu.Unlock()

	origin := callerInfo(2)
	call := &Call{t: ctrl.t, receiver: receiver, method: method, methodType: methodType, args: margs, origin: origin, minCalls: 1, maxCalls: 1}

	ctrl.expectedCalls.Add(call)
	return call
}

func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} {
	if h, ok := ctrl.t.(testHelper); ok {
		h.Helper()
	}

	ctrl.mu.Lock()
	defer ctrl.mu.Unlock()

	expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args)
	if err != nil {
		origin := callerInfo(2)
		ctrl.t.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err)
	}

	// Two things happen here:
	// * the matching call no longer needs to check prerequite calls,
	// * and the prerequite calls are no longer expected, so remove them.
	preReqCalls := expected.dropPrereqs()
	for _, preReqCall := range preReqCalls {
		ctrl.expectedCalls.Remove(preReqCall)
	}

	rets, action := expected.call(args)
	if expected.exhausted() {
		ctrl.expectedCalls.Remove(expected)
	}

	// Don't hold the lock while doing the call's action (if any)
	// so that actions may execute concurrently.
	// We use the deferred Unlock to capture any panics that happen above;
	// here we add a deferred Lock to balance it.
	ctrl.mu.Unlock()
	defer ctrl.mu.Lock()
	if action != nil {
		action()
	}

	return rets
}

func (ctrl *Controller) Finish() {
	if h, ok := ctrl.t.(testHelper); ok {
		h.Helper()
	}

	ctrl.mu.Lock()
	defer ctrl.mu.Unlock()

	// If we're currently panicking, probably because this is a deferred call,
	// pass through the panic.
	if err := recover(); err != nil {
		panic(err)
	}

	// Check that all remaining expected calls are satisfied.
	failures := false
	for _, methodMap := range ctrl.expectedCalls {
		for _, calls := range methodMap {
			for _, call := range calls {
				if !call.satisfied() {
					ctrl.t.Errorf("missing call(s) to %v", call)
					failures = true
				}
			}
		}
	}
	if failures {
		ctrl.t.Fatalf("aborting test due to missing call(s)")
	}
}

func callerInfo(skip int) string {
	if _, file, line, ok := runtime.Caller(skip + 1); ok {
		return fmt.Sprintf("%s:%d", file, line)
	}
	return "unknown file"
}

type testHelper interface {
	TestReporter
	Helper()
}
<commit_msg>fix backwards compatibility with golang < 1.7<commit_after>// Copyright 2010 Google 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.

// GoMock - a mock framework for Go.
//
// Standard usage:
//   (1) Define an interface that you wish to mock.
//         type MyInterface interface {
//           SomeMethod(x int64, y string)
//         }
//   (2) Use mockgen to generate a mock from the interface.
//   (3) Use the mock in a test:
//         func TestMyThing(t *testing.T) {
//           mockCtrl := gomock.NewController(t)
//           defer mockCtrl.Finish()
//
//           mockObj := something.NewMockMyInterface(mockCtrl)
//           mockObj.EXPECT().SomeMethod(4, "blah")
//           // pass mockObj to a real object and play with it.
//         }
//
// By default, expected calls are not enforced to run in any particular order.
// Call order dependency can be enforced by use of InOrder and/or Call.After.
// Call.After can create more varied call order dependencies, but InOrder is
// often more convenient.
//
// The following examples create equivalent call order dependencies.
//
// Example of using Call.After to chain expected call order:
//
//     firstCall := mockObj.EXPECT().SomeMethod(1, "first")
//     secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall)
//     mockObj.EXPECT().SomeMethod(3, "third").After(secondCall)
//
// Example of using InOrder to declare expected call order:
//
//     gomock.InOrder(
//         mockObj.EXPECT().SomeMethod(1, "first"),
//         mockObj.EXPECT().SomeMethod(2, "second"),
//         mockObj.EXPECT().SomeMethod(3, "third"),
//     )
//
// TODO:
//	- Handle different argument/return types (e.g. ..., chan, map, interface).
package gomock

import (
	"fmt"
	"golang.org/x/net/context"
	"reflect"
	"runtime"
	"sync"
)

// A TestReporter is something that can be used to report test failures.
// It is satisfied by the standard library's *testing.T.
type TestReporter interface {
	Errorf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})
}

// A Controller represents the top-level control of a mock ecosystem.
// It defines the scope and lifetime of mock objects, as well as their expectations.
// It is safe to call Controller's methods from multiple goroutines.
type Controller struct {
	mu            sync.Mutex
	t             TestReporter
	expectedCalls callSet
}

func NewController(t TestReporter) *Controller {
	return &Controller{
		t:             t,
		expectedCalls: make(callSet),
	}
}

type cancelReporter struct {
	t      TestReporter
	cancel func()
}

func (r *cancelReporter) Errorf(format string, args ...interface{}) { r.t.Errorf(format, args...) }
func (r *cancelReporter) Fatalf(format string, args ...interface{}) {
	defer r.cancel()
	r.t.Fatalf(format, args...)
}

// WithContext returns a new Controller and a Context, which is cancelled on any
// fatal failure.
func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) {
	ctx, cancel := context.WithCancel(ctx)
	return NewController(&cancelReporter{t, cancel}), ctx
}

func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call {
	if h, ok := ctrl.t.(testHelper); ok {
		h.Helper()
	}

	recv := reflect.ValueOf(receiver)
	for i := 0; i < recv.Type().NumMethod(); i++ {
		if recv.Type().Method(i).Name == method {
			return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...)
		}
	}
	ctrl.t.Fatalf("gomock: failed finding method %s on %T", method, receiver)
	// In case t.Fatalf does not panic.
	panic(fmt.Sprintf("gomock: failed finding method %s on %T", method, receiver))
}

func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call {
	// TODO: check arity, types.
	margs := make([]Matcher, len(args))
	for i, arg := range args {
		if m, ok := arg.(Matcher); ok {
			margs[i] = m
		} else if arg == nil {
			// Handle nil specially so that passing a nil interface value
			// will match the typed nils of concrete args.
			margs[i] = Nil()
		} else {
			margs[i] = Eq(arg)
		}
	}

	ctrl.mu.Lock()
	defer ctrl.mu.Unlock()

	origin := callerInfo(2)
	call := &Call{t: ctrl.t, receiver: receiver, method: method, methodType: methodType, args: margs, origin: origin, minCalls: 1, maxCalls: 1}

	ctrl.expectedCalls.Add(call)
	return call
}

func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} {
	if h, ok := ctrl.t.(testHelper); ok {
		h.Helper()
	}

	ctrl.mu.Lock()
	defer ctrl.mu.Unlock()

	expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args)
	if err != nil {
		origin := callerInfo(2)
		ctrl.t.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err)
	}

	// Two things happen here:
	// * the matching call no longer needs to check prerequite calls,
	// * and the prerequite calls are no longer expected, so remove them.
	preReqCalls := expected.dropPrereqs()
	for _, preReqCall := range preReqCalls {
		ctrl.expectedCalls.Remove(preReqCall)
	}

	rets, action := expected.call(args)
	if expected.exhausted() {
		ctrl.expectedCalls.Remove(expected)
	}

	// Don't hold the lock while doing the call's action (if any)
	// so that actions may execute concurrently.
	// We use the deferred Unlock to capture any panics that happen above;
	// here we add a deferred Lock to balance it.
	ctrl.mu.Unlock()
	defer ctrl.mu.Lock()
	if action != nil {
		action()
	}

	return rets
}

func (ctrl *Controller) Finish() {
	if h, ok := ctrl.t.(testHelper); ok {
		h.Helper()
	}

	ctrl.mu.Lock()
	defer ctrl.mu.Unlock()

	// If we're currently panicking, probably because this is a deferred call,
	// pass through the panic.
	if err := recover(); err != nil {
		panic(err)
	}

	// Check that all remaining expected calls are satisfied.
	failures := false
	for _, methodMap := range ctrl.expectedCalls {
		for _, calls := range methodMap {
			for _, call := range calls {
				if !call.satisfied() {
					ctrl.t.Errorf("missing call(s) to %v", call)
					failures = true
				}
			}
		}
	}
	if failures {
		ctrl.t.Fatalf("aborting test due to missing call(s)")
	}
}

func callerInfo(skip int) string {
	if _, file, line, ok := runtime.Caller(skip + 1); ok {
		return fmt.Sprintf("%s:%d", file, line)
	}
	return "unknown file"
}

type testHelper interface {
	TestReporter
	Helper()
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"testing"

	"google.golang.org/api/compute/v1"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccComputeImage_resolveImage(t *testing.T) {
	t.Parallel()

	var image compute.Image
	rand := acctest.RandString(10)
	name := fmt.Sprintf("test-image-%s", rand)
	fam := fmt.Sprintf("test-image-family-%s", rand)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_resolving(name, fam),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						"google_compute_image.foobar", &image),
					testAccCheckComputeImageResolution("google_compute_image.foobar"),
				),
			},
		},
	})
}

func testAccCheckComputeImageResolution(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		config := testAccProvider.Meta().(*Config)
		project := config.Project

		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Resource not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}
		if rs.Primary.Attributes["name"] == "" {
			return fmt.Errorf("No image name is set")
		}
		if rs.Primary.Attributes["family"] == "" {
			return fmt.Errorf("No image family is set")
		}
		if rs.Primary.Attributes["self_link"] == "" {
			return fmt.Errorf("No self_link is set")
		}

		name := rs.Primary.Attributes["name"]
		family := rs.Primary.Attributes["family"]
		link := rs.Primary.Attributes["self_link"]

		images := map[string]string{
			"family/debian-8":                                               "projects/debian-cloud/global/images/family/debian-8",
			"projects/debian-cloud/global/images/debian-8-jessie-v20170110": "projects/debian-cloud/global/images/debian-8-jessie-v20170110",
			"debian-8":                                                                                "projects/debian-cloud/global/images/family/debian-8",
			"debian-8-jessie-v20170110":                                                                           "projects/debian-cloud/global/images/debian-8-jessie-v20170110",
			"https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20170110": "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20170110",

			"global/images/" + name:          "global/images/" + name,
			"global/images/family/" + family: "global/images/family/" + family,
			name:                   "global/images/" + name,
			family:                 "global/images/family/" + family,
			"family/" + family:     "global/images/family/" + family,
			project + "/" + name:   "projects/" + project + "/global/images/" + name,
			project + "/" + family: "projects/" + project + "/global/images/family/" + family,
			link: link,
		}

		for input, expectation := range images {
			result, err := resolveImage(config, project, input)
			if err != nil {
				return fmt.Errorf("Error resolving input %s to image: %+v\n", input, err)
			}
			if result != expectation {
				return fmt.Errorf("Expected input '%s' to resolve to '%s', it resolved to '%s' instead.\n", input, expectation, result)
			}
		}
		return nil
	}
}

func testAccComputeImage_resolving(name, family string) string {
	return fmt.Sprintf(`
resource "google_compute_disk" "foobar" {
	name = "%s"
	zone = "us-central1-a"
	image = "debian-8-jessie-v20160803"
}
resource "google_compute_image" "foobar" {
	name = "%s"
	family = "%s"
	source_disk = "${google_compute_disk.foobar.self_link}"
}
`, name, name, family)
}
<commit_msg>Fix the last of the debian-8 updates.<commit_after>package google

import (
	"fmt"
	"testing"

	"google.golang.org/api/compute/v1"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccComputeImage_resolveImage(t *testing.T) {
	t.Parallel()

	var image compute.Image
	rand := acctest.RandString(10)
	name := fmt.Sprintf("test-image-%s", rand)
	fam := fmt.Sprintf("test-image-family-%s", rand)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckComputeImageDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccComputeImage_resolving(name, fam),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeImageExists(
						"google_compute_image.foobar", &image),
					testAccCheckComputeImageResolution("google_compute_image.foobar"),
				),
			},
		},
	})
}

func testAccCheckComputeImageResolution(n string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		config := testAccProvider.Meta().(*Config)
		project := config.Project

		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Resource not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}
		if rs.Primary.Attributes["name"] == "" {
			return fmt.Errorf("No image name is set")
		}
		if rs.Primary.Attributes["family"] == "" {
			return fmt.Errorf("No image family is set")
		}
		if rs.Primary.Attributes["self_link"] == "" {
			return fmt.Errorf("No self_link is set")
		}

		name := rs.Primary.Attributes["name"]
		family := rs.Primary.Attributes["family"]
		link := rs.Primary.Attributes["self_link"]

		latestDebian, err := config.clientCompute.Images.GetFromFamily("debian-cloud", "debian-9").Do()
		if err != nil {
			return fmt.Errorf("Error retrieving latest debian: %s", err)
		}

		images := map[string]string{
			"family/" + latestDebian.Family:                            "projects/debian-cloud/global/images/family/" + latestDebian.Family,
			"projects/debian-cloud/global/images/" + latestDebian.Name: "projects/debian-cloud/global/images/" + latestDebian.Name,
			latestDebian.Family:                                        "projects/debian-cloud/global/images/family/" + latestDebian.Family,
			latestDebian.Name:                                          "projects/debian-cloud/global/images/" + latestDebian.Name,
			latestDebian.SelfLink:                                      latestDebian.SelfLink,

			"global/images/" + name:          "global/images/" + name,
			"global/images/family/" + family: "global/images/family/" + family,
			name:                   "global/images/" + name,
			family:                 "global/images/family/" + family,
			"family/" + family:     "global/images/family/" + family,
			project + "/" + name:   "projects/" + project + "/global/images/" + name,
			project + "/" + family: "projects/" + project + "/global/images/family/" + family,
			link: link,
		}

		for input, expectation := range images {
			result, err := resolveImage(config, project, input)
			if err != nil {
				return fmt.Errorf("Error resolving input %s to image: %+v\n", input, err)
			}
			if result != expectation {
				return fmt.Errorf("Expected input '%s' to resolve to '%s', it resolved to '%s' instead.\n", input, expectation, result)
			}
		}
		return nil
	}
}

func testAccComputeImage_resolving(name, family string) string {
	return fmt.Sprintf(`
data "google_compute_image" "my_image" {
	family  = "debian-9"
	project = "debian-cloud"
}

resource "google_compute_disk" "foobar" {
	name = "%s"
	zone = "us-central1-a"
	image = "${data.google_compute_image.my_image.self_link}"
}
resource "google_compute_image" "foobar" {
	name = "%s"
	family = "%s"
	source_disk = "${google_compute_disk.foobar.self_link}"
}
`, name, name, family)
}
<|endoftext|>


<commit_before>// Copyright 2016 Stratumn SAS. All rights reserved.
// Use of this source code is governed by the license
// that can be found in the LICENSE file.
package bcbatchfossilizer

import (
	"encoding/json"
	"fmt"
	"reflect"
	"testing"
	"time"

	"github.com/stratumn/go/fossilizer"
	"github.com/stratumn/goprivate/batchfossilizer"
	"github.com/stratumn/goprivate/merkle"
	"github.com/stratumn/goprivate/testutil"
	"github.com/stratumn/goprivate/types"
)

type fossilizeTest struct {
	data       []byte
	meta       []byte
	path       merkle.Path
	sleep      time.Duration
	fossilized bool
}

func testFossilizeMultiple(t *testing.T, a *Fossilizer, tests []fossilizeTest) {
	rc := make(chan *fossilizer.Result)
	a.AddResultChan(rc)

	go func() {
		if err := a.Start(); err != nil {
			t.Error(err)
		}
	}()
	defer func() {
		if err := a.Stop(); err != nil {
			t.Error(err)
		}
		close(rc)
	}()

	for _, test := range tests {
		if err := a.Fossilize(test.data, test.meta); err != nil {
			t.Fatal(err)
		}
		if test.sleep > 0 {
			time.Sleep(test.sleep)
		}
	}

RESULT_LOOP:
	for _ = range tests {
		r := <-rc
		for i := range tests {
			test := &tests[i]
			if string(test.meta) == string(r.Meta) {
				test.fossilized = true
				if !reflect.DeepEqual(r.Data, test.data) {
					a := fmt.Sprintf("%x", r.Data)
					e := fmt.Sprintf("%x", test.data)
					t.Errorf("test#%d: Data = %q want %q", i, a, e)
				}
				evidence := r.Evidence.(map[string]*Evidence)["dummy"]
				if !reflect.DeepEqual(evidence.Path, test.path) {
					ajs, _ := json.MarshalIndent(evidence.Path, "", "  ")
					ejs, _ := json.MarshalIndent(test.path, "", "  ")
					t.Errorf("test#%d: Path = %s\nwant %s", i, ajs, ejs)
				}
				continue RESULT_LOOP
			}
		}
		a := fmt.Sprintf("%x", r.Meta)
		t.Errorf("unexpected Meta %q", a)
	}

	for i, test := range tests {
		if !test.fossilized {
			t.Errorf("test#%d: not fossilized", i)
		}
	}
}

func benchmarkFossilize(b *testing.B, config *Config, batchConfig *batchfossilizer.Config) {
	a, err := New(config, batchConfig)
	if err != nil {
		b.Fatal(err)
	}

	rc := make(chan *fossilizer.Result)
	a.AddResultChan(rc)

	go func() {
		if err := a.Start(); err != nil {
			b.Error(err)
		}
	}()

	defer func() {
		if err := a.Stop(); err != nil {
			b.Error(err)
		}
		close(rc)
	}()

	data := make([][]byte, b.N)
	for i := 0; i < b.N; i++ {
		data[i] = atos(*testutil.RandomHash())
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		if err := a.Fossilize(data[i], data[i]); err != nil {
			b.Error(err)
		}
	}

	for i := 0; i < b.N; i++ {
		<-rc
	}
}

func atos(a types.Bytes32) []byte {
	return a[:]
}
<commit_msg>bcbatchfossilizer: Tweak<commit_after>// Copyright 2016 Stratumn SAS. All rights reserved.
// Use of this source code is governed by the license
// that can be found in the LICENSE file.
package bcbatchfossilizer

import (
	"encoding/json"
	"fmt"
	"reflect"
	"testing"
	"time"

	"github.com/stratumn/go/fossilizer"
	"github.com/stratumn/goprivate/batchfossilizer"
	"github.com/stratumn/goprivate/merkle"
	"github.com/stratumn/goprivate/testutil"
	"github.com/stratumn/goprivate/types"
)

type fossilizeTest struct {
	data       []byte
	meta       []byte
	path       merkle.Path
	sleep      time.Duration
	fossilized bool
}

func testFossilizeMultiple(t *testing.T, a *Fossilizer, tests []fossilizeTest) {
	rc := make(chan *fossilizer.Result)
	a.AddResultChan(rc)

	go func() {
		if err := a.Start(); err != nil {
			t.Error(err)
		}
	}()
	defer func() {
		if err := a.Stop(); err != nil {
			t.Error(err)
		}
		close(rc)
	}()

	for _, test := range tests {
		if err := a.Fossilize(test.data, test.meta); err != nil {
			t.Fatal(err)
		}
		if test.sleep > 0 {
			time.Sleep(test.sleep)
		}
	}

RESULT_LOOP:
	for _ = range tests {
		r := <-rc
		for i := range tests {
			test := &tests[i]
			if string(test.meta) == string(r.Meta) {
				test.fossilized = true
				if !reflect.DeepEqual(r.Data, test.data) {
					a := fmt.Sprintf("%x", r.Data)
					e := fmt.Sprintf("%x", test.data)
					t.Errorf("test#%d: Data = %q want %q", i, a, e)
				}
				evidence := r.Evidence.(map[string]*Evidence)["dummy"]
				if !reflect.DeepEqual(evidence.Path, test.path) {
					ajs, _ := json.MarshalIndent(evidence.Path, "", "  ")
					ejs, _ := json.MarshalIndent(test.path, "", "  ")
					t.Errorf("test#%d: Path = %s\nwant %s", i, ajs, ejs)
				}
				continue RESULT_LOOP
			}
		}
		a := fmt.Sprintf("%x", r.Meta)
		t.Errorf("unexpected Meta %q", a)
	}

	for i, test := range tests {
		if !test.fossilized {
			t.Errorf("test#%d: not fossilized", i)
		}
	}
}

func benchmarkFossilize(b *testing.B, config *Config, batchConfig *batchfossilizer.Config) {
	a, err := New(config, batchConfig)
	if err != nil {
		b.Fatal(err)
	}

	rc := make(chan *fossilizer.Result)
	a.AddResultChan(rc)

	go func() {
		if err := a.Start(); err != nil {
			b.Error(err)
		}
	}()

	defer func() {
		if err := a.Stop(); err != nil {
			b.Error(err)
		}
		close(rc)
	}()

	data := make([][]byte, b.N)
	for i := 0; i < b.N; i++ {
		data[i] = atos(*testutil.RandomHash())
	}

	b.ResetTimer()

	go func() {
		for i := 0; i < b.N; i++ {
			if err := a.Fossilize(data[i], data[i]); err != nil {
				b.Error(err)
			}
		}
	}()

	for i := 0; i < b.N; i++ {
		<-rc
	}
}

func atos(a types.Bytes32) []byte {
	return a[:]
}
<|endoftext|>


<commit_before>package kegg

import (
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"image"
	"image/png"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/fjukstad/gocache"
	"github.com/fjukstad/gographer"
)

type Pathway struct {
	Id          string
	Name        string
	Class       string
	Pathway_Map string
	Diseases    []string
	Drugs       []string
	DBLinks     []string
	Organism    string
	Genes       []string
	Compounds   []string
}

type KeggPathway struct {
	XMLName   xml.Name       `xml:"pathway"`
	Name      string         `xml:"name,attr"`
	Org       string         `xml:"org,attr"`
	Number    string         `xml:"number,attr"`
	Title     string         `xml:"title,attr"`
	Image     string         `xml:"image,attr"`
	Link      string         `xml:"link,attr"`
	Entries   []KeggEntry    `xml:"entry"`
	Relations []KeggRelation `xml:"relation"`
}

type KeggEntry struct {
	Id       string       `xml:"id,attr"`
	Name     string       `xml:"name,attr"`
	Type     string       `xml:"type,attr"`
	Link     string       `xml:"link,attr"`
	Graphics KeggGraphics `xml:"graphics"`
}

type KeggRelation struct {
	Entry1   string        `xml:"entry1,attr"`
	Entry2   string        `xml:"entry2,attr"`
	Type     string        `xml:"type,attr"`
	Subtypes []KeggSubtype `xml:"relation>subtype"`
}

type KeggGraphics struct {
	Name    string `xml:"name,attr"`
	Fgcolor string `xml:"fgcolor,attr"`
	Bgcolor string `xml:"bgcolor,attr"`
	Type    string `xml:"type,attr"`
	X       string `xml:"x,attr"`
	Y       string `xml:"y,attr"`
	Width   string `xml:"width,attr"`
	Height  string `xml:"height,attr"`
}

type KeggSubtype struct {
	Name  string `xml:"name,attr"`
	Value string `xml:"value,attr"`
}

func GetAllHumanPathways() []string {

	res := make([]string, 0)

	url := "http://rest.kegg.jp/list/pathway/hsa"
	resp, err := http.Get(url)
	if err != nil {
		log.Panic("Could not fetch pathway list", err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Panic("Could not read body of pathway list response", err)
	}

	lines := strings.Split(string(body), "\n")
	for i := range lines {
		line := lines[i]
		id := strings.Split(line, "\t")[0]
		pathid := strings.Split(id, ":")

		// empty line
		if len(pathid) < 2 {
			continue
		}

		pwid := pathid[1]
		res = append(res, pwid)

	}

	// sort list of pathways
	res = SortPathwayIds(res)
	return res

}

type ByName []Pathway

func (a ByName) Len() int {
	return len(a)
}
func (a ByName) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a ByName) Less(i, j int) bool {
	return a[i].Name < a[j].Name
}

func SortPathwayIds(ids []string) []string {
	pws := make([]Pathway, 0)
	for _, id := range ids {
		pws = append(pws, GetPathway(id))
	}

	sort.Sort(ByName(pws))

	pwids := make([]string, 0)
	for _, pw := range pws {
		pwids = append(pwids, pw.Id)
	}

	return pwids

}

func ReadablePathwayNames(ids []string) []string {

	pathways := make([]string, len(ids))

	for i, id := range ids {
		pathways[i] = ReadablePathwayName(id)
	}

	return pathways

}

func ReadablePathwayName(id string) string {
	//
	name := GetPathway(id).Name
	shortName := strings.Trim(strings.SplitAfter(name, " - ")[0], " - ")

	return shortName
}

func getMap(url string) []byte {
	response, err := gocache.Get(url)
	if err != nil {
		log.Panic("Could not download pathway kgml:", err)
	}
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Panic("KGML body could not be read:", err)
	}
	return body
}

func (pathway *KeggPathway) Print() {
	log.Println("XMLName:", pathway.XMLName)
	log.Println("Name:", pathway.Name)
	log.Println("Org:", pathway.Org)
	log.Println("Title:", pathway.Title)
	log.Println("Image:", pathway.Image)
	log.Println("Link", pathway.Link)
	log.Println("Entries:", pathway.Entries)
	log.Println("Relations:", pathway.Relations)
}

func NewKeggPathway(keggId string) *KeggPathway {

	baseURL := "http://rest.kegg.jp/get/" + keggId
	url := baseURL + "/kgml"

	// url := "http://localhost:8000/public/pathway.kgml"
	pw := getMap(url)

	pathway := new(KeggPathway)
	err := xml.Unmarshal(pw, pathway)

	if err != nil {
		log.Panic("Could not unmarshal KGML ", err)
	}

	return pathway

}

func createPathwayGraph(keggId string, inputGraph *gographer.Graph) {

	baseURL := "http://rest.kegg.jp/get/" + keggId
	url := baseURL + "/kgml"

	// url := "http://localhost:8000/public/pathway.kgml"
	pw := getMap(url)

	pathway := new(KeggPathway)
	err := xml.Unmarshal(pw, pathway)

	if err != nil {
		log.Panic("Could not unmarshal KGML ", err)
	}

	imgurl := "http://www.genome.jp/kegg/pathway/hsa/" + keggId + ".png"

	log.Print("downloading image...")
	resp, err := http.Get(imgurl)
	if err != nil {
		log.Panic("Image could not be downloaded ", err)
	}

	log.Print("image downloaded....")
	img, err := png.Decode(resp.Body)

	if err != nil {
		log.Panic("Image could not be decoded ", err)
	}

	imgrect := img.Bounds()

	sizeX := imgrect.Max.X - imgrect.Min.X
	sizeY := imgrect.Max.Y - imgrect.Min.Y

	log.Print("Image is : ", sizeX, sizeY)

	// Store image for later use
	path := "public/pathways"
	filename := keggId + ".png"
	storeImage(path, filename, img)

	// First create a node that will serve as a background image to the pathway
	inputGraph.AddGraphicNode(
		0,
		"bg",
		0,
		1,
		imgurl,
		"#fff",
		"#fff",
		"rectangle",
		sizeX/2,
		sizeY/2,
		sizeY,
		sizeX)

	// Generate some nodes
	for j := range pathway.Entries {
		ent := pathway.Entries[j]
		id, _ := strconv.Atoi(ent.Id)
		name := ent.Name
		t, _ := strconv.Atoi(ent.Type)
		size := 1
		graphics := ent.Graphics

		// Trimming away :title for the node containing the pathway name
		description := strings.TrimPrefix(strings.Split(graphics.Name, ",")[0], "TITLE:")
		log.Println("description", description)
		fgcolor := graphics.Fgcolor
		bgcolor := graphics.Bgcolor
		shape := graphics.Type
		x, _ := strconv.Atoi(graphics.X)
		y, _ := strconv.Atoi(graphics.Y)
		height, _ := strconv.Atoi(graphics.Height)
		width, _ := strconv.Atoi(graphics.Width)

		inputGraph.AddGraphicNode(id, name, t, size, description, fgcolor, bgcolor, shape,
			x, y, height, width)
	}

	// Generate some edges
	for i := range pathway.Relations {
		rel := pathway.Relations[i]
		source, _ := strconv.Atoi(rel.Entry1)
		target, _ := strconv.Atoi(rel.Entry2)
		weight := 19
		inputGraph.AddEdge(source, target, i, weight)
	}

	return
}

func storeImage(path, filename string, image image.Image) error {

	err := os.MkdirAll(path, 0755)
	if err != nil {
		return err
	}

	fn := path + "/" + filename
	file, err := os.Create(fn)
	if err != nil {
		return err
	}

	return png.Encode(file, image)

}

func GetPathway(id string) Pathway {
	baseURL := "http://rest.kegg.jp/get/"
	url := baseURL + id

	log.Print(url)

	response, err := gocache.Get(url)
	if err != nil {
		log.Panic("Cannot download pathway:", err)
	}

	pathway := parsePathwayResponse(response.Body)

	return pathway

}

func (p Pathway) Print() {
	fmt.Println("\nPathway")
	fmt.Println("\tId:", p.Id)
	fmt.Println("\tName:", p.Name)
	fmt.Println("\tClass:", p.Class)
	fmt.Println("\tPathway map:", p.Pathway_Map)
	fmt.Println("\tDiseases:", p.Diseases)
	fmt.Println("\tDrugs:", p.Drugs)
	fmt.Println("\tOrganism:", p.Organism)
	fmt.Println("\tGenes:", p.Genes)
	fmt.Println("\tCompounds:", p.Compounds)
	fmt.Println("")
}

func GiveMeSomePathways() []string {
	pw := []string{
		"hsa05200",
		"hsa04915",
		"hsa04612",
		"hsa04062",
		"hsa04660",
		"hsa04630",
		"hsa04151",
		"hsa04310",
		"hsa04662",
	}
	return pw
}

func PathwayGraphFrom(pathway string) string {
	//pw := GetPathway(pathway)

	// Set up graph
	port := getRandomPort()
	graph := gographer.NewGraphAt(":" + strconv.Itoa(port))

	// Create a graph from pathways. Will add nodes and
	// edges and all that jazz
	createPathwayGraph(pathway, graph)

	// Return address where client can retrieve graph
	// TODO: maybe the graph initialization (after wsserver setup)
	// can be done in a go routine?

	return graph.ServerInfo()
}

// TODO: Should store ports used for visualization gateways

func getRandomPort() int {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	return 1024 + r.Intn(45000)
}

func parsePathwayResponse(response io.ReadCloser) Pathway {

	tsv := csv.NewReader(response)
	tsv.Comma = '\t'
	tsv.Comment = '#'
	tsv.LazyQuotes = true
	tsv.TrailingComma = true
	tsv.TrimLeadingSpace = false

	records, err := tsv.ReadAll()

	if err != nil {
		log.Panic("Error reading records:", err)
	}

	p := Pathway{}
	tmp := make([]string, 0)
	current := ""
	for i := range records {

		line := strings.Split(records[i][0], " ")

		switch line[0] {
		case "ENTRY":
			a := strings.Join(line[7:], " ")
			b := strings.Split(a, " ")[0]
			p.Id = b

		case "NAME":
			p.Name = strings.Join(line[8:], " ")

		case "CLASS":
			p.Class = strings.Join(line[8:], " ")

		case "PATHWAY_MAP":
			p.Pathway_Map = strings.Join(line[1:], " ")

		case "DISEASE":
			current = "DISEASE"

			a := strings.Join(line[5:], " ")
			tmp = append(tmp, a)

		case "DBLINKS":
			p.Diseases = tmp
			current = "DBLINKS"

			a := strings.Join(line[5:], " ")
			tmp = make([]string, 0)
			tmp = append(tmp, a)

		case "DRUG":
			p.Diseases = tmp
			tmp = make([]string, 0)
			current = "DRUG"
			a := strings.Join(line[8:], " ")
			tmp = append(tmp, a)

		case "ORGANISM":
			if current == "DISEASE" {
				p.Drugs = tmp
			}
			if current == "DBLINKS" {
				p.DBLinks = tmp
			}
			current = "ORGANISM"
			p.Organism = strings.Join(line[4:], " ")

		case "GENE":
			current = "GENE"
			tmp = make([]string, 0)
			a := strings.Join(line[8:], " ")
			b := strings.Split(a, " ")[0]
			tmp = append(tmp, b)

		case "COMPOUND":
			p.Genes = tmp
			current = "COMPOUND"
			tmp = make([]string, 0)
			a := strings.Join(line[4:], " ")

			tmp = append(tmp, a)

		case "REFERENCE":
			p.Compounds = tmp
			current = "REFERENCE"
			break

		default:
			if current == "DISEASE" {
				a := strings.Join(line[12:], " ")
				tmp = append(tmp, a)
			}
			if current == "DRUG" {
				a := strings.Join(line[0:], " ")
				b := strings.Replace(a, "    ", "", -1)
				tmp = append(tmp, b)
			}
			if current == "GENE" {
				a := strings.Join(line[0:], " ")
				a = strings.Replace(a, "    ", "", -1)
				b := strings.Split(a, " ")[0]
				tmp = append(tmp, b)

			}
			if current == "COMPOUND" {
				a := strings.Join(line[0:], " ")
				a = strings.Replace(a, "    ", "", -1)

				tmp = append(tmp, a)

			}

		}
	}
	return p

}
<commit_msg>now storing images to webapp dir<commit_after>package kegg

import (
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"image"
	"image/png"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/fjukstad/gocache"
	"github.com/fjukstad/gographer"
)

type Pathway struct {
	Id          string
	Name        string
	Class       string
	Pathway_Map string
	Diseases    []string
	Drugs       []string
	DBLinks     []string
	Organism    string
	Genes       []string
	Compounds   []string
}

type KeggPathway struct {
	XMLName   xml.Name       `xml:"pathway"`
	Name      string         `xml:"name,attr"`
	Org       string         `xml:"org,attr"`
	Number    string         `xml:"number,attr"`
	Title     string         `xml:"title,attr"`
	Image     string         `xml:"image,attr"`
	Link      string         `xml:"link,attr"`
	Entries   []KeggEntry    `xml:"entry"`
	Relations []KeggRelation `xml:"relation"`
}

type KeggEntry struct {
	Id       string       `xml:"id,attr"`
	Name     string       `xml:"name,attr"`
	Type     string       `xml:"type,attr"`
	Link     string       `xml:"link,attr"`
	Graphics KeggGraphics `xml:"graphics"`
}

type KeggRelation struct {
	Entry1   string        `xml:"entry1,attr"`
	Entry2   string        `xml:"entry2,attr"`
	Type     string        `xml:"type,attr"`
	Subtypes []KeggSubtype `xml:"relation>subtype"`
}

type KeggGraphics struct {
	Name    string `xml:"name,attr"`
	Fgcolor string `xml:"fgcolor,attr"`
	Bgcolor string `xml:"bgcolor,attr"`
	Type    string `xml:"type,attr"`
	X       string `xml:"x,attr"`
	Y       string `xml:"y,attr"`
	Width   string `xml:"width,attr"`
	Height  string `xml:"height,attr"`
}

type KeggSubtype struct {
	Name  string `xml:"name,attr"`
	Value string `xml:"value,attr"`
}

func GetAllHumanPathways() []string {

	res := make([]string, 0)

	url := "http://rest.kegg.jp/list/pathway/hsa"
	resp, err := http.Get(url)
	if err != nil {
		log.Panic("Could not fetch pathway list", err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Panic("Could not read body of pathway list response", err)
	}

	lines := strings.Split(string(body), "\n")
	for i := range lines {
		line := lines[i]
		id := strings.Split(line, "\t")[0]
		pathid := strings.Split(id, ":")

		// empty line
		if len(pathid) < 2 {
			continue
		}

		pwid := pathid[1]
		res = append(res, pwid)

	}

	// sort list of pathways
	res = SortPathwayIds(res)
	return res

}

type ByName []Pathway

func (a ByName) Len() int {
	return len(a)
}
func (a ByName) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a ByName) Less(i, j int) bool {
	return a[i].Name < a[j].Name
}

func SortPathwayIds(ids []string) []string {
	pws := make([]Pathway, 0)
	for _, id := range ids {
		pws = append(pws, GetPathway(id))
	}

	sort.Sort(ByName(pws))

	pwids := make([]string, 0)
	for _, pw := range pws {
		pwids = append(pwids, pw.Id)
	}

	return pwids

}

func ReadablePathwayNames(ids []string) []string {

	pathways := make([]string, len(ids))

	for i, id := range ids {
		pathways[i] = ReadablePathwayName(id)
	}

	return pathways

}

func ReadablePathwayName(id string) string {
	//
	name := GetPathway(id).Name
	shortName := strings.Trim(strings.SplitAfter(name, " - ")[0], " - ")

	return shortName
}

func getMap(url string) []byte {
	response, err := gocache.Get(url)
	if err != nil {
		log.Panic("Could not download pathway kgml:", err)
	}
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Panic("KGML body could not be read:", err)
	}
	return body
}

func (pathway *KeggPathway) Print() {
	log.Println("XMLName:", pathway.XMLName)
	log.Println("Name:", pathway.Name)
	log.Println("Org:", pathway.Org)
	log.Println("Title:", pathway.Title)
	log.Println("Image:", pathway.Image)
	log.Println("Link", pathway.Link)
	log.Println("Entries:", pathway.Entries)
	log.Println("Relations:", pathway.Relations)
}

func NewKeggPathway(keggId string) *KeggPathway {

	baseURL := "http://rest.kegg.jp/get/" + keggId
	url := baseURL + "/kgml"

	// url := "http://localhost:8000/public/pathway.kgml"
	pw := getMap(url)

	pathway := new(KeggPathway)
	err := xml.Unmarshal(pw, pathway)

	if err != nil {
		log.Panic("Could not unmarshal KGML ", err)
	}

	return pathway

}

func createPathwayGraph(keggId string, inputGraph *gographer.Graph) {

	baseURL := "http://rest.kegg.jp/get/" + keggId
	url := baseURL + "/kgml"

	// url := "http://localhost:8000/public/pathway.kgml"
	pw := getMap(url)

	pathway := new(KeggPathway)
	err := xml.Unmarshal(pw, pathway)

	if err != nil {
		log.Panic("Could not unmarshal KGML ", err)
	}

	imgurl := "http://www.genome.jp/kegg/pathway/hsa/" + keggId + ".png"

	log.Print("downloading image...")
	resp, err := http.Get(imgurl)
	if err != nil {
		log.Panic("Image could not be downloaded ", err)
	}

	log.Print("image downloaded....")
	img, err := png.Decode(resp.Body)

	if err != nil {
		log.Panic("Image could not be decoded ", err)
	}

	imgrect := img.Bounds()

	sizeX := imgrect.Max.X - imgrect.Min.X
	sizeY := imgrect.Max.Y - imgrect.Min.Y

	log.Print("Image is : ", sizeX, sizeY)

	// Store image for later use
	path := "../webapp/public/pathways"
	filename := keggId + ".png"
	err = storeImage(path, filename, img)
	if err != nil {
		log.Panic("Image could not be stored", err)
	}

	// First create a node that will serve as a background image to the pathway
	inputGraph.AddGraphicNode(
		0,
		"bg",
		0,
		1,
		imgurl,
		"#fff",
		"#fff",
		"rectangle",
		sizeX/2,
		sizeY/2,
		sizeY,
		sizeX)

	// Generate some nodes
	for j := range pathway.Entries {
		ent := pathway.Entries[j]
		id, _ := strconv.Atoi(ent.Id)
		name := ent.Name
		t, _ := strconv.Atoi(ent.Type)
		size := 1
		graphics := ent.Graphics

		// Trimming away :title for the node containing the pathway name
		description := strings.TrimPrefix(strings.Split(graphics.Name, ",")[0], "TITLE:")
		log.Println("description", description)
		fgcolor := graphics.Fgcolor
		bgcolor := graphics.Bgcolor
		shape := graphics.Type
		x, _ := strconv.Atoi(graphics.X)
		y, _ := strconv.Atoi(graphics.Y)
		height, _ := strconv.Atoi(graphics.Height)
		width, _ := strconv.Atoi(graphics.Width)

		inputGraph.AddGraphicNode(id, name, t, size, description, fgcolor, bgcolor, shape,
			x, y, height, width)
	}

	// Generate some edges
	for i := range pathway.Relations {
		rel := pathway.Relations[i]
		source, _ := strconv.Atoi(rel.Entry1)
		target, _ := strconv.Atoi(rel.Entry2)
		weight := 19
		inputGraph.AddEdge(source, target, i, weight)
	}

	return
}

func storeImage(path, filename string, image image.Image) error {

	err := os.MkdirAll(path, 0755)
	if err != nil {
		return err
	}

	fn := path + "/" + filename
	file, err := os.Create(fn)
	if err != nil {
		return err
	}

	return png.Encode(file, image)

}

func GetPathway(id string) Pathway {
	baseURL := "http://rest.kegg.jp/get/"
	url := baseURL + id

	log.Print(url)

	response, err := gocache.Get(url)
	if err != nil {
		log.Panic("Cannot download pathway:", err)
	}

	pathway := parsePathwayResponse(response.Body)

	return pathway

}

func (p Pathway) Print() {
	fmt.Println("\nPathway")
	fmt.Println("\tId:", p.Id)
	fmt.Println("\tName:", p.Name)
	fmt.Println("\tClass:", p.Class)
	fmt.Println("\tPathway map:", p.Pathway_Map)
	fmt.Println("\tDiseases:", p.Diseases)
	fmt.Println("\tDrugs:", p.Drugs)
	fmt.Println("\tOrganism:", p.Organism)
	fmt.Println("\tGenes:", p.Genes)
	fmt.Println("\tCompounds:", p.Compounds)
	fmt.Println("")
}

func GiveMeSomePathways() []string {
	pw := []string{
		"hsa05200",
		"hsa04915",
		"hsa04612",
		"hsa04062",
		"hsa04660",
		"hsa04630",
		"hsa04151",
		"hsa04310",
		"hsa04662",
	}
	return pw
}

func PathwayGraphFrom(pathway string) string {
	//pw := GetPathway(pathway)

	// Set up graph
	port := getRandomPort()
	graph := gographer.NewGraphAt(":" + strconv.Itoa(port))

	// Create a graph from pathways. Will add nodes and
	// edges and all that jazz
	createPathwayGraph(pathway, graph)

	// Return address where client can retrieve graph
	// TODO: maybe the graph initialization (after wsserver setup)
	// can be done in a go routine?

	return graph.ServerInfo()
}

// TODO: Should store ports used for visualization gateways

func getRandomPort() int {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	return 1024 + r.Intn(45000)
}

func parsePathwayResponse(response io.ReadCloser) Pathway {

	tsv := csv.NewReader(response)
	tsv.Comma = '\t'
	tsv.Comment = '#'
	tsv.LazyQuotes = true
	tsv.TrailingComma = true
	tsv.TrimLeadingSpace = false

	records, err := tsv.ReadAll()

	if err != nil {
		log.Panic("Error reading records:", err)
	}

	p := Pathway{}
	tmp := make([]string, 0)
	current := ""
	for i := range records {

		line := strings.Split(records[i][0], " ")

		switch line[0] {
		case "ENTRY":
			a := strings.Join(line[7:], " ")
			b := strings.Split(a, " ")[0]
			p.Id = b

		case "NAME":
			p.Name = strings.Join(line[8:], " ")

		case "CLASS":
			p.Class = strings.Join(line[8:], " ")

		case "PATHWAY_MAP":
			p.Pathway_Map = strings.Join(line[1:], " ")

		case "DISEASE":
			current = "DISEASE"

			a := strings.Join(line[5:], " ")
			tmp = append(tmp, a)

		case "DBLINKS":
			p.Diseases = tmp
			current = "DBLINKS"

			a := strings.Join(line[5:], " ")
			tmp = make([]string, 0)
			tmp = append(tmp, a)

		case "DRUG":
			p.Diseases = tmp
			tmp = make([]string, 0)
			current = "DRUG"
			a := strings.Join(line[8:], " ")
			tmp = append(tmp, a)

		case "ORGANISM":
			if current == "DISEASE" {
				p.Drugs = tmp
			}
			if current == "DBLINKS" {
				p.DBLinks = tmp
			}
			current = "ORGANISM"
			p.Organism = strings.Join(line[4:], " ")

		case "GENE":
			current = "GENE"
			tmp = make([]string, 0)
			a := strings.Join(line[8:], " ")
			b := strings.Split(a, " ")[0]
			tmp = append(tmp, b)

		case "COMPOUND":
			p.Genes = tmp
			current = "COMPOUND"
			tmp = make([]string, 0)
			a := strings.Join(line[4:], " ")

			tmp = append(tmp, a)

		case "REFERENCE":
			p.Compounds = tmp
			current = "REFERENCE"
			break

		default:
			if current == "DISEASE" {
				a := strings.Join(line[12:], " ")
				tmp = append(tmp, a)
			}
			if current == "DRUG" {
				a := strings.Join(line[0:], " ")
				b := strings.Replace(a, "    ", "", -1)
				tmp = append(tmp, b)
			}
			if current == "GENE" {
				a := strings.Join(line[0:], " ")
				a = strings.Replace(a, "    ", "", -1)
				b := strings.Split(a, " ")[0]
				tmp = append(tmp, b)

			}
			if current == "COMPOUND" {
				a := strings.Join(line[0:], " ")
				a = strings.Replace(a, "    ", "", -1)

				tmp = append(tmp, a)

			}

		}
	}
	return p

}
<|endoftext|>


<commit_before>package spinner

const (
	clockOneOClock = '\U0001F550'
	clockOneThirty = '\U0001F55C'
)

// CharSets contains the available character sets
var CharSets = map[int][]string{
	0:  {"←", "↖", "↑", "↗", "→", "↘", "↓", "↙"},
	1:  {"▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▁"},
	2:  {"▖", "▘", "▝", "▗"},
	3:  {"┤", "┘", "┴", "└", "├", "┌", "┬", "┐"},
	4:  {"◢", "◣", "◤", "◥"},
	5:  {"◰", "◳", "◲", "◱"},
	6:  {"◴", "◷", "◶", "◵"},
	7:  {"◐", "◓", "◑", "◒"},
	8:  {".", "o", "O", "@", "*"},
	9:  {"|", "/", "-", "\\"},
	10: {"◡◡", "⊙⊙", "◠◠"},
	11: {"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"},
	12: {">))'>", " >))'>", "  >))'>", "   >))'>", "    >))'>", "   <'((<", "  <'((<", " <'((<"},
	13: {"⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"},
	14: {"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
	15: {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"},
	16: {"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"},
	17: {"■", "□", "▪", "▫"},
	18: {"←", "↑", "→", "↓"},
	19: {"╫", "╪"},
	20: {"⇐", "⇖", "⇑", "⇗", "⇒", "⇘", "⇓", "⇙"},
	21: {"⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈", "⠈"},
	22: {"⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "⠦", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈"},
	23: {"⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠴", "⠲", "⠒", "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁"},
	24: {"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋"},
	25: {"ｦ", "ｧ", "ｨ", "ｩ", "ｪ", "ｫ", "ｬ", "ｭ", "ｮ", "ｯ", "ｱ", "ｲ", "ｳ", "ｴ", "ｵ", "ｶ", "ｷ", "ｸ", "ｹ", "ｺ", "ｻ", "ｼ", "ｽ", "ｾ", "ｿ", "ﾀ", "ﾁ", "ﾂ", "ﾃ", "ﾄ", "ﾅ", "ﾆ", "ﾇ", "ﾈ", "ﾉ", "ﾊ", "ﾋ", "ﾌ", "ﾍ", "ﾎ", "ﾏ", "ﾐ", "ﾑ", "ﾒ", "ﾓ", "ﾔ", "ﾕ", "ﾖ", "ﾗ", "ﾘ", "ﾙ", "ﾚ", "ﾛ", "ﾜ", "ﾝ"},
	26: {".", "..", "..."},
	27: {"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"},
	28: {".", "o", "O", "°", "O", "o", "."},
	29: {"+", "x"},
	30: {"v", "<", "^", ">"},
	31: {">>--->", " >>--->", "  >>--->", "   >>--->", "    >>--->", "    <---<<", "   <---<<", "  <---<<", " <---<<", "<---<<"},
	32: {"|", "||", "|||", "||||", "|||||", "|||||||", "||||||||", "|||||||", "||||||", "|||||", "||||", "|||", "||", "|"},
	33: {"[          ]", "[=         ]", "[==        ]", "[===       ]", "[====      ]", "[=====     ]", "[======    ]", "[=======   ]", "[========  ]", "[========= ]", "[==========]"},
	34: {"(*---------)", "(-*--------)", "(--*-------)", "(---*------)", "(----*-----)", "(-----*----)", "(------*---)", "(-------*--)", "(--------*-)", "(---------*)"},
	35: {"█▒▒▒▒▒▒▒▒▒", "███▒▒▒▒▒▒▒", "█████▒▒▒▒▒", "███████▒▒▒", "██████████"},
	36: {"[                    ]", "[=>                  ]", "[===>                ]", "[=====>              ]", "[======>             ]", "[========>           ]", "[==========>         ]", "[============>       ]", "[==============>     ]", "[================>   ]", "[==================> ]", "[===================>]"},
	39: {"🌍", "🌎", "🌏"},
	40: {"◜", "◝", "◞", "◟"},
	41: {"⬒", "⬔", "⬓", "⬕"},
	42: {"⬖", "⬘", "⬗", "⬙"},
	43: {"[>>>          >]", "[]>>>>        []", "[]  >>>>      []", "[]    >>>>    []", "[]      >>>>  []", "[]        >>>>[]", "[>>          >>]"},
	44: {"♠", "♣", "♥", "♦"},
	45: {"➞", "➟", "➠", "➡", "➠", "➟"},
}

func init() {
	for i := rune(0); i < 12; i++ {
		CharSets[37] = append(CharSets[37], string([]rune{clockOneOClock + i}))
		CharSets[38] = append(CharSets[38], string([]rune{clockOneOClock + i}), string([]rune{clockOneThirty + i}))
	}
}
<commit_msg>add new indicators<commit_after>package spinner

const (
	clockOneOClock = '\U0001F550'
	clockOneThirty = '\U0001F55C'
)

// CharSets contains the available character sets
var CharSets = map[int][]string{
	0:  {"←", "↖", "↑", "↗", "→", "↘", "↓", "↙"},
	1:  {"▁", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▁"},
	2:  {"▖", "▘", "▝", "▗"},
	3:  {"┤", "┘", "┴", "└", "├", "┌", "┬", "┐"},
	4:  {"◢", "◣", "◤", "◥"},
	5:  {"◰", "◳", "◲", "◱"},
	6:  {"◴", "◷", "◶", "◵"},
	7:  {"◐", "◓", "◑", "◒"},
	8:  {".", "o", "O", "@", "*"},
	9:  {"|", "/", "-", "\\"},
	10: {"◡◡", "⊙⊙", "◠◠"},
	11: {"⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"},
	12: {">))'>", " >))'>", "  >))'>", "   >))'>", "    >))'>", "   <'((<", "  <'((<", " <'((<"},
	13: {"⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"},
	14: {"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
	15: {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"},
	16: {"▉", "▊", "▋", "▌", "▍", "▎", "▏", "▎", "▍", "▌", "▋", "▊", "▉"},
	17: {"■", "□", "▪", "▫"},
	18: {"←", "↑", "→", "↓"},
	19: {"╫", "╪"},
	20: {"⇐", "⇖", "⇑", "⇗", "⇒", "⇘", "⇓", "⇙"},
	21: {"⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈", "⠈"},
	22: {"⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "⠦", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈"},
	23: {"⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠴", "⠲", "⠒", "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁"},
	24: {"⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋"},
	25: {"ｦ", "ｧ", "ｨ", "ｩ", "ｪ", "ｫ", "ｬ", "ｭ", "ｮ", "ｯ", "ｱ", "ｲ", "ｳ", "ｴ", "ｵ", "ｶ", "ｷ", "ｸ", "ｹ", "ｺ", "ｻ", "ｼ", "ｽ", "ｾ", "ｿ", "ﾀ", "ﾁ", "ﾂ", "ﾃ", "ﾄ", "ﾅ", "ﾆ", "ﾇ", "ﾈ", "ﾉ", "ﾊ", "ﾋ", "ﾌ", "ﾍ", "ﾎ", "ﾏ", "ﾐ", "ﾑ", "ﾒ", "ﾓ", "ﾔ", "ﾕ", "ﾖ", "ﾗ", "ﾘ", "ﾙ", "ﾚ", "ﾛ", "ﾜ", "ﾝ"},
	26: {".", "..", "..."},
	27: {"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"},
	28: {".", "o", "O", "°", "O", "o", "."},
	29: {"+", "x"},
	30: {"v", "<", "^", ">"},
	31: {">>--->", " >>--->", "  >>--->", "   >>--->", "    >>--->", "    <---<<", "   <---<<", "  <---<<", " <---<<", "<---<<"},
	32: {"|", "||", "|||", "||||", "|||||", "|||||||", "||||||||", "|||||||", "||||||", "|||||", "||||", "|||", "||", "|"},
	33: {"[          ]", "[=         ]", "[==        ]", "[===       ]", "[====      ]", "[=====     ]", "[======    ]", "[=======   ]", "[========  ]", "[========= ]", "[==========]"},
	34: {"(*---------)", "(-*--------)", "(--*-------)", "(---*------)", "(----*-----)", "(-----*----)", "(------*---)", "(-------*--)", "(--------*-)", "(---------*)"},
	35: {"█▒▒▒▒▒▒▒▒▒", "███▒▒▒▒▒▒▒", "█████▒▒▒▒▒", "███████▒▒▒", "██████████"},
	36: {"[                    ]", "[=>                  ]", "[===>                ]", "[=====>              ]", "[======>             ]", "[========>           ]", "[==========>         ]", "[============>       ]", "[==============>     ]", "[================>   ]", "[==================> ]", "[===================>]"},
	39: {"🌍", "🌎", "🌏"},
	40: {"◜", "◝", "◞", "◟"},
	41: {"⬒", "⬔", "⬓", "⬕"},
	42: {"⬖", "⬘", "⬗", "⬙"},
	43: {"[>>>          >]", "[]>>>>        []", "[]  >>>>      []", "[]    >>>>    []", "[]      >>>>  []", "[]        >>>>[]", "[>>          >>]"},
	44: {"♠", "♣", "♥", "♦"},
	45: {"➞", "➟", "➠", "➡", "➠", "➟"},
	46: {"  |  ", ` \   `, "_    ", ` \   `, "  |  ", "   / ", "    _", "   / "},
	47: {"  . . . .", ".   . . .", ". .   . .", ". . .   .", ". . . .  ", ". . . . ."},
	48: {" |     ", "  /    ", "   _   ", `    \  `, "     | ", `    \  `, "   _   ", "  /    "},
}

func init() {
	for i := rune(0); i < 12; i++ {
		CharSets[37] = append(CharSets[37], string([]rune{clockOneOClock + i}))
		CharSets[38] = append(CharSets[38], string([]rune{clockOneOClock + i}), string([]rune{clockOneThirty + i}))
	}
}
<|endoftext|>


<commit_before>// +build integration

package elasticsearch_test

import (
	"flag"
	"fmt"
	"net/http"
	"strings"
	"testing"
	"time"

	"github.com/digitalocean/vulcan/bus"
	oldes "github.com/digitalocean/vulcan/elasticsearch"
	"github.com/digitalocean/vulcan/storage"
	"github.com/digitalocean/vulcan/storage/elasticsearch"
	"github.com/olivere/elastic"
)

var es = flag.String("es", "http://localhost:9200", "elasticsearch url")

const matchAll = `{
  "template": "*",
  "order": 0,
  "settings": {
    "index": {
      "refresh_interval": "1s"
    }
  },
  "mappings": {
    "_default_": {
      "dynamic_templates": [
        {
          "string_fields": {
            "mapping": {
              "fields": {
                "raw": {
                  "ignore_above": 256,
                  "doc_values": true,
                  "index": "not_analyzed",
                  "type": "string"
                }
              },
              "omit_norms": true,
              "index": "analyzed",
              "type": "string"
            },
            "match_mapping_type": "string",
            "match": "*"
          }
        }
      ],
      "_all": {
        "omit_norms": true,
        "enabled": true
      }
    }
  }
}`

func down() error {
	err := downTemplate()
	if err != nil {
		return err
	}
	err = downIndex()
	return err
}

func downTemplate() error {
	req, err := http.NewRequest("DELETE", fmt.Sprintf("%s/_template/match_all_0", *es), nil)
	if err != nil {
		return err
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

func downIndex() error {
	req, err := http.NewRequest("DELETE", fmt.Sprintf("%s/vulcan-integration", *es), nil)
	if err != nil {
		return err
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

func up() error {
	err := upTemplate()
	if err != nil {
		return err
	}
	err = upEntries()
	return err
}

func upTemplate() error {
	url := fmt.Sprintf("%s/_template/match_all_0", *es)
	resp, err := http.DefaultClient.Post(url, "text/json", strings.NewReader(matchAll))
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

func upEntries() error {
	client, err := elastic.NewClient(elastic.SetURL(*es), elastic.SetSniff(false))
	if err != nil {
		return err
	}
	exists := []struct {
		Name   string
		Labels map[string]string
	}{
		{
			Name: "metric_1",
			Labels: map[string]string{
				"l": "value-one",
			},
		},
		{
			Name: "metric_1",
			Labels: map[string]string{
				"l":     "value-one",
				"other": "value",
			},
		},
		{
			Name: "metric_1",
			Labels: map[string]string{
				"l": "value-two",
			},
		},
		{
			Name: "metric_1",
			Labels: map[string]string{
				"l": "value-three",
			},
		},
	}
	i := oldes.NewSampleIndexer(&oldes.SampleIndexerConfig{
		Client: client,
		Index:  "vulcan-integration",
	})
	for _, e := range exists {
		err := i.IndexSample(&bus.Sample{
			Metric: bus.Metric{
				Name:   e.Name,
				Labels: e.Labels,
			},
		})
		if err != nil {
			return err
		}
	}
	// let elasticsearch realize it has data for a second
	// note the template needs time to match and it is set for a 1s refresh
	time.Sleep(time.Second * 2)
	return nil
}

func TestResolver(t *testing.T) {
	err := down()
	if err != nil {
		t.Error(err)
	}
	err = up()
	if err != nil {
		t.Error(err)
	}
	r, err := elasticsearch.NewResolver(&elasticsearch.ResolverConfig{
		URL:   *es,
		Sniff: false,
		Index: "vulcan-integration",
	})
	if err != nil {
		t.Error(err)
	}
	tests := []struct {
		Matches []*storage.Match
		Count   int
	}{
		{
			Matches: []*storage.Match{
				&storage.Match{
					Type:  storage.Equal,
					Name:  "l",
					Value: "value-one",
				},
			},
			Count: 2,
		},
	}
	for _, test := range tests {
		m, err := r.Resolve(test.Matches)
		if err != nil {
			t.Error(err)
		}
		if len(m) != test.Count {
			t.Errorf("want %d resolved metrics got %d", test.Count, len(m))
		}
	}
}
<commit_msg>es: adds more resolve tests<commit_after>// +build integration

package elasticsearch_test

import (
	"flag"
	"fmt"
	"net/http"
	"strings"
	"testing"
	"time"

	"github.com/digitalocean/vulcan/bus"
	oldes "github.com/digitalocean/vulcan/elasticsearch"
	"github.com/digitalocean/vulcan/storage"
	"github.com/digitalocean/vulcan/storage/elasticsearch"
	"github.com/olivere/elastic"
)

var es = flag.String("es", "http://localhost:9200", "elasticsearch url")

const matchAll = `{
  "template": "*",
  "order": 0,
  "settings": {
    "index": {
      "refresh_interval": "1s"
    }
  },
  "mappings": {
    "_default_": {
      "dynamic_templates": [
        {
          "string_fields": {
            "mapping": {
              "fields": {
                "raw": {
                  "ignore_above": 256,
                  "doc_values": true,
                  "index": "not_analyzed",
                  "type": "string"
                }
              },
              "omit_norms": true,
              "index": "analyzed",
              "type": "string"
            },
            "match_mapping_type": "string",
            "match": "*"
          }
        }
      ],
      "_all": {
        "omit_norms": true,
        "enabled": true
      }
    }
  }
}`

func down() error {
	err := downTemplate()
	if err != nil {
		return err
	}
	err = downIndex()
	return err
}

func downTemplate() error {
	req, err := http.NewRequest("DELETE", fmt.Sprintf("%s/_template/match_all_0", *es), nil)
	if err != nil {
		return err
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

func downIndex() error {
	req, err := http.NewRequest("DELETE", fmt.Sprintf("%s/vulcan-integration", *es), nil)
	if err != nil {
		return err
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

func up() error {
	err := upTemplate()
	if err != nil {
		return err
	}
	err = upEntries()
	return err
}

func upTemplate() error {
	url := fmt.Sprintf("%s/_template/match_all_0", *es)
	resp, err := http.DefaultClient.Post(url, "text/json", strings.NewReader(matchAll))
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

func upEntries() error {
	client, err := elastic.NewClient(elastic.SetURL(*es), elastic.SetSniff(false))
	if err != nil {
		return err
	}
	exists := []struct {
		Name   string
		Labels map[string]string
	}{
		{
			Name: "metric_1",
			Labels: map[string]string{
				"l": "value-one",
			},
		},
		{
			Name: "metric_1",
			Labels: map[string]string{
				"l":     "value-one",
				"other": "value",
			},
		},
		{
			Name: "metric_1",
			Labels: map[string]string{
				"l": "value-two",
			},
		},
		{
			Name: "metric_1",
			Labels: map[string]string{
				"l": "value-three",
			},
		},
	}
	i := oldes.NewSampleIndexer(&oldes.SampleIndexerConfig{
		Client: client,
		Index:  "vulcan-integration",
	})
	for _, e := range exists {
		err := i.IndexSample(&bus.Sample{
			Metric: bus.Metric{
				Name:   e.Name,
				Labels: e.Labels,
			},
		})
		if err != nil {
			return err
		}
	}
	// let elasticsearch realize it has data for a second
	// note the template needs time to match and it is set for a 1s refresh
	time.Sleep(time.Second * 2)
	return nil
}

func TestResolver(t *testing.T) {
	err := down()
	if err != nil {
		t.Error(err)
	}
	err = up()
	if err != nil {
		t.Error(err)
	}
	r, err := elasticsearch.NewResolver(&elasticsearch.ResolverConfig{
		URL:   *es,
		Sniff: false,
		Index: "vulcan-integration",
	})
	if err != nil {
		t.Error(err)
	}
	tests := []struct {
		Matches []*storage.Match
		Count   int
	}{
		{
			Matches: []*storage.Match{
				&storage.Match{
					Type:  storage.Equal,
					Name:  "__name__",
					Value: "metric_1",
				},
				&storage.Match{
					Type:  storage.Equal,
					Name:  "l",
					Value: "value-one",
				},
			},
			Count: 2,
		},
		{
			Matches: []*storage.Match{
				&storage.Match{
					Type:  storage.Equal,
					Name:  "__name__",
					Value: "metric_1",
				},
				&storage.Match{
					Type:  storage.Equal,
					Name:  "l",
					Value: "value-one",
				},

				&storage.Match{
					Type:  storage.Equal,
					Name:  "other",
					Value: "value",
				},
			},
			Count: 1,
		},
		{
			Matches: []*storage.Match{
				&storage.Match{
					Type:  storage.Equal,
					Name:  "__name__",
					Value: "metric_1",
				},
				&storage.Match{
					Type:  storage.NotEqual,
					Name:  "l",
					Value: "value-one",
				},
				&storage.Match{
					Type:  storage.Equal,
					Name:  "other",
					Value: "value",
				},
			},
			Count: 0,
		},
		{
			Matches: []*storage.Match{
				&storage.Match{
					Type:  storage.Equal,
					Name:  "__name__",
					Value: "metric_1",
				},
				&storage.Match{
					Type:  storage.NotEqual,
					Name:  "l",
					Value: "value-one",
				},
				&storage.Match{
					Type:  storage.Equal,
					Name:  "other",
					Value: "value",
				},
			},
			Count: 0,
		},
		{
			Matches: []*storage.Match{
				&storage.Match{
					Type:  storage.Equal,
					Name:  "__name__",
					Value: "metric_1",
				},
				&storage.Match{
					Type:  storage.RegexMatch,
					Name:  "l",
					Value: ".*one",
				},
				&storage.Match{
					Type:  storage.Equal,
					Name:  "other",
					Value: "value",
				},
			},
			Count: 1,
		},
		{
			Matches: []*storage.Match{
				&storage.Match{
					Type:  storage.Equal,
					Name:  "__name__",
					Value: "metric_1",
				},
				&storage.Match{
					Type:  storage.RegexNoMatch,
					Name:  "l",
					Value: ".*two",
				},
			},
			Count: 3,
		},
	}
	for _, test := range tests {
		m, err := r.Resolve(test.Matches)
		if err != nil {
			t.Error(err)
		}
		if len(m) != test.Count {
			t.Errorf("want %d resolved metrics got %d", test.Count, len(m))
		}
	}
}
<|endoftext|>