<commit_before>package models

import (
	"fmt"
	"github.com/coopernurse/gorp"
	"github.com/revel/revel"
	"strings"
	"regexp"
)

type Profile struct {
	ProfileId          int
	UserId             int
	UserName           string
	Name               string
	Summary            string
	Description        string
	PhotoUrl           string
	AggregateFollowers int
	AggregateFollowing int

	// Transient
	User               *User
}

var NameRegex = regexp.MustCompile("^[^#@]+$")

var UserNameRegex = regexp.MustCompile("^[a-zA-Z0-9]+$")

var UserNameBlacklistRegex = regexp.MustCompile("^(account|contact|about|find|search|public|log(in|out)|sign(in|up|out)|register|home|index|default|post(s)?|user(name)?(s)?|i)$")

func (p *Profile) String() string {
	return fmt.Sprintf("Profile(%s)", p.Summary)
}

func (profile *Profile) Validate(v *revel.Validation) {
	ValidateProfileName(v, profile.Name)
	ValidateProfileSummary(v, profile.Summary)
	ValidateProfileDescription(v, profile.Description)
	ValidateProfilePhotoUrl(v, profile.PhotoUrl)
}

func ValidateProfileUserName(v *revel.Validation, username string) *revel.ValidationResult {
	result := v.Required(username).Message("User name required")
	if !result.Ok {
		return result
	}

	result = v.MaxSize(username, 64).Message("User name can not exceed 64 characters")
	if !result.Ok {
		return result
	}

	result = v.Match(username, UserNameRegex).Message("Invalid User name. Alphanumerics allowed only")
	if !result.Ok {
		return result
	}

	// Inverse regexp matcher (username cannot be the same as any blacklisted usernames)
	if blacklistMatcher := UserNameBlacklistRegex.FindString(username); blacklistMatcher != "" {
		result = v.Error("Invalid User name. Reserved keywords not allowed")
	}

	return result
}

func ValidateProfileName(v *revel.Validation, name string) *revel.ValidationResult {
	result := v.Required(name).Message("Name required")
	if !result.Ok {
		return result
	}

	result = v.MinSize(name, 6).Message("Name must be at least 6 characters")
	if !result.Ok {
		return result
	}

	result = v.MaxSize(name, 100).Message("Name must be at most 100 characters")
	if !result.Ok {
		return result
	}

	// Inverse regexp matcher (name cannot contain reserved # or @ symbols)
	if invalidNameMatcher := NameRegex.FindString(name); invalidNameMatcher != "" {
		result = v.Error("Invalid Name. Reserved characters ('#' and '@') are not allowed")
	}

	return result
}

func ValidateProfileSummary(v *revel.Validation, summary string) *revel.ValidationResult {
	result := v.MaxSize(summary, 140).Message("Profile summary cannot exceed 140 characters")

	return result
}

func ValidateProfileDescription(v *revel.Validation, description string) *revel.ValidationResult {
	result := v.MaxSize(description, 400).Message("Profile description cannot exceed 400 characters")

	return result
}

func ValidateProfilePhotoUrl(v *revel.Validation, photoUrl string) *revel.ValidationResult {
	result := v.MaxSize(photoUrl, 200).Message("Photo URL cannot exceed 200 characters")

	return result
}

func (p *Profile) PreInsert(_ gorp.SqlExecutor) error {
	p.UserName = strings.ToLower(p.UserName)
	return nil
}

func (p *Profile) PreUpdate(_ gorp.SqlExecutor) error {
	p.UserName = strings.ToLower(p.UserName)
	return nil
}

func (p *Profile) PostGet(exe gorp.SqlExecutor) error {
	var (
		obj interface{}
		err error
	)

	obj, err = exe.Get(User{}, p.UserId)
	if err != nil {
		return fmt.Errorf("Error loading a profile's user (%d): %s", p.UserId, err)
	}
	p.User = obj.(*User)

	/*obj, err = exe.Get(Post{}, p.ProfileId)
	if err != nil {
		return fmt.Errorf("Error loading a profile's posts (%d): %s", p.ProfileId, err)
	}
	var posts []*Post
	for _, post := range obj {
		posts = append(posts, post.(*Post))
	}
	p.Posts = posts*/

	return nil
}
<commit_msg>Fix invalid name matcher in Profile model<commit_after>package models

import (
	"fmt"
	"github.com/coopernurse/gorp"
	"github.com/revel/revel"
	"strings"
	"regexp"
)

type Profile struct {
	ProfileId          int
	UserId             int
	UserName           string
	Name               string
	Summary            string
	Description        string
	PhotoUrl           string
	AggregateFollowers int
	AggregateFollowing int

	// Transient
	User               *User
}

var NameRegex = regexp.MustCompile("^[^#@]+$")

var UserNameRegex = regexp.MustCompile("^[a-zA-Z0-9]+$")

var UserNameBlacklistRegex = regexp.MustCompile("^(account|contact|about|find|search|public|log(in|out)|sign(in|up|out)|register|home|index|default|post(s)?|user(name)?(s)?|i)$")

func (p *Profile) String() string {
	return fmt.Sprintf("Profile(%s)", p.Summary)
}

func (profile *Profile) Validate(v *revel.Validation) {
	ValidateProfileName(v, profile.Name)
	ValidateProfileSummary(v, profile.Summary)
	ValidateProfileDescription(v, profile.Description)
	ValidateProfilePhotoUrl(v, profile.PhotoUrl)
}

func ValidateProfileUserName(v *revel.Validation, username string) *revel.ValidationResult {
	result := v.Required(username).Message("User name required")
	if !result.Ok {
		return result
	}

	result = v.MaxSize(username, 64).Message("User name can not exceed 64 characters")
	if !result.Ok {
		return result
	}

	result = v.Match(username, UserNameRegex).Message("Invalid User name. Alphanumerics allowed only")
	if !result.Ok {
		return result
	}

	// Inverse regexp matcher (username cannot be the same as any blacklisted usernames)
	if blacklistMatcher := UserNameBlacklistRegex.FindString(username); blacklistMatcher != "" {
		result = v.Error("Invalid User name. Reserved keywords not allowed")
	}

	return result
}

func ValidateProfileName(v *revel.Validation, name string) *revel.ValidationResult {
	result := v.Required(name).Message("Name required")
	if !result.Ok {
		return result
	}

	result = v.MinSize(name, 6).Message("Name must be at least 6 characters")
	if !result.Ok {
		return result
	}

	result = v.MaxSize(name, 100).Message("Name must be at most 100 characters")
	if !result.Ok {
		return result
	}

	// Inverse regexp matcher (name cannot contain reserved # or @ symbols)
	if invalidNameMatcher := NameRegex.FindString(name); invalidNameMatcher == "" {
		result = v.Error("Invalid Name. Reserved characters ('#' and '@') are not allowed")
	}

	return result
}

func ValidateProfileSummary(v *revel.Validation, summary string) *revel.ValidationResult {
	result := v.MaxSize(summary, 140).Message("Profile summary cannot exceed 140 characters")

	return result
}

func ValidateProfileDescription(v *revel.Validation, description string) *revel.ValidationResult {
	result := v.MaxSize(description, 400).Message("Profile description cannot exceed 400 characters")

	return result
}

func ValidateProfilePhotoUrl(v *revel.Validation, photoUrl string) *revel.ValidationResult {
	result := v.MaxSize(photoUrl, 200).Message("Photo URL cannot exceed 200 characters")

	return result
}

func (p *Profile) PreInsert(_ gorp.SqlExecutor) error {
	p.UserName = strings.ToLower(p.UserName)
	return nil
}

func (p *Profile) PreUpdate(_ gorp.SqlExecutor) error {
	p.UserName = strings.ToLower(p.UserName)
	return nil
}

func (p *Profile) PostGet(exe gorp.SqlExecutor) error {
	var (
		obj interface{}
		err error
	)

	obj, err = exe.Get(User{}, p.UserId)
	if err != nil {
		return fmt.Errorf("Error loading a profile's user (%d): %s", p.UserId, err)
	}
	p.User = obj.(*User)

	/*obj, err = exe.Get(Post{}, p.ProfileId)
	if err != nil {
		return fmt.Errorf("Error loading a profile's posts (%d): %s", p.ProfileId, err)
	}
	var posts []*Post
	for _, post := range obj {
		posts = append(posts, post.(*Post))
	}
	p.Posts = posts*/

	return nil
}
<|endoftext|>


<commit_before>// chris 072815

package rebnf

import (
	"errors"
	"fmt"
	"io"
	"log"
	"unicode"

	mathrand "math/rand"
	"unicode/utf8"

	fixrand "chrispennello.com/go/util/fix/math/rand"
	"golang.org/x/exp/ebnf"
)

// ErrNoStart is returned by Random when the specified start production
// cannot be found in the grammar.
var ErrNoStart = errors.New("start production not found")

// Random generates random productions of the given grammar starting at
// the given start production, and writes them into the destination
// io.Writer.
func (c *Ctx) Random(dst io.Writer, grammar ebnf.Grammar, start string) error {
	prod, ok := grammar[start]
	if !ok {
		return ErrNoStart
	}
	return c.random(dst, grammar, prod.Expr, 0)
}

// IsCapital returns a boolean indicating whether or not the first rune
// of the given string is upper case.
func IsCapital(s string) bool {
	ch, _ := utf8.DecodeRuneInString(s)
	return unicode.IsUpper(ch)
}

// IsTerminal returns a boolean that indicates whether the given
// Expression is a terminal one.  Ranges and Tokens are unconditionally
// considered to be terminal, and Names are terminal iff they're
// capitalized.  Productions are not considered because Alternatives
// contain Names, and you have to loo up the production by name in the
// grammar--it's just not a use case handled by this library, but could
// be added easily if needed.
func IsTerminal(expr ebnf.Expression) bool {
	switch expr.(type) {
	case *ebnf.Name:
		name := expr.(*ebnf.Name)
		return !IsCapital(name.String)
	case *ebnf.Range:
		return true
	case *ebnf.Token:
		return true
	default:
		return false
	}
}

// findTerminals is like filter(IsTerminal, exprs).  It ranges over all
// of the given expressions and produces a new slice of expressions
// containing only those for which IsTerminal returns true.
func findTerminals(exprs []ebnf.Expression) []ebnf.Expression {
	r := make([]ebnf.Expression, 0, len(exprs))
	for _, expr := range exprs {
		if IsTerminal(expr) {
			r = append(r, expr)
		}
	}
	return r
}

// pad picks a random rune from the padding string specified by the
// context and writes it to the destination writer.
func (c *Ctx) pad(dst io.Writer) error {
	runes := []rune(c.padding)
	if len(runes) == 0 {
		return nil
	}
	r := runes[mathrand.Intn(len(runes))]
	_, err := io.WriteString(dst, string([]rune{r}))
	return err
}

func (c *Ctx) log(format string, a ...interface{}) {
	if !c.debug {
		return
	}
	// Logging errors ignored.
	log.Printf(format, a...)
}

// random is the inner, recursive implementation of Random.  It handles
// each of the ebnf.Expression implementations, outputting productions
// randomly to the destination writer.  It implements a recursion depth
// counter, and once the counter exceeds the limit, it favors producing
// terminals over non-terminals.  Note that this does not guarantee
// termination, however.  For example, the pathological grammar "S = S"
// will still loop forever.
func (c *Ctx) random(dst io.Writer, grammar ebnf.Grammar, expr ebnf.Expression, depth int) error {
	c.log("recursion depth %d\n", depth)
	c.log("%#v\n\n", expr)

	switch expr.(type) {
	// Choose a random alternative.
	case ebnf.Alternative:
		alt := expr.(ebnf.Alternative)
		var exprs []ebnf.Expression
		// If maximum recursion depth has been exceeded, attempt
		// to select from only terminal expressions.
		if depth > c.maxdepth {
			exprs = findTerminals(alt)
			c.log("alternative: found %d terminals", len(exprs))
			if len(exprs) == 0 {
				// No luck, we have no choice but to
				// explore one of the non-terminals in
				// this alternative.
				c.log("alternative: no terminals\n")
				exprs = alt
			}
		} else {
			exprs = alt
		}
		err := c.random(dst, grammar, exprs[mathrand.Intn(len(exprs))], depth+1)
		if err != nil {
			return err
		}

	// Evalute the group.
	case *ebnf.Group:
		gr := expr.(*ebnf.Group)
		err := c.random(dst, grammar, gr.Body, depth+1)
		if err != nil {
			return err
		}

	// The name refers to a production; look it up and continue the
	// recursion.
	case *ebnf.Name:
		name := expr.(*ebnf.Name)
		// Pad non-terminals.
		pad := !IsTerminal(expr)
		if pad {
			c.pad(dst)
		}
		err := c.random(dst, grammar, grammar[name.String], depth+1)
		if err != nil {
			return err
		}
		if pad {
			c.pad(dst)
		}

	// Randomly include the option.
	case *ebnf.Option:
		opt := expr.(*ebnf.Option)
		// If recursion depth has been exceeded, and option is
		// non-termainl, unconditionally omit.
		if depth > c.maxdepth && !IsTerminal(opt.Body) {
			// Omit.
			c.log("option: non-terminal omitted due to having exceeded recursion depth limit\n")
		} else if fixrand.Bool() {
			// Otherwise, proceed with usual random
			// inclusion of option.
			err := c.random(dst, grammar, opt.Body, depth+1)
			if err != nil {
				return err
			}
		}

	// Produce the production.
	case *ebnf.Production:
		prod := expr.(*ebnf.Production)
		err := c.random(dst, grammar, prod.Expr, depth+1)
		if err != nil {
			return err
		}

	// Generate a random string in the given range.
	case *ebnf.Range:
		rng := expr.(*ebnf.Range)
		ch, err := fixrand.ChooseString(rng.Begin.String, rng.End.String)
		if err != nil {
			return err
		}
		if _, err := io.WriteString(dst, ch); err != nil {
			return err
		}

	// Choose a random number of repetitions.
	case *ebnf.Repetition:
		rep := expr.(*ebnf.Repetition)
		// If the recursion depth has been exceeded, and the
		// repetition is non-terminal, unconditionally omit it.
		if depth > c.maxdepth && !IsTerminal(rep.Body) {
			// Omit.
			c.log("repetition: non-terminal omitted due to having exceeded recursion depth limit\n")
		} else {
			// Otherwise, do normal inclusion of a random
			// number of repetitions.
			reps := mathrand.Intn(c.maxreps + 1)
			c.log("repetition: chose %d repetitions\n", reps)
			for i := 0; i < reps; i++ {
				err := c.random(dst, grammar, rep.Body, depth+1)
				if err != nil {
					return err
				}
			}
		}

	// Recurse on each of the expressions.
	case ebnf.Sequence:
		seq := expr.(ebnf.Sequence)
		for _, e := range seq {
			err := c.random(dst, grammar, e, depth+1)
			if err != nil {
				return err
			}
		}

	// Emit the token.
	case *ebnf.Token:
		tok := expr.(*ebnf.Token)
		if _, err := io.WriteString(dst, tok.String); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Adds panic to help detect programmer errors.<commit_after>// chris 072815

package rebnf

import (
	"errors"
	"fmt"
	"io"
	"log"
	"unicode"

	mathrand "math/rand"
	"unicode/utf8"

	fixrand "chrispennello.com/go/util/fix/math/rand"
	"golang.org/x/exp/ebnf"
)

// ErrNoStart is returned by Random when the specified start production
// cannot be found in the grammar.
var ErrNoStart = errors.New("start production not found")

// Random generates random productions of the given grammar starting at
// the given start production, and writes them into the destination
// io.Writer.
func (c *Ctx) Random(dst io.Writer, grammar ebnf.Grammar, start string) error {
	prod, ok := grammar[start]
	if !ok {
		return ErrNoStart
	}
	return c.random(dst, grammar, prod.Expr, 0)
}

// IsCapital returns a boolean indicating whether or not the first rune
// of the given string is upper case.
func IsCapital(s string) bool {
	ch, _ := utf8.DecodeRuneInString(s)
	return unicode.IsUpper(ch)
}

// IsTerminal returns a boolean that indicates whether the given
// Expression is a terminal one.  Ranges and Tokens are unconditionally
// considered to be terminal, and Names are terminal iff they're
// capitalized.  Productions are not considered because Alternatives
// contain Names, and you have to loo up the production by name in the
// grammar--it's just not a use case handled by this library, but could
// be added easily if needed.
func IsTerminal(expr ebnf.Expression) bool {
	switch expr.(type) {
	case *ebnf.Name:
		name := expr.(*ebnf.Name)
		return !IsCapital(name.String)
	case *ebnf.Range:
		return true
	case *ebnf.Token:
		return true
	default:
		return false
	}
}

// findTerminals is like filter(IsTerminal, exprs).  It ranges over all
// of the given expressions and produces a new slice of expressions
// containing only those for which IsTerminal returns true.
func findTerminals(exprs []ebnf.Expression) []ebnf.Expression {
	r := make([]ebnf.Expression, 0, len(exprs))
	for _, expr := range exprs {
		if IsTerminal(expr) {
			r = append(r, expr)
		}
	}
	return r
}

// pad picks a random rune from the padding string specified by the
// context and writes it to the destination writer.
func (c *Ctx) pad(dst io.Writer) error {
	runes := []rune(c.padding)
	if len(runes) == 0 {
		return nil
	}
	r := runes[mathrand.Intn(len(runes))]
	_, err := io.WriteString(dst, string([]rune{r}))
	return err
}

func (c *Ctx) log(format string, a ...interface{}) {
	if !c.debug {
		return
	}
	// Logging errors ignored.
	log.Printf(format, a...)
}

// random is the inner, recursive implementation of Random.  It handles
// each of the ebnf.Expression implementations, outputting productions
// randomly to the destination writer.  It implements a recursion depth
// counter, and once the counter exceeds the limit, it favors producing
// terminals over non-terminals.  Note that this does not guarantee
// termination, however.  For example, the pathological grammar "S = S"
// will still loop forever.
func (c *Ctx) random(dst io.Writer, grammar ebnf.Grammar, expr ebnf.Expression, depth int) error {
	c.log("recursion depth %d\n", depth)
	c.log("%#v\n\n", expr)

	switch expr.(type) {
	// Choose a random alternative.
	case ebnf.Alternative:
		alt := expr.(ebnf.Alternative)
		var exprs []ebnf.Expression
		// If maximum recursion depth has been exceeded, attempt
		// to select from only terminal expressions.
		if depth > c.maxdepth {
			exprs = findTerminals(alt)
			c.log("alternative: found %d terminals", len(exprs))
			if len(exprs) == 0 {
				// No luck, we have no choice but to
				// explore one of the non-terminals in
				// this alternative.
				c.log("alternative: no terminals\n")
				exprs = alt
			}
		} else {
			exprs = alt
		}
		err := c.random(dst, grammar, exprs[mathrand.Intn(len(exprs))], depth+1)
		if err != nil {
			return err
		}

	// Evalute the group.
	case *ebnf.Group:
		gr := expr.(*ebnf.Group)
		err := c.random(dst, grammar, gr.Body, depth+1)
		if err != nil {
			return err
		}

	// The name refers to a production; look it up and continue the
	// recursion.
	case *ebnf.Name:
		name := expr.(*ebnf.Name)
		// Pad non-terminals.
		pad := !IsTerminal(expr)
		if pad {
			c.pad(dst)
		}
		err := c.random(dst, grammar, grammar[name.String], depth+1)
		if err != nil {
			return err
		}
		if pad {
			c.pad(dst)
		}

	// Randomly include the option.
	case *ebnf.Option:
		opt := expr.(*ebnf.Option)
		// If recursion depth has been exceeded, and option is
		// non-termainl, unconditionally omit.
		if depth > c.maxdepth && !IsTerminal(opt.Body) {
			// Omit.
			c.log("option: non-terminal omitted due to having exceeded recursion depth limit\n")
		} else if fixrand.Bool() {
			// Otherwise, proceed with usual random
			// inclusion of option.
			err := c.random(dst, grammar, opt.Body, depth+1)
			if err != nil {
				return err
			}
		}

	// Produce the production.
	case *ebnf.Production:
		prod := expr.(*ebnf.Production)
		err := c.random(dst, grammar, prod.Expr, depth+1)
		if err != nil {
			return err
		}

	// Generate a random string in the given range.
	case *ebnf.Range:
		rng := expr.(*ebnf.Range)
		ch, err := fixrand.ChooseString(rng.Begin.String, rng.End.String)
		if err != nil {
			return err
		}
		if _, err := io.WriteString(dst, ch); err != nil {
			return err
		}

	// Choose a random number of repetitions.
	case *ebnf.Repetition:
		rep := expr.(*ebnf.Repetition)
		// If the recursion depth has been exceeded, and the
		// repetition is non-terminal, unconditionally omit it.
		if depth > c.maxdepth && !IsTerminal(rep.Body) {
			// Omit.
			c.log("repetition: non-terminal omitted due to having exceeded recursion depth limit\n")
		} else {
			// Otherwise, do normal inclusion of a random
			// number of repetitions.
			reps := mathrand.Intn(c.maxreps + 1)
			c.log("repetition: chose %d repetitions\n", reps)
			for i := 0; i < reps; i++ {
				err := c.random(dst, grammar, rep.Body, depth+1)
				if err != nil {
					return err
				}
			}
		}

	// Recurse on each of the expressions.
	case ebnf.Sequence:
		seq := expr.(ebnf.Sequence)
		for _, e := range seq {
			err := c.random(dst, grammar, e, depth+1)
			if err != nil {
				return err
			}
		}

	// Emit the token.
	case *ebnf.Token:
		tok := expr.(*ebnf.Token)
		if _, err := io.WriteString(dst, tok.String); err != nil {
			return err
		}

	default:
		// This indicates a bug in the code.
		panic(fmt.Sprintf("bad expression %#v", expr))
	}

	return nil
}
<|endoftext|>


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

package ceph

import (
	"encoding/json"
	"math"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/sirupsen/logrus"
)

// PoolUsageCollector displays statistics about each pool in the Ceph cluster.
type PoolUsageCollector struct {
	conn    Conn
	logger  *logrus.Logger
	version *Version

	// UsedBytes tracks the amount of bytes currently allocated for the pool. This
	// does not factor in the overcommitment made for individual images.
	UsedBytes *prometheus.GaugeVec

	// RawUsedBytes tracks the amount of raw bytes currently used for the pool. This
	// factors in the replication factor (size) of the pool.
	RawUsedBytes *prometheus.GaugeVec

	// MaxAvail tracks the amount of bytes currently free for the pool,
	// which depends on the replication settings for the pool in question.
	MaxAvail *prometheus.GaugeVec

	// PercentUsed is the percentage of raw space available to the pool currently in use
	PercentUsed *prometheus.GaugeVec

	// Objects shows the no. of RADOS objects created within the pool.
	Objects *prometheus.GaugeVec

	// DirtyObjects shows the no. of RADOS dirty objects in a cache-tier pool,
	// this doesn't make sense in a regular pool, see:
	// http://lists.ceph.com/pipermail/ceph-users-ceph.com/2015-April/000557.html
	DirtyObjects *prometheus.GaugeVec

	// UnfoundObjects shows the no. of RADOS unfound object within each pool.
	UnfoundObjects *prometheus.GaugeVec

	// ReadIO tracks the read IO calls made for the images within each pool.
	ReadIO *prometheus.GaugeVec

	// Readbytes tracks the read throughput made for the images within each pool.
	ReadBytes *prometheus.GaugeVec

	// WriteIO tracks the write IO calls made for the images within each pool.
	WriteIO *prometheus.GaugeVec

	// WriteBytes tracks the write throughput made for the images within each pool.
	WriteBytes *prometheus.GaugeVec
}

// NewPoolUsageCollector creates a new instance of PoolUsageCollector and returns
// its reference.
func NewPoolUsageCollector(exporter *Exporter) *PoolUsageCollector {
	var (
		subSystem = "pool"
		poolLabel = []string{"pool"}
	)

	labels := make(prometheus.Labels)
	labels["cluster"] = exporter.Cluster

	return &PoolUsageCollector{
		conn:    exporter.Conn,
		logger:  exporter.Logger,
		version: exporter.Version,

		UsedBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "used_bytes",
				Help:        "Capacity of the pool that is currently under use",
				ConstLabels: labels,
			},
			poolLabel,
		),
		RawUsedBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "raw_used_bytes",
				Help:        "Raw capacity of the pool that is currently under use, this factors in the size",
				ConstLabels: labels,
			},
			poolLabel,
		),
		MaxAvail: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "available_bytes",
				Help:        "Free space for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		PercentUsed: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "percent_used",
				Help:        "Percentage of the capacity available to this pool that is used by this pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		Objects: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "objects_total",
				Help:        "Total no. of objects allocated within the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		DirtyObjects: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "dirty_objects_total",
				Help:        "Total no. of dirty objects in a cache-tier pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		UnfoundObjects: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "unfound_objects_total",
				Help:        "Total no. of unfound objects for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		ReadIO: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "read_total",
				Help:        "Total read I/O calls for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		ReadBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "read_bytes_total",
				Help:        "Total read throughput for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		WriteIO: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "write_total",
				Help:        "Total write I/O calls for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
		WriteBytes: prometheus.NewGaugeVec(
			prometheus.GaugeOpts{
				Namespace:   cephNamespace,
				Subsystem:   subSystem,
				Name:        "write_bytes_total",
				Help:        "Total write throughput for the pool",
				ConstLabels: labels,
			},
			poolLabel,
		),
	}
}

func (p *PoolUsageCollector) collectorList() []prometheus.Collector {
	return []prometheus.Collector{
		p.UsedBytes,
		p.RawUsedBytes,
		p.MaxAvail,
		p.PercentUsed,
		p.Objects,
		p.DirtyObjects,
		p.UnfoundObjects,
		p.ReadIO,
		p.ReadBytes,
		p.WriteIO,
		p.WriteBytes,
	}
}

type cephPoolStats struct {
	Pools []struct {
		Name  string `json:"name"`
		ID    int    `json:"id"`
		Stats struct {
			BytesUsed    float64 `json:"bytes_used"`
			StoredRaw    float64 `json:"stored_raw"`
			Stored       float64 `json:"stored"`
			MaxAvail     float64 `json:"max_avail"`
			PercentUsed  float64 `json:"percent_used"`
			Objects      float64 `json:"objects"`
			DirtyObjects float64 `json:"dirty"`
			ReadIO       float64 `json:"rd"`
			ReadBytes    float64 `json:"rd_bytes"`
			WriteIO      float64 `json:"wr"`
			WriteBytes   float64 `json:"wr_bytes"`
		} `json:"stats"`
	} `json:"pools"`
}

func (p *PoolUsageCollector) collect() error {
	cmd := p.cephUsageCommand()
	buf, _, err := p.conn.MonCommand(cmd)
	if err != nil {
		p.logger.WithError(err).WithField(
			"args", string(cmd),
		).Error("error executing mon command")

		return err
	}

	stats := &cephPoolStats{}
	if err := json.Unmarshal(buf, stats); err != nil {
		return err
	}

	// Reset pool specfic metrics, pools can be removed
	p.UsedBytes.Reset()
	p.RawUsedBytes.Reset()
	p.MaxAvail.Reset()
	p.PercentUsed.Reset()
	p.Objects.Reset()
	p.DirtyObjects.Reset()
	p.UnfoundObjects.Reset()
	p.ReadIO.Reset()
	p.ReadBytes.Reset()
	p.WriteIO.Reset()
	p.WriteBytes.Reset()

	for _, pool := range stats.Pools {
		p.UsedBytes.WithLabelValues(pool.Name).Set(pool.Stats.Stored)
		p.RawUsedBytes.WithLabelValues(pool.Name).Set(math.Max(pool.Stats.StoredRaw, pool.Stats.BytesUsed))
		p.MaxAvail.WithLabelValues(pool.Name).Set(pool.Stats.MaxAvail)
		p.PercentUsed.WithLabelValues(pool.Name).Set(pool.Stats.PercentUsed)
		p.Objects.WithLabelValues(pool.Name).Set(pool.Stats.Objects)
		p.DirtyObjects.WithLabelValues(pool.Name).Set(pool.Stats.DirtyObjects)
		p.ReadIO.WithLabelValues(pool.Name).Set(pool.Stats.ReadIO)
		p.ReadBytes.WithLabelValues(pool.Name).Set(pool.Stats.ReadBytes)
		p.WriteIO.WithLabelValues(pool.Name).Set(pool.Stats.WriteIO)
		p.WriteBytes.WithLabelValues(pool.Name).Set(pool.Stats.WriteBytes)

		st, err := p.conn.GetPoolStats(pool.Name)
		if err != nil {
			p.logger.WithError(err).WithField(
				"pool", pool.Name,
			).Error("error getting pool stats")

			continue
		}

		p.UnfoundObjects.WithLabelValues(pool.Name).Set(float64(st.ObjectsUnfound))
	}

	return nil
}

func (p *PoolUsageCollector) cephUsageCommand() []byte {
	cmd, err := json.Marshal(map[string]interface{}{
		"prefix": "df",
		"detail": "detail",
		"format": "json",
	})
	if err != nil {
		p.logger.WithError(err).Panic("error marshalling ceph df detail")
	}
	return cmd
}

// Describe fulfills the prometheus.Collector's interface and sends the descriptors
// of pool's metrics to the given channel.
func (p *PoolUsageCollector) Describe(ch chan<- *prometheus.Desc) {
	for _, metric := range p.collectorList() {
		metric.Describe(ch)
	}
}

// Collect extracts the current values of all the metrics and sends them to the
// prometheus channel.
func (p *PoolUsageCollector) Collect(ch chan<- prometheus.Metric) {
	p.logger.Debug("collecting pool usage metrics")
	if err := p.collect(); err != nil {
		p.logger.WithError(err).Error("error collecting pool usage metrics")
		return
	}

	for _, metric := range p.collectorList() {
		metric.Collect(ch)
	}
}
<commit_msg>migrate pool_usage.go to constmetrics<commit_after>//   Copyright 2022 DigitalOcean
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package ceph

import (
	"encoding/json"
	"fmt"
	"math"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/sirupsen/logrus"
)

// PoolUsageCollector displays statistics about each pool in the Ceph cluster.
type PoolUsageCollector struct {
	conn    Conn
	logger  *logrus.Logger
	version *Version

	// UsedBytes tracks the amount of bytes currently allocated for the pool. This
	// does not factor in the overcommitment made for individual images.
	UsedBytes *prometheus.Desc

	// RawUsedBytes tracks the amount of raw bytes currently used for the pool. This
	// factors in the replication factor (size) of the pool.
	RawUsedBytes *prometheus.Desc

	// MaxAvail tracks the amount of bytes currently free for the pool,
	// which depends on the replication settings for the pool in question.
	MaxAvail *prometheus.Desc

	// PercentUsed is the percentage of raw space available to the pool currently in use
	PercentUsed *prometheus.Desc

	// Objects shows the no. of RADOS objects created within the pool.
	Objects *prometheus.Desc

	// DirtyObjects shows the no. of RADOS dirty objects in a cache-tier pool,
	// this doesn't make sense in a regular pool, see:
	// http://lists.ceph.com/pipermail/ceph-users-ceph.com/2015-April/000557.html
	DirtyObjects *prometheus.Desc

	// UnfoundObjects shows the no. of RADOS unfound object within each pool.
	UnfoundObjects *prometheus.Desc

	// ReadIO tracks the read IO calls made for the images within each pool.
	ReadIO *prometheus.Desc

	// Readbytes tracks the read throughput made for the images within each pool.
	ReadBytes *prometheus.Desc

	// WriteIO tracks the write IO calls made for the images within each pool.
	WriteIO *prometheus.Desc

	// WriteBytes tracks the write throughput made for the images within each pool.
	WriteBytes *prometheus.Desc
}

// NewPoolUsageCollector creates a new instance of PoolUsageCollector and returns
// its reference.
func NewPoolUsageCollector(exporter *Exporter) *PoolUsageCollector {
	var (
		subSystem = "pool"
		poolLabel = []string{"pool"}
	)

	labels := make(prometheus.Labels)
	labels["cluster"] = exporter.Cluster

	return &PoolUsageCollector{
		conn:    exporter.Conn,
		logger:  exporter.Logger,
		version: exporter.Version,

		UsedBytes: prometheus.NewDesc(fmt.Sprintf("%s_%s_used_bytes", cephNamespace, subSystem), "Capacity of the pool that is currently under use",
			poolLabel, labels,
		),
		RawUsedBytes: prometheus.NewDesc(fmt.Sprintf("%s_%s_raw_used_bytes", cephNamespace, subSystem), "Raw capacity of the pool that is currently under use, this factors in the size",
			poolLabel, labels,
		),
		MaxAvail: prometheus.NewDesc(fmt.Sprintf("%s_%s_available_bytes", cephNamespace, subSystem), "Free space for the pool",
			poolLabel, labels,
		),
		PercentUsed: prometheus.NewDesc(fmt.Sprintf("%s_%s_percent_used", cephNamespace, subSystem), "Percentage of the capacity available to this pool that is used by this pool",
			poolLabel, labels,
		),
		Objects: prometheus.NewDesc(fmt.Sprintf("%s_%s_objects_total", cephNamespace, subSystem), "Total no. of objects allocated within the pool",
			poolLabel, labels,
		),
		DirtyObjects: prometheus.NewDesc(fmt.Sprintf("%s_%s_dirty_objects_total", cephNamespace, subSystem), "Total no. of dirty objects in a cache-tier pool",
			poolLabel, labels,
		),
		UnfoundObjects: prometheus.NewDesc(fmt.Sprintf("%s_%s_unfound_objects_total", cephNamespace, subSystem), "Total no. of unfound objects for the pool",
			poolLabel, labels,
		),
		ReadIO: prometheus.NewDesc(fmt.Sprintf("%s_%s_read_total", cephNamespace, subSystem), "Total read I/O calls for the pool",
			poolLabel, labels,
		),
		ReadBytes: prometheus.NewDesc(fmt.Sprintf("%s_%s_read_bytes_total", cephNamespace, subSystem), "Total read throughput for the pool",
			poolLabel, labels,
		),
		WriteIO: prometheus.NewDesc(fmt.Sprintf("%s_%s_write_total", cephNamespace, subSystem), "Total write I/O calls for the pool",
			poolLabel, labels,
		),
		WriteBytes: prometheus.NewDesc(fmt.Sprintf("%s_%s_write_bytes_total", cephNamespace, subSystem), "Total write throughput for the pool",
			poolLabel, labels,
		),
	}
}

type cephPoolStats struct {
	Pools []struct {
		Name  string `json:"name"`
		ID    int    `json:"id"`
		Stats struct {
			BytesUsed    float64 `json:"bytes_used"`
			StoredRaw    float64 `json:"stored_raw"`
			Stored       float64 `json:"stored"`
			MaxAvail     float64 `json:"max_avail"`
			PercentUsed  float64 `json:"percent_used"`
			Objects      float64 `json:"objects"`
			DirtyObjects float64 `json:"dirty"`
			ReadIO       float64 `json:"rd"`
			ReadBytes    float64 `json:"rd_bytes"`
			WriteIO      float64 `json:"wr"`
			WriteBytes   float64 `json:"wr_bytes"`
		} `json:"stats"`
	} `json:"pools"`
}

func (p *PoolUsageCollector) collect(ch chan<- prometheus.Metric) error {
	cmd := p.cephUsageCommand()
	buf, _, err := p.conn.MonCommand(cmd)
	if err != nil {
		p.logger.WithError(err).WithField(
			"args", string(cmd),
		).Error("error executing mon command")

		return err
	}

	stats := &cephPoolStats{}
	if err := json.Unmarshal(buf, stats); err != nil {
		return err
	}

	for _, pool := range stats.Pools {
		ch <- prometheus.MustNewConstMetric(p.UsedBytes, prometheus.GaugeValue, pool.Stats.Stored, pool.Name)
		ch <- prometheus.MustNewConstMetric(p.RawUsedBytes, prometheus.GaugeValue, math.Max(pool.Stats.StoredRaw, pool.Stats.BytesUsed), pool.Name)
		ch <- prometheus.MustNewConstMetric(p.MaxAvail, prometheus.GaugeValue, pool.Stats.MaxAvail, pool.Name)
		ch <- prometheus.MustNewConstMetric(p.PercentUsed, prometheus.GaugeValue, pool.Stats.PercentUsed, pool.Name)
		ch <- prometheus.MustNewConstMetric(p.Objects, prometheus.GaugeValue, pool.Stats.Objects, pool.Name)
		ch <- prometheus.MustNewConstMetric(p.DirtyObjects, prometheus.GaugeValue, pool.Stats.DirtyObjects, pool.Name)
		ch <- prometheus.MustNewConstMetric(p.ReadIO, prometheus.GaugeValue, pool.Stats.ReadIO, pool.Name)
		ch <- prometheus.MustNewConstMetric(p.ReadBytes, prometheus.GaugeValue, pool.Stats.ReadBytes, pool.Name)
		ch <- prometheus.MustNewConstMetric(p.WriteIO, prometheus.GaugeValue, pool.Stats.WriteIO, pool.Name)
		ch <- prometheus.MustNewConstMetric(p.WriteBytes, prometheus.GaugeValue, pool.Stats.WriteBytes, pool.Name)

		st, err := p.conn.GetPoolStats(pool.Name)
		if err != nil {
			p.logger.WithError(err).WithField(
				"pool", pool.Name,
			).Error("error getting pool stats")

			continue
		}

		ch <- prometheus.MustNewConstMetric(p.UnfoundObjects, prometheus.GaugeValue, float64(st.ObjectsUnfound), pool.Name)
	}

	return nil
}

func (p *PoolUsageCollector) cephUsageCommand() []byte {
	cmd, err := json.Marshal(map[string]interface{}{
		"prefix": "df",
		"detail": "detail",
		"format": "json",
	})
	if err != nil {
		p.logger.WithError(err).Panic("error marshalling ceph df detail")
	}
	return cmd
}

// Describe fulfills the prometheus.Collector's interface and sends the descriptors
// of pool's metrics to the given channel.
func (p *PoolUsageCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- p.UsedBytes
	ch <- p.RawUsedBytes
	ch <- p.MaxAvail
	ch <- p.PercentUsed
	ch <- p.Objects
	ch <- p.DirtyObjects
	ch <- p.UnfoundObjects
	ch <- p.ReadIO
	ch <- p.ReadBytes
	ch <- p.WriteIO
	ch <- p.WriteBytes
}

// Collect extracts the current values of all the metrics and sends them to the
// prometheus channel.
func (p *PoolUsageCollector) Collect(ch chan<- prometheus.Metric) {
	p.logger.Debug("collecting pool usage metrics")
	if err := p.collect(ch); err != nil {
		p.logger.WithError(err).Error("error collecting pool usage metrics")
		return
	}
}
<|endoftext|>


<commit_before>package rethinkdb

import (
	"fmt"

	"testing"

	test "gopkg.in/check.v1"
	"gopkg.in/rethinkdb/rethinkdb-go.v5/internal/integration/tests"
)

// Hook up gocheck into the gotest runner.
func Test(t *testing.T) { test.TestingT(t) }

type MockSuite struct{}

var _ = test.Suite(&MockSuite{})

func (s *MockSuite) TestMockExecSuccess(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test").Insert(map[string]string{
		"id": "mocked",
	})).Return(nil, nil)

	err := DB("test").Table("test").Insert(map[string]string{
		"id": "mocked",
	}).Exec(mock)
	c.Assert(err, test.IsNil)
	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockExecFail(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test").Insert(map[string]string{
		"id": "mocked",
	})).Return(nil, fmt.Errorf("Expected error"))

	err := DB("test").Table("test").Insert(map[string]string{
		"id": "mocked",
	}).Exec(mock)
	c.Assert(err, test.NotNil)
	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockRunSuccessSingleResult(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test").Get("mocked")).Return(map[string]interface{}{
		"id": "mocked",
	}, nil)

	res, err := DB("test").Table("test").Get("mocked").Run(mock)
	c.Assert(err, test.IsNil)

	var response interface{}
	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, map[string]interface{}{"id": "mocked"})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunSuccessMultipleResults(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil)

	res, err := DB("test").Table("test").Run(mock)
	c.Assert(err, test.IsNil)

	var response []interface{}
	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []interface{}{map[string]interface{}{"id": "mocked"}})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunSuccessChannel(c *test.C) {
	mock := NewMock()
	ch := make(chan interface{})
	mock.On(DB("test").Table("test")).Return([]interface{}{ch, ch}, nil)
	go func() {
		ch <- 1
		ch <- 2
	}()
	res, err := DB("test").Table("test").Run(mock)
	c.Assert(err, test.IsNil)

	var response []interface{}
	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []interface{}{1, 2})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunSuccessFunction(c *test.C) {
	mock := NewMock()
	n := 0
	f := func() interface{} {
		n++
		return n
	}
	mock.On(DB("test").Table("test")).Return([]interface{}{f, f, 3}, nil)
	res, err := DB("test").Table("test").Run(mock)
	c.Assert(err, test.IsNil)

	var response []interface{}
	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []interface{}{1, 2, 3})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunSuccessMultipleResults_type(c *test.C) {
	type document struct {
		Id string
	}

	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]document{
		document{"mocked"},
	}, nil)

	res, err := DB("test").Table("test").Run(mock)
	c.Assert(err, test.IsNil)

	var response []interface{}
	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []document{document{"mocked"}})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunMissingMock(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil).Once()

	c.Assert(func() {
		c.Assert(DB("test").Table("test").Exec(mock), test.IsNil)
		c.Assert(DB("test").Table("test").Exec(mock), test.IsNil)
	}, test.PanicMatches, ""+
		"rethinkdb: mock: This query was unexpected:(?s:.*)")
	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockRunMissingQuery(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil).Twice()

	c.Assert(DB("test").Table("test").Exec(mock), test.IsNil)

	t := &simpleTestingT{}
	mock.AssertExpectations(t)

	c.Assert(t.Failed(), test.Equals, true)
}

func (s *MockSuite) TestMockRunMissingQuerySingle(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil).Once()

	t := &simpleTestingT{}
	mock.AssertExpectations(t)

	c.Assert(t.Failed(), test.Equals, true)
}

func (s *MockSuite) TestMockRunMissingQueryMultiple(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil).Twice()

	c.Assert(DB("test").Table("test").Exec(mock), test.IsNil)

	t := &simpleTestingT{}
	mock.AssertExpectations(t)

	c.Assert(t.Failed(), test.Equals, true)
}

func (s *MockSuite) TestMockRunMutlipleQueries(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test").Get("mocked1")).Return(map[string]interface{}{
		"id": "mocked1",
	}, nil).Times(2)
	mock.On(DB("test").Table("test").Get("mocked2")).Return(map[string]interface{}{
		"id": "mocked2",
	}, nil).Times(1)

	var response interface{}

	// Query 1
	res, err := DB("test").Table("test").Get("mocked1").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, map[string]interface{}{"id": "mocked1"})

	// Query 2
	res, err = DB("test").Table("test").Get("mocked1").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, map[string]interface{}{"id": "mocked1"})

	// Query 3
	res, err = DB("test").Table("test").Get("mocked2").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, map[string]interface{}{"id": "mocked2"})

	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockQueriesWithFuncs(c *test.C) {
	mock := NewMock()
	mock.On(Expr([]int{2}).Map(func(row Term) interface{} {
		return row.Add(1)
	})).Return([]int{3}, nil).Times(2)
	mock.On(Expr([]int{4}).Map(func(row1, row2 Term) interface{} {
		return row1.Add(1)
	})).Return([]int{5}, nil).Times(1)
	mock.On(Expr([]int{9}).Map(func(row1, row2 Term) interface{} {
		return row2.Add(1)
	})).Return([]int{10}, nil).Times(1)

	var response []int

	// Query 1
	res, err := Expr([]int{2}).Map(func(row Term) interface{} {
		return row.Add(1)
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []int{3})

	// Query 2
	res, err = Expr([]int{2}).Map(func(row Term) interface{} {
		return row.Add(1)
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []int{3})

	// Query 3
	res, err = Expr([]int{4}).Map(func(row1, row2 Term) interface{} {
		return row1.Add(1)
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []int{5})

	// Query 5
	res, err = Expr([]int{9}).Map(func(row1, row2 Term) interface{} {
		return row2.Add(1)
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []int{10})

	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockAnything(c *test.C) {
	mock := NewMock()
	mock.On(MockAnything()).Return("okay", nil).Times(1)
	mock.On(Table("test").MockAnything()).Return("okay2", nil).Times(1)
	mock.On(Table("test").Insert(map[string]interface{}{
		"id": MockAnything(),
	})).Return("okay3", nil).Times(1)
	mock.On(Expr([]interface{}{1, 2, MockAnything()})).Return("okay4", nil).Times(1)

	var response string

	// Query 1
	res, err := Expr("test_1").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, "okay")

	// Query 2
	res, err = Table("test").Get("mocked1").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, "okay2")

	// Query 3
	res, err = Table("test").Insert(map[string]interface{}{
		"id": "10ECE456-3C4D-4864-A843-879FCB0D133F",
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, "okay3")

	// Query 3
	res, err = Expr([]interface{}{1, 2, 3}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, "okay4")

	mock.AssertExpectations(c)
}

type simpleTestingT struct {
	failed bool
}

func (t *simpleTestingT) Logf(format string, args ...interface{}) {
}
func (t *simpleTestingT) Errorf(format string, args ...interface{}) {
	t.failed = true
}
func (t *simpleTestingT) FailNow() {
	t.failed = true
}
func (t *simpleTestingT) Failed() bool {
	return t.failed
}

func TestSomething(t *testing.T) {
	mock := NewMock()
	ch := make(chan interface{})
	mock.On(Table("people")).Return([]interface{}{ch, ch}, nil)
	go func() {
		ch <- map[string]interface{}{"id": 1, "name": "John Smith"}
		ch <- map[string]interface{}{"id": 2, "name": "Jane Smith"}
	}()
	cursor, err := Table("people").Run(mock)
	if err != nil {
		t.Errorf("err is: %v", err)
	}

	var rows []interface{}
	err = cursor.All(&rows)
	if err != nil {
		t.Errorf("err is: %v", err)
	}

	// Test result of rows

	mock.AssertExpectations(t)
}
<commit_msg>Remove TestSomething committed by mistake<commit_after>package rethinkdb

import (
	"fmt"

	"testing"

	test "gopkg.in/check.v1"
	"gopkg.in/rethinkdb/rethinkdb-go.v5/internal/integration/tests"
)

// Hook up gocheck into the gotest runner.
func Test(t *testing.T) { test.TestingT(t) }

type MockSuite struct{}

var _ = test.Suite(&MockSuite{})

func (s *MockSuite) TestMockExecSuccess(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test").Insert(map[string]string{
		"id": "mocked",
	})).Return(nil, nil)

	err := DB("test").Table("test").Insert(map[string]string{
		"id": "mocked",
	}).Exec(mock)
	c.Assert(err, test.IsNil)
	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockExecFail(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test").Insert(map[string]string{
		"id": "mocked",
	})).Return(nil, fmt.Errorf("Expected error"))

	err := DB("test").Table("test").Insert(map[string]string{
		"id": "mocked",
	}).Exec(mock)
	c.Assert(err, test.NotNil)
	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockRunSuccessSingleResult(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test").Get("mocked")).Return(map[string]interface{}{
		"id": "mocked",
	}, nil)

	res, err := DB("test").Table("test").Get("mocked").Run(mock)
	c.Assert(err, test.IsNil)

	var response interface{}
	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, map[string]interface{}{"id": "mocked"})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunSuccessMultipleResults(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil)

	res, err := DB("test").Table("test").Run(mock)
	c.Assert(err, test.IsNil)

	var response []interface{}
	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []interface{}{map[string]interface{}{"id": "mocked"}})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunSuccessChannel(c *test.C) {
	mock := NewMock()
	ch := make(chan interface{})
	mock.On(DB("test").Table("test")).Return([]interface{}{ch, ch}, nil)
	go func() {
		ch <- 1
		ch <- 2
	}()
	res, err := DB("test").Table("test").Run(mock)
	c.Assert(err, test.IsNil)

	var response []interface{}
	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []interface{}{1, 2})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunSuccessFunction(c *test.C) {
	mock := NewMock()
	n := 0
	f := func() interface{} {
		n++
		return n
	}
	mock.On(DB("test").Table("test")).Return([]interface{}{f, f, 3}, nil)
	res, err := DB("test").Table("test").Run(mock)
	c.Assert(err, test.IsNil)

	var response []interface{}
	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []interface{}{1, 2, 3})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunSuccessMultipleResults_type(c *test.C) {
	type document struct {
		Id string
	}

	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]document{
		document{"mocked"},
	}, nil)

	res, err := DB("test").Table("test").Run(mock)
	c.Assert(err, test.IsNil)

	var response []interface{}
	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []document{document{"mocked"}})
	mock.AssertExpectations(c)

	res.Close()
}

func (s *MockSuite) TestMockRunMissingMock(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil).Once()

	c.Assert(func() {
		c.Assert(DB("test").Table("test").Exec(mock), test.IsNil)
		c.Assert(DB("test").Table("test").Exec(mock), test.IsNil)
	}, test.PanicMatches, ""+
		"rethinkdb: mock: This query was unexpected:(?s:.*)")
	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockRunMissingQuery(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil).Twice()

	c.Assert(DB("test").Table("test").Exec(mock), test.IsNil)

	t := &simpleTestingT{}
	mock.AssertExpectations(t)

	c.Assert(t.Failed(), test.Equals, true)
}

func (s *MockSuite) TestMockRunMissingQuerySingle(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil).Once()

	t := &simpleTestingT{}
	mock.AssertExpectations(t)

	c.Assert(t.Failed(), test.Equals, true)
}

func (s *MockSuite) TestMockRunMissingQueryMultiple(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test")).Return([]interface{}{
		map[string]interface{}{"id": "mocked"},
	}, nil).Twice()

	c.Assert(DB("test").Table("test").Exec(mock), test.IsNil)

	t := &simpleTestingT{}
	mock.AssertExpectations(t)

	c.Assert(t.Failed(), test.Equals, true)
}

func (s *MockSuite) TestMockRunMutlipleQueries(c *test.C) {
	mock := NewMock()
	mock.On(DB("test").Table("test").Get("mocked1")).Return(map[string]interface{}{
		"id": "mocked1",
	}, nil).Times(2)
	mock.On(DB("test").Table("test").Get("mocked2")).Return(map[string]interface{}{
		"id": "mocked2",
	}, nil).Times(1)

	var response interface{}

	// Query 1
	res, err := DB("test").Table("test").Get("mocked1").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, map[string]interface{}{"id": "mocked1"})

	// Query 2
	res, err = DB("test").Table("test").Get("mocked1").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, map[string]interface{}{"id": "mocked1"})

	// Query 3
	res, err = DB("test").Table("test").Get("mocked2").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, map[string]interface{}{"id": "mocked2"})

	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockQueriesWithFuncs(c *test.C) {
	mock := NewMock()
	mock.On(Expr([]int{2}).Map(func(row Term) interface{} {
		return row.Add(1)
	})).Return([]int{3}, nil).Times(2)
	mock.On(Expr([]int{4}).Map(func(row1, row2 Term) interface{} {
		return row1.Add(1)
	})).Return([]int{5}, nil).Times(1)
	mock.On(Expr([]int{9}).Map(func(row1, row2 Term) interface{} {
		return row2.Add(1)
	})).Return([]int{10}, nil).Times(1)

	var response []int

	// Query 1
	res, err := Expr([]int{2}).Map(func(row Term) interface{} {
		return row.Add(1)
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []int{3})

	// Query 2
	res, err = Expr([]int{2}).Map(func(row Term) interface{} {
		return row.Add(1)
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []int{3})

	// Query 3
	res, err = Expr([]int{4}).Map(func(row1, row2 Term) interface{} {
		return row1.Add(1)
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []int{5})

	// Query 5
	res, err = Expr([]int{9}).Map(func(row1, row2 Term) interface{} {
		return row2.Add(1)
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.All(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, []int{10})

	mock.AssertExpectations(c)
}

func (s *MockSuite) TestMockAnything(c *test.C) {
	mock := NewMock()
	mock.On(MockAnything()).Return("okay", nil).Times(1)
	mock.On(Table("test").MockAnything()).Return("okay2", nil).Times(1)
	mock.On(Table("test").Insert(map[string]interface{}{
		"id": MockAnything(),
	})).Return("okay3", nil).Times(1)
	mock.On(Expr([]interface{}{1, 2, MockAnything()})).Return("okay4", nil).Times(1)

	var response string

	// Query 1
	res, err := Expr("test_1").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, "okay")

	// Query 2
	res, err = Table("test").Get("mocked1").Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, "okay2")

	// Query 3
	res, err = Table("test").Insert(map[string]interface{}{
		"id": "10ECE456-3C4D-4864-A843-879FCB0D133F",
	}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, "okay3")

	// Query 3
	res, err = Expr([]interface{}{1, 2, 3}).Run(mock)
	c.Assert(err, test.IsNil)

	err = res.One(&response)

	c.Assert(err, test.IsNil)
	c.Assert(response, tests.JsonEquals, "okay4")

	mock.AssertExpectations(c)
}

type simpleTestingT struct {
	failed bool
}

func (t *simpleTestingT) Logf(format string, args ...interface{}) {
}
func (t *simpleTestingT) Errorf(format string, args ...interface{}) {
	t.failed = true
}
func (t *simpleTestingT) FailNow() {
	t.failed = true
}
func (t *simpleTestingT) Failed() bool {
	return t.failed
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	//"fmt"
	"path"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
)

/* This function takes a string and returns
   a (potentially nil) error object */
func TTWS(filename string) error {
	/* Open the input file */
	inf, err := os.Open(filename);
	/* In case this function generates a "panic", be sure to close this file */
	defer inf.Close();
	/* Did we open it successfully?  If not, close and return. */
	if (err!=nil) { inf.Close(); return err; }

	/* Open the output file in system temp dir*/
	outf, err := ioutil.TempFile("","");
	/* In case this function generates a "panic", be sure to close this file */
	defer outf.Close();
	/* Did we open it succesfully?  If not, close all and return. */
	if (err!=nil) { inf.Close(); outf.Close(); return err; }
	/* Create a scanner object to break this in to lines */
	scanner := bufio.NewScanner(inf);
	/* Declare a variable for the line */
	var line string;
	/* Loop over lines */
	for scanner.Scan() {
		/* Trim right space and then add the \n back on the end before writing */
		line = strings.TrimRight(scanner.Text(), " \t")+"\n"
		outf.Write([]byte(line));
	}
	/* Close all open files */
	inf.Close();
	outf.Close();
	/* Replace the source file by the trimmed file */
	os.Rename(outf.Name(), filename);

	/* No errors, so we return nil */
	return nil;
}

var blacklist = []string{".bzr", ".cvs", ".git", ".hg", ".svn"}

func processFile(filename string) error {
	inf, err := os.Open(filename)
	defer inf.Close();
	if (err!=nil) { inf.Close(); return err; }

	readStart := io.LimitReader(inf, 512);

	data, err := ioutil.ReadAll(readStart);

	/* Close all open files */
	inf.Close();

	/* Determine file type */
	fileType := http.DetectContentType(data);

	/* only act on text files */
	if (strings.Contains(fileType, "text/plain")){
		//fmt.Printf("Trimming: %v\n", filename);
		return TTWS(filename);
	} else {
		//fmt.Printf("Skipping file of type '%v': %v\n", fileType, filename)
		return nil;
	}
}

func processNode(node string) error {
	fi, err := os.Lstat(node)
	if (err!=nil) { return err; }

	if (fi.IsDir()) {
		if contains(fi.Name(), blacklist) { return nil; }
		contents, err := ioutil.ReadDir(node);
		if (err!=nil) { return err; }
		for _, n := range(contents) {
			serr := processNode(path.Join(node, n.Name()));
			if (serr!=nil) { return serr; }
		}
		return nil;
	} else {
		return processFile(node);
	}
}

func contains(x string, a []string) bool {
	for _, e := range(a) {
		if (x==e) { return true; }
	}
	return false;
}

func main() {
	flag.Parse()
	root := flag.Arg(0)
	//err := filepath.Walk(root, WalkFunc)
	//filepath.Walk(root, WalkFunc)
	processNode(root);
	//fmt.Printf("filepath.Walk() returned %v\n", err)
}
<commit_msg>Added verbose flag<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"path"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
)

/* This function takes a string and returns
   a (potentially nil) error object */
func TTWS(filename string) error {
	/* Open the input file */
	inf, err := os.Open(filename);
	/* In case this function generates a "panic", be sure to close this file */
	defer inf.Close();
	/* Did we open it successfully?  If not, close and return. */
	if (err!=nil) { inf.Close(); return err; }

	/* Open the output file in system temp dir*/
	outf, err := ioutil.TempFile("","");
	/* In case this function generates a "panic", be sure to close this file */
	defer outf.Close();
	/* Did we open it succesfully?  If not, close all and return. */
	if (err!=nil) { inf.Close(); outf.Close(); return err; }
	/* Create a scanner object to break this in to lines */
	scanner := bufio.NewScanner(inf);
	/* Declare a variable for the line */
	var line string;
	/* Loop over lines */
	for scanner.Scan() {
		/* Trim right space and then add the \n back on the end before writing */
		line = strings.TrimRight(scanner.Text(), " \t")+"\n"
		outf.Write([]byte(line));
	}
	/* Close all open files */
	inf.Close();
	outf.Close();
	/* Replace the source file by the trimmed file */
	os.Rename(outf.Name(), filename);

	/* No errors, so we return nil */
	return nil;
}

var blacklist = []string{".bzr", ".cvs", ".git", ".hg", ".svn"}

func processFile(filename string, verbose bool) error {
	inf, err := os.Open(filename)
	defer inf.Close();
	if (err!=nil) { inf.Close(); return err; }

	readStart := io.LimitReader(inf, 512);

	data, err := ioutil.ReadAll(readStart);

	/* Close all open files */
	inf.Close();

	/* Determine file type */
	fileType := http.DetectContentType(data);

	/* only act on text files */
	if (strings.Contains(fileType, "text/plain")){
		if (verbose) { fmt.Printf("Trimming: %v\n", filename); }
		return TTWS(filename);
	} else {
		if (verbose) { fmt.Printf("Skipping file of type '%v': %v\n", fileType, filename); }
		return nil;
	}
}

func processNode(node string, verbose bool) error {
	fi, err := os.Lstat(node)
	if (err!=nil) { return err; }

	if (fi.IsDir()) {
		if contains(fi.Name(), blacklist) { return nil; }
		contents, err := ioutil.ReadDir(node);
		if (err!=nil) { return err; }
		for _, n := range(contents) {
			serr := processNode(path.Join(node, n.Name()), verbose);
			if (serr!=nil) { return serr; }
		}
		return nil;
	} else {
		return processFile(node, verbose);
	}
}

func contains(x string, a []string) bool {
	for _, e := range(a) {
		if (x==e) { return true; }
	}
	return false;
}

func main() {
	flag.Parse()
	root := flag.Arg(0)
	err := processNode(root, true);
	fmt.Printf("processNode("+root+") returned %v\n", err);
}
<|endoftext|>


<commit_before>package cmd

import (
	"io"
	"os"
	"fmt"
	"strconv"

	"github.com/minio/minio-go/pkg/policy"
)

// How many seconds to wait to purge object from SiaBridge cache
var SIA_CACHE_PURGE_AFTER_SEC = 24*60*60 // 24 hours
var SIA_DAEMON_ADDR = "127.0.0.1:9980"
var SIA_CACHE_DIR = ".sia_cache"
var SIA_DB_FILE = ".sia.db"
var SIA_DEBUG = 0

type siaObjects struct {
	siacl *SiaCacheLayer
	fs ObjectLayer
}

// newSiaGateway returns Sia gatewaylayer
func newSiaGateway(host string) (GatewayLayer, error) {
	loadSiaEnv()

	// Create the filesystem layer
	f, err := newFSObjectLayer(SIA_CACHE_DIR)
	if err != nil {
		return nil, err
	}
	// Create the Sia cache layer
	s := &SiaCacheLayer{SIA_DAEMON_ADDR, SIA_CACHE_DIR, SIA_DB_FILE}

	// Start the Sia cache layer
	err = s.Start()
	if err != nil {
		panic(err)
	}

	return &siaObjects{
		siacl:	s,
		fs:     f,
	}, nil
}

// Attempt to load Sia config from ENV
func loadSiaEnv() {
	tmp := os.Getenv("SIA_CACHE_DIR")
	if tmp != "" {
		SIA_CACHE_DIR = tmp
	}
	fmt.Printf("SIA_CACHE_DIR: %s\n", SIA_CACHE_DIR)

	tmp = os.Getenv("SIA_CACHE_PURGE_AFTER_SEC")
	if tmp != "" {
		i, err := strconv.Atoi(tmp)
		if err == nil {
			SIA_CACHE_PURGE_AFTER_SEC = i
		}
	}
	fmt.Printf("SIA_CACHE_PURGE_AFTER_SEC: %d\n", SIA_CACHE_PURGE_AFTER_SEC)

	tmp = os.Getenv("SIA_DAEMON_ADDR")
	if tmp != "" {
		SIA_DAEMON_ADDR = tmp
	}
	fmt.Printf("SIA_DAEMON_ADDR: %s\n", SIA_DAEMON_ADDR)

	tmp = os.Getenv("SIA_DB_FILE")
	if tmp != "" {
		SIA_DB_FILE = tmp
	}
	fmt.Printf("SIA_DB_FILE: %s\n", SIA_DB_FILE)

	tmp = os.Getenv("SIA_DEBUG")
	if tmp != "" {
		i, err := strconv.Atoi(tmp)
		if err == nil {
			SIA_DEBUG = i
		}
	}
	fmt.Printf("SIA_DEBUG: %d\n", SIA_DEBUG)
}

// Shutdown saves any gateway metadata to disk
// if necessary and reload upon next restart.
func (s *siaObjects) Shutdown() error {
	debugmsg("Gateway.Shutdown")

	// Stop the Sia caching layer
	s.siacl.Stop()

	return nil
}

// StorageInfo is not relevant to Sia backend.
func (s *siaObjects) StorageInfo() (si StorageInfo) {
	debugmsg("Gateway.StorageInfo")
	return si
}

// MakeBucket creates a new container on Sia backend.
func (s *siaObjects) MakeBucketWithLocation(bucket, location string) error {
	debugmsg(fmt.Sprintf("Gateway.MakeBucketWithLocation(%s, %s)", bucket, location))
	err := s.fs.MakeBucketWithLocation(bucket, location)
	if err != nil {
		return err
	}

	return s.siacl.InsertBucket(bucket)
}

// GetBucketInfo gets bucket metadata.
func (s *siaObjects) GetBucketInfo(bucket string) (bi BucketInfo, e error) {
	debugmsg("Gateway.GetBucketInfo")
	return s.fs.GetBucketInfo(bucket)
}

// ListBuckets lists all Sia buckets
func (s *siaObjects) ListBuckets() (buckets []BucketInfo, e error) {
	debugmsg("Gateway.ListBuckets")
	return s.fs.ListBuckets()
}

// DeleteBucket deletes a bucket on Sia
func (s *siaObjects) DeleteBucket(bucket string) error {
	debugmsg("Gateway.DeleteBucket")
	err := s.siacl.DeleteBucket(bucket)
	if err != nil {
		return err
	}

	return s.fs.DeleteBucket(bucket)
}

func (s *siaObjects) ListObjects(bucket string, prefix string, marker string, delimiter string, maxKeys int) (loi ListObjectsInfo, e error) {
	debugmsg("Gateway.ListObjects")
	sobjs, err := s.siacl.ListObjects(bucket)
	if err != nil {
		return loi, err
	}

	loi.IsTruncated = false
	loi.NextMarker = ""

	for _, sobj := range sobjs {
		loi.Objects = append(loi.Objects, ObjectInfo{
			Bucket:          bucket,
			Name:            sobj.Name,
			ModTime:         sobj.Queued,
			Size:            int64(sobj.Size),
			//ETag:            azureToS3ETag(object.Properties.Etag),
			//ContentType:     object.Properties.ContentType,
			//ContentEncoding: object.Properties.ContentEncoding,
		})
	}

return loi, nil
}

func (s *siaObjects) ListObjectsV2(bucket, prefix, continuationToken string, fetchOwner bool, delimiter string, maxKeys int) (loi ListObjectsV2Info, e error) {
	debugmsg("Gateway.ListObjectsV2")
	return loi, nil
}

func (s *siaObjects) GetObject(bucket string, key string, startOffset int64, length int64, writer io.Writer) error {
	debugmsg("Gateway.GetObject")
	err := s.siacl.GuaranteeObjectIsInCache(bucket, key)
	if err != nil {
		return err
	}

	return s.fs.GetObject(bucket, key, startOffset, length, writer)
}

// GetObjectInfo reads object info and replies back ObjectInfo
func (s *siaObjects) GetObjectInfo(bucket string, object string) (objInfo ObjectInfo, err error) {
	debugmsg("Gateway.GetObjectInfo")
	return s.fs.GetObjectInfo(bucket, object)
}

// PutObject creates a new object with the incoming data,
func (s *siaObjects) PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string, sha256sum string) (objInfo ObjectInfo, e error) {
	debugmsg("Gateway.PutObject")
	oi, e := s.fs.PutObject(bucket, object, size, data, metadata, sha256sum)
	if e != nil {
		return oi, e
	}

	src_file := pathJoin(abs(SIA_CACHE_DIR), bucket, object)
	e = s.siacl.PutObject(bucket, object, size, int64(SIA_CACHE_PURGE_AFTER_SEC), src_file)
	// If put fails to the cache layer, then delete from object layer
	if e != nil {
		s.fs.DeleteObject(bucket, object)
	}
	return oi, e
}

// CopyObject copies a blob from source container to destination container.
func (s *siaObjects) CopyObject(srcBucket string, srcObject string, destBucket string, destObject string, metadata map[string]string) (objInfo ObjectInfo, e error) {
	debugmsg("Gateway.CopyObject")
	return s.fs.CopyObject(srcBucket, srcObject, destBucket, destObject, metadata)
}

// DeleteObject deletes a blob in bucket
func (s *siaObjects) DeleteObject(bucket string, object string) error {
	debugmsg("Gateway.DeleteObject")
	err := s.siacl.DeleteObject(bucket, object)
	if err != nil {
		return err
	}

	return s.fs.DeleteObject(bucket, object)
}

// ListMultipartUploads lists all multipart uploads.
func (s *siaObjects) ListMultipartUploads(bucket string, prefix string, keyMarker string, uploadIDMarker string, delimiter string, maxUploads int) (lmi ListMultipartsInfo, e error) {
	debugmsg("Gateway.ListMultipartUploads")
	return s.fs.ListMultipartUploads(bucket, prefix, keyMarker, uploadIDMarker, delimiter, maxUploads)
}

// NewMultipartUpload upload object in multiple parts
func (s *siaObjects) NewMultipartUpload(bucket string, object string, metadata map[string]string) (uploadID string, err error) {
	debugmsg("Gateway.NewMultipartUpload")
	return s.fs.NewMultipartUpload(bucket, object, metadata)
}

// CopyObjectPart copy part of object to other bucket and object
func (s *siaObjects) CopyObjectPart(srcBucket string, srcObject string, destBucket string, destObject string, uploadID string, partID int, startOffset int64, length int64) (info PartInfo, err error) {
	debugmsg("Gateway.CopyObjectPart")
	return s.fs.CopyObjectPart(srcBucket, srcObject, destBucket, destObject, uploadID, partID, startOffset, length)
}

// PutObjectPart puts a part of object in bucket
func (s *siaObjects) PutObjectPart(bucket string, object string, uploadID string, partID int, size int64, data io.Reader, md5Hex string, sha256sum string) (pi PartInfo, e error) {
	debugmsg("Gateway.PutObjectPart")
	return s.fs.PutObjectPart(bucket, object, uploadID, partID, size, data, md5Hex, sha256sum)
}

// ListObjectParts returns all object parts for specified object in specified bucket
func (s *siaObjects) ListObjectParts(bucket string, object string, uploadID string, partNumberMarker int, maxParts int) (lpi ListPartsInfo, e error) {
	debugmsg("Gateway.ListObjectParts")
	return s.fs.ListObjectParts(bucket, object, uploadID, partNumberMarker, maxParts)
}

// AbortMultipartUpload aborts a ongoing multipart upload
func (s *siaObjects) AbortMultipartUpload(bucket string, object string, uploadID string) error {
	debugmsg("Gateway.AbortMultipartUpload")
	return s.fs.AbortMultipartUpload(bucket, object, uploadID)
}

// CompleteMultipartUpload completes ongoing multipart upload and finalizes object
func (s *siaObjects) CompleteMultipartUpload(bucket string, object string, uploadID string, uploadedParts []completePart) (oi ObjectInfo, e error) {
	debugmsg("Gateway.CompleteMultipartUpload")
	oi, err := s.fs.CompleteMultipartUpload(bucket, object, uploadID, uploadedParts)
	if err != nil {
		return oi, err
	}

	src_file := pathJoin(abs(SIA_CACHE_DIR), bucket, object)
	fi, err := os.Stat(src_file)
	if err != nil {
		return oi, err
	}

	err = s.siacl.PutObject(bucket, object, fi.Size(), int64(SIA_CACHE_PURGE_AFTER_SEC), src_file)
	// If put fails to the cache layer, then delete from object layer
	if err != nil {
		s.fs.DeleteObject(bucket, object)
	}

	return oi, nil
}

// SetBucketPolicies sets policy on bucket
func (s *siaObjects) SetBucketPolicies(bucket string, policyInfo policy.BucketAccessPolicy) error {
	debugmsg("Gateway.SetBucketPolicies")
	//return s.fs.SetBucketPolicies(bucket, policyInfo)
	return nil
}

// GetBucketPolicies will get policy on bucket
func (s *siaObjects) GetBucketPolicies(bucket string) (policy.BucketAccessPolicy, error) {
	debugmsg("Gateway.GetBucketPolicies")
	//return s.fs.GetBucketPolicies(bucket)
	return policy.BucketAccessPolicy{}, nil
}

// DeleteBucketPolicies deletes all policies on bucket
func (s *siaObjects) DeleteBucketPolicies(bucket string) error {
	debugmsg("Gateway.DeleteBucketPolicies")
	//return s.fs.DeleteBucketPolciies(bucket)
	return nil
}
<commit_msg>Minor debug change<commit_after>package cmd

import (
	"io"
	"os"
	"fmt"
	"strconv"

	"github.com/minio/minio-go/pkg/policy"
)

// How many seconds to wait to purge object from SiaBridge cache
var SIA_CACHE_PURGE_AFTER_SEC = 24*60*60 // 24 hours
var SIA_DAEMON_ADDR = "127.0.0.1:9980"
var SIA_CACHE_DIR = ".sia_cache"
var SIA_DB_FILE = ".sia.db"
var SIA_DEBUG = 0

type siaObjects struct {
	siacl *SiaCacheLayer
	fs ObjectLayer
}

// newSiaGateway returns Sia gatewaylayer
func newSiaGateway(host string) (GatewayLayer, error) {
	loadSiaEnv()

	// Create the filesystem layer
	f, err := newFSObjectLayer(SIA_CACHE_DIR)
	if err != nil {
		return nil, err
	}
	// Create the Sia cache layer
	s := &SiaCacheLayer{SIA_DAEMON_ADDR, SIA_CACHE_DIR, SIA_DB_FILE}

	// Start the Sia cache layer
	err = s.Start()
	if err != nil {
		panic(err)
	}

	return &siaObjects{
		siacl:	s,
		fs:     f,
	}, nil
}

// Attempt to load Sia config from ENV
func loadSiaEnv() {
	tmp := os.Getenv("SIA_CACHE_DIR")
	if tmp != "" {
		SIA_CACHE_DIR = tmp
	}
	fmt.Printf("SIA_CACHE_DIR: %s\n", SIA_CACHE_DIR)

	tmp = os.Getenv("SIA_CACHE_PURGE_AFTER_SEC")
	if tmp != "" {
		i, err := strconv.Atoi(tmp)
		if err == nil {
			SIA_CACHE_PURGE_AFTER_SEC = i
		}
	}
	fmt.Printf("SIA_CACHE_PURGE_AFTER_SEC: %d\n", SIA_CACHE_PURGE_AFTER_SEC)

	tmp = os.Getenv("SIA_DAEMON_ADDR")
	if tmp != "" {
		SIA_DAEMON_ADDR = tmp
	}
	fmt.Printf("SIA_DAEMON_ADDR: %s\n", SIA_DAEMON_ADDR)

	tmp = os.Getenv("SIA_DB_FILE")
	if tmp != "" {
		SIA_DB_FILE = tmp
	}
	fmt.Printf("SIA_DB_FILE: %s\n", SIA_DB_FILE)

	tmp = os.Getenv("SIA_DEBUG")
	if tmp != "" {
		i, err := strconv.Atoi(tmp)
		if err == nil {
			SIA_DEBUG = i
		}
	}
	fmt.Printf("SIA_DEBUG: %d\n", SIA_DEBUG)
}

// Shutdown saves any gateway metadata to disk
// if necessary and reload upon next restart.
func (s *siaObjects) Shutdown() error {
	debugmsg("Gateway.Shutdown")

	// Stop the Sia caching layer
	s.siacl.Stop()

	return nil
}

// StorageInfo is not relevant to Sia backend.
func (s *siaObjects) StorageInfo() (si StorageInfo) {
	debugmsg("Gateway.StorageInfo")
	return si
}

// MakeBucket creates a new container on Sia backend.
func (s *siaObjects) MakeBucketWithLocation(bucket, location string) error {
	debugmsg(fmt.Sprintf("Gateway.MakeBucketWithLocation(%s, %s)", bucket, location))
	err := s.fs.MakeBucketWithLocation(bucket, location)
	if err != nil {
		return err
	}

	return s.siacl.InsertBucket(bucket)
}

// GetBucketInfo gets bucket metadata.
func (s *siaObjects) GetBucketInfo(bucket string) (bi BucketInfo, e error) {
	debugmsg("Gateway.GetBucketInfo")
	return s.fs.GetBucketInfo(bucket)
}

// ListBuckets lists all Sia buckets
func (s *siaObjects) ListBuckets() (buckets []BucketInfo, e error) {
	debugmsg("Gateway.ListBuckets")
	return s.fs.ListBuckets()
}

// DeleteBucket deletes a bucket on Sia
func (s *siaObjects) DeleteBucket(bucket string) error {
	debugmsg("Gateway.DeleteBucket")
	err := s.siacl.DeleteBucket(bucket)
	if err != nil {
		return err
	}

	return s.fs.DeleteBucket(bucket)
}

func (s *siaObjects) ListObjects(bucket string, prefix string, marker string, delimiter string, maxKeys int) (loi ListObjectsInfo, e error) {
	debugmsg("Gateway.ListObjects")
	sobjs, err := s.siacl.ListObjects(bucket)
	if err != nil {
		return loi, err
	}

	loi.IsTruncated = false
	loi.NextMarker = ""

	for _, sobj := range sobjs {
		loi.Objects = append(loi.Objects, ObjectInfo{
			Bucket:          bucket,
			Name:            sobj.Name,
			ModTime:         sobj.Queued,
			Size:            int64(sobj.Size),
			//ETag:            azureToS3ETag(object.Properties.Etag),
			//ContentType:     object.Properties.ContentType,
			//ContentEncoding: object.Properties.ContentEncoding,
		})
	}

return loi, nil
}

func (s *siaObjects) ListObjectsV2(bucket, prefix, continuationToken string, fetchOwner bool, delimiter string, maxKeys int) (loi ListObjectsV2Info, e error) {
	debugmsg("Gateway.ListObjectsV2")
	return loi, nil
}

func (s *siaObjects) GetObject(bucket string, key string, startOffset int64, length int64, writer io.Writer) error {
	debugmsg("Gateway.GetObject %s %s startOffset: %d, length: %d", bucket, key, startOffset, length)
	err := s.siacl.GuaranteeObjectIsInCache(bucket, key)
	if err != nil {
		return err
	}

	return s.fs.GetObject(bucket, key, startOffset, length, writer)
}

// GetObjectInfo reads object info and replies back ObjectInfo
func (s *siaObjects) GetObjectInfo(bucket string, object string) (objInfo ObjectInfo, err error) {
	debugmsg("Gateway.GetObjectInfo")
	return s.fs.GetObjectInfo(bucket, object)
}

// PutObject creates a new object with the incoming data,
func (s *siaObjects) PutObject(bucket string, object string, size int64, data io.Reader, metadata map[string]string, sha256sum string) (objInfo ObjectInfo, e error) {
	debugmsg("Gateway.PutObject")
	oi, e := s.fs.PutObject(bucket, object, size, data, metadata, sha256sum)
	if e != nil {
		return oi, e
	}

	src_file := pathJoin(abs(SIA_CACHE_DIR), bucket, object)
	e = s.siacl.PutObject(bucket, object, size, int64(SIA_CACHE_PURGE_AFTER_SEC), src_file)
	// If put fails to the cache layer, then delete from object layer
	if e != nil {
		s.fs.DeleteObject(bucket, object)
	}
	return oi, e
}

// CopyObject copies a blob from source container to destination container.
func (s *siaObjects) CopyObject(srcBucket string, srcObject string, destBucket string, destObject string, metadata map[string]string) (objInfo ObjectInfo, e error) {
	debugmsg("Gateway.CopyObject")
	return s.fs.CopyObject(srcBucket, srcObject, destBucket, destObject, metadata)
}

// DeleteObject deletes a blob in bucket
func (s *siaObjects) DeleteObject(bucket string, object string) error {
	debugmsg("Gateway.DeleteObject")
	err := s.siacl.DeleteObject(bucket, object)
	if err != nil {
		return err
	}

	return s.fs.DeleteObject(bucket, object)
}

// ListMultipartUploads lists all multipart uploads.
func (s *siaObjects) ListMultipartUploads(bucket string, prefix string, keyMarker string, uploadIDMarker string, delimiter string, maxUploads int) (lmi ListMultipartsInfo, e error) {
	debugmsg("Gateway.ListMultipartUploads")
	return s.fs.ListMultipartUploads(bucket, prefix, keyMarker, uploadIDMarker, delimiter, maxUploads)
}

// NewMultipartUpload upload object in multiple parts
func (s *siaObjects) NewMultipartUpload(bucket string, object string, metadata map[string]string) (uploadID string, err error) {
	debugmsg("Gateway.NewMultipartUpload")
	return s.fs.NewMultipartUpload(bucket, object, metadata)
}

// CopyObjectPart copy part of object to other bucket and object
func (s *siaObjects) CopyObjectPart(srcBucket string, srcObject string, destBucket string, destObject string, uploadID string, partID int, startOffset int64, length int64) (info PartInfo, err error) {
	debugmsg("Gateway.CopyObjectPart")
	return s.fs.CopyObjectPart(srcBucket, srcObject, destBucket, destObject, uploadID, partID, startOffset, length)
}

// PutObjectPart puts a part of object in bucket
func (s *siaObjects) PutObjectPart(bucket string, object string, uploadID string, partID int, size int64, data io.Reader, md5Hex string, sha256sum string) (pi PartInfo, e error) {
	debugmsg("Gateway.PutObjectPart")
	return s.fs.PutObjectPart(bucket, object, uploadID, partID, size, data, md5Hex, sha256sum)
}

// ListObjectParts returns all object parts for specified object in specified bucket
func (s *siaObjects) ListObjectParts(bucket string, object string, uploadID string, partNumberMarker int, maxParts int) (lpi ListPartsInfo, e error) {
	debugmsg("Gateway.ListObjectParts")
	return s.fs.ListObjectParts(bucket, object, uploadID, partNumberMarker, maxParts)
}

// AbortMultipartUpload aborts a ongoing multipart upload
func (s *siaObjects) AbortMultipartUpload(bucket string, object string, uploadID string) error {
	debugmsg("Gateway.AbortMultipartUpload")
	return s.fs.AbortMultipartUpload(bucket, object, uploadID)
}

// CompleteMultipartUpload completes ongoing multipart upload and finalizes object
func (s *siaObjects) CompleteMultipartUpload(bucket string, object string, uploadID string, uploadedParts []completePart) (oi ObjectInfo, e error) {
	debugmsg("Gateway.CompleteMultipartUpload")
	oi, err := s.fs.CompleteMultipartUpload(bucket, object, uploadID, uploadedParts)
	if err != nil {
		return oi, err
	}

	src_file := pathJoin(abs(SIA_CACHE_DIR), bucket, object)
	fi, err := os.Stat(src_file)
	if err != nil {
		return oi, err
	}

	err = s.siacl.PutObject(bucket, object, fi.Size(), int64(SIA_CACHE_PURGE_AFTER_SEC), src_file)
	// If put fails to the cache layer, then delete from object layer
	if err != nil {
		s.fs.DeleteObject(bucket, object)
	}

	return oi, nil
}

// SetBucketPolicies sets policy on bucket
func (s *siaObjects) SetBucketPolicies(bucket string, policyInfo policy.BucketAccessPolicy) error {
	debugmsg("Gateway.SetBucketPolicies")
	//return s.fs.SetBucketPolicies(bucket, policyInfo)
	return nil
}

// GetBucketPolicies will get policy on bucket
func (s *siaObjects) GetBucketPolicies(bucket string) (policy.BucketAccessPolicy, error) {
	debugmsg("Gateway.GetBucketPolicies")
	//return s.fs.GetBucketPolicies(bucket)
	return policy.BucketAccessPolicy{}, nil
}

// DeleteBucketPolicies deletes all policies on bucket
func (s *siaObjects) DeleteBucketPolicies(bucket string) error {
	debugmsg("Gateway.DeleteBucketPolicies")
	//return s.fs.DeleteBucketPolciies(bucket)
	return nil
}
<|endoftext|>


<commit_before>package fail

import "net/http"

type NotFoundError struct {
	Err
}

func NewNotFoundError(err error) NotFoundError {
	return NotFoundError{
		Err: Err{
			OriginalError: err,
		},
	}
}

// StatusCode implements the `vc.StatusError` interface.
func (err NotFoundError) StatusCode() int {
	return http.StatusNotFound
}
<commit_msg>Now with comments ;-)<commit_after>package fail

import "net/http"

// NotFoundError represents a resource not found.
type NotFoundError struct {
	Err
}

// NewNotFoundError returns a new NotFoundError to wrap the supplied error.
func NewNotFoundError(err error) NotFoundError {
	return NotFoundError{
		Err: Err{
			OriginalError: err,
		},
	}
}

// StatusCode implements the `vc.StatusError` interface.
func (err NotFoundError) StatusCode() int {
	return http.StatusNotFound
}
<|endoftext|>


<commit_before>package mesh

import (
	"fmt"
	"time"
)

type PeerInfo struct {
	ID        string
	Protocols map[string][]string
}

type peerInfoProtocol struct {
	PeerID      string
	Name        string
	Address     string
	LastUpdated time.Time
	Pinned      bool
}

// TODO maybe a better or just faster hash function?
func (p *peerInfoProtocol) Hash() string {
	return fmt.Sprintf("%s/%s/%s", p.PeerID, p.Name, p.Address)
}
<commit_msg>Add peer info json attrs<commit_after>package mesh

import (
	"fmt"
	"time"
)

type PeerInfo struct {
	ID        string              `json:"id"`
	Protocols map[string][]string `json:"protocols"`
}

type peerInfoProtocol struct {
	PeerID      string    `json:"peer_id"`
	Name        string    `json:"name"`
	Address     string    `json:"address"`
	LastUpdated time.Time `json:"last_updated,omitempty"`
	Pinned      bool      `json:"pinned,omitempty"`
}

// TODO maybe a better or just faster hash function?
func (p *peerInfoProtocol) Hash() string {
	return fmt.Sprintf("%s/%s/%s", p.PeerID, p.Name, p.Address)
}
<|endoftext|>


<commit_before>package scenarios

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sync"
	"time"

	"github.com/golang/protobuf/proto"
	"v2ray.com/core"
	"v2ray.com/core/app/dispatcher"
	"v2ray.com/core/app/proxyman"
	"v2ray.com/core/common"
	"v2ray.com/core/common/log"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/serial"
)

func xor(b []byte) []byte {
	r := make([]byte, len(b))
	for i, v := range b {
		r[i] = v ^ 'c'
	}
	return r
}

func readFrom(conn net.Conn, timeout time.Duration, length int) []byte {
	b := make([]byte, length)
	deadline := time.Now().Add(timeout)
	conn.SetReadDeadline(deadline)
	n, err := io.ReadFull(conn, b[:length])
	if err != nil {
		fmt.Println("Unexpected error from readFrom:", err)
	}
	return b[:n]
}

func InitializeServerConfigs(configs ...*core.Config) ([]*exec.Cmd, error) {
	servers := make([]*exec.Cmd, 0, 10)

	for _, config := range configs {
		server, err := InitializeServerConfig(config)
		if err != nil {
			CloseAllServers(servers)
			return nil, err
		}
		servers = append(servers, server)
	}

	time.Sleep(time.Second * 2)

	return servers, nil
}

func InitializeServerConfig(config *core.Config) (*exec.Cmd, error) {
	err := BuildV2Ray()
	if err != nil {
		return nil, err
	}

	config = withDefaultApps(config)
	configBytes, err := proto.Marshal(config)
	if err != nil {
		return nil, err
	}
	proc := RunV2RayProtobuf(configBytes)

	if err := proc.Start(); err != nil {
		return nil, err
	}

	return proc, nil
}

var (
	testBinaryPath    string
	testBinaryPathGen sync.Once
)

func genTestBinaryPath() {
	testBinaryPathGen.Do(func() {
		var tempDir string
		common.Must(retry.Timed(5, 100).On(func() error {
			dir, err := ioutil.TempDir("", "v2ray")
			if err != nil {
				return err
			}
			tempDir = dir
			return nil
		}))
		file := filepath.Join(tempDir, "v2ray.test")
		if runtime.GOOS == "windows" {
			file += ".exe"
		}
		testBinaryPath = file
		fmt.Printf("Generated binary path: %s\n", file)
	})
}

func GetSourcePath() string {
	return filepath.Join("v2ray.com", "core", "main")
}

func CloseAllServers(servers []*exec.Cmd) {
	log.Record(&log.GeneralMessage{
		Severity: log.Severity_Info,
		Content:  "Closing all servers.",
	})
	for _, server := range servers {
		server.Process.Signal(os.Interrupt)
	}
	for _, server := range servers {
		server.Process.Wait()
	}
	log.Record(&log.GeneralMessage{
		Severity: log.Severity_Info,
		Content:  "All server closed.",
	})
}

func withDefaultApps(config *core.Config) *core.Config {
	config.App = append(config.App, serial.ToTypedMessage(&dispatcher.Config{}))
	config.App = append(config.App, serial.ToTypedMessage(&proxyman.InboundConfig{}))
	config.App = append(config.App, serial.ToTypedMessage(&proxyman.OutboundConfig{}))
	return config
}
<commit_msg>change to sigterm<commit_after>package scenarios

import (
	"fmt"
	"io"
	"io/ioutil"
	"os/exec"
	"path/filepath"
	"runtime"
	"sync"
	"syscall"
	"time"

	"github.com/golang/protobuf/proto"
	"v2ray.com/core"
	"v2ray.com/core/app/dispatcher"
	"v2ray.com/core/app/proxyman"
	"v2ray.com/core/common"
	"v2ray.com/core/common/log"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/retry"
	"v2ray.com/core/common/serial"
)

func xor(b []byte) []byte {
	r := make([]byte, len(b))
	for i, v := range b {
		r[i] = v ^ 'c'
	}
	return r
}

func readFrom(conn net.Conn, timeout time.Duration, length int) []byte {
	b := make([]byte, length)
	deadline := time.Now().Add(timeout)
	conn.SetReadDeadline(deadline)
	n, err := io.ReadFull(conn, b[:length])
	if err != nil {
		fmt.Println("Unexpected error from readFrom:", err)
	}
	return b[:n]
}

func InitializeServerConfigs(configs ...*core.Config) ([]*exec.Cmd, error) {
	servers := make([]*exec.Cmd, 0, 10)

	for _, config := range configs {
		server, err := InitializeServerConfig(config)
		if err != nil {
			CloseAllServers(servers)
			return nil, err
		}
		servers = append(servers, server)
	}

	time.Sleep(time.Second * 2)

	return servers, nil
}

func InitializeServerConfig(config *core.Config) (*exec.Cmd, error) {
	err := BuildV2Ray()
	if err != nil {
		return nil, err
	}

	config = withDefaultApps(config)
	configBytes, err := proto.Marshal(config)
	if err != nil {
		return nil, err
	}
	proc := RunV2RayProtobuf(configBytes)

	if err := proc.Start(); err != nil {
		return nil, err
	}

	return proc, nil
}

var (
	testBinaryPath    string
	testBinaryPathGen sync.Once
)

func genTestBinaryPath() {
	testBinaryPathGen.Do(func() {
		var tempDir string
		common.Must(retry.Timed(5, 100).On(func() error {
			dir, err := ioutil.TempDir("", "v2ray")
			if err != nil {
				return err
			}
			tempDir = dir
			return nil
		}))
		file := filepath.Join(tempDir, "v2ray.test")
		if runtime.GOOS == "windows" {
			file += ".exe"
		}
		testBinaryPath = file
		fmt.Printf("Generated binary path: %s\n", file)
	})
}

func GetSourcePath() string {
	return filepath.Join("v2ray.com", "core", "main")
}

func CloseAllServers(servers []*exec.Cmd) {
	log.Record(&log.GeneralMessage{
		Severity: log.Severity_Info,
		Content:  "Closing all servers.",
	})
	for _, server := range servers {
		server.Process.Signal(syscall.SIGTERM)
	}
	for _, server := range servers {
		server.Process.Wait()
	}
	log.Record(&log.GeneralMessage{
		Severity: log.Severity_Info,
		Content:  "All server closed.",
	})
}

func withDefaultApps(config *core.Config) *core.Config {
	config.App = append(config.App, serial.ToTypedMessage(&dispatcher.Config{}))
	config.App = append(config.App, serial.ToTypedMessage(&proxyman.InboundConfig{}))
	config.App = append(config.App, serial.ToTypedMessage(&proxyman.OutboundConfig{}))
	return config
}
<|endoftext|>