<commit_before>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"bytes"
	"crypto/rand"
	"encoding/base32"
	"encoding/json"
	"fmt"
	"io"
	"net/mail"
	"net/url"
	"regexp"
	"strings"
	"time"

	goi18n "github.com/nicksnyder/go-i18n/i18n"
	"github.com/pborman/uuid"
)

type StringInterface map[string]interface{}
type StringMap map[string]string
type StringArray []string
type EncryptStringMap map[string]string

// AppError is returned for any http response that's not in the 200 range.
type AppError struct {
	LocId         string                 `json:"loc_id"`         // Message to be display to the end user without debugging information
	Message       string                 `json:"message"`        // Message to be display to the end user without debugging information
	DetailedError string                 `json:"detailed_error"` // Internal error string to help the developer
	RequestId     string                 `json:"request_id"`     // The RequestId that's also set in the header
	StatusCode    int                    `json:"status_code"`    // The http status code
	Where         string                 `json:"-"`              // The function where it happened in the form of Struct.Func
	IsOAuth       bool                   `json:"is_oauth"`       // Whether the error is OAuth specific
	params        map[string]interface{} `json:"-"`
}

func (er *AppError) Error() string {
	return er.Where + ": " + er.Message + ", " + er.DetailedError
}

func (er *AppError) Translate(T goi18n.TranslateFunc) {
	if len(er.Message) == 0 {
		if er.params == nil {
			er.Message = T(er.LocId)
		} else {
			er.Message = T(er.LocId, er.params)
		}
	}
}

func (er *AppError) ToJson() string {
	b, err := json.Marshal(er)
	if err != nil {
		return ""
	} else {
		return string(b)
	}
}

// AppErrorFromJson will decode the input and return an AppError
func AppErrorFromJson(data io.Reader) *AppError {
	decoder := json.NewDecoder(data)
	var er AppError
	err := decoder.Decode(&er)
	if err == nil {
		return &er
	} else {
		return NewAppError("AppErrorFromJson", "could not decode", err.Error())
	}
}

func NewAppError(where string, message string, details string) *AppError {
	ap := &AppError{}
	ap.Message = message
	ap.Where = where
	ap.DetailedError = details
	ap.StatusCode = 500
	ap.IsOAuth = false
	return ap
}

func NewLocAppError(where string, locId string, params map[string]interface{}, details string) *AppError {
	ap := &AppError{}
	ap.LocId = locId
	ap.params = params
	ap.Where = where
	ap.DetailedError = details
	ap.StatusCode = 500
	ap.IsOAuth = false
	return ap
}

var encoding = base32.NewEncoding("ybndrfg8ejkmcpqxot1uwisza345h769")

// NewId is a globally unique identifier.  It is a [A-Z0-9] string 26
// characters long.  It is a UUID version 4 Guid that is zbased32 encoded
// with the padding stripped off.
func NewId() string {
	var b bytes.Buffer
	encoder := base32.NewEncoder(encoding, &b)
	encoder.Write(uuid.NewRandom())
	encoder.Close()
	b.Truncate(26) // removes the '==' padding
	return b.String()
}

func NewRandomString(length int) string {
	var b bytes.Buffer
	str := make([]byte, length+8)
	rand.Read(str)
	encoder := base32.NewEncoder(encoding, &b)
	encoder.Write(str)
	encoder.Close()
	b.Truncate(length) // removes the '==' padding
	return b.String()
}

// GetMillis is a convience method to get milliseconds since epoch.
func GetMillis() int64 {
	return time.Now().UnixNano() / int64(time.Millisecond)
}

// MapToJson converts a map to a json string
func MapToJson(objmap map[string]string) string {
	if b, err := json.Marshal(objmap); err != nil {
		return ""
	} else {
		return string(b)
	}
}

// MapFromJson will decode the key/value pair map
func MapFromJson(data io.Reader) map[string]string {
	decoder := json.NewDecoder(data)

	var objmap map[string]string
	if err := decoder.Decode(&objmap); err != nil {
		return make(map[string]string)
	} else {
		return objmap
	}
}

func ArrayToJson(objmap []string) string {
	if b, err := json.Marshal(objmap); err != nil {
		return ""
	} else {
		return string(b)
	}
}

func ArrayFromJson(data io.Reader) []string {
	decoder := json.NewDecoder(data)

	var objmap []string
	if err := decoder.Decode(&objmap); err != nil {
		return make([]string, 0)
	} else {
		return objmap
	}
}

func StringInterfaceToJson(objmap map[string]interface{}) string {
	if b, err := json.Marshal(objmap); err != nil {
		return ""
	} else {
		return string(b)
	}
}

func StringInterfaceFromJson(data io.Reader) map[string]interface{} {
	decoder := json.NewDecoder(data)

	var objmap map[string]interface{}
	if err := decoder.Decode(&objmap); err != nil {
		return make(map[string]interface{})
	} else {
		return objmap
	}
}

func IsLower(s string) bool {
	if strings.ToLower(s) == s {
		return true
	}

	return false
}

func IsValidEmail(email string) bool {

	if !IsLower(email) {
		return false
	}

	if _, err := mail.ParseAddress(email); err == nil {
		return true
	}

	return false
}

var reservedName = []string{
	"www",
	"web",
	"admin",
	"support",
	"notify",
	"test",
	"demo",
	"mail",
	"team",
	"channel",
	"internal",
	"localhost",
	"dockerhost",
	"stag",
	"post",
	"cluster",
	"api",
	"oauth",
}

var wwwStart = regexp.MustCompile(`^www`)
var betaStart = regexp.MustCompile(`^beta`)
var ciStart = regexp.MustCompile(`^ci`)

func GetSubDomain(s string) (string, string) {
	s = strings.Replace(s, "http://", "", 1)
	s = strings.Replace(s, "https://", "", 1)

	match := wwwStart.MatchString(s)
	if match {
		return "", ""
	}

	match = betaStart.MatchString(s)
	if match {
		return "", ""
	}

	match = ciStart.MatchString(s)
	if match {
		return "", ""
	}

	parts := strings.Split(s, ".")

	if len(parts) != 3 {
		return "", ""
	}

	return parts[0], parts[1]
}

func IsValidChannelIdentifier(s string) bool {

	if !IsValidAlphaNum(s, true) {
		return false
	}

	if len(s) < 2 {
		return false
	}

	return true
}

var validAlphaNumUnderscore = regexp.MustCompile(`^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]+$`)
var validAlphaNum = regexp.MustCompile(`^[a-z0-9]+([a-z\-0-9]+|(__)?)[a-z0-9]+$`)

func IsValidAlphaNum(s string, allowUnderscores bool) bool {
	var match bool
	if allowUnderscores {
		match = validAlphaNumUnderscore.MatchString(s)
	} else {
		match = validAlphaNum.MatchString(s)
	}

	if !match {
		return false
	}

	return true
}

func Etag(parts ...interface{}) string {

	etag := CurrentVersion

	for _, part := range parts {
		etag += fmt.Sprintf(".%v", part)
	}

	return etag
}

var validHashtag = regexp.MustCompile(`^(#[A-Za-zäöüÄÖÜß]+[A-Za-z0-9äöüÄÖÜß_\-]*[A-Za-z0-9äöüÄÖÜß])$`)
var puncStart = regexp.MustCompile(`^[.,()&$!\?\[\]{}':;\\]+`)
var puncEnd = regexp.MustCompile(`[.,()&$#!\?\[\]{}';\\]+$`)

func ParseHashtags(text string) (string, string) {
	words := strings.Fields(text)

	hashtagString := ""
	plainString := ""
	for _, word := range words {
		word = puncStart.ReplaceAllString(word, "")
		word = puncEnd.ReplaceAllString(word, "")
		if validHashtag.MatchString(word) {
			hashtagString += " " + word
		} else {
			plainString += " " + word
		}
	}

	if len(hashtagString) > 1000 {
		hashtagString = hashtagString[:999]
		lastSpace := strings.LastIndex(hashtagString, " ")
		if lastSpace > -1 {
			hashtagString = hashtagString[:lastSpace]
		} else {
			hashtagString = ""
		}
	}

	return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString)
}

func IsFileExtImage(ext string) bool {
	ext = strings.ToLower(ext)
	for _, imgExt := range IMAGE_EXTENSIONS {
		if ext == imgExt {
			return true
		}
	}
	return false
}

func GetImageMimeType(ext string) string {
	ext = strings.ToLower(ext)
	if len(IMAGE_MIME_TYPES[ext]) == 0 {
		return "image"
	} else {
		return IMAGE_MIME_TYPES[ext]
	}
}

func ClearMentionTags(post string) string {
	post = strings.Replace(post, "<mention>", "", -1)
	post = strings.Replace(post, "</mention>", "", -1)
	return post
}

var UrlRegex = regexp.MustCompile(`^((?:[a-z]+:\/\/)?(?:(?:[a-z0-9\-]+\.)+(?:[a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|local|internal))(:[0-9]{1,5})?(?:\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(?:\?[a-z0-9+_~\-\.%=&]*)?)?(?:#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)(?:\s+|$)$`)
var PartialUrlRegex = regexp.MustCompile(`/([A-Za-z0-9]{26})/([A-Za-z0-9]{26})/((?:[A-Za-z0-9]{26})?.+(?:\.[A-Za-z0-9]{3,})?)`)

var SplitRunes = map[rune]bool{',': true, ' ': true, '.': true, '!': true, '?': true, ':': true, ';': true, '\n': true, '<': true, '>': true, '(': true, ')': true, '{': true, '}': true, '[': true, ']': true, '+': true, '/': true, '\\': true}

func IsValidHttpUrl(rawUrl string) bool {
	if strings.Index(rawUrl, "http://") != 0 && strings.Index(rawUrl, "https://") != 0 {
		return false
	}

	if _, err := url.ParseRequestURI(rawUrl); err != nil {
		return false
	}

	return true
}
<commit_msg>tweaking<commit_after>// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.

package model

import (
	"bytes"
	"crypto/rand"
	"encoding/base32"
	"encoding/json"
	"fmt"
	"io"
	"net/mail"
	"net/url"
	"regexp"
	"strings"
	"time"

	goi18n "github.com/nicksnyder/go-i18n/i18n"
	"github.com/pborman/uuid"
)

type StringInterface map[string]interface{}
type StringMap map[string]string
type StringArray []string
type EncryptStringMap map[string]string

type AppError struct {
	Id            string                 `json:"id"`
	Message       string                 `json:"message"`        // Message to be display to the end user without debugging information
	DetailedError string                 `json:"detailed_error"` // Internal error string to help the developer
	RequestId     string                 `json:"request_id"`     // The RequestId that's also set in the header
	StatusCode    int                    `json:"status_code"`    // The http status code
	Where         string                 `json:"-"`              // The function where it happened in the form of Struct.Func
	IsOAuth       bool                   `json:"is_oauth"`       // Whether the error is OAuth specific
	params        map[string]interface{} `json:"-"`
}

func (er *AppError) Error() string {
	return er.Where + ": " + er.Message + ", " + er.DetailedError
}

func (er *AppError) Translate(T goi18n.TranslateFunc) {
	if len(er.Message) == 0 {
		if er.params == nil {
			er.Message = T(er.Id)
		} else {
			er.Message = T(er.Id, er.params)
		}
	}
}

func (er *AppError) ToJson() string {
	b, err := json.Marshal(er)
	if err != nil {
		return ""
	} else {
		return string(b)
	}
}

// AppErrorFromJson will decode the input and return an AppError
func AppErrorFromJson(data io.Reader) *AppError {
	decoder := json.NewDecoder(data)
	var er AppError
	err := decoder.Decode(&er)
	if err == nil {
		return &er
	} else {
		return NewAppError("AppErrorFromJson", "could not decode", err.Error())
	}
}

func NewAppError(where string, message string, details string) *AppError {
	ap := &AppError{}
	ap.Message = message
	ap.Where = where
	ap.DetailedError = details
	ap.StatusCode = 500
	ap.IsOAuth = false
	return ap
}

func NewLocAppError(where string, id string, params map[string]interface{}, details string) *AppError {
	ap := &AppError{}
	ap.Id = id
	ap.params = params
	ap.Where = where
	ap.DetailedError = details
	ap.StatusCode = 500
	ap.IsOAuth = false
	return ap
}

var encoding = base32.NewEncoding("ybndrfg8ejkmcpqxot1uwisza345h769")

// NewId is a globally unique identifier.  It is a [A-Z0-9] string 26
// characters long.  It is a UUID version 4 Guid that is zbased32 encoded
// with the padding stripped off.
func NewId() string {
	var b bytes.Buffer
	encoder := base32.NewEncoder(encoding, &b)
	encoder.Write(uuid.NewRandom())
	encoder.Close()
	b.Truncate(26) // removes the '==' padding
	return b.String()
}

func NewRandomString(length int) string {
	var b bytes.Buffer
	str := make([]byte, length+8)
	rand.Read(str)
	encoder := base32.NewEncoder(encoding, &b)
	encoder.Write(str)
	encoder.Close()
	b.Truncate(length) // removes the '==' padding
	return b.String()
}

// GetMillis is a convience method to get milliseconds since epoch.
func GetMillis() int64 {
	return time.Now().UnixNano() / int64(time.Millisecond)
}

// MapToJson converts a map to a json string
func MapToJson(objmap map[string]string) string {
	if b, err := json.Marshal(objmap); err != nil {
		return ""
	} else {
		return string(b)
	}
}

// MapFromJson will decode the key/value pair map
func MapFromJson(data io.Reader) map[string]string {
	decoder := json.NewDecoder(data)

	var objmap map[string]string
	if err := decoder.Decode(&objmap); err != nil {
		return make(map[string]string)
	} else {
		return objmap
	}
}

func ArrayToJson(objmap []string) string {
	if b, err := json.Marshal(objmap); err != nil {
		return ""
	} else {
		return string(b)
	}
}

func ArrayFromJson(data io.Reader) []string {
	decoder := json.NewDecoder(data)

	var objmap []string
	if err := decoder.Decode(&objmap); err != nil {
		return make([]string, 0)
	} else {
		return objmap
	}
}

func StringInterfaceToJson(objmap map[string]interface{}) string {
	if b, err := json.Marshal(objmap); err != nil {
		return ""
	} else {
		return string(b)
	}
}

func StringInterfaceFromJson(data io.Reader) map[string]interface{} {
	decoder := json.NewDecoder(data)

	var objmap map[string]interface{}
	if err := decoder.Decode(&objmap); err != nil {
		return make(map[string]interface{})
	} else {
		return objmap
	}
}

func IsLower(s string) bool {
	if strings.ToLower(s) == s {
		return true
	}

	return false
}

func IsValidEmail(email string) bool {

	if !IsLower(email) {
		return false
	}

	if _, err := mail.ParseAddress(email); err == nil {
		return true
	}

	return false
}

var reservedName = []string{
	"www",
	"web",
	"admin",
	"support",
	"notify",
	"test",
	"demo",
	"mail",
	"team",
	"channel",
	"internal",
	"localhost",
	"dockerhost",
	"stag",
	"post",
	"cluster",
	"api",
	"oauth",
}

var wwwStart = regexp.MustCompile(`^www`)
var betaStart = regexp.MustCompile(`^beta`)
var ciStart = regexp.MustCompile(`^ci`)

func GetSubDomain(s string) (string, string) {
	s = strings.Replace(s, "http://", "", 1)
	s = strings.Replace(s, "https://", "", 1)

	match := wwwStart.MatchString(s)
	if match {
		return "", ""
	}

	match = betaStart.MatchString(s)
	if match {
		return "", ""
	}

	match = ciStart.MatchString(s)
	if match {
		return "", ""
	}

	parts := strings.Split(s, ".")

	if len(parts) != 3 {
		return "", ""
	}

	return parts[0], parts[1]
}

func IsValidChannelIdentifier(s string) bool {

	if !IsValidAlphaNum(s, true) {
		return false
	}

	if len(s) < 2 {
		return false
	}

	return true
}

var validAlphaNumUnderscore = regexp.MustCompile(`^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]+$`)
var validAlphaNum = regexp.MustCompile(`^[a-z0-9]+([a-z\-0-9]+|(__)?)[a-z0-9]+$`)

func IsValidAlphaNum(s string, allowUnderscores bool) bool {
	var match bool
	if allowUnderscores {
		match = validAlphaNumUnderscore.MatchString(s)
	} else {
		match = validAlphaNum.MatchString(s)
	}

	if !match {
		return false
	}

	return true
}

func Etag(parts ...interface{}) string {

	etag := CurrentVersion

	for _, part := range parts {
		etag += fmt.Sprintf(".%v", part)
	}

	return etag
}

var validHashtag = regexp.MustCompile(`^(#[A-Za-zäöüÄÖÜß]+[A-Za-z0-9äöüÄÖÜß_\-]*[A-Za-z0-9äöüÄÖÜß])$`)
var puncStart = regexp.MustCompile(`^[.,()&$!\?\[\]{}':;\\]+`)
var puncEnd = regexp.MustCompile(`[.,()&$#!\?\[\]{}';\\]+$`)

func ParseHashtags(text string) (string, string) {
	words := strings.Fields(text)

	hashtagString := ""
	plainString := ""
	for _, word := range words {
		word = puncStart.ReplaceAllString(word, "")
		word = puncEnd.ReplaceAllString(word, "")
		if validHashtag.MatchString(word) {
			hashtagString += " " + word
		} else {
			plainString += " " + word
		}
	}

	if len(hashtagString) > 1000 {
		hashtagString = hashtagString[:999]
		lastSpace := strings.LastIndex(hashtagString, " ")
		if lastSpace > -1 {
			hashtagString = hashtagString[:lastSpace]
		} else {
			hashtagString = ""
		}
	}

	return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString)
}

func IsFileExtImage(ext string) bool {
	ext = strings.ToLower(ext)
	for _, imgExt := range IMAGE_EXTENSIONS {
		if ext == imgExt {
			return true
		}
	}
	return false
}

func GetImageMimeType(ext string) string {
	ext = strings.ToLower(ext)
	if len(IMAGE_MIME_TYPES[ext]) == 0 {
		return "image"
	} else {
		return IMAGE_MIME_TYPES[ext]
	}
}

func ClearMentionTags(post string) string {
	post = strings.Replace(post, "<mention>", "", -1)
	post = strings.Replace(post, "</mention>", "", -1)
	return post
}

var UrlRegex = regexp.MustCompile(`^((?:[a-z]+:\/\/)?(?:(?:[a-z0-9\-]+\.)+(?:[a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|local|internal))(:[0-9]{1,5})?(?:\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(?:\?[a-z0-9+_~\-\.%=&]*)?)?(?:#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)(?:\s+|$)$`)
var PartialUrlRegex = regexp.MustCompile(`/([A-Za-z0-9]{26})/([A-Za-z0-9]{26})/((?:[A-Za-z0-9]{26})?.+(?:\.[A-Za-z0-9]{3,})?)`)

var SplitRunes = map[rune]bool{',': true, ' ': true, '.': true, '!': true, '?': true, ':': true, ';': true, '\n': true, '<': true, '>': true, '(': true, ')': true, '{': true, '}': true, '[': true, ']': true, '+': true, '/': true, '\\': true}

func IsValidHttpUrl(rawUrl string) bool {
	if strings.Index(rawUrl, "http://") != 0 && strings.Index(rawUrl, "https://") != 0 {
		return false
	}

	if _, err := url.ParseRequestURI(rawUrl); err != nil {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package swim

import (
	"errors"
	"fmt"
	"testing"
	"time"

	"github.com/benbjohnson/clock"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber/ringpop-go/discovery/statichosts"
	"github.com/uber/ringpop-go/shared"
	"github.com/uber/ringpop-go/util"
	"github.com/uber/tchannel-go"
)

var testNow = time.Now()
var testInc = util.TimeNowMS()

var testSuspect = Change{
	Address:           "127.0.0.1:3002",
	Incarnation:       testInc,
	Source:            "127.0.0.1:3001",
	SourceIncarnation: testInc,
	Status:            Suspect,
	Timestamp:         util.Timestamp(testNow),
}

type dummyIter struct{}

func (dummyIter) Next() (*Member, bool) {
	return &Member{
		Address:     "127.0.0.1:3010",
		Status:      Alive,
		Incarnation: testInc,
	}, true
}

type testNode struct {
	node    *Node
	channel *tchannel.Channel
}

func (n *testNode) Destroy() {
	n.node.Destroy()
	n.channel.Close()
}

func (n *testNode) closeAndWait(sender *tchannel.Channel) {
	n.channel.Close()

	// wait for tchannel to respond with connection refused errors.
	for {
		ctx, cancel := shared.NewTChannelContext(time.Millisecond * 50)

		err := sender.Ping(ctx, n.node.Address())
		if err == nil {
			cancel()
			continue
		}

		_, ok := err.(tchannel.SystemError)
		if ok {
			cancel()
			continue
		}

		cancel()
		break
	}
}

// newChannelNode creates a testNode with a listening channel and associated
// SWIM node. The channel listens on a random port assigned by the OS.
func newChannelNode(t *testing.T) *testNode {
	ch, err := tchannel.NewChannel("test", nil)
	require.NoError(t, err, "channel must create successfully")

	// Set the channel listening so it binds to the socket and we get a port
	// allocated by the OS
	err = ch.ListenAndServe("127.0.0.1:0")
	require.NoError(t, err, "channel must listen")

	hostport := ch.PeerInfo().HostPort
	node := NewNode("test", hostport, ch.GetSubChannel("test"), &Options{
		Clock: clock.NewMock(),
	})

	return &testNode{node, ch}
}

// newChannelNodeWithHostPort creates a testNode with the address specified by
// the hostport parameter.
func newChannelNodeWithHostPort(t *testing.T, hostport string) *testNode {
	ch, err := tchannel.NewChannel("test", nil)
	require.NoError(t, err, "channel must create successfully")

	node := NewNode("test", hostport, ch.GetSubChannel("test"), &Options{
		Clock: clock.NewMock(),
	})

	return &testNode{node, ch}
}

func genChannelNodes(t *testing.T, n int) (nodes []*testNode) {
	for i := 0; i < n; i++ {
		node := newChannelNode(t)
		nodes = append(nodes, node)
	}

	return
}

func memberlistHasMembers(t *testing.T, m *memberlist, members []Member) {
	for _, expected := range members {
		member, ok := m.Member(expected.Address)
		require.NotNil(t, member, "member cannot be nil")
		assert.True(t, ok, "expected member to be in memberlist")
		assert.Equal(t, expected.Status, member.Status, "expected statuses to be the same")
	}
}

func bootstrapNodes(t *testing.T, testNodes ...*testNode) []string {
	var hostports []string

	for _, tn := range testNodes {
		hostports = append(hostports, tn.node.Address())

		_, err := tn.node.Bootstrap(&BootstrapOptions{
			DiscoverProvider: statichosts.New(hostports...),
			Stopped:          true,
		})
		require.NoError(t, err, "node must bootstrap successfully")
	}
	return hostports
}

func waitForConvergence(t *testing.T, timeout time.Duration, testNodes ...*testNode) {
	timeoutCh := time.After(timeout)

	nodes := testNodesToNodes(testNodes)

	// To get the cluster to a converged state we will let the nodes gossip until
	// there are no more changes. After the cluster finished gossipping we double
	// check that all nodes have the same checksum for the memberlist, this means
	// that the cluster is converged.
Tick:
	for {
		select {
		case <-timeoutCh:
			t.Errorf("timeout during wait for convergence")
			return
		default:
			for _, node := range nodes {
				node.gossip.ProtocolPeriod()
			}
			for _, node := range nodes {
				if node.HasChanges() {
					continue Tick
				}
			}

			if !nodesConverged(nodes) {
				t.Errorf("nodes did not converge to 1 checksum")
			}

			return
		}
	}
}

func destroyNodes(tnodes ...*testNode) {
	for _, tnode := range tnodes {
		tnode.Destroy()
	}
}

// fakeAddresses returns a slice of fake IP address/port combinations that can
// be used during testing. Note that these addresses cannot be used in tests
// which require real communication or binding to a socket.
//
// The IP addresses returned are from the TEST-NET-1 block which are defined in
// RFC 5737 as to be used for documentation and recommended to be unrouteable.
// In practice, these addresses may also just time out.
//
// See:
// http://tools.ietf.org/html/rfc5737
// http://stackoverflow.com/questions/10456044/what-is-a-good-invalid-ip-address-to-use-for-unit-tests
//
func fakeHostPorts(fromHost, toHost, fromPort, toPort int) []string {
	var hostports []string
	for h := fromHost; h <= toHost; h++ {
		for p := fromPort; p <= toPort; p++ {
			hostports = append(hostports, fmt.Sprintf("192.0.2.%v:%v", h, p))
		}
	}
	return hostports
}

// swimCluster is a group of real swim nodes listening on randomly-assigned
// ports.
type swimCluster struct {
	nodes    []*Node
	channels []*tchannel.Channel
}

// newSwimCluster creates a new swimCluster with the number of nodes specified
// by size. These nodes are not joined together at creation. Use Bootstrap if you
// need a bootstrapped cluster.
func newSwimCluster(size int) *swimCluster {
	var nodes []*Node
	var channels []*tchannel.Channel
	for i := 0; i < size; i++ {
		ch, err := tchannel.NewChannel("test", nil)
		if err != nil {
			panic(err)
		}

		if err := ch.ListenAndServe("127.0.0.1:0"); err != nil {
			panic(err)
		}
		channels = append(channels, ch)

		hostport := ch.PeerInfo().HostPort
		node := NewNode("test", hostport, ch.GetSubChannel("test"), nil)

		nodes = append(nodes, node)
	}
	return &swimCluster{nodes: nodes, channels: channels}
}

// Add adds the specified node to the cluster and bootstraps it so that it is
// joined to the existing nodes.
func (c *swimCluster) Add(n *Node) {
	n.Bootstrap(&BootstrapOptions{
		DiscoverProvider: statichosts.New(c.Addresses()...),
	})
	c.nodes = append(c.nodes, n)
}

// Addresses returns a slice of addresses of all nodes in the cluster.
func (c *swimCluster) Addresses() (hostports []string) {
	for _, node := range c.nodes {
		hostports = append(hostports, node.Address())
	}
	return
}

// Bootstrap joins all the nodes in this cluster together using Bootstrap calls.
func (c *swimCluster) Bootstrap() {
	for _, node := range c.nodes {
		node.Bootstrap(&BootstrapOptions{
			DiscoverProvider: statichosts.New(c.Addresses()...),
		})
	}
}

// WaitForConvergence polls the checksums of each node in the cluster and returns when they all match, or until timeout occurs.
func (c *swimCluster) WaitForConvergence(timeout time.Duration) error {
	timeoutCh := time.After(timeout)

	for {
		select {
		case <-time.After(time.Millisecond):
			if nodesConverged(c.nodes) {
				return nil
			}
		case <-timeoutCh:
			return errors.New("timeout during converging")
		}
	}
}

func testNodesToNodes(testNodes []*testNode) []*Node {
	nodes := make([]*Node, len(testNodes))
	for i, tn := range testNodes {
		nodes[i] = tn.node
	}
	return nodes
}

func nodesConverged(nodes []*Node) bool {
	if len(nodes) == 0 {
		return true
	}

	first := nodes[0].memberlist.Checksum()
	for _, node := range nodes {
		if node.memberlist.Checksum() != first {
			return false
		}
	}

	return true
}

// Destroy destroys all nodes in this cluster. It also closes channels, but
// only those that were created as part of newSwimCluster.
func (c *swimCluster) Destroy() {
	for _, node := range c.nodes {
		node.Destroy()
	}
	for _, ch := range c.channels {
		ch.Close()
	}
}

// Nodes returns a slice of all nodes in the cluster.
func (c *swimCluster) Nodes() []*Node {
	return c.nodes
}
<commit_msg>remove unnecessary concurrency in waitForConvergence<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package swim

import (
	"errors"
	"fmt"
	"testing"
	"time"

	"github.com/benbjohnson/clock"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber/ringpop-go/discovery/statichosts"
	"github.com/uber/ringpop-go/shared"
	"github.com/uber/ringpop-go/util"
	"github.com/uber/tchannel-go"
)

var testNow = time.Now()
var testInc = util.TimeNowMS()

var testSuspect = Change{
	Address:           "127.0.0.1:3002",
	Incarnation:       testInc,
	Source:            "127.0.0.1:3001",
	SourceIncarnation: testInc,
	Status:            Suspect,
	Timestamp:         util.Timestamp(testNow),
}

type dummyIter struct{}

func (dummyIter) Next() (*Member, bool) {
	return &Member{
		Address:     "127.0.0.1:3010",
		Status:      Alive,
		Incarnation: testInc,
	}, true
}

type testNode struct {
	node    *Node
	channel *tchannel.Channel
}

func (n *testNode) Destroy() {
	n.node.Destroy()
	n.channel.Close()
}

func (n *testNode) closeAndWait(sender *tchannel.Channel) {
	n.channel.Close()

	// wait for tchannel to respond with connection refused errors.
	for {
		ctx, cancel := shared.NewTChannelContext(time.Millisecond * 50)

		err := sender.Ping(ctx, n.node.Address())
		if err == nil {
			cancel()
			continue
		}

		_, ok := err.(tchannel.SystemError)
		if ok {
			cancel()
			continue
		}

		cancel()
		break
	}
}

// newChannelNode creates a testNode with a listening channel and associated
// SWIM node. The channel listens on a random port assigned by the OS.
func newChannelNode(t *testing.T) *testNode {
	ch, err := tchannel.NewChannel("test", nil)
	require.NoError(t, err, "channel must create successfully")

	// Set the channel listening so it binds to the socket and we get a port
	// allocated by the OS
	err = ch.ListenAndServe("127.0.0.1:0")
	require.NoError(t, err, "channel must listen")

	hostport := ch.PeerInfo().HostPort
	node := NewNode("test", hostport, ch.GetSubChannel("test"), &Options{
		Clock: clock.NewMock(),
	})

	return &testNode{node, ch}
}

// newChannelNodeWithHostPort creates a testNode with the address specified by
// the hostport parameter.
func newChannelNodeWithHostPort(t *testing.T, hostport string) *testNode {
	ch, err := tchannel.NewChannel("test", nil)
	require.NoError(t, err, "channel must create successfully")

	node := NewNode("test", hostport, ch.GetSubChannel("test"), &Options{
		Clock: clock.NewMock(),
	})

	return &testNode{node, ch}
}

func genChannelNodes(t *testing.T, n int) (nodes []*testNode) {
	for i := 0; i < n; i++ {
		node := newChannelNode(t)
		nodes = append(nodes, node)
	}

	return
}

func memberlistHasMembers(t *testing.T, m *memberlist, members []Member) {
	for _, expected := range members {
		member, ok := m.Member(expected.Address)
		require.NotNil(t, member, "member cannot be nil")
		assert.True(t, ok, "expected member to be in memberlist")
		assert.Equal(t, expected.Status, member.Status, "expected statuses to be the same")
	}
}

func bootstrapNodes(t *testing.T, testNodes ...*testNode) []string {
	var hostports []string

	for _, tn := range testNodes {
		hostports = append(hostports, tn.node.Address())

		_, err := tn.node.Bootstrap(&BootstrapOptions{
			DiscoverProvider: statichosts.New(hostports...),
			Stopped:          true,
		})
		require.NoError(t, err, "node must bootstrap successfully")
	}
	return hostports
}

func waitForConvergence(t *testing.T, timeout time.Duration, testNodes ...*testNode) {
	deadline := time.Now().Add(timeout)

	nodes := testNodesToNodes(testNodes)

	// To get the cluster to a converged state we will let the nodes gossip until
	// there are no more changes. After the cluster finished gossipping we double
	// check that all nodes have the same checksum for the memberlist, this means
	// that the cluster is converged.
Tick:
	// return when deadline is reached
	if time.Now().After(deadline) {
		t.Errorf("timeout during wait for convergence")
		return
	}

	// tick all the nodes
	for _, node := range nodes {
		node.gossip.ProtocolPeriod()
	}

	// repeat if we stil have changes
	for _, node := range nodes {
		if node.HasChanges() {
			goto Tick
		}
	}

	// check for convergence if there are no changes left
	if !nodesConverged(nodes) {
		t.Errorf("nodes did not converge to 1 checksum")
	}
}

func destroyNodes(tnodes ...*testNode) {
	for _, tnode := range tnodes {
		tnode.Destroy()
	}
}

// fakeAddresses returns a slice of fake IP address/port combinations that can
// be used during testing. Note that these addresses cannot be used in tests
// which require real communication or binding to a socket.
//
// The IP addresses returned are from the TEST-NET-1 block which are defined in
// RFC 5737 as to be used for documentation and recommended to be unrouteable.
// In practice, these addresses may also just time out.
//
// See:
// http://tools.ietf.org/html/rfc5737
// http://stackoverflow.com/questions/10456044/what-is-a-good-invalid-ip-address-to-use-for-unit-tests
//
func fakeHostPorts(fromHost, toHost, fromPort, toPort int) []string {
	var hostports []string
	for h := fromHost; h <= toHost; h++ {
		for p := fromPort; p <= toPort; p++ {
			hostports = append(hostports, fmt.Sprintf("192.0.2.%v:%v", h, p))
		}
	}
	return hostports
}

// swimCluster is a group of real swim nodes listening on randomly-assigned
// ports.
type swimCluster struct {
	nodes    []*Node
	channels []*tchannel.Channel
}

// newSwimCluster creates a new swimCluster with the number of nodes specified
// by size. These nodes are not joined together at creation. Use Bootstrap if you
// need a bootstrapped cluster.
func newSwimCluster(size int) *swimCluster {
	var nodes []*Node
	var channels []*tchannel.Channel
	for i := 0; i < size; i++ {
		ch, err := tchannel.NewChannel("test", nil)
		if err != nil {
			panic(err)
		}

		if err := ch.ListenAndServe("127.0.0.1:0"); err != nil {
			panic(err)
		}
		channels = append(channels, ch)

		hostport := ch.PeerInfo().HostPort
		node := NewNode("test", hostport, ch.GetSubChannel("test"), nil)

		nodes = append(nodes, node)
	}
	return &swimCluster{nodes: nodes, channels: channels}
}

// Add adds the specified node to the cluster and bootstraps it so that it is
// joined to the existing nodes.
func (c *swimCluster) Add(n *Node) {
	n.Bootstrap(&BootstrapOptions{
		DiscoverProvider: statichosts.New(c.Addresses()...),
	})
	c.nodes = append(c.nodes, n)
}

// Addresses returns a slice of addresses of all nodes in the cluster.
func (c *swimCluster) Addresses() (hostports []string) {
	for _, node := range c.nodes {
		hostports = append(hostports, node.Address())
	}
	return
}

// Bootstrap joins all the nodes in this cluster together using Bootstrap calls.
func (c *swimCluster) Bootstrap() {
	for _, node := range c.nodes {
		node.Bootstrap(&BootstrapOptions{
			DiscoverProvider: statichosts.New(c.Addresses()...),
		})
	}
}

// WaitForConvergence polls the checksums of each node in the cluster and returns when they all match, or until timeout occurs.
func (c *swimCluster) WaitForConvergence(timeout time.Duration) error {
	timeoutCh := time.After(timeout)

	for {
		select {
		case <-time.After(time.Millisecond):
			if nodesConverged(c.nodes) {
				return nil
			}
		case <-timeoutCh:
			return errors.New("timeout during converging")
		}
	}
}

func testNodesToNodes(testNodes []*testNode) []*Node {
	nodes := make([]*Node, len(testNodes))
	for i, tn := range testNodes {
		nodes[i] = tn.node
	}
	return nodes
}

func nodesConverged(nodes []*Node) bool {
	if len(nodes) == 0 {
		return true
	}

	first := nodes[0].memberlist.Checksum()
	for _, node := range nodes {
		if node.memberlist.Checksum() != first {
			return false
		}
	}

	return true
}

// Destroy destroys all nodes in this cluster. It also closes channels, but
// only those that were created as part of newSwimCluster.
func (c *swimCluster) Destroy() {
	for _, node := range c.nodes {
		node.Destroy()
	}
	for _, ch := range c.channels {
		ch.Close()
	}
}

// Nodes returns a slice of all nodes in the cluster.
func (c *swimCluster) Nodes() []*Node {
	return c.nodes
}
<|endoftext|>


<commit_before>package system

import (
	"fmt"
	"strconv"
	"testing"
)

const (
	serviceCommand = "while true ; do echo LONG RUNNING SERVICE ; sleep 10 ; done"
	taskCommand    = "sleep 10"
)

type BenchmarkTestCase struct {
	Environments  int
	Deploys       int
	Services      int
	DeployCommand string
}

/*
func BenchmarkStress1Environment0Deploys0Services(b *testing.B)   { benchmarkStress(1, 0, 0, b) }
func BenchmarkStress5Environments0Deploys0Services(b *testing.B)  { benchmarkStress(5, 0, 0, b) }
func BenchmarkStress10Environments0Deploys0Services(b *testing.B) { benchmarkStress(10, 0, 0, b) }

func BenchmarkStress1Environment1Deploy0Service(b *testing.B)    { benchmarkStress(1, 1, 0, b) }
func BenchmarkStress1Environment5Deploys0Services(b *testing.B)  { benchmarkStress(1, 5, 0, b) }
func BenchmarkStress1Environment10Deploys0Services(b *testing.B) { benchmarkStress(1, 10, 0, b) }

func BenchmarkStress2Environments2Deploys1Service(b *testing.B)   { benchmarkStress(2, 2, 1, b) }
func BenchmarkStress2Environments2Deploy5Services(b *testing.B)   { benchmarkStress(2, 2, 5, b) }
func BenchmarkStress2Environments2Deploys10Services(b *testing.B) { benchmarkStress(2, 2, 10, b) }
*/

func BenchmarkStress(b *testing.B) {

	testCases := []BenchmarkTestCase{
		{1, 0, 0, ""},
		{5, 0, 0, ""},
		{10, 0, 0, ""},
		{1, 1, 0, ""},
		{1, 5, 0, ""},
		{1, 10, 0, ""},
		{2, 2, 1, serviceCommand},
		{2, 2, 5, serviceCommand},
		{2, 2, 10, serviceCommand},
	}

	for _, tc := range testCases {
		tfvars := map[string]string{
			"num_environments": strconv.Itoa(tc.Environments),
			"num_deploys":      strconv.Itoa(tc.Deploys),
			"num_services":     strconv.Itoa(tc.Services),
			"deploy_command":   tc.DeployCommand,
		}

		log.Debugf("Testing with Environments: %v, Deploys: %v, Services: %v, Deploy Command: '%v'", tc.Environments, tc.Deploys, tc.Services, tc.DeployCommand)

		title := fmt.Sprintf("Envs:%v_Deps:%v_Svcs:%v/", tc.Environments, tc.Deploys, tc.Services)

		s := NewStressTest(b, "cases/stress", tfvars)
		s.Terraform.Apply()
		defer s.Terraform.Destroy()

		b.Run(title+"ListEnvironments", func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				s.Layer0.ListEnvironments()
			}
		})

		b.Run(title+"ListDeploys", func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				s.Layer0.ListDeploys()
			}
		})

		b.Run(title+"ListLoadBalancers", func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				s.Layer0.ListLoadBalancers()
			}
		})

		b.Run(title+"ListServices", func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				s.Layer0.ListServices()
			}
		})
	}
}
<commit_msg>232: Removing defer Terraform.Destroy() and instead explicitly calling Destroy() at end of for loop<commit_after>package system

import (
	"fmt"
	"strconv"
	"testing"
)

const (
	serviceCommand = "while true ; do echo LONG RUNNING SERVICE ; sleep 10 ; done"
	taskCommand    = "sleep 10"
)

type BenchmarkTestCase struct {
	Environments  int
	Deploys       int
	Services      int
	DeployCommand string
}

/*
func BenchmarkStress1Environment0Deploys0Services(b *testing.B)   { benchmarkStress(1, 0, 0, b) }
func BenchmarkStress5Environments0Deploys0Services(b *testing.B)  { benchmarkStress(5, 0, 0, b) }
func BenchmarkStress10Environments0Deploys0Services(b *testing.B) { benchmarkStress(10, 0, 0, b) }

func BenchmarkStress1Environment1Deploy0Service(b *testing.B)    { benchmarkStress(1, 1, 0, b) }
func BenchmarkStress1Environment5Deploys0Services(b *testing.B)  { benchmarkStress(1, 5, 0, b) }
func BenchmarkStress1Environment10Deploys0Services(b *testing.B) { benchmarkStress(1, 10, 0, b) }

func BenchmarkStress2Environments2Deploys1Service(b *testing.B)   { benchmarkStress(2, 2, 1, b) }
func BenchmarkStress2Environments2Deploy5Services(b *testing.B)   { benchmarkStress(2, 2, 5, b) }
func BenchmarkStress2Environments2Deploys10Services(b *testing.B) { benchmarkStress(2, 2, 10, b) }
*/

func BenchmarkStress(b *testing.B) {

	testCases := []BenchmarkTestCase{
		{1, 0, 0, ""},
		{5, 0, 0, ""},
		{10, 0, 0, ""},
		{1, 1, 0, ""},
		{1, 5, 0, ""},
		{1, 10, 0, ""},
		{2, 2, 1, serviceCommand},
		{2, 2, 5, serviceCommand},
		{2, 2, 10, serviceCommand},
	}

	for _, tc := range testCases {
		tfvars := map[string]string{
			"num_environments": strconv.Itoa(tc.Environments),
			"num_deploys":      strconv.Itoa(tc.Deploys),
			"num_services":     strconv.Itoa(tc.Services),
			"deploy_command":   tc.DeployCommand,
		}

		log.Debugf("Testing with Environments: %v, Deploys: %v, Services: %v, Deploy Command: '%v'", tc.Environments, tc.Deploys, tc.Services, tc.DeployCommand)

		title := fmt.Sprintf("Envs:%v_Deps:%v_Svcs:%v/", tc.Environments, tc.Deploys, tc.Services)

		s := NewStressTest(b, "cases/stress", tfvars)
		s.Terraform.Apply()

		b.Run(title+"ListEnvironments", func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				s.Layer0.ListEnvironments()
			}
		})

		b.Run(title+"ListDeploys", func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				s.Layer0.ListDeploys()
			}
		})

		b.Run(title+"ListLoadBalancers", func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				s.Layer0.ListLoadBalancers()
			}
		})

		b.Run(title+"ListServices", func(b *testing.B) {
			for n := 0; n < b.N; n++ {
				s.Layer0.ListServices()
			}
		})

		s.Terraform.Destroy()
	}
}
<|endoftext|>


<commit_before>package systray

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"syscall"
	"unsafe"
)

var (
	iconFiles = make([]*os.File, 0)
	dllDir    = path.Join(os.Getenv("APPDATA"), "systray")
	dllFile   = path.Join(dllDir, "systray.dll")

	mod                      = syscall.NewLazyDLL(dllFile)
	_nativeLoop              = mod.NewProc("nativeLoop")
	_quit                    = mod.NewProc("quit")
	_setIcon                 = mod.NewProc("setIcon")
	_setTitle                = mod.NewProc("setTitle")
	_setTooltip              = mod.NewProc("setTooltip")
	_add_or_update_menu_item = mod.NewProc("add_or_update_menu_item")
)

func init() {
	// Write DLL to file
	b, err := Asset("systray.dll")
	if err != nil {
		panic(fmt.Errorf("Unable to read systray.dll: %v", err))
	}

	err = os.MkdirAll(dllDir, 0755)
	if err != nil {
		panic(fmt.Errorf("Unable to create directory %v to hold systray.dll: %v", dllDir, err))
	}

	err = ioutil.WriteFile(dllFile, b, 0644)
	if err != nil {
		panic(fmt.Errorf("Unable to save systray.dll to %v: %v", dllFile, err))
	}
}

func nativeLoop() {
	_nativeLoop.Call(
		syscall.NewCallbackCDecl(systray_ready),
		syscall.NewCallbackCDecl(systray_menu_item_selected))
}

func quit() {
	_quit.Call()
	for _, f := range iconFiles {
		err := os.Remove(f.Name())
		if err != nil {
			log.Debugf("Unable to delete temporary icon file %v: %v", f.Name(), err)
		}
	}
}

// SetIcon sets the systray icon.
// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
// for other platforms.
func SetIcon(iconBytes []byte) {
	f, err := ioutil.TempFile("", "systray_temp_icon")
	if err != nil {
		log.Errorf("Unable to create temp icon: %v", err)
		return
	}
	defer f.Close()
	_, err = f.Write(iconBytes)
	if err != nil {
		log.Errorf("Unable to write icon to temp file %v: %v", f.Name(), f)
		return
	}
	// Need to close file before we load it to make sure contents is flushed.
	f.Close()
	name, err := strUTF16(f.Name())
	if err != nil {
		log.Errorf("Unable to convert name to string pointer: %v", err)
		return
	}
	_setIcon.Call(name.Raw())
}

// SetTitle sets the systray title, only available on Mac.
func SetTitle(title string) {
	// do nothing
}

// SetTooltip sets the systray tooltip to display on mouse hover of the tray icon,
// only available on Mac and Windows.
func SetTooltip(tooltip string) {
	t, err := strUTF16(tooltip)
	if err != nil {
		log.Errorf("Unable to convert tooltip to string pointer: %v", err)
		return
	}
	_setTooltip.Call(t.Raw())
}

func addOrUpdateMenuItem(item *MenuItem) {
	var disabled = 0
	if item.disabled {
		disabled = 1
	}
	var checked = 0
	if item.checked {
		checked = 1
	}
	title, err := strUTF16(item.title)
	if err != nil {
		log.Errorf("Unable to convert title to string pointer: %v", err)
		return
	}
	tooltip, err := strUTF16(item.tooltip)
	if err != nil {
		log.Errorf("Unable to convert tooltip to string pointer: %v", err)
		return
	}
	_add_or_update_menu_item.Call(
		uintptr(item.id),
		title.Raw(),
		tooltip.Raw(),
		uintptr(disabled),
		uintptr(checked),
	)
}

type utf16 []uint16

// Raw returns the underlying *wchar_t of an utf16 so we can pass to DLL
func (u utf16) Raw() uintptr {
	return uintptr(unsafe.Pointer(&u[0]))
}

// strUTF16 converts a Go string into a utf16 byte sequence
func strUTF16(s string) (utf16, error) {
	return syscall.UTF16FromString(s)
}

// systray_ready takes an ignored parameter just so we can compile a callback
// (for some reason in Go 1.4.x, syscall.NewCallback panics if there's no
// parameter to the function).
func systray_ready(ignore uintptr) uintptr {
	systrayReady()
	return 0
}

func systray_menu_item_selected(id uintptr) uintptr {
	systrayMenuItemSelected(int32(id))
	return 0
}
<commit_msg>Fixed pathing of systray.dll<commit_after>package systray

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"
	"unsafe"

	"github.com/getlantern/filepersist"
)

var (
	iconFiles = make([]*os.File, 0)
	dllDir    = filepath.Join(os.Getenv("APPDATA"), "systray")
	dllFile   = filepath.Join(dllDir, "systray.dll")

	mod                      = syscall.NewLazyDLL(dllFile)
	_nativeLoop              = mod.NewProc("nativeLoop")
	_quit                    = mod.NewProc("quit")
	_setIcon                 = mod.NewProc("setIcon")
	_setTitle                = mod.NewProc("setTitle")
	_setTooltip              = mod.NewProc("setTooltip")
	_add_or_update_menu_item = mod.NewProc("add_or_update_menu_item")
)

func init() {
	// Write DLL to file
	b, err := Asset("systray.dll")
	if err != nil {
		panic(fmt.Errorf("Unable to read systray.dll: %v", err))
	}

	err = os.MkdirAll(dllDir, 0755)
	if err != nil {
		panic(fmt.Errorf("Unable to create directory %v to hold systray.dll: %v", dllDir, err))
	}

	err = filepersist.Save(dllFile, b, 0644)
	if err != nil {
		panic(fmt.Errorf("Unable to save systray.dll to %v: %v", dllFile, err))
	}
}

func nativeLoop() {
	_nativeLoop.Call(
		syscall.NewCallbackCDecl(systray_ready),
		syscall.NewCallbackCDecl(systray_menu_item_selected))
}

func quit() {
	_quit.Call()
	for _, f := range iconFiles {
		err := os.Remove(f.Name())
		if err != nil {
			log.Debugf("Unable to delete temporary icon file %v: %v", f.Name(), err)
		}
	}
}

// SetIcon sets the systray icon.
// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
// for other platforms.
func SetIcon(iconBytes []byte) {
	f, err := ioutil.TempFile("", "systray_temp_icon")
	if err != nil {
		log.Errorf("Unable to create temp icon: %v", err)
		return
	}
	defer f.Close()
	_, err = f.Write(iconBytes)
	if err != nil {
		log.Errorf("Unable to write icon to temp file %v: %v", f.Name(), f)
		return
	}
	// Need to close file before we load it to make sure contents is flushed.
	f.Close()
	name, err := strUTF16(f.Name())
	if err != nil {
		log.Errorf("Unable to convert name to string pointer: %v", err)
		return
	}
	_setIcon.Call(name.Raw())
}

// SetTitle sets the systray title, only available on Mac.
func SetTitle(title string) {
	// do nothing
}

// SetTooltip sets the systray tooltip to display on mouse hover of the tray icon,
// only available on Mac and Windows.
func SetTooltip(tooltip string) {
	t, err := strUTF16(tooltip)
	if err != nil {
		log.Errorf("Unable to convert tooltip to string pointer: %v", err)
		return
	}
	_setTooltip.Call(t.Raw())
}

func addOrUpdateMenuItem(item *MenuItem) {
	var disabled = 0
	if item.disabled {
		disabled = 1
	}
	var checked = 0
	if item.checked {
		checked = 1
	}
	title, err := strUTF16(item.title)
	if err != nil {
		log.Errorf("Unable to convert title to string pointer: %v", err)
		return
	}
	tooltip, err := strUTF16(item.tooltip)
	if err != nil {
		log.Errorf("Unable to convert tooltip to string pointer: %v", err)
		return
	}
	_add_or_update_menu_item.Call(
		uintptr(item.id),
		title.Raw(),
		tooltip.Raw(),
		uintptr(disabled),
		uintptr(checked),
	)
}

type utf16 []uint16

// Raw returns the underlying *wchar_t of an utf16 so we can pass to DLL
func (u utf16) Raw() uintptr {
	return uintptr(unsafe.Pointer(&u[0]))
}

// strUTF16 converts a Go string into a utf16 byte sequence
func strUTF16(s string) (utf16, error) {
	return syscall.UTF16FromString(s)
}

// systray_ready takes an ignored parameter just so we can compile a callback
// (for some reason in Go 1.4.x, syscall.NewCallback panics if there's no
// parameter to the function).
func systray_ready(ignore uintptr) uintptr {
	systrayReady()
	return 0
}

func systray_menu_item_selected(id uintptr) uintptr {
	systrayMenuItemSelected(int32(id))
	return 0
}
<|endoftext|>


<commit_before>// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

import (
	"fmt"
	"math/rand"
	"net"
	"sync"
	"time"

	"github.com/google/syzkaller/pkg/cover"
	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/rpctype"
	"github.com/google/syzkaller/pkg/signal"
	"github.com/google/syzkaller/prog"
)

type RPCServer struct {
	mgr                   RPCManagerView
	port                  int
	target                *prog.Target
	configEnabledSyscalls []int
	targetEnabledSyscalls map[*prog.Syscall]bool
	stats                 *Stats
	sandbox               string
	batchSize             int

	mu           sync.Mutex
	fuzzers      map[string]*Fuzzer
	checkResult  *rpctype.CheckArgs
	maxSignal    signal.Signal
	corpusSignal signal.Signal
	corpusCover  cover.Cover
	rotator      *prog.Rotator
	rnd          *rand.Rand
}

type Fuzzer struct {
	name          string
	inputs        []rpctype.RPCInput
	newMaxSignal  signal.Signal
	rotatedSignal signal.Signal
	machineInfo   []byte
}

type BugFrames struct {
	memoryLeaks []string
	dataRaces   []string
}

// RPCManagerView restricts interface between RPCServer and Manager.
type RPCManagerView interface {
	fuzzerConnect() ([]rpctype.RPCInput, BugFrames)
	machineChecked(result *rpctype.CheckArgs, enabledSyscalls map[*prog.Syscall]bool)
	newInput(inp rpctype.RPCInput, sign signal.Signal) bool
	candidateBatch(size int) []rpctype.RPCCandidate
	rotateCorpus() bool
}

func startRPCServer(mgr *Manager) (*RPCServer, error) {
	serv := &RPCServer{
		mgr:                   mgr,
		target:                mgr.target,
		configEnabledSyscalls: mgr.configEnabledSyscalls,
		stats:                 mgr.stats,
		sandbox:               mgr.cfg.Sandbox,
		fuzzers:               make(map[string]*Fuzzer),
		rnd:                   rand.New(rand.NewSource(time.Now().UnixNano())),
	}
	serv.batchSize = 5
	if serv.batchSize < mgr.cfg.Procs {
		serv.batchSize = mgr.cfg.Procs
	}
	s, err := rpctype.NewRPCServer(mgr.cfg.RPC, "Manager", serv)
	if err != nil {
		return nil, err
	}
	log.Logf(0, "serving rpc on tcp://%v", s.Addr())
	serv.port = s.Addr().(*net.TCPAddr).Port
	go s.Serve()
	return serv, nil
}

func (serv *RPCServer) Connect(a *rpctype.ConnectArgs, r *rpctype.ConnectRes) error {
	log.Logf(1, "fuzzer %v connected", a.Name)
	serv.stats.vmRestarts.inc()

	corpus, bugFrames := serv.mgr.fuzzerConnect()

	serv.mu.Lock()
	defer serv.mu.Unlock()

	f := &Fuzzer{
		name:        a.Name,
		machineInfo: a.MachineInfo,
	}
	serv.fuzzers[a.Name] = f
	r.MemoryLeakFrames = bugFrames.memoryLeaks
	r.DataRaceFrames = bugFrames.dataRaces
	r.EnabledCalls = serv.configEnabledSyscalls
	r.GitRevision = prog.GitRevision
	r.TargetRevision = serv.target.Revision
	// TODO: temporary disabled b/c we suspect this negatively affects fuzzing.
	if false && serv.mgr.rotateCorpus() && serv.rnd.Intn(3) != 0 {
		// We do rotation every other time because there are no objective
		// proofs regarding its efficiency either way.
		// Also, rotation gives significantly skewed syscall selection
		// (run prog.TestRotationCoverage), it may or may not be OK.
		r.CheckResult = serv.rotateCorpus(f, corpus)
	} else {
		r.CheckResult = serv.checkResult
		f.inputs = corpus
		f.newMaxSignal = serv.maxSignal.Copy()
	}
	return nil
}

func (serv *RPCServer) rotateCorpus(f *Fuzzer, corpus []rpctype.RPCInput) *rpctype.CheckArgs {
	// Fuzzing tends to stuck in some local optimum and then it fails to cover
	// other state space points since code coverage is only a very approximate
	// measure of logic coverage. To overcome this we introduce some variation
	// into the process which should cause steady corpus rotation over time
	// (the same coverage is achieved in different ways).
	//
	// First, we select a subset of all syscalls for each VM run (result.EnabledCalls).
	// This serves 2 goals: (1) target fuzzer at a particular area of state space,
	// (2) disable syscalls that cause frequent crashes at least in some runs
	// to allow it to do actual fuzzing.
	//
	// Then, we remove programs that contain disabled syscalls from corpus
	// that will be sent to the VM (f.inputs). We also remove 10% of remaining
	// programs at random to allow to rediscover different variations of these programs.
	//
	// Then, we drop signal provided by the removed programs and also 10%
	// of the remaining signal at random (f.newMaxSignal). This again allows
	// rediscovery of this signal by different programs.
	//
	// Finally, we adjust criteria for accepting new programs from this VM (f.rotatedSignal).
	// This allows to accept rediscovered varied programs even if they don't
	// increase overall coverage. As the result we have multiple programs
	// providing the same duplicate coverage, these are removed during periodic
	// corpus minimization process. The minimization process is specifically
	// non-deterministic to allow the corpus rotation.
	//
	// Note: at no point we drop anything globally and permanently.
	// Everything we remove during this process is temporal and specific to a single VM.
	calls := serv.rotator.Select()

	var callIDs []int
	callNames := make(map[string]bool)
	for call := range calls {
		callNames[call.Name] = true
		callIDs = append(callIDs, call.ID)
	}

	f.inputs, f.newMaxSignal = serv.selectInputs(callNames, corpus, serv.maxSignal)
	// Remove the corresponding signal from rotatedSignal which will
	// be used to accept new inputs from this manager.
	f.rotatedSignal = serv.corpusSignal.Intersection(f.newMaxSignal)

	result := *serv.checkResult
	result.EnabledCalls = map[string][]int{serv.sandbox: callIDs}
	return &result
}

func (serv *RPCServer) selectInputs(enabled map[string]bool, inputs0 []rpctype.RPCInput, signal0 signal.Signal) (
	inputs []rpctype.RPCInput, signal signal.Signal) {
	signal = signal0.Copy()
	for _, inp := range inputs0 {
		calls, _, err := prog.CallSet(inp.Prog)
		if err != nil {
			panic(fmt.Sprintf("rotateInputs: CallSet failed: %v\n%s", err, inp.Prog))
		}
		for call := range calls {
			if !enabled[call] {
				goto drop
			}
		}
		if serv.rnd.Float64() > 0.9 {
			goto drop
		}
		inputs = append(inputs, inp)
		continue
	drop:
		for _, sig := range inp.Signal.Elems {
			delete(signal, sig)
		}
	}
	signal.Split(len(signal) / 10)
	return inputs, signal
}

func (serv *RPCServer) Check(a *rpctype.CheckArgs, r *int) error {
	serv.mu.Lock()
	defer serv.mu.Unlock()

	if serv.checkResult != nil {
		return nil
	}
	serv.targetEnabledSyscalls = make(map[*prog.Syscall]bool)
	for _, call := range a.EnabledCalls[serv.sandbox] {
		serv.targetEnabledSyscalls[serv.target.Syscalls[call]] = true
	}
	serv.mgr.machineChecked(a, serv.targetEnabledSyscalls)
	a.DisabledCalls = nil
	serv.checkResult = a
	serv.rotator = prog.MakeRotator(serv.target, serv.targetEnabledSyscalls, serv.rnd)
	return nil
}

func (serv *RPCServer) NewInput(a *rpctype.NewInputArgs, r *int) error {
	inputSignal := a.Signal.Deserialize()
	log.Logf(4, "new input from %v for syscall %v (signal=%v, cover=%v)",
		a.Name, a.Call, inputSignal.Len(), len(a.Cover))
	bad, disabled := checkProgram(serv.target, serv.targetEnabledSyscalls, a.RPCInput.Prog)
	if bad || disabled {
		log.Logf(0, "rejecting program from fuzzer (bad=%v, disabled=%v):\n%s", bad, disabled, a.RPCInput.Prog)
		return nil
	}
	serv.mu.Lock()
	defer serv.mu.Unlock()

	f := serv.fuzzers[a.Name]
	genuine := !serv.corpusSignal.Diff(inputSignal).Empty()
	rotated := false
	if !genuine && f.rotatedSignal != nil {
		rotated = !f.rotatedSignal.Diff(inputSignal).Empty()
	}
	if !genuine && !rotated {
		return nil
	}
	if !serv.mgr.newInput(a.RPCInput, inputSignal) {
		return nil
	}

	if f.rotatedSignal != nil {
		f.rotatedSignal.Merge(inputSignal)
	}
	serv.corpusCover.Merge(a.Cover)
	serv.stats.corpusCover.set(len(serv.corpusCover))
	serv.stats.newInputs.inc()
	if rotated {
		serv.stats.rotatedInputs.inc()
	}

	if genuine {
		serv.corpusSignal.Merge(inputSignal)
		serv.stats.corpusSignal.set(serv.corpusSignal.Len())

		a.RPCInput.Cover = nil // Don't send coverage back to all fuzzers.
		for _, other := range serv.fuzzers {
			if other == f {
				continue
			}
			other.inputs = append(other.inputs, a.RPCInput)
		}
	}
	return nil
}

func (serv *RPCServer) Poll(a *rpctype.PollArgs, r *rpctype.PollRes) error {
	serv.stats.mergeNamed(a.Stats)

	serv.mu.Lock()
	defer serv.mu.Unlock()

	f := serv.fuzzers[a.Name]
	if f == nil {
		log.Fatalf("fuzzer %v is not connected", a.Name)
	}
	newMaxSignal := serv.maxSignal.Diff(a.MaxSignal.Deserialize())
	if !newMaxSignal.Empty() {
		serv.maxSignal.Merge(newMaxSignal)
		serv.stats.maxSignal.set(len(serv.maxSignal))
		for _, f1 := range serv.fuzzers {
			if f1 == f {
				continue
			}
			f1.newMaxSignal.Merge(newMaxSignal)
		}
	}
	r.MaxSignal = f.newMaxSignal.Split(500).Serialize()
	if a.NeedCandidates {
		r.Candidates = serv.mgr.candidateBatch(serv.batchSize)
	}
	if len(r.Candidates) == 0 {
		batchSize := serv.batchSize
		// When the fuzzer starts, it pumps the whole corpus.
		// If we do it using the final batchSize, it can be very slow
		// (batch of size 6 can take more than 10 mins for 50K corpus and slow kernel).
		// So use a larger batch initially (we use no stats as approximation of initial pump).
		const initialBatch = 30
		if len(a.Stats) == 0 && batchSize < initialBatch {
			batchSize = initialBatch
		}
		for i := 0; i < batchSize && len(f.inputs) > 0; i++ {
			last := len(f.inputs) - 1
			r.NewInputs = append(r.NewInputs, f.inputs[last])
			f.inputs[last] = rpctype.RPCInput{}
			f.inputs = f.inputs[:last]
		}
		if len(f.inputs) == 0 {
			f.inputs = nil
		}
	}
	log.Logf(4, "poll from %v: candidates=%v inputs=%v maxsignal=%v",
		a.Name, len(r.Candidates), len(r.NewInputs), len(r.MaxSignal.Elems))
	return nil
}

func (serv *RPCServer) shutdownInstance(name string) []byte {
	serv.mu.Lock()
	defer serv.mu.Unlock()

	fuzzer := serv.fuzzers[name]
	if fuzzer == nil {
		return nil
	}
	delete(serv.fuzzers, name)
	return fuzzer.machineInfo
}
<commit_msg>syz-manager: fix logical races in rpc request handling<commit_after>// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

import (
	"fmt"
	"math/rand"
	"net"
	"sync"
	"time"

	"github.com/google/syzkaller/pkg/cover"
	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/rpctype"
	"github.com/google/syzkaller/pkg/signal"
	"github.com/google/syzkaller/prog"
)

type RPCServer struct {
	mgr                   RPCManagerView
	port                  int
	target                *prog.Target
	configEnabledSyscalls []int
	targetEnabledSyscalls map[*prog.Syscall]bool
	stats                 *Stats
	sandbox               string
	batchSize             int

	mu           sync.Mutex
	fuzzers      map[string]*Fuzzer
	checkResult  *rpctype.CheckArgs
	maxSignal    signal.Signal
	corpusSignal signal.Signal
	corpusCover  cover.Cover
	rotator      *prog.Rotator
	rnd          *rand.Rand
}

type Fuzzer struct {
	name          string
	inputs        []rpctype.RPCInput
	newMaxSignal  signal.Signal
	rotatedSignal signal.Signal
	machineInfo   []byte
}

type BugFrames struct {
	memoryLeaks []string
	dataRaces   []string
}

// RPCManagerView restricts interface between RPCServer and Manager.
type RPCManagerView interface {
	fuzzerConnect() ([]rpctype.RPCInput, BugFrames)
	machineChecked(result *rpctype.CheckArgs, enabledSyscalls map[*prog.Syscall]bool)
	newInput(inp rpctype.RPCInput, sign signal.Signal) bool
	candidateBatch(size int) []rpctype.RPCCandidate
	rotateCorpus() bool
}

func startRPCServer(mgr *Manager) (*RPCServer, error) {
	serv := &RPCServer{
		mgr:                   mgr,
		target:                mgr.target,
		configEnabledSyscalls: mgr.configEnabledSyscalls,
		stats:                 mgr.stats,
		sandbox:               mgr.cfg.Sandbox,
		fuzzers:               make(map[string]*Fuzzer),
		rnd:                   rand.New(rand.NewSource(time.Now().UnixNano())),
	}
	serv.batchSize = 5
	if serv.batchSize < mgr.cfg.Procs {
		serv.batchSize = mgr.cfg.Procs
	}
	s, err := rpctype.NewRPCServer(mgr.cfg.RPC, "Manager", serv)
	if err != nil {
		return nil, err
	}
	log.Logf(0, "serving rpc on tcp://%v", s.Addr())
	serv.port = s.Addr().(*net.TCPAddr).Port
	go s.Serve()
	return serv, nil
}

func (serv *RPCServer) Connect(a *rpctype.ConnectArgs, r *rpctype.ConnectRes) error {
	log.Logf(1, "fuzzer %v connected", a.Name)
	serv.stats.vmRestarts.inc()

	corpus, bugFrames := serv.mgr.fuzzerConnect()

	serv.mu.Lock()
	defer serv.mu.Unlock()

	f := &Fuzzer{
		name:        a.Name,
		machineInfo: a.MachineInfo,
	}
	serv.fuzzers[a.Name] = f
	r.MemoryLeakFrames = bugFrames.memoryLeaks
	r.DataRaceFrames = bugFrames.dataRaces
	r.EnabledCalls = serv.configEnabledSyscalls
	r.GitRevision = prog.GitRevision
	r.TargetRevision = serv.target.Revision
	// TODO: temporary disabled b/c we suspect this negatively affects fuzzing.
	if false && serv.mgr.rotateCorpus() && serv.rnd.Intn(3) != 0 {
		// We do rotation every other time because there are no objective
		// proofs regarding its efficiency either way.
		// Also, rotation gives significantly skewed syscall selection
		// (run prog.TestRotationCoverage), it may or may not be OK.
		r.CheckResult = serv.rotateCorpus(f, corpus)
	} else {
		r.CheckResult = serv.checkResult
		f.inputs = corpus
		f.newMaxSignal = serv.maxSignal.Copy()
	}
	return nil
}

func (serv *RPCServer) rotateCorpus(f *Fuzzer, corpus []rpctype.RPCInput) *rpctype.CheckArgs {
	// Fuzzing tends to stuck in some local optimum and then it fails to cover
	// other state space points since code coverage is only a very approximate
	// measure of logic coverage. To overcome this we introduce some variation
	// into the process which should cause steady corpus rotation over time
	// (the same coverage is achieved in different ways).
	//
	// First, we select a subset of all syscalls for each VM run (result.EnabledCalls).
	// This serves 2 goals: (1) target fuzzer at a particular area of state space,
	// (2) disable syscalls that cause frequent crashes at least in some runs
	// to allow it to do actual fuzzing.
	//
	// Then, we remove programs that contain disabled syscalls from corpus
	// that will be sent to the VM (f.inputs). We also remove 10% of remaining
	// programs at random to allow to rediscover different variations of these programs.
	//
	// Then, we drop signal provided by the removed programs and also 10%
	// of the remaining signal at random (f.newMaxSignal). This again allows
	// rediscovery of this signal by different programs.
	//
	// Finally, we adjust criteria for accepting new programs from this VM (f.rotatedSignal).
	// This allows to accept rediscovered varied programs even if they don't
	// increase overall coverage. As the result we have multiple programs
	// providing the same duplicate coverage, these are removed during periodic
	// corpus minimization process. The minimization process is specifically
	// non-deterministic to allow the corpus rotation.
	//
	// Note: at no point we drop anything globally and permanently.
	// Everything we remove during this process is temporal and specific to a single VM.
	calls := serv.rotator.Select()

	var callIDs []int
	callNames := make(map[string]bool)
	for call := range calls {
		callNames[call.Name] = true
		callIDs = append(callIDs, call.ID)
	}

	f.inputs, f.newMaxSignal = serv.selectInputs(callNames, corpus, serv.maxSignal)
	// Remove the corresponding signal from rotatedSignal which will
	// be used to accept new inputs from this manager.
	f.rotatedSignal = serv.corpusSignal.Intersection(f.newMaxSignal)

	result := *serv.checkResult
	result.EnabledCalls = map[string][]int{serv.sandbox: callIDs}
	return &result
}

func (serv *RPCServer) selectInputs(enabled map[string]bool, inputs0 []rpctype.RPCInput, signal0 signal.Signal) (
	inputs []rpctype.RPCInput, signal signal.Signal) {
	signal = signal0.Copy()
	for _, inp := range inputs0 {
		calls, _, err := prog.CallSet(inp.Prog)
		if err != nil {
			panic(fmt.Sprintf("rotateInputs: CallSet failed: %v\n%s", err, inp.Prog))
		}
		for call := range calls {
			if !enabled[call] {
				goto drop
			}
		}
		if serv.rnd.Float64() > 0.9 {
			goto drop
		}
		inputs = append(inputs, inp)
		continue
	drop:
		for _, sig := range inp.Signal.Elems {
			delete(signal, sig)
		}
	}
	signal.Split(len(signal) / 10)
	return inputs, signal
}

func (serv *RPCServer) Check(a *rpctype.CheckArgs, r *int) error {
	serv.mu.Lock()
	defer serv.mu.Unlock()

	if serv.checkResult != nil {
		return nil
	}
	serv.targetEnabledSyscalls = make(map[*prog.Syscall]bool)
	for _, call := range a.EnabledCalls[serv.sandbox] {
		serv.targetEnabledSyscalls[serv.target.Syscalls[call]] = true
	}
	serv.mgr.machineChecked(a, serv.targetEnabledSyscalls)
	a.DisabledCalls = nil
	serv.checkResult = a
	serv.rotator = prog.MakeRotator(serv.target, serv.targetEnabledSyscalls, serv.rnd)
	return nil
}

func (serv *RPCServer) NewInput(a *rpctype.NewInputArgs, r *int) error {
	inputSignal := a.Signal.Deserialize()
	log.Logf(4, "new input from %v for syscall %v (signal=%v, cover=%v)",
		a.Name, a.Call, inputSignal.Len(), len(a.Cover))
	bad, disabled := checkProgram(serv.target, serv.targetEnabledSyscalls, a.RPCInput.Prog)
	if bad || disabled {
		log.Logf(0, "rejecting program from fuzzer (bad=%v, disabled=%v):\n%s", bad, disabled, a.RPCInput.Prog)
		return nil
	}
	serv.mu.Lock()
	defer serv.mu.Unlock()

	f := serv.fuzzers[a.Name]
	// Note: f may be nil if we called shutdownInstance,
	// but this request is already in-flight.
	genuine := !serv.corpusSignal.Diff(inputSignal).Empty()
	rotated := false
	if !genuine && f != nil && f.rotatedSignal != nil {
		rotated = !f.rotatedSignal.Diff(inputSignal).Empty()
	}
	if !genuine && !rotated {
		return nil
	}
	if !serv.mgr.newInput(a.RPCInput, inputSignal) {
		return nil
	}

	if f != nil && f.rotatedSignal != nil {
		f.rotatedSignal.Merge(inputSignal)
	}
	serv.corpusCover.Merge(a.Cover)
	serv.stats.corpusCover.set(len(serv.corpusCover))
	serv.stats.newInputs.inc()
	if rotated {
		serv.stats.rotatedInputs.inc()
	}

	if genuine {
		serv.corpusSignal.Merge(inputSignal)
		serv.stats.corpusSignal.set(serv.corpusSignal.Len())

		a.RPCInput.Cover = nil // Don't send coverage back to all fuzzers.
		for _, other := range serv.fuzzers {
			if other == f {
				continue
			}
			other.inputs = append(other.inputs, a.RPCInput)
		}
	}
	return nil
}

func (serv *RPCServer) Poll(a *rpctype.PollArgs, r *rpctype.PollRes) error {
	serv.stats.mergeNamed(a.Stats)

	serv.mu.Lock()
	defer serv.mu.Unlock()

	f := serv.fuzzers[a.Name]
	if f == nil {
		// This is possible if we called shutdownInstance,
		// but already have a pending request from this instance in-flight.
		log.Logf(1, "poll: fuzzer %v is not connected", a.Name)
		return nil
	}
	newMaxSignal := serv.maxSignal.Diff(a.MaxSignal.Deserialize())
	if !newMaxSignal.Empty() {
		serv.maxSignal.Merge(newMaxSignal)
		serv.stats.maxSignal.set(len(serv.maxSignal))
		for _, f1 := range serv.fuzzers {
			if f1 == f {
				continue
			}
			f1.newMaxSignal.Merge(newMaxSignal)
		}
	}
	r.MaxSignal = f.newMaxSignal.Split(500).Serialize()
	if a.NeedCandidates {
		r.Candidates = serv.mgr.candidateBatch(serv.batchSize)
	}
	if len(r.Candidates) == 0 {
		batchSize := serv.batchSize
		// When the fuzzer starts, it pumps the whole corpus.
		// If we do it using the final batchSize, it can be very slow
		// (batch of size 6 can take more than 10 mins for 50K corpus and slow kernel).
		// So use a larger batch initially (we use no stats as approximation of initial pump).
		const initialBatch = 30
		if len(a.Stats) == 0 && batchSize < initialBatch {
			batchSize = initialBatch
		}
		for i := 0; i < batchSize && len(f.inputs) > 0; i++ {
			last := len(f.inputs) - 1
			r.NewInputs = append(r.NewInputs, f.inputs[last])
			f.inputs[last] = rpctype.RPCInput{}
			f.inputs = f.inputs[:last]
		}
		if len(f.inputs) == 0 {
			f.inputs = nil
		}
	}
	log.Logf(4, "poll from %v: candidates=%v inputs=%v maxsignal=%v",
		a.Name, len(r.Candidates), len(r.NewInputs), len(r.MaxSignal.Elems))
	return nil
}

func (serv *RPCServer) shutdownInstance(name string) []byte {
	serv.mu.Lock()
	defer serv.mu.Unlock()

	fuzzer := serv.fuzzers[name]
	if fuzzer == nil {
		return nil
	}
	delete(serv.fuzzers, name)
	return fuzzer.machineInfo
}
<|endoftext|>


<commit_before>// Copyright 2017 Mathew Robinson <mrobinson@praelatus.io>. All rights reserved.
// Use of this source code is governed by the AGPLv3 license that can be found in
// the LICENSE file.

package mongo_test

import (
	"strings"
	"testing"

	"github.com/praelatus/praelatus/ql/ast"
)

func TestTicketGet(t *testing.T) {
	ticket, err := r.Tickets().Get(&admin, "TEST-1")
	if err != nil {
		t.Error(err)
	}

	if ticket.Key == "" {
		t.Error("Expected a key got: ", ticket)
	}
}

func TestTicketSearch(t *testing.T) {
	tks, e := r.Tickets().Search(&admin, ast.AST{})
	if e != nil {
		t.Error(e)
		return
	}

	if tks == nil || len(tks) == 0 {
		t.Error("Expected to get tickets instead got none.")
	}
}

func TestTicketUpdate(t *testing.T) {
	t.Skip("Ticket Update is unimplemented")

	tk, e := r.Tickets().Get(&admin, "TEST-4")
	if e != nil {
		t.Error(e)
		return
	}

	tk.Summary = "Test ticket save"

	e = r.Tickets().Update(&admin, tk.Key, tk)
	if e != nil {
		t.Error(e)
		return
	}

	tk2, e := r.Tickets().Get(&admin, "TEST-4")
	if e != nil {
		t.Error(e)
		return
	}

	if tk2.Summary != "Test ticket save" {
		t.Errorf("Expected: Test ticket save Got: %s\n", tk.Summary)
	}
}

func TestTicketDelete(t *testing.T) {
	e := r.Tickets().Delete(&admin, "TEST-3")
	if e != nil {
		t.Error(e)
		return
	}

	if _, e = r.Tickets().Get(&admin, "TEST-3"); e == nil {
		t.Errorf("Expected an error getting ticket but got none.")
	}
}

func TestLabelSearch(t *testing.T) {
	lbls, e := r.Tickets().LabelSearch(&admin, "example")
	if e != nil {
		t.Error(e)
		return
	}

	if len(lbls) == 0 {
		t.Error("Expected 2 Labels Got 0")
		return
	}

	for i := range lbls {
		if !strings.HasPrefix(lbls[i], "example") {
			t.Errorf("Expected labels to start with example- Got %s\n", lbls[i])
			return
		}
	}
}
<commit_msg>Add a test for modifier statement LIMIT<commit_after>// Copyright 2017 Mathew Robinson <mrobinson@praelatus.io>. All rights reserved.
// Use of this source code is governed by the AGPLv3 license that can be found in
// the LICENSE file.

package mongo_test

import (
	"strings"
	"testing"

	"github.com/praelatus/praelatus/ql/ast"
	"github.com/praelatus/praelatus/ql/lexer"
	"github.com/praelatus/praelatus/ql/parser"
)

func TestTicketGet(t *testing.T) {
	ticket, err := r.Tickets().Get(&admin, "TEST-1")
	if err != nil {
		t.Error(err)
	}

	if ticket.Key == "" {
		t.Error("Expected a key got: ", ticket)
	}
}

func TestTicketSearch(t *testing.T) {
	tks, e := r.Tickets().Search(&admin, ast.AST{})
	if e != nil {
		t.Error(e)
		return
	}

	if tks == nil || len(tks) == 0 {
		t.Error("Expected to get tickets instead got none.")
	}
}

func TestTicketSearchLimit(t *testing.T) {
	l := lexer.New("LIMIT 5")
	p := parser.New(l)
	a := p.Parse()

	if len(p.Errors()) != 0 {
		t.Errorf("Parsing error: %v", p.Errors())
		return
	}

	tks, e := r.Tickets().Search(&admin, a)
	if e != nil {
		t.Error(e)
		return
	}

	if tks == nil || len(tks) == 0 {
		t.Error("Expected to get tickets instead got none.")
	}

	if len(tks) != 5 {
		t.Errorf("Expected 5 tickets Got %d", len(tks))
	}
}

func TestTicketUpdate(t *testing.T) {
	t.Skip("Ticket Update is unimplemented")

	tk, e := r.Tickets().Get(&admin, "TEST-4")
	if e != nil {
		t.Error(e)
		return
	}

	tk.Summary = "Test ticket save"

	e = r.Tickets().Update(&admin, tk.Key, tk)
	if e != nil {
		t.Error(e)
		return
	}

	tk2, e := r.Tickets().Get(&admin, "TEST-4")
	if e != nil {
		t.Error(e)
		return
	}

	if tk2.Summary != "Test ticket save" {
		t.Errorf("Expected: Test ticket save Got: %s\n", tk.Summary)
	}
}

func TestTicketDelete(t *testing.T) {
	e := r.Tickets().Delete(&admin, "TEST-3")
	if e != nil {
		t.Error(e)
		return
	}

	if _, e = r.Tickets().Get(&admin, "TEST-3"); e == nil {
		t.Errorf("Expected an error getting ticket but got none.")
	}
}

func TestLabelSearch(t *testing.T) {
	lbls, e := r.Tickets().LabelSearch(&admin, "example")
	if e != nil {
		t.Error(e)
		return
	}

	if len(lbls) == 0 {
		t.Error("Expected 2 Labels Got 0")
		return
	}

	for i := range lbls {
		if !strings.HasPrefix(lbls[i], "example") {
			t.Errorf("Expected labels to start with example- Got %s\n", lbls[i])
			return
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 1&1 Internet AG, http://1und1.de . All rights reserved. Licensed under the Apache v2 License.
 */

package oneandone_cloudserver_api

import ()

type MonitoringPolicy struct {
	withId
	withName
	LastStatus []MonitoringStatus `json:"last_status"`
}

type MonitoringStatus struct {
	Resource string          `json:"resource"`
	Date     string          `json:"date"`
	State    string          `json:"state"`
	Value    MonitoringValue `json:"value"`
}

type MonitoringValue struct {
	Unit   string           `json:"unit"`
	Value  string           `json:"value"`
	Limits MonitoringLimits `json:"limits"`
}

type MonitoringLimits struct {
	Upper int `json:"upper"`
	Lower int `json:"lower"`
}

type MonitoringPolicyCreateData struct {
}

// GET /monitoring_policies
func (api *API) GetMonitoringPolicies() []MonitoringPolicy {
	return []MonitoringPolicy{}
}

// POST /monitoring_policies
func (api *API) CreateMonitoringPolicy(configuration MonitoringPolicyCreateData) MonitoringPolicy {
	return MonitoringPolicy{}
}

// GET /monitoring_policies/{id}
func (api *API) GetMonitoringPolicy(Id string) MonitoringPolicy {
	return MonitoringPolicy{}
}

// DELETE /monitoring_policies/{id}
func (mp *MonitoringPolicy) Delete() MonitoringPolicy {
	return MonitoringPolicy{}
}

// PUT /monitoring_policies/{id}

// GET /monitoring_policies/{id}/ports

// PUT /monitoring_policies/{id}/ports

// GET /monitoring_policies/{id}/ports/{id}

// DELETE /monitoring_policies/{id}/ports/{id}

// PUT /monitoring_policies/{id}/ports/{id}

// GET /monitoring_policies/{id}/processes

// PUT /monitoring_policies/{id}/processes

// GET /monitoring_policies/{id}/processes/{id}

// DELETE /monitoring_policies/{id}/processes/{id}

// PUT /monitoring_policies/{id}/processes/{id}

// GET /monitoring_policies/{id}/servers

// PUT /monitoring_policies/{id}/servers

// GET /monitoring_policies/{id}/servers/{id}

// DELETE /monitoring_policies/{id}/servers/{id}
<commit_msg>Implement base lifecycle of the monitoring policies - GetAll - Get by id - Create - Delete by id<commit_after>/*
 * Copyright 2015 1&1 Internet AG, http://1und1.de . All rights reserved. Licensed under the Apache v2 License.
 */

package oneandone_cloudserver_api

import (
	"github.com/docker/machine/log"
	"net/http"
)

type MonitoringPolicy struct {
	withId
	withDescription
	withApi
	Status
	Name         string              `json:"name"`
	Default      int                 `json:"default"`
	CreationDate string              `json:"creation_date"`
	Email        string              `json:"email"`
	Agent        bool                `json:"agent"`
	Servers      []MonitoringServer  `json:"servers"`
	Thresholds   MonitoringThreshold `json:"thresholds"`
	Ports        []MonitoringPort    `json:"ports"`
	Processes    []MonitoringProcess `json:"processes"`
	CloudPanelId string              `json:"cloudpanel_id"`
}

type MonitoringServer struct {
	withId
	withName
}

type MonitoringThreshold struct {
	Cpu          MonitoringLevel `json:"cpu"`
	Ram          MonitoringLevel `json:"ram"`
	Disk         MonitoringLevel `json:"disk"`
	Transfer     MonitoringLevel `json:"transfer"`
	InternalPing MonitoringLevel `json:"internal_ping"`
}

type MonitoringLevel struct {
	Warning  MonitoringValue `json:"warning"`
	Critical MonitoringValue `json:"critical"`
}

type MonitoringValue struct {
	Value int  `json:"value"`
	Alert bool `json:"alert"`
}

type MonitoringPort struct {
	Protocol          string `json:"protocol"`
	Port              int    `json:"port"`
	AlertIf           string `json:"alert_if"`
	EmailNotification bool   `json:"email_notification"`
}

type MonitoringProcess struct {
	Process           string `json:"process"`
	AlertIf           string `json:"alert_if"`
	EmailNotification bool   `json:"email_notification"`
}

type MonitoringStatus struct {
	Resource string          `json:"resource"`
	Date     string          `json:"date"`
	State    string          `json:"state"`
	Value    MonitoringValue `json:"value"`
}
type MonitoringLimits struct {
	Upper int `json:"upper"`
	Lower int `json:"lower"`
}

type MonitoringPolicyCreateData struct {
}

// GET /monitoring_policies
func (api *API) GetMonitoringPolicies() ([]MonitoringPolicy, error) {
	log.Debug("requesting information about monitoring policies")
	result := []MonitoringPolicy{}
	err := api.Client.Get(createUrl(api, "monitoring_policies"), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range result {
		result[index].api = api
	}
	return result, nil
}

// POST /monitoring_policies
func (api *API) CreateMonitoringPolicy(configuration MonitoringPolicy) (*MonitoringPolicy, error) {
	log.Debug("requesting to create a new monitoring policy")
	result := new(MonitoringPolicy)
	err := api.Client.Post(createUrl(api, "monitoring_policies"), &configuration, &result, http.StatusCreated)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// GET /monitoring_policies/{id}
func (api *API) GetMonitoringPolicy(Id string) (*MonitoringPolicy, error) {
	log.Debug("requesting information about monitoring policy ", Id)
	result := new(MonitoringPolicy)
	err := api.Client.Get(createUrl(api, "monitoring_policies", Id), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// DELETE /monitoring_policies/{id}
func (mp *MonitoringPolicy) Delete() MonitoringPolicy {
	log.Debugf("Requested to delete monitoring policy '%v' ", mp.Id) (*MonitoringPolicy, error)
	result := new(MonitoringPolicy)
	err := mp.api.Client.Delete(createUrl(mp.api, "monitoring_policies", mp.Id), &result, http.StatusAccepted)
	if err != nil {
		return nil, err
	}
	result.api = mp.api
	return result, nil
}

// PUT /monitoring_policies/{id}

// GET /monitoring_policies/{id}/ports

// PUT /monitoring_policies/{id}/ports

// GET /monitoring_policies/{id}/ports/{id}

// DELETE /monitoring_policies/{id}/ports/{id}

// PUT /monitoring_policies/{id}/ports/{id}

// GET /monitoring_policies/{id}/processes

// PUT /monitoring_policies/{id}/processes

// GET /monitoring_policies/{id}/processes/{id}

// DELETE /monitoring_policies/{id}/processes/{id}

// PUT /monitoring_policies/{id}/processes/{id}

// GET /monitoring_policies/{id}/servers

// PUT /monitoring_policies/{id}/servers

// GET /monitoring_policies/{id}/servers/{id}

// DELETE /monitoring_policies/{id}/servers/{id}
<|endoftext|>


<commit_before>package main

import (
	"github.com/monsti/form"
	"github.com/monsti/util/l10n"
	"github.com/monsti/rpc/client"
	"github.com/monsti/util/template"
	"github.com/monsti/util"
	"flag"
	"fmt"
	"github.com/chrneumann/mimemail"
	htmlT "html/template"
	"log"
	"os"
)

type cfsettings struct {
	// Absolute paths to used directories.
	Directories struct {
		// HTML Templates
		Templates string
		// Locales, i.e. the gettext machine objects (.mo)
		Locales string
	}
}

var renderer template.Renderer
var settings cfsettings

type contactFormData struct {
	Name, Email, Subject, Message string
}

func handle(req client.Request, res *client.Response, c client.Connection) {
	switch req.Action {
	case "edit":
		edit(req, res, c)
	default:
		view(req, res, c)
	}
}

func view(req client.Request, res *client.Response, c client.Connection) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := contactFormData{}
	form := form.NewForm(&data, form.Fields{
		"Name":    form.Field{G("Name"), "", form.Required(G("Required.")), nil},
		"Email":   form.Field{G("Email"), "", form.Required(G("Required.")), nil},
		"Subject": form.Field{G("Subject"), "", form.Required(G("Required.")), nil},
		"Message": form.Field{G("Message"), "", form.Required(G("Required.")),
			new(form.TextArea)}})
	context := template.Context{}
	switch req.Method {
	case "GET":
		if _, submitted := req.Query["submitted"]; submitted {
			context["Submitted"] = 1
		}
	case "POST":
		if form.Fill(c.GetFormData()) {
			c.SendMail(mimemail.Mail{
				From:    mimemail.Address{data.Name, data.Email},
				Subject: data.Subject,
				Body:    []byte(data.Message)})
			res.Redirect = req.Node.Path + "/?submitted"
			return
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	res.Node = &req.Node
	res.Node.HideSidebar = true
	body := c.GetNodeData(req.Node.Path, "body.html")
	context["Body"] = htmlT.HTML(string(body))
	context["Form"] = form.RenderData()
	fmt.Fprint(res, renderer.Render("view/contactform", context,
		req.Session.Locale, ""))
}

type editFormData struct {
	Title, Body string
}

func edit(req client.Request, res *client.Response, c client.Connection) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := editFormData{}
	form := form.NewForm(&data, form.Fields{
		"Title": form.Field{G("Title"), "", form.Required(G("Required.")), nil},
		"Body": form.Field{G("Body"), "", form.Required(G("Required.")),
			new(form.AlohaEditor)}})
	switch req.Method {
	case "GET":
		data.Title = req.Node.Title
		data.Body = string(c.GetNodeData(req.Node.Path, "body.html"))
	case "POST":
		if form.Fill(c.GetFormData()) {
			node := req.Node
			node.Title = data.Title
			c.UpdateNode(node)
			c.WriteNodeData(req.Node.Path, "body.html", data.Body)
			res.Redirect = req.Node.Path
			return
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	fmt.Fprint(res, renderer.Render("edit/contactform",
		template.Context{"Form": form.RenderData()},
		req.Session.Locale, ""))
}

func main() {
	logger := log.New(os.Stderr, "contactform", log.LstdFlags)
	flag.Parse()
	cfgPath := util.GetConfigPath("contactform", flag.Arg(0))
	if err := util.ParseYAML(cfgPath, &settings); err != nil {
		logger.Fatal("Could not load monsti-contactform configuration file: ", err)
	}
	l10n.Setup("monsti-contactform", settings.Directories.Locales)
	renderer.Root = settings.Directories.Templates
	client.NewConnection("contactform", logger).Serve(handle)
}
<commit_msg>Sidebar option no longer used.<commit_after>package main

import (
	"github.com/monsti/form"
	"github.com/monsti/util/l10n"
	"github.com/monsti/rpc/client"
	"github.com/monsti/util/template"
	"github.com/monsti/util"
	"flag"
	"fmt"
	"github.com/chrneumann/mimemail"
	htmlT "html/template"
	"log"
	"os"
)

type cfsettings struct {
	// Absolute paths to used directories.
	Directories struct {
		// HTML Templates
		Templates string
		// Locales, i.e. the gettext machine objects (.mo)
		Locales string
	}
}

var renderer template.Renderer
var settings cfsettings

type contactFormData struct {
	Name, Email, Subject, Message string
}

func handle(req client.Request, res *client.Response, c client.Connection) {
	switch req.Action {
	case "edit":
		edit(req, res, c)
	default:
		view(req, res, c)
	}
}

func view(req client.Request, res *client.Response, c client.Connection) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := contactFormData{}
	form := form.NewForm(&data, form.Fields{
		"Name":    form.Field{G("Name"), "", form.Required(G("Required.")), nil},
		"Email":   form.Field{G("Email"), "", form.Required(G("Required.")), nil},
		"Subject": form.Field{G("Subject"), "", form.Required(G("Required.")), nil},
		"Message": form.Field{G("Message"), "", form.Required(G("Required.")),
			new(form.TextArea)}})
	context := template.Context{}
	switch req.Method {
	case "GET":
		if _, submitted := req.Query["submitted"]; submitted {
			context["Submitted"] = 1
		}
	case "POST":
		if form.Fill(c.GetFormData()) {
			c.SendMail(mimemail.Mail{
				From:    mimemail.Address{data.Name, data.Email},
				Subject: data.Subject,
				Body:    []byte(data.Message)})
			res.Redirect = req.Node.Path + "/?submitted"
			return
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	res.Node = &req.Node
	body := c.GetNodeData(req.Node.Path, "body.html")
	context["Body"] = htmlT.HTML(string(body))
	context["Form"] = form.RenderData()
	fmt.Fprint(res, renderer.Render("view/contactform", context,
		req.Session.Locale, ""))
}

type editFormData struct {
	Title, Body string
}

func edit(req client.Request, res *client.Response, c client.Connection) {
	G := l10n.UseCatalog(req.Session.Locale)
	data := editFormData{}
	form := form.NewForm(&data, form.Fields{
		"Title": form.Field{G("Title"), "", form.Required(G("Required.")), nil},
		"Body": form.Field{G("Body"), "", form.Required(G("Required.")),
			new(form.AlohaEditor)}})
	switch req.Method {
	case "GET":
		data.Title = req.Node.Title
		data.Body = string(c.GetNodeData(req.Node.Path, "body.html"))
	case "POST":
		if form.Fill(c.GetFormData()) {
			node := req.Node
			node.Title = data.Title
			c.UpdateNode(node)
			c.WriteNodeData(req.Node.Path, "body.html", data.Body)
			res.Redirect = req.Node.Path
			return
		}
	default:
		panic("Request method not supported: " + req.Method)
	}
	fmt.Fprint(res, renderer.Render("edit/contactform",
		template.Context{"Form": form.RenderData()},
		req.Session.Locale, ""))
}

func main() {
	logger := log.New(os.Stderr, "contactform", log.LstdFlags)
	flag.Parse()
	cfgPath := util.GetConfigPath("contactform", flag.Arg(0))
	if err := util.ParseYAML(cfgPath, &settings); err != nil {
		logger.Fatal("Could not load monsti-contactform configuration file: ", err)
	}
	l10n.Setup("monsti-contactform", settings.Directories.Locales)
	renderer.Root = settings.Directories.Templates
	client.NewConnection("contactform", logger).Serve(handle)
}
<|endoftext|>


<commit_before>package gring_test

import (
	"container/ring"
	"github.com/gogf/gf/g"
	"github.com/gogf/gf/g/container/gring"
	"github.com/gogf/gf/g/test/gtest"
	"testing"
)
type Student struct {
	position int
	name    string
	upgrade bool
}

func TestRing_Val(t *testing.T) {
	gtest.Case(t, func() {
		//定义cap 为3的ring类型数据
		r := gring.New(3, true)
		//分别给3个元素初始化赋值
		r.Put(&Student{1,"jimmy", true})
		r.Put(&Student{2,"tom", true})
		r.Put(&Student{3,"alon", false})

		//元素取值并判断和预设值是否相等
		gtest.Assert(r.Val().(*Student).name,"jimmy")
		//从当前位置往后移两个元素
		r.Move(2)
		gtest.Assert(r.Val().(*Student).name,"alon")
		//更新元素值
		//测试 value == nil
		r.Set(nil)
		gtest.Assert(r.Val(),nil)
		//测试value != nil
		r.Set(&Student{3, "jack", true})
	})
}
func TestRing_CapLen(t *testing.T) {
	gtest.Case(t, func() {
		r := gring.New(10)
		r.Put("goframe")
		//cap长度 10
		gtest.Assert(r.Cap(), 10)
		//已有数据项 1
		gtest.Assert(r.Len(), 1)
	})
}

func TestRing_Position(t *testing.T) {
	gtest.Case(t, func() {
		r := gring.New(2)
		r.Put(1)
		r.Put(2)
		//往后移动1个元素
		r.Next()
		gtest.Assert(r.Val(),2)
		//往前移动1个元素
		r.Prev()
		gtest.Assert(r.Val(),1)

	})
}

func TestRing_Link(t *testing.T) {
	gtest.Case(t, func() {
		r := gring.New(3)
		r.Put(1)
		r.Put(2)
		r.Put(3)
		s := gring.New(2)
		s.Put("a")
		s.Put("b")

		rs := r.Link(s)
		gtest.Assert(rs.Move(2).Val(), "b")

	})
}

func TestRing_Unlink(t *testing.T) {
	gtest.Case(t, func() {
		r := gring.New(5)
		for i := 0; i< 5; i++  {
			r.Put(i+1)
		}
		// 1 2 3 4 5
		// 删除当前位置往后的2个数据，返回被删除的数据
		s := r.Unlink(2)		// 2 3
		gtest.Assert(s.Val(), 2)
	})
}

func TestRing_Slice(t *testing.T) {
	gtest.Case(t, func() {
		ringLen := 5
		r := gring.New(ringLen)
		for i := 0; i< ringLen; i++  {
			r.Put(i+1)
		}
		r.Move(2)	// 3
		array := r.SliceNext()		// [3 4 5 1 2]
		gtest.Assert(array[0], 3)
		gtest.Assert(len(array), 5)

		//判断array是否等于[3 4 5 1 2]
		ra := []int{3,4,5,1,2}
		gtest.Assert(ra, array)

		//第3个元素设为nil
		r.Set(nil)
		array2 := r.SliceNext() 	//[4 5 1 2]
		//返回当前位置往后不为空的元素数组，长度为4
		gtest.Assert(array2, g.Slice{4,5,1,2})

		array3 := r.SlicePrev() 	//[2 1 5 4]
		gtest.Assert(array3, g.Slice{2,1,5,4})

		s := gring.New(ringLen)
		array4 := s.SlicePrev()	// []
		gtest.Assert(array4, g.Slice{})

	})
}

func TestRing_RLockIterator(t *testing.T) {
	gtest.Case(t, func() {
		ringLen := 5
		r := gring.New(ringLen)

		//ring不存在有值元素
		r.RLockIteratorNext(func(value interface{}) bool {
			gtest.Assert(r.Val(), nil)
			return true
		})

		r.RLockIteratorPrev(func(value interface{}) bool {
			gtest.Assert(r.Val(), nil)
			return true
		})

		for i := 0; i< ringLen; i++  {
			r.Put(i+1)
		}

		//回调函数返回true,RLockIteratorNext遍历5次
		r.RLockIteratorNext(func(value interface{}) bool {
			gtest.Assert(r.Val(), 1)
			return true
		})

		//RLockIteratorPrev遍历3次返回 false,退出遍历
		r.RLockIteratorPrev(func(value interface{}) bool {
			gtest.Assert(r.Val(), 1)
			return false
		})

	})
}

func TestRing_LockIterator(t *testing.T) {
	gtest.Case(t, func() {
		ringLen := 5
		r := gring.New(ringLen)

		//不存在有值元素
		r.LockIteratorNext(func(item *ring.Ring) bool {
			gtest.Assert(item.Value, nil)
			return true
		})

		r.LockIteratorPrev(func(item *ring.Ring) bool {
			gtest.Assert(item.Value, nil)
			return true
		})

		//ring初始化元素值
		for i := 0; i< ringLen; i++  {
			r.Put(i+1)
		}

		//往后遍历组成数据 [1,2,3,4,5]
		array1 := g.Slice{1,2,3,4,5}
		ii := 0
		r.LockIteratorNext(func(item *ring.Ring) bool {
			//校验每一次遍历取值是否是期望值
			gtest.Assert(item.Value, array1[ii])
			ii++;
			return true
		})

		//往后取3个元素组成数组
		//获得 [1,5,4]
		i := 0
		a := g.Slice{1,5,4}
		r.LockIteratorPrev(func(item *ring.Ring) bool {
			if i > 2 {
				return false
			}
			gtest.Assert(item.Value, a[i])
			i++;
			return true
		})

	})
}<commit_msg>update unit test for gring<commit_after>package gring_test

import (
	"container/ring"
	"github.com/gogf/gf/g"
	"github.com/gogf/gf/g/container/gring"
	"github.com/gogf/gf/g/test/gtest"
	"testing"
)
type Student struct {
	position int
	name    string
	upgrade bool
}

func TestRing_Val(t *testing.T) {
	gtest.Case(t, func() {
		//定义cap 为3的ring类型数据
		r := gring.New(3, true)
		//分别给3个元素初始化赋值
		r.Put(&Student{1,"jimmy", true})
		r.Put(&Student{2,"tom", true})
		r.Put(&Student{3,"alon", false})

		//元素取值并判断和预设值是否相等
		gtest.Assert(r.Val().(*Student).name,"jimmy")
		//从当前位置往后移两个元素
		r.Move(2)
		gtest.Assert(r.Val().(*Student).name,"alon")
		//更新元素值
		//测试 value == nil
		r.Set(nil)
		gtest.Assert(r.Val(),nil)
		//测试value != nil
		r.Set(&Student{3, "jack", true})
	})
}
func TestRing_CapLen(t *testing.T) {
	gtest.Case(t, func() {
		r := gring.New(10)
		r.Put("goframe")
		//cap长度 10
		gtest.Assert(r.Cap(), 10)
		//已有数据项 1
		gtest.Assert(r.Len(), 1)
	})
}

func TestRing_Position(t *testing.T) {
	gtest.Case(t, func() {
		r := gring.New(2)
		r.Put(1)
		r.Put(2)
		//往后移动1个元素
		r.Next()
		gtest.Assert(r.Val(),2)
		//往前移动1个元素
		r.Prev()
		gtest.Assert(r.Val(),1)

	})
}

func TestRing_Link(t *testing.T) {
	gtest.Case(t, func() {
		r := gring.New(3)
		r.Put(1)
		r.Put(2)
		r.Put(3)
		s := gring.New(2)
		s.Put("a")
		s.Put("b")

		rs := r.Link(s)
		gtest.Assert(rs.Move(2).Val(), "b")

	})
}

func TestRing_Unlink(t *testing.T) {
	gtest.Case(t, func() {
		r := gring.New(5)
		for i := 0; i< 5; i++  {
			r.Put(i+1)
		}
		// 1 2 3 4 5
		// 删除当前位置往后的2个数据，返回被删除的数据
		// 重新计算s len
		s := r.Unlink(2)		// 2 3
		gtest.Assert(s.Val(), 2)
		gtest.Assert(s.Len(), 1)
	})
}

func TestRing_Slice(t *testing.T) {
	gtest.Case(t, func() {
		ringLen := 5
		r := gring.New(ringLen)
		for i := 0; i< ringLen; i++  {
			r.Put(i+1)
		}
		r.Move(2)	// 3
		array := r.SliceNext()		// [3 4 5 1 2]
		gtest.Assert(array[0], 3)
		gtest.Assert(len(array), 5)

		//判断array是否等于[3 4 5 1 2]
		ra := []int{3,4,5,1,2}
		gtest.Assert(ra, array)

		//第3个元素设为nil
		r.Set(nil)
		array2 := r.SliceNext() 	//[4 5 1 2]
		//返回当前位置往后不为空的元素数组，长度为4
		gtest.Assert(array2, g.Slice{4,5,1,2})

		array3 := r.SlicePrev() 	//[2 1 5 4]
		gtest.Assert(array3, g.Slice{2,1,5,4})

		s := gring.New(ringLen)
		array4 := s.SlicePrev()	// []
		gtest.Assert(array4, g.Slice{})

	})
}

func TestRing_RLockIterator(t *testing.T) {
	gtest.Case(t, func() {
		ringLen := 5
		r := gring.New(ringLen)

		//ring不存在有值元素
		r.RLockIteratorNext(func(value interface{}) bool {
			gtest.Assert(r.Val(), nil)
			return true
		})

		r.RLockIteratorPrev(func(value interface{}) bool {
			gtest.Assert(r.Val(), nil)
			return true
		})

		for i := 0; i< ringLen; i++  {
			r.Put(i+1)
		}

		//回调函数返回true,RLockIteratorNext遍历5次
		r.RLockIteratorNext(func(value interface{}) bool {
			gtest.Assert(r.Val(), 1)
			return true
		})

		//RLockIteratorPrev遍历3次返回 false,退出遍历
		r.RLockIteratorPrev(func(value interface{}) bool {
			gtest.Assert(r.Val(), 1)
			return false
		})

	})
}

func TestRing_LockIterator(t *testing.T) {
	gtest.Case(t, func() {
		ringLen := 5
		r := gring.New(ringLen)

		//不存在有值元素
		r.LockIteratorNext(func(item *ring.Ring) bool {
			gtest.Assert(item.Value, nil)
			return true
		})

		r.LockIteratorPrev(func(item *ring.Ring) bool {
			gtest.Assert(item.Value, nil)
			return true
		})

		//ring初始化元素值
		for i := 0; i< ringLen; i++  {
			r.Put(i+1)
		}

		//往后遍历组成数据 [1,2,3,4,5]
		array1 := g.Slice{1,2,3,4,5}
		ii := 0
		r.LockIteratorNext(func(item *ring.Ring) bool {
			//校验每一次遍历取值是否是期望值
			gtest.Assert(item.Value, array1[ii])
			ii++;
			return true
		})

		//往后取3个元素组成数组
		//获得 [1,5,4]
		i := 0
		a := g.Slice{1,5,4}
		r.LockIteratorPrev(func(item *ring.Ring) bool {
			if i > 2 {
				return false
			}
			gtest.Assert(item.Value, a[i])
			i++;
			return true
		})

	})
}<|endoftext|>


<commit_before>package multitemplate

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

	"github.com/stretchr/testify/assert"
	"gopkg.in/gin-gonic/gin.v1"
)

func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func createFromFile() Render {
	r := New()
	r.AddFromFiles("index", "tests/base.html", "tests/article.html")

	return r
}

func createFromGlob() Render {
	r := New()
	r.AddFromGlob("index", "tests/global/*")

	return r
}

func createFromString() Render {
	r := New()
	r.AddFromString("index", "Welcome to {{ .name }} template")

	return r
}

func TestAddFromFiles(t *testing.T) {
	router := gin.New()
	router.HTMLRender = createFromFile()
	router.GET("/", func(c *gin.Context) {
		c.HTML(200, "index", gin.H{
			"title": "Test Multiple Template",
		})
	})

	w := performRequest(router, "GET", "/")
	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "
Test Multiple Template
\nHi, this is article template\n", w.Body.String())
}

func TestAddFromGlob(t *testing.T) {
	router := gin.New()
	router.HTMLRender = createFromGlob()
	router.GET("/", func(c *gin.Context) {
		c.HTML(200, "index", gin.H{
			"title": "Test Multiple Template",
		})
	})

	w := performRequest(router, "GET", "/")
	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "
Test Multiple Template
\nHi, this is login template\n", w.Body.String())
}

func TestAddFromString(t *testing.T) {
	router := gin.New()
	router.HTMLRender = createFromString()
	router.GET("/", func(c *gin.Context) {
		c.HTML(200, "index", gin.H{
			"name": "index",
		})
	})

	w := performRequest(router, "GET", "/")
	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "Welcome to index template", w.Body.String())
}
<commit_msg>Test Missing Template Or Name<commit_after>package multitemplate

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

	"github.com/stretchr/testify/assert"
	"gopkg.in/gin-gonic/gin.v1"
)

func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func createFromFile() Render {
	r := New()
	r.AddFromFiles("index", "tests/base.html", "tests/article.html")

	return r
}

func createFromGlob() Render {
	r := New()
	r.AddFromGlob("index", "tests/global/*")

	return r
}

func createFromString() Render {
	r := New()
	r.AddFromString("index", "Welcome to {{ .name }} template")

	return r
}

func TestMissingTemplateOrName(t *testing.T) {
	r := New()
	tmpl := template.Must(template.New("test").Parse("Welcome to {{ .name }} template"))
	assert.Panics(t, func() {
		r.Add("", tmpl)
	}, "template name cannot be empty")

	assert.Panics(t, func() {
		r.Add("test", nil)
	}, "template can not be nil")
}

func TestAddFromFiles(t *testing.T) {
	router := gin.New()
	router.HTMLRender = createFromFile()
	router.GET("/", func(c *gin.Context) {
		c.HTML(200, "index", gin.H{
			"title": "Test Multiple Template",
		})
	})

	w := performRequest(router, "GET", "/")
	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "
Test Multiple Template
\nHi, this is article template\n", w.Body.String())
}

func TestAddFromGlob(t *testing.T) {
	router := gin.New()
	router.HTMLRender = createFromGlob()
	router.GET("/", func(c *gin.Context) {
		c.HTML(200, "index", gin.H{
			"title": "Test Multiple Template",
		})
	})

	w := performRequest(router, "GET", "/")
	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "
Test Multiple Template
\nHi, this is login template\n", w.Body.String())
}

func TestAddFromString(t *testing.T) {
	router := gin.New()
	router.HTMLRender = createFromString()
	router.GET("/", func(c *gin.Context) {
		c.HTML(200, "index", gin.H{
			"name": "index",
		})
	})

	w := performRequest(router, "GET", "/")
	assert.Equal(t, 200, w.Code)
	assert.Equal(t, "Welcome to index template", w.Body.String())
}
<|endoftext|>