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

// Package plist implements parsing of Apple plist files.
package plist

import (
	"bytes"
	"fmt"
	"reflect"
	"strconv"
)

func next(data []byte) (skip, tag, rest []byte) {
	i := bytes.IndexByte(data, '<')
	if i < 0 {
		return data, nil, nil
	}
	var j int
	if i+1 < len(data) && data[i+1] == '?' {
		j = bytes.Index(data[i:], []byte("?>"))
	} else {
		j = bytes.IndexByte(data[i:], '>')
	}
	if j < 0 {
		return data, nil, nil
	}
	j += i + 1
	return data[:i], data[i:j], data[j:]
}

func Unmarshal(data []byte, v interface{}) error {
	_, tag, data := next(data)
	if bytes.HasPrefix(tag, []byte("<?xml")) {
		_, tag, data = next(data)
	}
	if bytes.HasPrefix(tag, []byte("<!DOCTYPE")) {
		_, tag, data = next(data)
	}
	if !bytes.HasPrefix(tag, []byte("<plist")) {
		return fmt.Errorf("not a plist")
	}

	data, err := unmarshalValue(data, reflect.ValueOf(v))
	if err != nil {
		return err
	}
	_, tag, data = next(data)
	if !bytes.Equal(tag, []byte("</plist>")) {
		return fmt.Errorf("junk on end of plist")
	}
	return nil
}

func unmarshalValue(data []byte, v reflect.Value) (rest []byte, err error) {
	_, tag, data := next(data)
	if tag == nil {
		return nil, fmt.Errorf("unexpected end of data")
	}

	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		v = v.Elem()
	}

	switch stag := string(tag); stag {
	case "<dict>":
		t := v.Type()
		if v.Kind() != reflect.Struct {
			return nil, fmt.Errorf("cannot unmarshal <dict> into non-struct %s", v.Type())
		}
	Dict:
		for {
			_, tag, data = next(data)
			if len(tag) == 0 {
				return nil, fmt.Errorf("eof inside <dict>")
			}
			if string(tag) == "</dict>" {
				break
			}
			if string(tag) != "<key>" {
				return nil, fmt.Errorf("unexpected tag %s inside <dict>", tag)
			}
			var body []byte
			body, tag, data = next(data)
			if len(tag) == 0 {
				return nil, fmt.Errorf("eof inside <dict>")
			}
			if string(tag) != "</key>" {
				return nil, fmt.Errorf("unexpected tag %s inside <dict>", tag)
			}
			name := string(body)
			var i int
			for i = 0; i < t.NumField(); i++ {
				f := t.Field(i)
				if f.Name == name || f.Tag.Get("plist") == name {
					data, err = unmarshalValue(data, v.Field(i))
					continue Dict
				}
			}
			data, err = skipValue(data)
			if err != nil {
				return nil, err
			}
		}
		return data, nil

	case "<array>":
		t := v.Type()
		if v.Kind() != reflect.Slice {
			return nil, fmt.Errorf("cannot unmarshal <array> into non-slice %s", v.Type())
		}
		for {
			_, tag, rest := next(data)
			if len(tag) == 0 {
				return nil, fmt.Errorf("eof inside <array>")
			}
			if string(tag) == "</array>" {
				data = rest
				break
			}
			elem := reflect.New(t.Elem()).Elem()
			data, err = unmarshalValue(data, elem)
			if err != nil {
				return nil, err
			}
			v.Set(reflect.Append(v, elem))
		}
		return data, nil

	case "<string>":
		if v.Kind() != reflect.String {
			return nil, fmt.Errorf("cannot unmarshal <string> into non-string %s", v.Type())
		}
		body, etag, data := next(data)
		if len(etag) == 0 {
			return nil, fmt.Errorf("eof inside <string>")
		}
		if string(etag) != "</string>" {
			return nil, fmt.Errorf("expected </string> but got %s", etag)
		}
		v.SetString(string(body)) // TODO: unescape
		return data, nil

	case "<integer>":
		if v.Kind() != reflect.Int {
			return nil, fmt.Errorf("cannot unmarshal <integer> into non-int %s", v.Type())
		}
		body, etag, data := next(data)
		if len(etag) == 0 {
			return nil, fmt.Errorf("eof inside <integer>")
		}
		if string(etag) != "</integer>" {
			return nil, fmt.Errorf("expected </integer> but got %s", etag)
		}
		i, err := strconv.Atoi(string(body))
		if err != nil {
			return nil, fmt.Errorf("non-integer in <integer> tag: %s", body)
		}
		v.SetInt(int64(i))
		return data, nil

	case "<true/>", "<false/>":
		if v.Kind() != reflect.Bool {
			return nil, fmt.Errorf("cannot unmarshal %s into non-bool %s", stag, v.Type())
		}
		v.SetBool(stag == "<true/>")
		return data, nil
	}
	return nil, fmt.Errorf("unexpected tag %s", tag)
}

func skipValue(data []byte) (rest []byte, err error) {
	n := 0
	for {
		var tag []byte
		_, tag, data = next(data)
		if len(tag) == 0 {
			return nil, fmt.Errorf("unexpected eof")
		}
		if tag[1] == '/' {
			if n == 0 {
				return nil, fmt.Errorf("unexpected closing tag")
			}
			n--
			if n == 0 {
				break
			}
		} else if tag[len(tag)-2] == '/' {
			if n == 0 {
				break
			}
		} else {
			n++
		}
	}
	return data, nil
}
<commit_msg>Added support for plist <date> tags<commit_after>// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package plist implements parsing of Apple plist files.
package plist

import (
	"bytes"
	"fmt"
	"reflect"
	"strconv"
	"time"
)

func next(data []byte) (skip, tag, rest []byte) {
	i := bytes.IndexByte(data, '<')
	if i < 0 {
		return data, nil, nil
	}
	var j int
	if i+1 < len(data) && data[i+1] == '?' {
		j = bytes.Index(data[i:], []byte("?>"))
	} else {
		j = bytes.IndexByte(data[i:], '>')
	}
	if j < 0 {
		return data, nil, nil
	}
	j += i + 1
	return data[:i], data[i:j], data[j:]
}

func Unmarshal(data []byte, v interface{}) error {
	_, tag, data := next(data)
	if bytes.HasPrefix(tag, []byte("<?xml")) {
		_, tag, data = next(data)
	}
	if bytes.HasPrefix(tag, []byte("<!DOCTYPE")) {
		_, tag, data = next(data)
	}
	if !bytes.HasPrefix(tag, []byte("<plist")) {
		return fmt.Errorf("not a plist")
	}

	data, err := unmarshalValue(data, reflect.ValueOf(v))
	if err != nil {
		return err
	}
	_, tag, data = next(data)
	if !bytes.Equal(tag, []byte("</plist>")) {
		return fmt.Errorf("junk on end of plist")
	}
	return nil
}

func unmarshalValue(data []byte, v reflect.Value) (rest []byte, err error) {
	_, tag, data := next(data)
	if tag == nil {
		return nil, fmt.Errorf("unexpected end of data")
	}

	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			v.Set(reflect.New(v.Type().Elem()))
		}
		v = v.Elem()
	}

	switch stag := string(tag); stag {
	case "<dict>":
		t := v.Type()
		if v.Kind() != reflect.Struct {
			return nil, fmt.Errorf("cannot unmarshal <dict> into non-struct %s", v.Type())
		}
	Dict:
		for {
			_, tag, data = next(data)
			if len(tag) == 0 {
				return nil, fmt.Errorf("eof inside <dict>")
			}
			if string(tag) == "</dict>" {
				break
			}
			if string(tag) != "<key>" {
				return nil, fmt.Errorf("unexpected tag %s inside <dict>", tag)
			}
			var body []byte
			body, tag, data = next(data)
			if len(tag) == 0 {
				return nil, fmt.Errorf("eof inside <dict>")
			}
			if string(tag) != "</key>" {
				return nil, fmt.Errorf("unexpected tag %s inside <dict>", tag)
			}
			name := string(body)
			var i int
			for i = 0; i < t.NumField(); i++ {
				f := t.Field(i)
				if f.Name == name || f.Tag.Get("plist") == name {
					data, err = unmarshalValue(data, v.Field(i))
					continue Dict
				}
			}
			data, err = skipValue(data)
			if err != nil {
				return nil, err
			}
		}
		return data, nil

	case "<array>":
		t := v.Type()
		if v.Kind() != reflect.Slice {
			return nil, fmt.Errorf("cannot unmarshal <array> into non-slice %s", v.Type())
		}
		for {
			_, tag, rest := next(data)
			if len(tag) == 0 {
				return nil, fmt.Errorf("eof inside <array>")
			}
			if string(tag) == "</array>" {
				data = rest
				break
			}
			elem := reflect.New(t.Elem()).Elem()
			data, err = unmarshalValue(data, elem)
			if err != nil {
				return nil, err
			}
			v.Set(reflect.Append(v, elem))
		}
		return data, nil

	case "<string>":
		if v.Kind() != reflect.String {
			return nil, fmt.Errorf("cannot unmarshal <string> into non-string %s", v.Type())
		}
		body, etag, data := next(data)
		if len(etag) == 0 {
			return nil, fmt.Errorf("eof inside <string>")
		}
		if string(etag) != "</string>" {
			return nil, fmt.Errorf("expected </string> but got %s", etag)
		}
		v.SetString(string(body)) // TODO: unescape
		return data, nil

	case "<integer>":
		if v.Kind() != reflect.Int {
			return nil, fmt.Errorf("cannot unmarshal <integer> into non-int %s", v.Type())
		}
		body, etag, data := next(data)
		if len(etag) == 0 {
			return nil, fmt.Errorf("eof inside <integer>")
		}
		if string(etag) != "</integer>" {
			return nil, fmt.Errorf("expected </integer> but got %s", etag)
		}
		i, err := strconv.Atoi(string(body))
		if err != nil {
			return nil, fmt.Errorf("non-integer in <integer> tag: %s", body)
		}
		v.SetInt(int64(i))
		return data, nil

	case "<true/>", "<false/>":
		if v.Kind() != reflect.Bool {
			return nil, fmt.Errorf("cannot unmarshal %s into non-bool %s", stag, v.Type())
		}
		v.SetBool(stag == "<true/>")
		return data, nil

	case "<date>":
		if v.Type() != reflect.TypeOf(time.Time{}) {
			return nil, fmt.Errorf("cannot unmarshal %s into %s (should be time.Time)", stag, v.Type())
		}
		body, etag, data := next(data)
		if len(etag) == 0 {
			return nil, fmt.Errorf("eof inside <date>")
		}
		if string(etag) != "</date>" {
			return nil, fmt.Errorf("expected </date> but got %s", etag)
		}
		t, err := time.Parse(time.RFC3339, string(body))
		if err != nil {
			return nil, fmt.Errorf("cannot unmarshal %s into %s: %v", stag, v.Type(), err)
		}
		v.Set(reflect.ValueOf(t))
		return data, nil
	}
	return nil, fmt.Errorf("unexpected tag %s", tag)
}

func skipValue(data []byte) (rest []byte, err error) {
	n := 0
	for {
		var tag []byte
		_, tag, data = next(data)
		if len(tag) == 0 {
			return nil, fmt.Errorf("unexpected eof")
		}
		if tag[1] == '/' {
			if n == 0 {
				return nil, fmt.Errorf("unexpected closing tag")
			}
			n--
			if n == 0 {
				break
			}
		} else if tag[len(tag)-2] == '/' {
			if n == 0 {
				break
			}
		} else {
			n++
		}
	}
	return data, nil
}
<|endoftext|>


<commit_before>package casbin

import "testing"

func TestDBLoadPolicy(t *testing.T) {
	e := &Enforcer{}
	e.Init("examples/basic_model.conf", "")

	a := newDbAdapter("mysql", "root:@tcp(127.0.0.1:3306)/")
	a.open()
	a.loadPolicy(e.model)
	printPolicy(e.model)
	a.close()
}

func TestDBSavePolicy(t *testing.T) {
	e := &Enforcer{}
	e.Init("examples/basic_model.conf", "examples/basic_policy.csv")

	a := newDbAdapter("mysql", "root:@tcp(127.0.0.1:3306)/")
	a.open()
	a.savePolicy(e.model)
	a.close()
}
<commit_msg>Improve the DB adapter test.<commit_after>package casbin

import "testing"

func TestDBSavePolicy(t *testing.T) {
	e := &Enforcer{}
	e.Init("examples/rbac_model.conf", "examples/rbac_policy.csv")

	a := newDbAdapter("mysql", "root:@tcp(127.0.0.1:3306)/")
	a.open()
	a.savePolicy(e.model)
	a.close()
}

func TestDBSaveAndLoadPolicy(t *testing.T) {
	e := &Enforcer{}
	e.Init("examples/rbac_model.conf", "examples/rbac_policy.csv")

	a := newDbAdapter("mysql", "root:@tcp(127.0.0.1:3306)/")
	a.open()
	a.savePolicy(e.model)

	clearPolicy(e.model)
	testGetPolicy(t, e, [][]string{})

	a.loadPolicy(e.model)
	testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})

	a.close()
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of getgauge/html-report.

// getgauge/html-report is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// getgauge/html-report is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with getgauge/html-report.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/getgauge/common"
	"github.com/getgauge/html-report/gauge_messages"
	"github.com/getgauge/html-report/listener"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const (
	reportTemplateDir           = "report-template"
	defaultReportsDir           = "reports"
	gaugeReportsDirEnvName      = "gauge_reports_dir" // directory where reports are generated by plugins
	overwriteReportsEnvProperty = "overwrite_reports"
	resultJsFile                = "result.js"
	htmlReport                  = "html-report"
	SETUP_ACTION                = "setup"
	EXECUTION_ACTION            = "execution"
	GAUGE_HOST                  = "localhost"
	GAUGE_PORT_ENV              = "plugin_connection_port"
	PLUGIN_ACTION_ENV           = "html-report_action"
	timeFormat                  = "2006-01-02 15.04.05"
)

var projectRoot string
var pluginDir string

type nameGenerator interface {
	randomName() string
}

type timeStampedNameGenerator struct {
}

func (T timeStampedNameGenerator) randomName() string {
	return time.Now().Format(timeFormat)
}

func findPluginAndProjectRoot() {
	projectRoot = os.Getenv(common.GaugeProjectRootEnv)
	if projectRoot == "" {
		fmt.Printf("Environment variable '%s' is not set. \n", common.GaugeProjectRootEnv)
		os.Exit(1)
	}

	var err error
	pluginDir, err = os.Getwd()
	if err != nil {
		fmt.Printf("Error finding current working directory: %s \n", err)
		os.Exit(1)
	}
}

func createExecutionReport() {
	os.Chdir(projectRoot)
	listener, err := listener.NewGaugeListener(GAUGE_HOST, os.Getenv(GAUGE_PORT_ENV))
	if err != nil {
		fmt.Println("Could not create the gauge listener")
		os.Exit(1)
	}
	listener.OnSuiteResult(createReport)
	listener.Start()
}

func addDefaultPropertiesToProject() {
	defaultPropertiesFile := getDefaultPropertiesFile()

	reportsDirProperty := &(common.Property{
		Comment:      "The path to the gauge reports directory. Should be either relative to the project directory or an absolute path",
		Name:         gaugeReportsDirEnvName,
		DefaultValue: defaultReportsDir})

	overwriteReportProperty := &(common.Property{
		Comment:      "Set as false if gauge reports should not be overwritten on each execution. A new time-stamped directory will be created on each execution.",
		Name:         overwriteReportsEnvProperty,
		DefaultValue: "true"})

	if !common.FileExists(defaultPropertiesFile) {
		fmt.Printf("Failed to setup html report plugin in project. Default properties file does not exist at %s. \n", defaultPropertiesFile)
		return
	}
	if err := common.AppendProperties(defaultPropertiesFile, reportsDirProperty, overwriteReportProperty); err != nil {
		fmt.Printf("Failed to setup html report plugin in project: %s \n", err)
		return
	}
	fmt.Println("Succesfully added configurations for html-report to env/default/default.properties")
}

func getDefaultPropertiesFile() string {
	return filepath.Join(projectRoot, "env", "default", "default.properties")
}

func createReport(suiteResult *gauge_messages.SuiteExecutionResult) {
	jsContents := generateJsFileContents(suiteResult)
	reportDir, err := createHtmlReport(createReportsDirectory(), jsContents, getNameGen())
	if err != nil {
		fmt.Printf("Report generation failed: %s \n", err)
		os.Exit(1)
	} else {
		fmt.Printf("Sucessfully generated Html-report to => %s\n", reportDir)
	}

}

func getNameGen() nameGenerator {
	var nameGen nameGenerator
	if shouldOverwriteReports() {
		nameGen = nil
	} else {
		nameGen = timeStampedNameGenerator{}
	}
	return nameGen
}

func createHtmlReport(reportsDir string, jsContents []byte, nameGen nameGenerator) (string, error) {
	var currentReportDir string
	if nameGen != nil {
		currentReportDir = filepath.Join(reportsDir, htmlReport, nameGen.randomName())
	} else {
		currentReportDir = filepath.Join(reportsDir, htmlReport)
	}
	createDirectory(currentReportDir)
	err := copyReportTemplateFiles(currentReportDir)
	if err != nil {
		return "", errors.New(fmt.Sprintf("Error copying template directory :%s\n", err))
	}
	return currentReportDir, writeResultJsFile(currentReportDir, jsContents)
}

func createReportsDirectory() string {
	reportsDir, err := filepath.Abs(os.Getenv(gaugeReportsDirEnvName))
	if reportsDir == "" || err != nil {
		reportsDir = defaultReportsDir
	}
	createDirectory(reportsDir)
	return reportsDir
}

func copyReportTemplateFiles(reportDir string) error {
	reportTemplateDir := filepath.Join(pluginDir, reportTemplateDir)
	_, err := common.MirrorDir(reportTemplateDir, reportDir)
	return err
}

func writeResultJsFile(reportDir string, jsContents []byte) error {
	resultJsPath := filepath.Join(reportDir, "js", resultJsFile)
	err := ioutil.WriteFile(resultJsPath, jsContents, common.NewFilePermissions)
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to copy file: %s %s\n", resultJsFile, err))
	}
	return nil
}

func shouldOverwriteReports() bool {
	envValue := os.Getenv(overwriteReportsEnvProperty)
	if strings.ToLower(envValue) == "true" {
		return true
	}
	return false
}

func generateJsFileContents(suiteResult *gauge_messages.SuiteExecutionResult) []byte {
	var buffer bytes.Buffer
	executionResultJson := marshal(suiteResult)
	itemsTypeJson := marshal(convertKeysToString(gauge_messages.ProtoItem_ItemType_name))
	parameterTypeJson := marshal(convertKeysToString(gauge_messages.Parameter_ParameterType_name))
	fragmentTypeJson := marshal(convertKeysToString(gauge_messages.Fragment_FragmentType_name))

	buffer.WriteString("var gaugeExecutionResult = ")
	buffer.Write(executionResultJson)
	buffer.WriteString(";")
	buffer.WriteString("\n var itemTypesMap = ")
	buffer.Write(itemsTypeJson)
	buffer.WriteString(";")
	buffer.WriteString("\n var parameterTypesMap = ")
	buffer.Write(parameterTypeJson)
	buffer.WriteString(";")
	buffer.WriteString("\n var fragmentTypesMap = ")
	buffer.Write(fragmentTypeJson)
	buffer.WriteString(";")

	return buffer.Bytes()
}

func convertKeysToString(intKeyMap map[int32]string) map[string]string {
	stringKeyMap := make(map[string]string, 0)
	for key, val := range intKeyMap {
		stringKeyMap[fmt.Sprintf("%d", key)] = val
	}
	return stringKeyMap
}

func marshal(item interface{}) []byte {
	marshalledResult, err := json.Marshal(item)
	if err != nil {
		fmt.Printf("Failed to convert to json :%s\n", err)
		os.Exit(1)
	}
	return marshalledResult
}

func createDirectory(dir string) {
	if common.DirExists(dir) {
		return
	}
	if err := os.MkdirAll(dir, common.NewDirectoryPermissions); err != nil {
		fmt.Printf("Failed to create directory %s: %s\n", defaultReportsDir, err)
		os.Exit(1)
	}
}
<commit_msg>fixing typo in message<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of getgauge/html-report.

// getgauge/html-report is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// getgauge/html-report is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with getgauge/html-report.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/getgauge/common"
	"github.com/getgauge/html-report/gauge_messages"
	"github.com/getgauge/html-report/listener"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const (
	reportTemplateDir           = "report-template"
	defaultReportsDir           = "reports"
	gaugeReportsDirEnvName      = "gauge_reports_dir" // directory where reports are generated by plugins
	overwriteReportsEnvProperty = "overwrite_reports"
	resultJsFile                = "result.js"
	htmlReport                  = "html-report"
	SETUP_ACTION                = "setup"
	EXECUTION_ACTION            = "execution"
	GAUGE_HOST                  = "localhost"
	GAUGE_PORT_ENV              = "plugin_connection_port"
	PLUGIN_ACTION_ENV           = "html-report_action"
	timeFormat                  = "2006-01-02 15.04.05"
)

var projectRoot string
var pluginDir string

type nameGenerator interface {
	randomName() string
}

type timeStampedNameGenerator struct {
}

func (T timeStampedNameGenerator) randomName() string {
	return time.Now().Format(timeFormat)
}

func findPluginAndProjectRoot() {
	projectRoot = os.Getenv(common.GaugeProjectRootEnv)
	if projectRoot == "" {
		fmt.Printf("Environment variable '%s' is not set. \n", common.GaugeProjectRootEnv)
		os.Exit(1)
	}

	var err error
	pluginDir, err = os.Getwd()
	if err != nil {
		fmt.Printf("Error finding current working directory: %s \n", err)
		os.Exit(1)
	}
}

func createExecutionReport() {
	os.Chdir(projectRoot)
	listener, err := listener.NewGaugeListener(GAUGE_HOST, os.Getenv(GAUGE_PORT_ENV))
	if err != nil {
		fmt.Println("Could not create the gauge listener")
		os.Exit(1)
	}
	listener.OnSuiteResult(createReport)
	listener.Start()
}

func addDefaultPropertiesToProject() {
	defaultPropertiesFile := getDefaultPropertiesFile()

	reportsDirProperty := &(common.Property{
		Comment:      "The path to the gauge reports directory. Should be either relative to the project directory or an absolute path",
		Name:         gaugeReportsDirEnvName,
		DefaultValue: defaultReportsDir})

	overwriteReportProperty := &(common.Property{
		Comment:      "Set as false if gauge reports should not be overwritten on each execution. A new time-stamped directory will be created on each execution.",
		Name:         overwriteReportsEnvProperty,
		DefaultValue: "true"})

	if !common.FileExists(defaultPropertiesFile) {
		fmt.Printf("Failed to setup html report plugin in project. Default properties file does not exist at %s. \n", defaultPropertiesFile)
		return
	}
	if err := common.AppendProperties(defaultPropertiesFile, reportsDirProperty, overwriteReportProperty); err != nil {
		fmt.Printf("Failed to setup html report plugin in project: %s \n", err)
		return
	}
	fmt.Println("Succesfully added configurations for html-report to env/default/default.properties")
}

func getDefaultPropertiesFile() string {
	return filepath.Join(projectRoot, "env", "default", "default.properties")
}

func createReport(suiteResult *gauge_messages.SuiteExecutionResult) {
	jsContents := generateJsFileContents(suiteResult)
	reportDir, err := createHtmlReport(createReportsDirectory(), jsContents, getNameGen())
	if err != nil {
		fmt.Printf("Report generation failed: %s \n", err)
		os.Exit(1)
	} else {
		fmt.Printf("Successfully generated html-report to => %s\n", reportDir)
	}

}

func getNameGen() nameGenerator {
	var nameGen nameGenerator
	if shouldOverwriteReports() {
		nameGen = nil
	} else {
		nameGen = timeStampedNameGenerator{}
	}
	return nameGen
}

func createHtmlReport(reportsDir string, jsContents []byte, nameGen nameGenerator) (string, error) {
	var currentReportDir string
	if nameGen != nil {
		currentReportDir = filepath.Join(reportsDir, htmlReport, nameGen.randomName())
	} else {
		currentReportDir = filepath.Join(reportsDir, htmlReport)
	}
	createDirectory(currentReportDir)
	err := copyReportTemplateFiles(currentReportDir)
	if err != nil {
		return "", errors.New(fmt.Sprintf("Error copying template directory :%s\n", err))
	}
	return currentReportDir, writeResultJsFile(currentReportDir, jsContents)
}

func createReportsDirectory() string {
	reportsDir, err := filepath.Abs(os.Getenv(gaugeReportsDirEnvName))
	if reportsDir == "" || err != nil {
		reportsDir = defaultReportsDir
	}
	createDirectory(reportsDir)
	return reportsDir
}

func copyReportTemplateFiles(reportDir string) error {
	reportTemplateDir := filepath.Join(pluginDir, reportTemplateDir)
	_, err := common.MirrorDir(reportTemplateDir, reportDir)
	return err
}

func writeResultJsFile(reportDir string, jsContents []byte) error {
	resultJsPath := filepath.Join(reportDir, "js", resultJsFile)
	err := ioutil.WriteFile(resultJsPath, jsContents, common.NewFilePermissions)
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to copy file: %s %s\n", resultJsFile, err))
	}
	return nil
}

func shouldOverwriteReports() bool {
	envValue := os.Getenv(overwriteReportsEnvProperty)
	if strings.ToLower(envValue) == "true" {
		return true
	}
	return false
}

func generateJsFileContents(suiteResult *gauge_messages.SuiteExecutionResult) []byte {
	var buffer bytes.Buffer
	executionResultJson := marshal(suiteResult)
	itemsTypeJson := marshal(convertKeysToString(gauge_messages.ProtoItem_ItemType_name))
	parameterTypeJson := marshal(convertKeysToString(gauge_messages.Parameter_ParameterType_name))
	fragmentTypeJson := marshal(convertKeysToString(gauge_messages.Fragment_FragmentType_name))

	buffer.WriteString("var gaugeExecutionResult = ")
	buffer.Write(executionResultJson)
	buffer.WriteString(";")
	buffer.WriteString("\n var itemTypesMap = ")
	buffer.Write(itemsTypeJson)
	buffer.WriteString(";")
	buffer.WriteString("\n var parameterTypesMap = ")
	buffer.Write(parameterTypeJson)
	buffer.WriteString(";")
	buffer.WriteString("\n var fragmentTypesMap = ")
	buffer.Write(fragmentTypeJson)
	buffer.WriteString(";")

	return buffer.Bytes()
}

func convertKeysToString(intKeyMap map[int32]string) map[string]string {
	stringKeyMap := make(map[string]string, 0)
	for key, val := range intKeyMap {
		stringKeyMap[fmt.Sprintf("%d", key)] = val
	}
	return stringKeyMap
}

func marshal(item interface{}) []byte {
	marshalledResult, err := json.Marshal(item)
	if err != nil {
		fmt.Printf("Failed to convert to json :%s\n", err)
		os.Exit(1)
	}
	return marshalledResult
}

func createDirectory(dir string) {
	if common.DirExists(dir) {
		return
	}
	if err := os.MkdirAll(dir, common.NewDirectoryPermissions); err != nil {
		fmt.Printf("Failed to create directory %s: %s\n", defaultReportsDir, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package http

import (
	"net/http"
	"github.com/vulcand/oxy/stream"
	"github.com/davepgreene/turnstile/proxy"
)

func proxy(url string) http.Handler {
	prox := proxy.New(url)

	stream, err := stream.New(prox)
	if err != nil {
		panic(err)
	}

	return stream
}
<commit_msg>Fixed naming issue.<commit_after>package http

import (
	"net/http"
	"github.com/vulcand/oxy/stream"
	prox "github.com/davepgreene/turnstile/proxy"
)

func proxy(url string) http.Handler {
	proxy := prox.New(url)

	stream, err := stream.New(proxy)
	if err != nil {
		panic(err)
	}

	return stream
}
<|endoftext|>


<commit_before>package controllers

import (
	"github.com/astaxie/beego"
	"github.com/lfq7413/tomato/config"
	"github.com/lfq7413/tomato/rest"
)

// PublicController 处理密码修改与邮箱验证请求
type PublicController struct {
	beego.Controller
}

// VerifyEmail 处理验证邮箱请求
// 该接口从验证邮件内部发起请求，见 rest.SendVerificationEmail()
// @router /verify_email [get]
func (p *PublicController) VerifyEmail() {
	token := p.GetString("token")
	username := p.GetString("username")

	if config.TConfig.ServerURL == "" {
		p.missingPublicServerURL()
		return
	}

	if token == "" || username == "" {
		p.invalid()
		return
	}

	ok := rest.VerifyEmail(username, token)
	if ok {
		p.Ctx.Output.SetStatus(302)
		p.Ctx.Output.Header("location", config.TConfig.ServerURL+"app/verify_email_success")
	} else {
		p.invalid()
	}
}

// ChangePassword ...
// @router /choose_password [get]
func (p *PublicController) ChangePassword() {

}

// ResetPassword ...
// @router /request_password_reset [post]
func (p *PublicController) ResetPassword() {

}

// RequestResetPassword 处理重置密码请求
// 该接口从重置密码邮件内部发起请求，见 rest.SendPasswordResetEmail()
// @router /request_password_reset [get]
func (p *PublicController) RequestResetPassword() {
	token := p.GetString("token")
	username := p.GetString("username")

	if config.TConfig.ServerURL == "" {
		p.missingPublicServerURL()
		return
	}

	if token == "" || username == "" {
		p.invalid()
		return
	}

	ok := rest.CheckResetTokenValidity(username, token)
	if ok {
		p.Ctx.Output.SetStatus(302)
		location := config.TConfig.ServerURL + "app/choose_password"
		location += "?token=" + token
		location += "&id=" + config.TConfig.AppID
		location += "&username=" + username
		location += "&app=" + config.TConfig.AppName
		p.Ctx.Output.Header("location", location)
	} else {
		p.invalid()
	}
}

// InvalidLink 无效链接页面
// @router /invalid_link [get]
func (p *PublicController) InvalidLink() {

}

// PasswordResetSuccess 密码重置成功页面
// @router /password_reset_success [get]
func (p *PublicController) PasswordResetSuccess() {

}

// VerifyEmailSuccess 验证邮箱成功页面
// @router /verify_email_success [get]
func (p *PublicController) VerifyEmailSuccess() {

}

func (p *PublicController) invalid() {
	p.Ctx.Output.SetStatus(302)
	p.Ctx.Output.Header("location", config.TConfig.ServerURL+"app/invalid_link")
}

func (p *PublicController) missingPublicServerURL() {
	p.Ctx.Output.SetStatus(404)
	p.Ctx.Output.Body([]byte("Not found."))
}
<commit_msg>完成 ChangePassword<commit_after>package controllers

import (
	"strings"

	"github.com/astaxie/beego"
	"github.com/lfq7413/tomato/config"
	"github.com/lfq7413/tomato/rest"
)

// PublicController 处理密码修改与邮箱验证请求
type PublicController struct {
	beego.Controller
}

// VerifyEmail 处理验证邮箱请求
// 该接口从验证邮件内部发起请求，见 rest.SendVerificationEmail()
// @router /verify_email [get]
func (p *PublicController) VerifyEmail() {
	token := p.GetString("token")
	username := p.GetString("username")

	if config.TConfig.ServerURL == "" {
		p.missingPublicServerURL()
		return
	}

	if token == "" || username == "" {
		p.invalid()
		return
	}

	ok := rest.VerifyEmail(username, token)
	if ok {
		p.Ctx.Output.SetStatus(302)
		p.Ctx.Output.Header("location", config.TConfig.ServerURL+"app/verify_email_success")
	} else {
		p.invalid()
	}
}

// ChangePassword 修改密码页面
// @router /choose_password [get]
func (p *PublicController) ChangePassword() {
	if config.TConfig.ServerURL == "" {
		p.missingPublicServerURL()
		return
	}
	data := strings.Replace(choosePassword, "PARSE_SERVER_URL", config.TConfig.ServerURL, -1)
	p.Ctx.Output.ContentType("text/html")
	p.Ctx.Output.Body([]byte(data))
}

// ResetPassword ...
// @router /request_password_reset [post]
func (p *PublicController) ResetPassword() {

}

// RequestResetPassword 处理重置密码请求
// 该接口从重置密码邮件内部发起请求，见 rest.SendPasswordResetEmail()
// @router /request_password_reset [get]
func (p *PublicController) RequestResetPassword() {
	token := p.GetString("token")
	username := p.GetString("username")

	if config.TConfig.ServerURL == "" {
		p.missingPublicServerURL()
		return
	}

	if token == "" || username == "" {
		p.invalid()
		return
	}

	ok := rest.CheckResetTokenValidity(username, token)
	if ok {
		p.Ctx.Output.SetStatus(302)
		location := config.TConfig.ServerURL + "app/choose_password"
		location += "?token=" + token
		location += "&id=" + config.TConfig.AppID
		location += "&username=" + username
		location += "&app=" + config.TConfig.AppName
		p.Ctx.Output.Header("location", location)
	} else {
		p.invalid()
	}
}

// InvalidLink 无效链接页面
// @router /invalid_link [get]
func (p *PublicController) InvalidLink() {

}

// PasswordResetSuccess 密码重置成功页面
// @router /password_reset_success [get]
func (p *PublicController) PasswordResetSuccess() {

}

// VerifyEmailSuccess 验证邮箱成功页面
// @router /verify_email_success [get]
func (p *PublicController) VerifyEmailSuccess() {

}

func (p *PublicController) invalid() {
	p.Ctx.Output.SetStatus(302)
	p.Ctx.Output.Header("location", config.TConfig.ServerURL+"app/invalid_link")
}

func (p *PublicController) missingPublicServerURL() {
	p.Ctx.Output.SetStatus(404)
	p.Ctx.Output.Body([]byte("Not found."))
}

var choosePassword = `
<!DOCTYPE html>

  <title>Password Reset</title>

Reset Your Password

  We apologize, but resetting your password requires javascript

  <form id='form' action='#' method='POST'>
    New Password for
    <input name="new_password" type="password" />
    <input name='utf-8' type='hidden' value='✓' />
    <input name="username" id="username" type="hidden" />
    <input name="token" id="token" type="hidden" />
    <button>Change Password</button>
  </form>

`
<|endoftext|>


<commit_before>package httpclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
)

type Encoding string

const (
	EncodingJSON = "JSON"
)

type RequestData struct {
	Method          string
	Path            string
	Params          url.Values
	FullURL         string // optional
	Headers         http.Header
	ReqReader       io.Reader
	ReqEncoding     Encoding
	ReqValue        interface{}
	ExpectedStatus  []int
	IgnoreRedirects bool
	RespEncoding    Encoding
	RespValue       interface{}
	RespConsume     bool
}

type InvalidStatusError struct {
	Expected []int
	Got      int
}

func (e InvalidStatusError) Error() string {
	return fmt.Sprintf("Invalid response status! Got %d, expected %d", e.Got, e.Expected)
}

type HTTPClient struct {
	BaseURL   *url.URL
	Headers   http.Header
	Client    *http.Client
	PostHooks map[int]func(*http.Request, *http.Response) error
}

func New() (httpClient *HTTPClient) {
	return &HTTPClient{
		Client:    HttpClient,
		Headers:   make(http.Header),
		PostHooks: make(map[int]func(*http.Request, *http.Response) error),
	}
}

func Insecure() (httpClient *HTTPClient) {
	return &HTTPClient{
		Client:    InsecureHttpClient,
		Headers:   make(http.Header),
		PostHooks: make(map[int]func(*http.Request, *http.Response) error),
	}
}

func (c *HTTPClient) SetPostHook(onStatus int, hook func(*http.Request, *http.Response) error) {
	c.PostHooks[onStatus] = hook
}

func (c *HTTPClient) buildURL(req *RequestData) string {
	if req.FullURL != "" {
		return req.FullURL
	}

	bu := c.BaseURL

	u := url.URL{
		Scheme: bu.Scheme,
		Host:   bu.Host,
		Path:   bu.Path + req.Path,
	}

	if req.Params != nil {
		u.RawQuery = req.Params.Encode()
	}

	return u.String()
}

func (c *HTTPClient) setHeaders(req *RequestData, httpReq *http.Request) {

	switch req.ReqEncoding {
	case EncodingJSON:
		httpReq.Header.Set("Content-Type", "application/json")
	}

	switch req.RespEncoding {
	case EncodingJSON:
		httpReq.Header.Set("Accept", "application/json")
	}

	if c.Headers != nil {
		for key, values := range c.Headers {
			for _, value := range values {
				httpReq.Header.Set(key, value)
			}
		}
	}

	if req.Headers != nil {
		for key, values := range req.Headers {
			for _, value := range values {
				httpReq.Header.Set(key, value)
			}
		}
	}
}

func (c *HTTPClient) checkStatus(req *RequestData, response *http.Response) (err error) {
	if req.ExpectedStatus != nil {
		statusOk := false

		for _, status := range req.ExpectedStatus {
			if response.StatusCode == status {
				statusOk = true
			}
		}

		if !statusOk {
			err = InvalidStatusError{req.ExpectedStatus, response.StatusCode}
			return
		}
	}

	return
}

func (c *HTTPClient) unmarshalResponse(req *RequestData, response *http.Response) (err error) {
	var buf []byte

	switch req.RespEncoding {
	case EncodingJSON:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return
		}

		err = json.Unmarshal(buf, req.RespValue)

		return
	}

	switch req.RespValue.(type) {
	case *[]byte:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return
		}

		respVal := req.RespValue.(*[]byte)
		*respVal = buf

		return
	}

	if req.RespConsume {
		defer response.Body.Close()
		ioutil.ReadAll(response.Body)
	}

	return
}

func (c *HTTPClient) marshalRequest(req *RequestData) (err error) {
	if req.ReqValue != nil && req.ReqEncoding != "" && req.ReqReader == nil {
		var buf []byte
		buf, err = json.Marshal(req.ReqValue)
		if err != nil {
			return
		}
		req.ReqReader = bytes.NewReader(buf)
	}
	return
}

func (c *HTTPClient) runPostHook(req *http.Request, response *http.Response) (err error) {
	hook, ok := c.PostHooks[response.StatusCode]

	if ok {
		err = hook(req, response)
	}

	return
}

func (c *HTTPClient) Request(req *RequestData) (response *http.Response, err error) {
	reqURL := c.buildURL(req)

	err = c.marshalRequest(req)

	if err != nil {
		return
	}

	r, err := http.NewRequest(req.Method, reqURL, req.ReqReader)

	if err != nil {
		return
	}

	c.setHeaders(req, r)

	if req.IgnoreRedirects {
		transport := c.Client.Transport

		if transport == nil {
			transport = http.DefaultTransport
		}

		response, err = transport.RoundTrip(r)
	} else {
		response, err = c.Client.Do(r)
	}

	if err != nil {
		return
	}

	if err = c.runPostHook(r, response); err != nil {
		return
	}

	if err = c.checkStatus(req, response); err != nil {
		return
	}

	if err = c.unmarshalResponse(req, response); err != nil {
		return
	}

	return
}
<commit_msg>close response body if status is invalid<commit_after>package httpclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
)

type Encoding string

const (
	EncodingJSON = "JSON"
)

type RequestData struct {
	Method          string
	Path            string
	Params          url.Values
	FullURL         string // optional
	Headers         http.Header
	ReqReader       io.Reader
	ReqEncoding     Encoding
	ReqValue        interface{}
	ExpectedStatus  []int
	IgnoreRedirects bool
	RespEncoding    Encoding
	RespValue       interface{}
	RespConsume     bool
}

type InvalidStatusError struct {
	Expected []int
	Got      int
}

func (e InvalidStatusError) Error() string {
	return fmt.Sprintf("Invalid response status! Got %d, expected %d", e.Got, e.Expected)
}

type HTTPClient struct {
	BaseURL   *url.URL
	Headers   http.Header
	Client    *http.Client
	PostHooks map[int]func(*http.Request, *http.Response) error
}

func New() (httpClient *HTTPClient) {
	return &HTTPClient{
		Client:    HttpClient,
		Headers:   make(http.Header),
		PostHooks: make(map[int]func(*http.Request, *http.Response) error),
	}
}

func Insecure() (httpClient *HTTPClient) {
	return &HTTPClient{
		Client:    InsecureHttpClient,
		Headers:   make(http.Header),
		PostHooks: make(map[int]func(*http.Request, *http.Response) error),
	}
}

func (c *HTTPClient) SetPostHook(onStatus int, hook func(*http.Request, *http.Response) error) {
	c.PostHooks[onStatus] = hook
}

func (c *HTTPClient) buildURL(req *RequestData) string {
	if req.FullURL != "" {
		return req.FullURL
	}

	bu := c.BaseURL

	u := url.URL{
		Scheme: bu.Scheme,
		Host:   bu.Host,
		Path:   bu.Path + req.Path,
	}

	if req.Params != nil {
		u.RawQuery = req.Params.Encode()
	}

	return u.String()
}

func (c *HTTPClient) setHeaders(req *RequestData, httpReq *http.Request) {

	switch req.ReqEncoding {
	case EncodingJSON:
		httpReq.Header.Set("Content-Type", "application/json")
	}

	switch req.RespEncoding {
	case EncodingJSON:
		httpReq.Header.Set("Accept", "application/json")
	}

	if c.Headers != nil {
		for key, values := range c.Headers {
			for _, value := range values {
				httpReq.Header.Set(key, value)
			}
		}
	}

	if req.Headers != nil {
		for key, values := range req.Headers {
			for _, value := range values {
				httpReq.Header.Set(key, value)
			}
		}
	}
}

func (c *HTTPClient) checkStatus(req *RequestData, response *http.Response) (err error) {
	if req.ExpectedStatus != nil {
		statusOk := false

		for _, status := range req.ExpectedStatus {
			if response.StatusCode == status {
				statusOk = true
			}
		}

		if !statusOk {
			err = InvalidStatusError{req.ExpectedStatus, response.StatusCode}
			return
		}
	}

	return
}

func (c *HTTPClient) unmarshalResponse(req *RequestData, response *http.Response) (err error) {
	var buf []byte

	switch req.RespEncoding {
	case EncodingJSON:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return
		}

		err = json.Unmarshal(buf, req.RespValue)

		return
	}

	switch req.RespValue.(type) {
	case *[]byte:
		defer response.Body.Close()

		if buf, err = ioutil.ReadAll(response.Body); err != nil {
			return
		}

		respVal := req.RespValue.(*[]byte)
		*respVal = buf

		return
	}

	if req.RespConsume {
		defer response.Body.Close()
		ioutil.ReadAll(response.Body)
	}

	return
}

func (c *HTTPClient) marshalRequest(req *RequestData) (err error) {
	if req.ReqValue != nil && req.ReqEncoding != "" && req.ReqReader == nil {
		var buf []byte
		buf, err = json.Marshal(req.ReqValue)
		if err != nil {
			return
		}
		req.ReqReader = bytes.NewReader(buf)
	}
	return
}

func (c *HTTPClient) runPostHook(req *http.Request, response *http.Response) (err error) {
	hook, ok := c.PostHooks[response.StatusCode]

	if ok {
		err = hook(req, response)
	}

	return
}

func (c *HTTPClient) Request(req *RequestData) (response *http.Response, err error) {
	reqURL := c.buildURL(req)

	err = c.marshalRequest(req)

	if err != nil {
		return
	}

	r, err := http.NewRequest(req.Method, reqURL, req.ReqReader)

	if err != nil {
		return
	}

	c.setHeaders(req, r)

	if req.IgnoreRedirects {
		transport := c.Client.Transport

		if transport == nil {
			transport = http.DefaultTransport
		}

		response, err = transport.RoundTrip(r)
	} else {
		response, err = c.Client.Do(r)
	}

	if err != nil {
		return
	}

	if err = c.runPostHook(r, response); err != nil {
		return
	}

	if err = c.checkStatus(req, response); err != nil {
		defer response.Body.Close()
		return
	}

	if err = c.unmarshalResponse(req, response); err != nil {
		return
	}

	return
}
<|endoftext|>


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

package virtcontainers

import (
	"fmt"
)

// HypervisorType describes an hypervisor type.
type HypervisorType string

const (
	// QemuHypervisor is the QEMU hypervisor.
	QemuHypervisor HypervisorType = "qemu"

	// MockHypervisor is a mock hypervisor for testing purposes
	MockHypervisor HypervisorType = "mock"
)

// deviceType describes a virtualized device type.
type deviceType int

const (
	// ImgDev is the image device type.
	imgDev deviceType = iota

	// FsDev is the filesystem device type.
	fsDev

	// NetDev is the network device type.
	netDev

	// SerialDev is the serial device type.
	serialDev

	// BlockDev is the block device type.
	blockDev

	// ConsoleDev is the console device type.
	consoleDev
)

// Set sets an hypervisor type based on the input string.
func (hType *HypervisorType) Set(value string) error {
	switch value {
	case "qemu":
		*hType = QemuHypervisor
		return nil
	case "mock":
		*hType = MockHypervisor
		return nil
	default:
		return fmt.Errorf("Unknown hypervisor type %s", value)
	}
}

// String converts an hypervisor type to a string.
func (hType *HypervisorType) String() string {
	switch *hType {
	case QemuHypervisor:
		return string(QemuHypervisor)
	case MockHypervisor:
		return string(MockHypervisor)
	default:
		return ""
	}
}

// newHypervisor returns an hypervisor from and hypervisor type.
func newHypervisor(hType HypervisorType) (hypervisor, error) {
	switch hType {
	case QemuHypervisor:
		return &qemu{}, nil
	case MockHypervisor:
		return &mockHypervisor{}, nil
	default:
		return nil, fmt.Errorf("Unknown hypervisor type %s", hType)
	}
}

// Param is a key/value representation for hypervisor and kernel parameters.
type Param struct {
	parameter string
	value     string
}

// HypervisorConfig is the hypervisor configuration.
type HypervisorConfig struct {
	// KernelPath is the guest kernel host path.
	KernelPath string

	// ImagePath is the guest image host path.
	ImagePath string

	// HypervisorPath is the hypervisor executable host path.
	HypervisorPath string

	// KernelParams are additional guest kernel parameters.
	KernelParams []Param

	// HypervisorParams are additional hypervisor parameters.
	HypervisorParams []Param
}

func (conf *HypervisorConfig) valid() (bool, error) {
	if conf.KernelPath == "" {
		return false, fmt.Errorf("Missing kernel path")
	}

	if conf.ImagePath == "" {
		return false, fmt.Errorf("Missing image path")
	}

	if conf.HypervisorPath == "" {
		return false, fmt.Errorf("Missing hypervisor path")
	}

	return true, nil
}

func appendParam(params []Param, parameter string, value string) []Param {
	return append(params, Param{parameter, value})
}

func serializeParams(params []Param, delim string) []string {
	var parameters []string

	for _, p := range params {
		if p.parameter == "" && p.value == "" {
			continue
		} else if p.parameter == "" {
			parameters = append(parameters, fmt.Sprintf("%s", p.value))
		} else if p.value == "" {
			parameters = append(parameters, fmt.Sprintf("%s", p.parameter))
		} else if delim == "" {
			parameters = append(parameters, fmt.Sprintf("%s", p.parameter))
			parameters = append(parameters, fmt.Sprintf("%s", p.value))
		} else {
			parameters = append(parameters, fmt.Sprintf("%s%s%s", p.parameter, delim, p.value))
		}
	}

	return parameters
}

// hypervisor is the virtcontainers hypervisor interface.
// The default hypervisor implementation is Qemu.
type hypervisor interface {
	init(config HypervisorConfig) error
	createPod(podConfig PodConfig) error
	startPod(startCh, stopCh chan struct{}) error
	stopPod() error
	addDevice(devInfo interface{}, devType deviceType) error
}
<commit_msg>hypervisor: Add new device type serialPortDev<commit_after>//
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package virtcontainers

import (
	"fmt"
)

// HypervisorType describes an hypervisor type.
type HypervisorType string

const (
	// QemuHypervisor is the QEMU hypervisor.
	QemuHypervisor HypervisorType = "qemu"

	// MockHypervisor is a mock hypervisor for testing purposes
	MockHypervisor HypervisorType = "mock"
)

// deviceType describes a virtualized device type.
type deviceType int

const (
	// ImgDev is the image device type.
	imgDev deviceType = iota

	// FsDev is the filesystem device type.
	fsDev

	// NetDev is the network device type.
	netDev

	// SerialDev is the serial device type.
	serialDev

	// BlockDev is the block device type.
	blockDev

	// ConsoleDev is the console device type.
	consoleDev

	// SerialPortDev is the serial port device type.
	serialPortDev
)

// Set sets an hypervisor type based on the input string.
func (hType *HypervisorType) Set(value string) error {
	switch value {
	case "qemu":
		*hType = QemuHypervisor
		return nil
	case "mock":
		*hType = MockHypervisor
		return nil
	default:
		return fmt.Errorf("Unknown hypervisor type %s", value)
	}
}

// String converts an hypervisor type to a string.
func (hType *HypervisorType) String() string {
	switch *hType {
	case QemuHypervisor:
		return string(QemuHypervisor)
	case MockHypervisor:
		return string(MockHypervisor)
	default:
		return ""
	}
}

// newHypervisor returns an hypervisor from and hypervisor type.
func newHypervisor(hType HypervisorType) (hypervisor, error) {
	switch hType {
	case QemuHypervisor:
		return &qemu{}, nil
	case MockHypervisor:
		return &mockHypervisor{}, nil
	default:
		return nil, fmt.Errorf("Unknown hypervisor type %s", hType)
	}
}

// Param is a key/value representation for hypervisor and kernel parameters.
type Param struct {
	parameter string
	value     string
}

// HypervisorConfig is the hypervisor configuration.
type HypervisorConfig struct {
	// KernelPath is the guest kernel host path.
	KernelPath string

	// ImagePath is the guest image host path.
	ImagePath string

	// HypervisorPath is the hypervisor executable host path.
	HypervisorPath string

	// KernelParams are additional guest kernel parameters.
	KernelParams []Param

	// HypervisorParams are additional hypervisor parameters.
	HypervisorParams []Param
}

func (conf *HypervisorConfig) valid() (bool, error) {
	if conf.KernelPath == "" {
		return false, fmt.Errorf("Missing kernel path")
	}

	if conf.ImagePath == "" {
		return false, fmt.Errorf("Missing image path")
	}

	if conf.HypervisorPath == "" {
		return false, fmt.Errorf("Missing hypervisor path")
	}

	return true, nil
}

func appendParam(params []Param, parameter string, value string) []Param {
	return append(params, Param{parameter, value})
}

func serializeParams(params []Param, delim string) []string {
	var parameters []string

	for _, p := range params {
		if p.parameter == "" && p.value == "" {
			continue
		} else if p.parameter == "" {
			parameters = append(parameters, fmt.Sprintf("%s", p.value))
		} else if p.value == "" {
			parameters = append(parameters, fmt.Sprintf("%s", p.parameter))
		} else if delim == "" {
			parameters = append(parameters, fmt.Sprintf("%s", p.parameter))
			parameters = append(parameters, fmt.Sprintf("%s", p.value))
		} else {
			parameters = append(parameters, fmt.Sprintf("%s%s%s", p.parameter, delim, p.value))
		}
	}

	return parameters
}

// hypervisor is the virtcontainers hypervisor interface.
// The default hypervisor implementation is Qemu.
type hypervisor interface {
	init(config HypervisorConfig) error
	createPod(podConfig PodConfig) error
	startPod(startCh, stopCh chan struct{}) error
	stopPod() error
	addDevice(devInfo interface{}, devType deviceType) error
}
<|endoftext|>


<commit_before>package ultron

import (
	"errors"
	"math/rand"
	"sync"
	"time"
)

const (
	// NoDuration 无等待
	NoDuration time.Duration = time.Duration(0)
	// DefaultMinWait 默认最小等待时间
	DefaultMinWait time.Duration = time.Second * 1
	// DefaultMaxWait 默认最大等待时间
	DefaultMaxWait time.Duration = time.Second * 5
)

type (
	// Query .
	Query interface {
		Name() string
		Fire() (time.Duration, error)
	}

	// // QuerySet 查询事件集合
	// QuerySet interface {
	// 	OnStart()
	// 	Queries() map[Query]int
	// 	MinWait() time.Duration
	// 	MaxWait() time.Duration
	// }

	// TaskSet 任务集
	TaskSet struct {
		queries     map[Query]int
		MinWait     time.Duration
		MaxWait     time.Duration
		totalWeight int
		lock        *sync.RWMutex
	}
)

// NewTaskSet 新建任务集
func NewTaskSet() *TaskSet {
	return &TaskSet{
		queries:     map[Query]int{},
		MinWait:     DefaultMinWait,
		MaxWait:     DefaultMaxWait,
		totalWeight: 0,
		lock:        &sync.RWMutex{},
	}
}

// Add 添加Query以及权重
func (t *TaskSet) Add(q Query, w int) *TaskSet {
	t.lock.Lock()
	defer t.lock.Unlock()

	if w > 0 {
		t.totalWeight += w
	}
	t.queries[q] = w
	return t
}

// Choice 根据权重获取一个Query对象
func (t *TaskSet) Choice() Query {
	t.lock.RLock()
	defer t.lock.RUnlock()

	hint := rand.Intn(t.totalWeight) + 1
	for q, w := range t.queries {
		if w > 0 {
			if hint <= w {
				return q
			}
			hint -= w
		}
	}
	panic(errors.New("what happened?"))
}

// Wait return wait time
func (t *TaskSet) Wait() time.Duration {
	t.lock.RLock()
	defer t.lock.RUnlock()

	delta := NoDuration
	if t.MaxWait == t.MinWait || t.MinWait < t.MaxWait {
	} else {
		delta = time.Duration(rand.Int63n(int64(t.MaxWait-t.MinWait)) + 1)
	}
	return t.MinWait + delta
}
<commit_msg>update<commit_after>package ultron

import (
	"errors"
	"math/rand"
	"sync"
	"time"
)

const (
	// NoDuration 无等待
	NoDuration time.Duration = time.Duration(0)
	// DefaultMinWait 默认最小等待时间
	DefaultMinWait time.Duration = time.Second * 1
	// DefaultMaxWait 默认最大等待时间
	DefaultMaxWait time.Duration = time.Second * 5
	// DefaultConcurrency 默认并发数
	DefaultConcurrency = 100
)

type (
	// Query .
	Query interface {
		Name() string
		Fire() (time.Duration, error)
	}

	// TaskSet 任务集
	TaskSet struct {
		queries     map[Query]int
		totalWeight int
		MinWait     time.Duration
		MaxWait     time.Duration
		Duration    time.Duration
		Concurrency int
		lock        *sync.RWMutex
	}
)

// NewTaskSet 新建任务集
func NewTaskSet() *TaskSet {
	return &TaskSet{
		queries:     map[Query]int{},
		MinWait:     DefaultMinWait,
		MaxWait:     DefaultMaxWait,
		Concurrency: DefaultConcurrency,
		lock:        &sync.RWMutex{},
	}
}

// Add 添加Query以及权重
func (t *TaskSet) Add(q Query, w int) *TaskSet {
	t.lock.Lock()
	defer t.lock.Unlock()

	if w > 0 {
		t.totalWeight += w
	}
	t.queries[q] = w
	return t
}

// Choice 根据权重获取一个Query对象
func (t *TaskSet) Choice() Query {
	t.lock.RLock()
	defer t.lock.RUnlock()

	hint := rand.Intn(t.totalWeight) + 1
	for q, w := range t.queries {
		if w > 0 {
			if hint <= w {
				return q
			}
			hint -= w
		}
	}
	panic(errors.New("what happened?"))
}

// Wait return wait time
func (t *TaskSet) Wait() time.Duration {
	t.lock.RLock()
	defer t.lock.RUnlock()

	delta := NoDuration
	if t.MaxWait == t.MinWait || t.MinWait < t.MaxWait {
	} else {
		delta = time.Duration(rand.Int63n(int64(t.MaxWait-t.MinWait)) + 1)
	}
	return t.MinWait + delta
}

func init() {
	rand.Seed(time.Now().UnixNano())
}
<|endoftext|>


<commit_before>package commands

import (
	"io"
	"strings"

	cmds "github.com/ipfs/go-ipfs/commands"
	files "github.com/ipfs/go-ipfs/core/commands/files"
	ocmd "github.com/ipfs/go-ipfs/core/commands/object"
	unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs"
	logging "gx/ipfs/QmaDNZ4QMdBdku1YZWBysufYyoQt1negQGNav6PLYarbY8/go-log"
)

var log = logging.Logger("core/commands")

const (
	ApiOption = "api"
)

var Root = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Global p2p merkle-dag filesystem.",
		Synopsis: `
ipfs [<flags>] <command> [<arg>] ...
`,
		Subcommands: `
BASIC COMMANDS
  init          Initialize ipfs local configuration
  add <path>    Add a file to ipfs
  cat <ref>     Show ipfs object data
  get <ref>     Download ipfs objects
  ls <ref>      List links from an object
  refs <ref>    List hashes of links from an object

DATA STRUCTURE COMMANDS
  block         Interact with raw blocks in the datastore
  object        Interact with raw dag nodes
  files         Interact with objects as if they were a unix filesystem

ADVANCED COMMANDS
  daemon        Start a long-running daemon process
  mount         Mount an ipfs read-only mountpoint
  resolve       Resolve any type of name
  name          Publish or resolve IPNS names
  dns           Resolve DNS links
  pin           Pin objects to local storage
  repo          Manipulate the IPFS repository

NETWORK COMMANDS
  id            Show info about ipfs peers
  bootstrap     Add or remove bootstrap peers
  swarm         Manage connections to the p2p network
  dht           Query the DHT for values or peers
  ping          Measure the latency of a connection
  diag          Print diagnostics

TOOL COMMANDS
  config        Manage configuration
  version       Show ipfs version information
  update        Download and apply go-ipfs updates
  commands      List all available commands

Use 'ipfs <command> --help' to learn more about each command.

ipfs uses a repository in the local file system. By default, the repo is located
at ~/.ipfs. To change the repo location, set the $IPFS_PATH environment variable:

  export IPFS_PATH=/path/to/ipfsrepo
`,
	},
	Options: []cmds.Option{
		cmds.StringOption("config", "c", "Path to the configuration file to use."),
		cmds.BoolOption("debug", "D", "Operate in debug mode."),
		cmds.BoolOption("help", "Show the full command help text."),
		cmds.BoolOption("h", "Show a short version of the command help text."),
		cmds.BoolOption("local", "L", "Run the command locally, instead of using the daemon."),
		cmds.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"),
	},
}

// commandsDaemonCmd is the "ipfs commands" command for daemon
var CommandsDaemonCmd = CommandsCmd(Root)

var rootSubcommands = map[string]*cmds.Command{
	"add":       AddCmd,
	"block":     BlockCmd,
	"bootstrap": BootstrapCmd,
	"cat":       CatCmd,
	"commands":  CommandsDaemonCmd,
	"config":    ConfigCmd,
	"dht":       DhtCmd,
	"diag":      DiagCmd,
	"dns":       DNSCmd,
	"files":     files.FilesCmd,
	"get":       GetCmd,
	"id":        IDCmd,
	"log":       LogCmd,
	"ls":        LsCmd,
	"mount":     MountCmd,
	"name":      NameCmd,
	"object":    ocmd.ObjectCmd,
	"pin":       PinCmd,
	"ping":      PingCmd,
	"refs":      RefsCmd,
	"repo":      RepoCmd,
	"resolve":   ResolveCmd,
	"stats":     StatsCmd,
	"swarm":     SwarmCmd,
	"tar":       TarCmd,
	"tour":      tourCmd,
	"file":      unixfs.UnixFSCmd,
	"update":    ExternalBinary(),
	"version":   VersionCmd,
	"bitswap":   BitswapCmd,
}

// RootRO is the readonly version of Root
var RootRO = &cmds.Command{}

var CommandsDaemonROCmd = CommandsCmd(RootRO)

var RefsROCmd = &cmds.Command{}

var rootROSubcommands = map[string]*cmds.Command{
	"block": &cmds.Command{
		Subcommands: map[string]*cmds.Command{
			"stat": blockStatCmd,
			"get":  blockGetCmd,
		},
	},
	"cat":      CatCmd,
	"commands": CommandsDaemonROCmd,
	"dns":      DNSCmd,
	"get":      GetCmd,
	"ls":       LsCmd,
	"name": &cmds.Command{
		Subcommands: map[string]*cmds.Command{
			"resolve": IpnsCmd,
		},
	},
	"object": &cmds.Command{
		Subcommands: map[string]*cmds.Command{
			"data":  ocmd.ObjectDataCmd,
			"links": ocmd.ObjectLinksCmd,
			"get":   ocmd.ObjectGetCmd,
			"stat":  ocmd.ObjectStatCmd,
			"patch": ocmd.ObjectPatchCmd,
		},
	},
	"refs":    RefsROCmd,
	"resolve": ResolveCmd,
	"version": VersionCmd,
}

func init() {
	*RootRO = *Root

	// sanitize readonly refs command
	*RefsROCmd = *RefsCmd
	RefsROCmd.Subcommands = map[string]*cmds.Command{}

	Root.Subcommands = rootSubcommands
	RootRO.Subcommands = rootROSubcommands
}

type MessageOutput struct {
	Message string
}

func MessageTextMarshaler(res cmds.Response) (io.Reader, error) {
	return strings.NewReader(res.Output().(*MessageOutput).Message), nil
}
<commit_msg>Also added to Root<commit_after>package commands

import (
	"io"
	"strings"

	cmds "github.com/ipfs/go-ipfs/commands"
	files "github.com/ipfs/go-ipfs/core/commands/files"
	ocmd "github.com/ipfs/go-ipfs/core/commands/object"
	unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs"
	logging "gx/ipfs/QmaDNZ4QMdBdku1YZWBysufYyoQt1negQGNav6PLYarbY8/go-log"
)

var log = logging.Logger("core/commands")

const (
	ApiOption = "api"
)

var Root = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Global p2p merkle-dag filesystem.",
		Synopsis: `
ipfs [<flags>] <command> [<arg>] ...
`,
		Subcommands: `
BASIC COMMANDS
  init          Initialize ipfs local configuration
  add <path>    Add a file to ipfs
  cat <ref>     Show ipfs object data
  get <ref>     Download ipfs objects
  ls <ref>      List links from an object
  refs <ref>    List hashes of links from an object

DATA STRUCTURE COMMANDS
  block         Interact with raw blocks in the datastore
  object        Interact with raw dag nodes
  files         Interact with objects as if they were a unix filesystem

ADVANCED COMMANDS
  daemon        Start a long-running daemon process
  mount         Mount an ipfs read-only mountpoint
  resolve       Resolve any type of name
  name          Publish or resolve IPNS names
  dns           Resolve DNS links
  pin           Pin objects to local storage
  repo          Manipulate the IPFS repository

NETWORK COMMANDS
  id            Show info about ipfs peers
  bootstrap     Add or remove bootstrap peers
  swarm         Manage connections to the p2p network
  dht           Query the DHT for values or peers
  ping          Measure the latency of a connection
  diag          Print diagnostics

TOOL COMMANDS
  config        Manage configuration
  version       Show ipfs version information
  update        Download and apply go-ipfs updates
  commands      List all available commands

Use 'ipfs <command> --help' to learn more about each command.

ipfs uses a repository in the local file system. By default, the repo is located
at ~/.ipfs. To change the repo location, set the $IPFS_PATH environment variable:

  export IPFS_PATH=/path/to/ipfsrepo
`,
	},
	Options: []cmds.Option{
		cmds.StringOption("config", "c", "Path to the configuration file to use."),
		cmds.BoolOption("debug", "D", "Operate in debug mode.").Default(false),
		cmds.BoolOption("help", "Show the full command help text.").Default(false),
		cmds.BoolOption("h", "Show a short version of the command help text.").Default(false),
		cmds.BoolOption("local", "L", "Run the command locally, instead of using the daemon.").Default(false),
		cmds.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"),
	},
}

// commandsDaemonCmd is the "ipfs commands" command for daemon
var CommandsDaemonCmd = CommandsCmd(Root)

var rootSubcommands = map[string]*cmds.Command{
	"add":       AddCmd,
	"block":     BlockCmd,
	"bootstrap": BootstrapCmd,
	"cat":       CatCmd,
	"commands":  CommandsDaemonCmd,
	"config":    ConfigCmd,
	"dht":       DhtCmd,
	"diag":      DiagCmd,
	"dns":       DNSCmd,
	"files":     files.FilesCmd,
	"get":       GetCmd,
	"id":        IDCmd,
	"log":       LogCmd,
	"ls":        LsCmd,
	"mount":     MountCmd,
	"name":      NameCmd,
	"object":    ocmd.ObjectCmd,
	"pin":       PinCmd,
	"ping":      PingCmd,
	"refs":      RefsCmd,
	"repo":      RepoCmd,
	"resolve":   ResolveCmd,
	"stats":     StatsCmd,
	"swarm":     SwarmCmd,
	"tar":       TarCmd,
	"tour":      tourCmd,
	"file":      unixfs.UnixFSCmd,
	"update":    ExternalBinary(),
	"version":   VersionCmd,
	"bitswap":   BitswapCmd,
}

// RootRO is the readonly version of Root
var RootRO = &cmds.Command{}

var CommandsDaemonROCmd = CommandsCmd(RootRO)

var RefsROCmd = &cmds.Command{}

var rootROSubcommands = map[string]*cmds.Command{
	"block": &cmds.Command{
		Subcommands: map[string]*cmds.Command{
			"stat": blockStatCmd,
			"get":  blockGetCmd,
		},
	},
	"cat":      CatCmd,
	"commands": CommandsDaemonROCmd,
	"dns":      DNSCmd,
	"get":      GetCmd,
	"ls":       LsCmd,
	"name": &cmds.Command{
		Subcommands: map[string]*cmds.Command{
			"resolve": IpnsCmd,
		},
	},
	"object": &cmds.Command{
		Subcommands: map[string]*cmds.Command{
			"data":  ocmd.ObjectDataCmd,
			"links": ocmd.ObjectLinksCmd,
			"get":   ocmd.ObjectGetCmd,
			"stat":  ocmd.ObjectStatCmd,
			"patch": ocmd.ObjectPatchCmd,
		},
	},
	"refs":    RefsROCmd,
	"resolve": ResolveCmd,
	"version": VersionCmd,
}

func init() {
	*RootRO = *Root

	// sanitize readonly refs command
	*RefsROCmd = *RefsCmd
	RefsROCmd.Subcommands = map[string]*cmds.Command{}

	Root.Subcommands = rootSubcommands
	RootRO.Subcommands = rootROSubcommands
}

type MessageOutput struct {
	Message string
}

func MessageTextMarshaler(res cmds.Response) (io.Reader, error) {
	return strings.NewReader(res.Output().(*MessageOutput).Message), nil
}
<|endoftext|>


<commit_before>package queue

import (
	"fmt"
	"log"
	"strings"
	"time"

	redis "github.com/adjust/redis-latest-head" // TODO: update
	"github.com/adjust/uniuri"
)

const (
	connectionsKey                   = "rmq::connections"                                         // Set of connection names
	connectionHeartbeatTemplate      = "rmq::connection::{connection}::heartbeat"                 // expires after {connection} died
	connectionQueuesTemplate         = "rmq::connection::{connection}::queues"                    // Set of queues consumers of {connection} are consuming
	connectionQueueConsumersTemplate = "rmq::connection::{connection}::queue::{queue}::consumers" // Set of all consumers from {connection} consuming from {queue}
	connectionQueueUnackedTemplate   = "rmq::connection::{connection}::queue::{queue}::unacked"   // List of deliveries consumers of {connection} are currently consuming

	queuesKey             = "rmq::queues"                   // Set of all open queues
	queueReadyTemplate    = "rmq::queue::{queue}::ready"    // List of deliveries in that {queue} (right is first and oldest, left is last and youngest)
	queueRejectedTemplate = "rmq::queue::{queue}::rejected" // List of rejected deliveries from that {queue}

	phConnection = "{connection}" // connection name
	phQueue      = "{queue}"      // queue name
	phConsumer   = "{consumer}"   // consumer name (consisting of tag and token)
)

// PublishQueue is an interface that can be used to test publishing
type Queue interface {
	Publish(payload string) bool
	StartConsuming(prefetchLimit int, pollDuration time.Duration) bool
	AddConsumer(tag string, consumer Consumer) string
	PurgeReady() bool
	PurgeRejected() bool
	ReturnRejected(count int) int
	ReturnAllRejected() int
	Close() bool
}

type redisQueue struct {
	name             string
	connectionName   string
	queuesKey        string // key to list of queues consumed by this connection
	consumersKey     string // key to set of consumers using this connection
	readyKey         string // key to list of ready deliveries
	rejectedKey      string // key to list of rejected deliveries
	unackedKey       string // key to list of currently consuming deliveries
	redisClient      *redis.Client
	deliveryChan     chan Delivery // nil for publish channels, not nil for consuming channels
	prefetchLimit    int           // max number of prefetched deliveries number of unacked can go up to prefetchLimit + numConsumers
	pollDuration     time.Duration
	consumingStopped bool
}

func newQueue(name, connectionName, queuesKey string, redisClient *redis.Client) *redisQueue {
	consumersKey := strings.Replace(connectionQueueConsumersTemplate, phConnection, connectionName, 1)
	consumersKey = strings.Replace(consumersKey, phQueue, name, 1)

	readyKey := strings.Replace(queueReadyTemplate, phQueue, name, 1)
	rejectedKey := strings.Replace(queueRejectedTemplate, phQueue, name, 1)

	unackedKey := strings.Replace(connectionQueueUnackedTemplate, phConnection, connectionName, 1)
	unackedKey = strings.Replace(unackedKey, phQueue, name, 1)

	queue := &redisQueue{
		name:           name,
		connectionName: connectionName,
		queuesKey:      queuesKey,
		consumersKey:   consumersKey,
		readyKey:       readyKey,
		rejectedKey:    rejectedKey,
		unackedKey:     unackedKey,
		redisClient:    redisClient,
	}
	return queue
}

func (queue *redisQueue) String() string {
	return fmt.Sprintf("[%s conn:%s]", queue.name, queue.connectionName)
}

// Publish adds a delivery with the given payload to the queue
func (queue *redisQueue) Publish(payload string) bool {
	// debug(fmt.Sprintf("publish %s %s", payload, queue)) // COMMENTOUT
	return !redisErrIsNil(queue.redisClient.LPush(queue.readyKey, payload))
}

// PurgeReady removes all ready deliveries from the queue and returns the number of purged deliveries
func (queue *redisQueue) PurgeReady() bool {
	result := queue.redisClient.Del(queue.readyKey)
	if redisErrIsNil(result) {
		return false
	}
	return result.Val() > 0
}

// PurgeRejected removes all rejected deliveries from the queue and returns the number of purged deliveries
func (queue *redisQueue) PurgeRejected() bool {
	result := queue.redisClient.Del(queue.rejectedKey)
	if redisErrIsNil(result) {
		return false
	}
	return result.Val() > 0
}

// Close purges and removes the queue from the list of queues
func (queue *redisQueue) Close() bool {
	queue.PurgeRejected()
	queue.PurgeReady()
	result := queue.redisClient.SRem(queuesKey, queue.name)
	if redisErrIsNil(result) {
		return false
	}
	return result.Val() > 0
}

func (queue *redisQueue) ReadyCount() int {
	result := queue.redisClient.LLen(queue.readyKey)
	if redisErrIsNil(result) {
		return 0
	}
	return int(result.Val())
}

func (queue *redisQueue) UnackedCount() int {
	result := queue.redisClient.LLen(queue.unackedKey)
	if redisErrIsNil(result) {
		return 0
	}
	return int(result.Val())
}

func (queue *redisQueue) RejectedCount() int {
	result := queue.redisClient.LLen(queue.rejectedKey)
	if redisErrIsNil(result) {
		return 0
	}
	return int(result.Val())
}

// ReturnAllUnacked moves all unacked deliveries back to the ready
// queue and deletes the unacked key afterwards, returns number of returned
// deliveries
func (queue *redisQueue) ReturnAllUnacked() int {
	result := queue.redisClient.LLen(queue.unackedKey)
	if redisErrIsNil(result) {
		return 0
	}

	unackedCount := int(result.Val())
	for i := 0; i < unackedCount; i++ {
		if redisErrIsNil(queue.redisClient.RPopLPush(queue.unackedKey, queue.readyKey)) {
			return i
		}
		// debug(fmt.Sprintf("queue returned unacked delivery %s %s", result.Val(), queue.readyKey)) // COMMENTOUT
	}

	return unackedCount
}

// ReturnAllRejected moves all rejected deliveries back to the ready
// list and returns the number of returned deliveries
func (queue *redisQueue) ReturnAllRejected() int {
	result := queue.redisClient.LLen(queue.rejectedKey)
	if redisErrIsNil(result) {
		return 0
	}

	rejectedCount := int(result.Val())
	return queue.ReturnRejected(rejectedCount)
}

// ReturnRejected tries to return count rejected deliveries back to
// the ready list and returns the number of returned deliveries
func (queue *redisQueue) ReturnRejected(count int) int {
	if count == 0 {
		return 0
	}

	for i := 0; i < count; i++ {
		result := queue.redisClient.RPopLPush(queue.rejectedKey, queue.readyKey)
		if redisErrIsNil(result) {
			return i
		}
		// debug(fmt.Sprintf("queue returned rejected delivery %s %s", result.Val(), queue.readyKey)) // COMMENTOUT
	}

	return count
}

// CloseInConnection closes the queue in the associated connection by removing all related keys
func (queue *redisQueue) CloseInConnection() {
	redisErrIsNil(queue.redisClient.Del(queue.unackedKey))
	redisErrIsNil(queue.redisClient.Del(queue.consumersKey))
	redisErrIsNil(queue.redisClient.SRem(queue.queuesKey, queue.name))
}

// StartConsuming starts consuming into a channel of size prefetchLimit
// must be called before consumers can be added!
// pollDuration is the duration the queue sleeps before checking for new deliveries
func (queue *redisQueue) StartConsuming(prefetchLimit int, pollDuration time.Duration) bool {
	if queue.deliveryChan != nil {
		return false
	}

	// add queue to list of queues consumed on this connection
	if redisErrIsNil(queue.redisClient.SAdd(queue.queuesKey, queue.name)) {
		log.Panicf("queue failed to start consuming %s", queue)
	}

	queue.prefetchLimit = prefetchLimit
	queue.pollDuration = pollDuration
	queue.deliveryChan = make(chan Delivery, prefetchLimit)
	log.Printf("queue started consuming %s %d", queue, prefetchLimit)
	go queue.consume()
	return true
}

func (queue *redisQueue) StopConsuming() {
	queue.consumingStopped = true
}

// AddConsumer adds a consumer to the queue and returns its internal name
// panics if StartConsuming wasn't called before!
func (queue *redisQueue) AddConsumer(tag string, consumer Consumer) string {
	if queue.deliveryChan == nil {
		log.Panicf("queue failed to add consumer, call StartConsuming first! %s", queue)
	}

	name := fmt.Sprintf("%s-%s", tag, uniuri.NewLen(6))

	// add consumer to list of consumers of this queue
	if redisErrIsNil(queue.redisClient.SAdd(queue.consumersKey, name)) {
		log.Panicf("queue failed to add consumer %s %s", queue, consumer)
	}

	go queue.addConsumer(consumer)
	log.Printf("queue added consumer %s %s", queue, name)
	return name
}

func (queue *redisQueue) GetConsumers() []string {
	result := queue.redisClient.SMembers(queue.consumersKey)
	if redisErrIsNil(result) {
		return []string{}
	}
	return result.Val()
}

func (queue *redisQueue) RemoveConsumer(name string) bool {
	result := queue.redisClient.SRem(queue.consumersKey, name)
	if redisErrIsNil(result) {
		return false
	}
	return result.Val() > 0
}

func (queue *redisQueue) RemoveAllConsumers() int {
	result := queue.redisClient.Del(queue.consumersKey)
	if redisErrIsNil(result) {
		return 0
	}
	return int(result.Val())
}

func (queue *redisQueue) consume() {
	for {
		batchSize := queue.batchSize()
		wantMore := queue.consumeBatch(batchSize)

		if !wantMore {
			time.Sleep(queue.pollDuration)
		}

		if queue.consumingStopped {
			log.Printf("queue stopped consuming %s", queue)
			return
		}
	}
}

func (queue *redisQueue) batchSize() int {
	prefetchCount := len(queue.deliveryChan)
	prefetchLimit := queue.prefetchLimit - prefetchCount
	// TODO: ignore ready count here and just return prefetchLimit?
	if readyCount := queue.ReadyCount(); readyCount < prefetchLimit {
		return readyCount
	}
	return prefetchLimit
}

// consumeBatch tries to read batchSize deliveries, returns true if any and all were consumed
func (queue *redisQueue) consumeBatch(batchSize int) bool {
	if batchSize == 0 {
		return false
	}

	for i := 0; i < batchSize; i++ {
		result := queue.redisClient.RPopLPush(queue.readyKey, queue.unackedKey)
		if redisErrIsNil(result) {
			// debug(fmt.Sprintf("queue consumed last batch %s %d", queue, i)) // COMMENTOUT
			return false
		}

		// debug(fmt.Sprintf("consume %d/%d %s %s", i, batchSize, result.Val(), queue)) // COMMENTOUT
		queue.deliveryChan <- newDelivery(result.Val(), queue.unackedKey, queue.rejectedKey, queue.redisClient)
	}

	// debug(fmt.Sprintf("queue consumed batch %s %d", queue, batchSize)) // COMMENTOUT
	return true
}

func (queue *redisQueue) addConsumer(consumer Consumer) {
	for delivery := range queue.deliveryChan {
		// debug(fmt.Sprintf("consumer consume %s %s", delivery, consumer)) // COMMENTOUT
		consumer.Consume(delivery)
	}
}

// redisErrIsNil returns false if there is no error, true if the result error is nil and panics if there's another error
func redisErrIsNil(result redis.Cmder) bool {
	switch result.Err() {
	case nil:
		return false
	case redis.Nil:
		return true
	default:
		log.Panicf("redis error is not nil %s", result.Err())
		return false
	}
}

func debug(message string) {
	// log.Printf("queue.debug: %s", message) // COMMENTOUT
}
<commit_msg>queue.Queue.StartConsuming log pollDuration<commit_after>package queue

import (
	"fmt"
	"log"
	"strings"
	"time"

	redis "github.com/adjust/redis-latest-head" // TODO: update
	"github.com/adjust/uniuri"
)

const (
	connectionsKey                   = "rmq::connections"                                         // Set of connection names
	connectionHeartbeatTemplate      = "rmq::connection::{connection}::heartbeat"                 // expires after {connection} died
	connectionQueuesTemplate         = "rmq::connection::{connection}::queues"                    // Set of queues consumers of {connection} are consuming
	connectionQueueConsumersTemplate = "rmq::connection::{connection}::queue::{queue}::consumers" // Set of all consumers from {connection} consuming from {queue}
	connectionQueueUnackedTemplate   = "rmq::connection::{connection}::queue::{queue}::unacked"   // List of deliveries consumers of {connection} are currently consuming

	queuesKey             = "rmq::queues"                   // Set of all open queues
	queueReadyTemplate    = "rmq::queue::{queue}::ready"    // List of deliveries in that {queue} (right is first and oldest, left is last and youngest)
	queueRejectedTemplate = "rmq::queue::{queue}::rejected" // List of rejected deliveries from that {queue}

	phConnection = "{connection}" // connection name
	phQueue      = "{queue}"      // queue name
	phConsumer   = "{consumer}"   // consumer name (consisting of tag and token)
)

// PublishQueue is an interface that can be used to test publishing
type Queue interface {
	Publish(payload string) bool
	StartConsuming(prefetchLimit int, pollDuration time.Duration) bool
	AddConsumer(tag string, consumer Consumer) string
	PurgeReady() bool
	PurgeRejected() bool
	ReturnRejected(count int) int
	ReturnAllRejected() int
	Close() bool
}

type redisQueue struct {
	name             string
	connectionName   string
	queuesKey        string // key to list of queues consumed by this connection
	consumersKey     string // key to set of consumers using this connection
	readyKey         string // key to list of ready deliveries
	rejectedKey      string // key to list of rejected deliveries
	unackedKey       string // key to list of currently consuming deliveries
	redisClient      *redis.Client
	deliveryChan     chan Delivery // nil for publish channels, not nil for consuming channels
	prefetchLimit    int           // max number of prefetched deliveries number of unacked can go up to prefetchLimit + numConsumers
	pollDuration     time.Duration
	consumingStopped bool
}

func newQueue(name, connectionName, queuesKey string, redisClient *redis.Client) *redisQueue {
	consumersKey := strings.Replace(connectionQueueConsumersTemplate, phConnection, connectionName, 1)
	consumersKey = strings.Replace(consumersKey, phQueue, name, 1)

	readyKey := strings.Replace(queueReadyTemplate, phQueue, name, 1)
	rejectedKey := strings.Replace(queueRejectedTemplate, phQueue, name, 1)

	unackedKey := strings.Replace(connectionQueueUnackedTemplate, phConnection, connectionName, 1)
	unackedKey = strings.Replace(unackedKey, phQueue, name, 1)

	queue := &redisQueue{
		name:           name,
		connectionName: connectionName,
		queuesKey:      queuesKey,
		consumersKey:   consumersKey,
		readyKey:       readyKey,
		rejectedKey:    rejectedKey,
		unackedKey:     unackedKey,
		redisClient:    redisClient,
	}
	return queue
}

func (queue *redisQueue) String() string {
	return fmt.Sprintf("[%s conn:%s]", queue.name, queue.connectionName)
}

// Publish adds a delivery with the given payload to the queue
func (queue *redisQueue) Publish(payload string) bool {
	// debug(fmt.Sprintf("publish %s %s", payload, queue)) // COMMENTOUT
	return !redisErrIsNil(queue.redisClient.LPush(queue.readyKey, payload))
}

// PurgeReady removes all ready deliveries from the queue and returns the number of purged deliveries
func (queue *redisQueue) PurgeReady() bool {
	result := queue.redisClient.Del(queue.readyKey)
	if redisErrIsNil(result) {
		return false
	}
	return result.Val() > 0
}

// PurgeRejected removes all rejected deliveries from the queue and returns the number of purged deliveries
func (queue *redisQueue) PurgeRejected() bool {
	result := queue.redisClient.Del(queue.rejectedKey)
	if redisErrIsNil(result) {
		return false
	}
	return result.Val() > 0
}

// Close purges and removes the queue from the list of queues
func (queue *redisQueue) Close() bool {
	queue.PurgeRejected()
	queue.PurgeReady()
	result := queue.redisClient.SRem(queuesKey, queue.name)
	if redisErrIsNil(result) {
		return false
	}
	return result.Val() > 0
}

func (queue *redisQueue) ReadyCount() int {
	result := queue.redisClient.LLen(queue.readyKey)
	if redisErrIsNil(result) {
		return 0
	}
	return int(result.Val())
}

func (queue *redisQueue) UnackedCount() int {
	result := queue.redisClient.LLen(queue.unackedKey)
	if redisErrIsNil(result) {
		return 0
	}
	return int(result.Val())
}

func (queue *redisQueue) RejectedCount() int {
	result := queue.redisClient.LLen(queue.rejectedKey)
	if redisErrIsNil(result) {
		return 0
	}
	return int(result.Val())
}

// ReturnAllUnacked moves all unacked deliveries back to the ready
// queue and deletes the unacked key afterwards, returns number of returned
// deliveries
func (queue *redisQueue) ReturnAllUnacked() int {
	result := queue.redisClient.LLen(queue.unackedKey)
	if redisErrIsNil(result) {
		return 0
	}

	unackedCount := int(result.Val())
	for i := 0; i < unackedCount; i++ {
		if redisErrIsNil(queue.redisClient.RPopLPush(queue.unackedKey, queue.readyKey)) {
			return i
		}
		// debug(fmt.Sprintf("queue returned unacked delivery %s %s", result.Val(), queue.readyKey)) // COMMENTOUT
	}

	return unackedCount
}

// ReturnAllRejected moves all rejected deliveries back to the ready
// list and returns the number of returned deliveries
func (queue *redisQueue) ReturnAllRejected() int {
	result := queue.redisClient.LLen(queue.rejectedKey)
	if redisErrIsNil(result) {
		return 0
	}

	rejectedCount := int(result.Val())
	return queue.ReturnRejected(rejectedCount)
}

// ReturnRejected tries to return count rejected deliveries back to
// the ready list and returns the number of returned deliveries
func (queue *redisQueue) ReturnRejected(count int) int {
	if count == 0 {
		return 0
	}

	for i := 0; i < count; i++ {
		result := queue.redisClient.RPopLPush(queue.rejectedKey, queue.readyKey)
		if redisErrIsNil(result) {
			return i
		}
		// debug(fmt.Sprintf("queue returned rejected delivery %s %s", result.Val(), queue.readyKey)) // COMMENTOUT
	}

	return count
}

// CloseInConnection closes the queue in the associated connection by removing all related keys
func (queue *redisQueue) CloseInConnection() {
	redisErrIsNil(queue.redisClient.Del(queue.unackedKey))
	redisErrIsNil(queue.redisClient.Del(queue.consumersKey))
	redisErrIsNil(queue.redisClient.SRem(queue.queuesKey, queue.name))
}

// StartConsuming starts consuming into a channel of size prefetchLimit
// must be called before consumers can be added!
// pollDuration is the duration the queue sleeps before checking for new deliveries
func (queue *redisQueue) StartConsuming(prefetchLimit int, pollDuration time.Duration) bool {
	if queue.deliveryChan != nil {
		return false
	}

	// add queue to list of queues consumed on this connection
	if redisErrIsNil(queue.redisClient.SAdd(queue.queuesKey, queue.name)) {
		log.Panicf("queue failed to start consuming %s", queue)
	}

	queue.prefetchLimit = prefetchLimit
	queue.pollDuration = pollDuration
	queue.deliveryChan = make(chan Delivery, prefetchLimit)
	log.Printf("queue started consuming %s %d %s", queue, prefetchLimit, pollDuration)
	go queue.consume()
	return true
}

func (queue *redisQueue) StopConsuming() {
	queue.consumingStopped = true
}

// AddConsumer adds a consumer to the queue and returns its internal name
// panics if StartConsuming wasn't called before!
func (queue *redisQueue) AddConsumer(tag string, consumer Consumer) string {
	if queue.deliveryChan == nil {
		log.Panicf("queue failed to add consumer, call StartConsuming first! %s", queue)
	}

	name := fmt.Sprintf("%s-%s", tag, uniuri.NewLen(6))

	// add consumer to list of consumers of this queue
	if redisErrIsNil(queue.redisClient.SAdd(queue.consumersKey, name)) {
		log.Panicf("queue failed to add consumer %s %s", queue, consumer)
	}

	go queue.addConsumer(consumer)
	log.Printf("queue added consumer %s %s", queue, name)
	return name
}

func (queue *redisQueue) GetConsumers() []string {
	result := queue.redisClient.SMembers(queue.consumersKey)
	if redisErrIsNil(result) {
		return []string{}
	}
	return result.Val()
}

func (queue *redisQueue) RemoveConsumer(name string) bool {
	result := queue.redisClient.SRem(queue.consumersKey, name)
	if redisErrIsNil(result) {
		return false
	}
	return result.Val() > 0
}

func (queue *redisQueue) RemoveAllConsumers() int {
	result := queue.redisClient.Del(queue.consumersKey)
	if redisErrIsNil(result) {
		return 0
	}
	return int(result.Val())
}

func (queue *redisQueue) consume() {
	for {
		batchSize := queue.batchSize()
		wantMore := queue.consumeBatch(batchSize)

		if !wantMore {
			time.Sleep(queue.pollDuration)
		}

		if queue.consumingStopped {
			log.Printf("queue stopped consuming %s", queue)
			return
		}
	}
}

func (queue *redisQueue) batchSize() int {
	prefetchCount := len(queue.deliveryChan)
	prefetchLimit := queue.prefetchLimit - prefetchCount
	// TODO: ignore ready count here and just return prefetchLimit?
	if readyCount := queue.ReadyCount(); readyCount < prefetchLimit {
		return readyCount
	}
	return prefetchLimit
}

// consumeBatch tries to read batchSize deliveries, returns true if any and all were consumed
func (queue *redisQueue) consumeBatch(batchSize int) bool {
	if batchSize == 0 {
		return false
	}

	for i := 0; i < batchSize; i++ {
		result := queue.redisClient.RPopLPush(queue.readyKey, queue.unackedKey)
		if redisErrIsNil(result) {
			// debug(fmt.Sprintf("queue consumed last batch %s %d", queue, i)) // COMMENTOUT
			return false
		}

		// debug(fmt.Sprintf("consume %d/%d %s %s", i, batchSize, result.Val(), queue)) // COMMENTOUT
		queue.deliveryChan <- newDelivery(result.Val(), queue.unackedKey, queue.rejectedKey, queue.redisClient)
	}

	// debug(fmt.Sprintf("queue consumed batch %s %d", queue, batchSize)) // COMMENTOUT
	return true
}

func (queue *redisQueue) addConsumer(consumer Consumer) {
	for delivery := range queue.deliveryChan {
		// debug(fmt.Sprintf("consumer consume %s %s", delivery, consumer)) // COMMENTOUT
		consumer.Consume(delivery)
	}
}

// redisErrIsNil returns false if there is no error, true if the result error is nil and panics if there's another error
func redisErrIsNil(result redis.Cmder) bool {
	switch result.Err() {
	case nil:
		return false
	case redis.Nil:
		return true
	default:
		log.Panicf("redis error is not nil %s", result.Err())
		return false
	}
}

func debug(message string) {
	// log.Printf("queue.debug: %s", message) // COMMENTOUT
}
<|endoftext|>