<commit_before>package poll

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/venicegeo/pzsvc-exec/dispatcher/cfwrapper"
	"github.com/venicegeo/pzsvc-exec/dispatcher/model"
	"github.com/venicegeo/pzsvc-exec/pzsvc"
)

const defaultTaskDiskMB = 6142
const defaultTaskMemoryMB = 3072

var pzsvcGetS3FileSizeInMegabytes = pzsvc.GetS3FileSizeInMegabytes
var pzsvcRequestKnownJSON = pzsvc.RequestKnownJSON
var pzsvcSendExecResultNoData = pzsvc.SendExecResultNoData

// Loop is an encapsulation of configuration and functionality needed for a job polling loop
type Loop struct {
	PzSession     *pzsvc.Session
	PzConfig      pzsvc.Config
	SvcID         string
	ConfigPath    string
	ClientFactory cfwrapper.Factory
	vcapID        string
	taskLimit     int
	intervalTick  time.Duration

	stopChan         chan bool
	runIterationFunc func(l Loop) error
}

// NewLoop creates a Loop and does starting configuration based on the given parameters
func NewLoop(s *pzsvc.Session, configObj pzsvc.Config, svcID string, configPath string, clientFactory cfwrapper.Factory) (*Loop, error) {
	pzsvc.LogInfo(*s, "Initializing polling loop object")

	appID, err := getVCAPApplicationID()
	if err != nil {
		return nil, err
	}
	pzsvc.LogInfo(*s, "Found application name from VCAP Tree: "+appID)

	// Read the # of simultaneous Tasks that are allowed to be run by the Dispatcher
	taskLimit := 3
	if envTaskLimit := os.Getenv("TASK_LIMIT"); envTaskLimit != "" {
		taskLimit, _ = strconv.Atoi(envTaskLimit)
	}

	return &Loop{
		PzSession:        s,
		PzConfig:         configObj,
		SvcID:            svcID,
		ConfigPath:       configPath,
		ClientFactory:    clientFactory,
		vcapID:           appID,
		taskLimit:        taskLimit,
		intervalTick:     5 * time.Second,
		stopChan:         nil, // initialized when loop starts
		runIterationFunc: runIteration,
	}, nil
}

// Start begins the polling interval loop and returns a channel that feeds
// through any errors encountered in each interval
func (l *Loop) Start() <-chan error {
	errChan := make(chan error)
	l.stopChan = make(chan bool)
	go func() {
		ticker := time.Tick(l.intervalTick)
		for {
			select {
			case <-ticker:
				err := l.runIterationFunc(*l)
				if err != nil {
					errChan <- err
				}
			case <-l.stopChan:
				close(errChan)
				return
			}
		}
	}()
	return errChan
}

// Stop halts the loop's iteration
func (l Loop) Stop() {
	l.stopChan <- true
	close(l.stopChan)
}

func runIteration(l Loop) error {
	pzsvc.LogInfo(*l.PzSession, "Starting polling loop iteration")

	cfSession, err := l.ClientFactory.GetSession()
	if err != nil {
		pzsvc.LogSimpleErr(*l.PzSession, "Error generating valid CF Client", err)
		return err
	}

	numTasks, err := cfSession.CountTasksForApp(l.vcapID)
	if err != nil {
		pzsvc.LogSimpleErr(*l.PzSession, "Error checking running tasks. ", err)
		return err
	}
	if numTasks >= l.taskLimit {
		pzsvc.LogInfo(*l.PzSession, "Too many tasks already running, skipping this iteration cycle")
		return nil
	}

	taskItem, _, err := l.getPzTaskItem()
	if err != nil {
		return err
	}

	jobID := taskItem.Data.SvcData.JobID
	jobData := taskItem.Data.SvcData.Data.DataInputs.Body.Content
	if jobData == "" {
		pzsvc.LogInfo(*l.PzSession, ("No jobs available in task queue (jobID=''); skipping this iteration cycle"))
		return nil
	}
	pzsvc.LogInfo(*l.PzSession, "New Task Grabbed.  JobID: "+jobID)

	jobInput, err := l.parseJobInput(jobData)
	if err != nil {
		return err
	}

	workerCommand, err := l.buildWorkerCommand(jobInput, jobID)
	if err != nil {
		return err
	}

	diskMB, memoryMB := l.calculateDiskAndMemoryLimits(jobInput)

	taskRequest := cfwrapper.TaskRequest{
		Command:          workerCommand,
		Name:             jobID,
		DropletGUID:      l.vcapID,
		DiskInMegabyte:   diskMB,
		MemoryInMegabyte: memoryMB,
	}

	serializedInput, _ := json.Marshal(jobInput)
	pzsvc.LogAudit(*l.PzSession, l.PzSession.UserID, "Creating CF Task for Job "+jobID+" : "+workerCommand, l.PzSession.AppName, string(serializedInput), pzsvc.INFO)

	if err = cfSession.CreateTask(taskRequest); err != nil {
		if cfwrapper.IsMemoryLimitError(err) {
			pzsvc.LogAudit(*l.PzSession, l.PzSession.UserID, "Audit failure", l.PzSession.AppName, "The Memory limit of CF Org has been exceeded. No further jobs can be created.", pzsvc.ERROR)
			return errors.New("CF memory limit hit, will retry job later")
		}
		// General error - fail the job.
		pzsvc.LogAudit(*l.PzSession, l.PzSession.UserID, "Audit failure", l.PzSession.AppName, "Could not Create PCF Task for Job. Job Failed: "+err.Error(), pzsvc.ERROR)
		pzsvcSendExecResultNoData(*l.PzSession, l.PzSession.PzAddr, l.SvcID, jobID, pzsvc.PiazzaStatusFail)
		return err
	}

	return nil
}

func (l Loop) getPzTaskItem() (*model.PzTaskItem, []byte, error) {
	var pzTaskItem model.PzTaskItem
	url := fmt.Sprintf("%s/service/%s/task", l.PzSession.PzAddr, l.SvcID)

	byts, err := pzsvcRequestKnownJSON("POST", "", url, l.PzSession.PzAuth, &pzTaskItem)
	if err != nil {
		err.Log(*l.PzSession, "Dispatcher: error getting new task:"+string(byts))
		return nil, nil, err
	}
	return &pzTaskItem, byts, nil
}

func (l Loop) parseJobInput(jobInputStr string) (*pzsvc.InpStruct, error) {
	var err error
	var jobInputContent pzsvc.InpStruct

	if err = json.Unmarshal([]byte(jobInputStr), &jobInputContent); err != nil {
		pzsvc.LogSimpleErr(*l.PzSession, "Error decoding job input body", err)
		return nil, err
	}

	if jobInputContent.ExtAuth != "" {
		jobInputContent.ExtAuth = "*****"
	}
	if jobInputContent.PzAuth != "" {
		jobInputContent.PzAuth = "*****"
	}

	return &jobInputContent, nil
}

func (l Loop) buildWorkerCommand(jobInput *pzsvc.InpStruct, jobID string) (string, error) {
	workerCommand := fmt.Sprintf("worker --cliExtra '%s' --userID '%s' --config '%s' --serviceID '%s' --jobID '%s'",
		jobInput.Command, jobInput.UserID, l.ConfigPath, l.SvcID, jobID)

	if len(jobInput.InExtFiles) != len(jobInput.InExtNames) {
		return "", errors.New("Number of input file names and URLs did not match")
	}

	commandParts := []string{workerCommand}

	for i := range jobInput.InExtNames {
		inputPair := fmt.Sprintf("%s:%s", jobInput.InExtNames[i], jobInput.InExtFiles[i])
		commandParts = append(commandParts, "-i", inputPair)
	}

	for _, outputFile := range jobInput.OutGeoJs { // TODO: non-geojson outputs?
		commandParts = append(commandParts, "-o", outputFile)
	}

	return strings.Join(commandParts, " "), nil
}

func (l Loop) calculateAWSInputFileSizeMB(jobInput *pzsvc.InpStruct) (total int) {
	for _, url := range jobInput.InExtFiles {
		if strings.Contains(url, "amazonaws") {
			fileSize, err := pzsvcGetS3FileSizeInMegabytes(url)
			if err == nil {
				pzsvc.LogInfo(*l.PzSession, fmt.Sprintf("S3 File Size for %s found to be %d", url, fileSize))
				total += fileSize
			} else {
				err.Log(*l.PzSession, "Tried to get File Size from S3 File "+url+" but encountered an error; giving up on calculating input sizes")
				return 0
			}
		} else {
			pzsvc.LogInfo(*l.PzSession, fmt.Sprintf("Input file %s is not AWS; giving up on calculating input sizes", url))
			return 0
		}
	}
	return
}

func (l Loop) calculateDiskAndMemoryLimits(jobInput *pzsvc.InpStruct) (diskMB int, memoryMB int) {
	diskMB = defaultTaskDiskMB
	memoryMB = defaultTaskMemoryMB

	if inputSize := l.calculateAWSInputFileSizeMB(jobInput); inputSize > 0 {
		// Allocate 2G for the filesystem and executables (with some buffer), then add the image sizes
		diskMB = 2048 + (inputSize * 2)
		memoryMB = memoryMB + (inputSize * 5)
		pzsvc.LogInfo(*l.PzSession, fmt.Sprintf("Obtained S3 File Sizes for input files; will use Dynamic Disk Space of %d in Task container and Dynamic Memory Size of %d", diskMB, memoryMB))
	} else {
		pzsvc.LogInfo(*l.PzSession, "Could not get the S3 File Sizes for input files. Will use the default Disk and Memory Space when running Task.")
	}
	return
}
<commit_msg>Increase initial disk size (PCF 2.0)<commit_after>package poll

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/venicegeo/pzsvc-exec/dispatcher/cfwrapper"
	"github.com/venicegeo/pzsvc-exec/dispatcher/model"
	"github.com/venicegeo/pzsvc-exec/pzsvc"
)

const defaultTaskDiskMB = 6142
const defaultTaskMemoryMB = 3072

var pzsvcGetS3FileSizeInMegabytes = pzsvc.GetS3FileSizeInMegabytes
var pzsvcRequestKnownJSON = pzsvc.RequestKnownJSON
var pzsvcSendExecResultNoData = pzsvc.SendExecResultNoData

// Loop is an encapsulation of configuration and functionality needed for a job polling loop
type Loop struct {
	PzSession     *pzsvc.Session
	PzConfig      pzsvc.Config
	SvcID         string
	ConfigPath    string
	ClientFactory cfwrapper.Factory
	vcapID        string
	taskLimit     int
	intervalTick  time.Duration

	stopChan         chan bool
	runIterationFunc func(l Loop) error
}

// NewLoop creates a Loop and does starting configuration based on the given parameters
func NewLoop(s *pzsvc.Session, configObj pzsvc.Config, svcID string, configPath string, clientFactory cfwrapper.Factory) (*Loop, error) {
	pzsvc.LogInfo(*s, "Initializing polling loop object")

	appID, err := getVCAPApplicationID()
	if err != nil {
		return nil, err
	}
	pzsvc.LogInfo(*s, "Found application name from VCAP Tree: "+appID)

	// Read the # of simultaneous Tasks that are allowed to be run by the Dispatcher
	taskLimit := 3
	if envTaskLimit := os.Getenv("TASK_LIMIT"); envTaskLimit != "" {
		taskLimit, _ = strconv.Atoi(envTaskLimit)
	}

	return &Loop{
		PzSession:        s,
		PzConfig:         configObj,
		SvcID:            svcID,
		ConfigPath:       configPath,
		ClientFactory:    clientFactory,
		vcapID:           appID,
		taskLimit:        taskLimit,
		intervalTick:     5 * time.Second,
		stopChan:         nil, // initialized when loop starts
		runIterationFunc: runIteration,
	}, nil
}

// Start begins the polling interval loop and returns a channel that feeds
// through any errors encountered in each interval
func (l *Loop) Start() <-chan error {
	errChan := make(chan error)
	l.stopChan = make(chan bool)
	go func() {
		ticker := time.Tick(l.intervalTick)
		for {
			select {
			case <-ticker:
				err := l.runIterationFunc(*l)
				if err != nil {
					errChan <- err
				}
			case <-l.stopChan:
				close(errChan)
				return
			}
		}
	}()
	return errChan
}

// Stop halts the loop's iteration
func (l Loop) Stop() {
	l.stopChan <- true
	close(l.stopChan)
}

func runIteration(l Loop) error {
	pzsvc.LogInfo(*l.PzSession, "Starting polling loop iteration")

	cfSession, err := l.ClientFactory.GetSession()
	if err != nil {
		pzsvc.LogSimpleErr(*l.PzSession, "Error generating valid CF Client", err)
		return err
	}

	numTasks, err := cfSession.CountTasksForApp(l.vcapID)
	if err != nil {
		pzsvc.LogSimpleErr(*l.PzSession, "Error checking running tasks. ", err)
		return err
	}
	if numTasks >= l.taskLimit {
		pzsvc.LogInfo(*l.PzSession, "Too many tasks already running, skipping this iteration cycle")
		return nil
	}

	taskItem, _, err := l.getPzTaskItem()
	if err != nil {
		return err
	}

	jobID := taskItem.Data.SvcData.JobID
	jobData := taskItem.Data.SvcData.Data.DataInputs.Body.Content
	if jobData == "" {
		pzsvc.LogInfo(*l.PzSession, ("No jobs available in task queue (jobID=''); skipping this iteration cycle"))
		return nil
	}
	pzsvc.LogInfo(*l.PzSession, "New Task Grabbed.  JobID: "+jobID)

	jobInput, err := l.parseJobInput(jobData)
	if err != nil {
		return err
	}

	workerCommand, err := l.buildWorkerCommand(jobInput, jobID)
	if err != nil {
		return err
	}

	diskMB, memoryMB := l.calculateDiskAndMemoryLimits(jobInput)

	taskRequest := cfwrapper.TaskRequest{
		Command:          workerCommand,
		Name:             jobID,
		DropletGUID:      l.vcapID,
		DiskInMegabyte:   diskMB,
		MemoryInMegabyte: memoryMB,
	}

	serializedInput, _ := json.Marshal(jobInput)
	pzsvc.LogAudit(*l.PzSession, l.PzSession.UserID, "Creating CF Task for Job "+jobID+" : "+workerCommand, l.PzSession.AppName, string(serializedInput), pzsvc.INFO)

	if err = cfSession.CreateTask(taskRequest); err != nil {
		if cfwrapper.IsMemoryLimitError(err) {
			pzsvc.LogAudit(*l.PzSession, l.PzSession.UserID, "Audit failure", l.PzSession.AppName, "The Memory limit of CF Org has been exceeded. No further jobs can be created.", pzsvc.ERROR)
			return errors.New("CF memory limit hit, will retry job later")
		}
		// General error - fail the job.
		pzsvc.LogAudit(*l.PzSession, l.PzSession.UserID, "Audit failure", l.PzSession.AppName, "Could not Create PCF Task for Job. Job Failed: "+err.Error(), pzsvc.ERROR)
		pzsvcSendExecResultNoData(*l.PzSession, l.PzSession.PzAddr, l.SvcID, jobID, pzsvc.PiazzaStatusFail)
		return err
	}

	return nil
}

func (l Loop) getPzTaskItem() (*model.PzTaskItem, []byte, error) {
	var pzTaskItem model.PzTaskItem
	url := fmt.Sprintf("%s/service/%s/task", l.PzSession.PzAddr, l.SvcID)

	byts, err := pzsvcRequestKnownJSON("POST", "", url, l.PzSession.PzAuth, &pzTaskItem)
	if err != nil {
		err.Log(*l.PzSession, "Dispatcher: error getting new task:"+string(byts))
		return nil, nil, err
	}
	return &pzTaskItem, byts, nil
}

func (l Loop) parseJobInput(jobInputStr string) (*pzsvc.InpStruct, error) {
	var err error
	var jobInputContent pzsvc.InpStruct

	if err = json.Unmarshal([]byte(jobInputStr), &jobInputContent); err != nil {
		pzsvc.LogSimpleErr(*l.PzSession, "Error decoding job input body", err)
		return nil, err
	}

	if jobInputContent.ExtAuth != "" {
		jobInputContent.ExtAuth = "*****"
	}
	if jobInputContent.PzAuth != "" {
		jobInputContent.PzAuth = "*****"
	}

	return &jobInputContent, nil
}

func (l Loop) buildWorkerCommand(jobInput *pzsvc.InpStruct, jobID string) (string, error) {
	workerCommand := fmt.Sprintf("worker --cliExtra '%s' --userID '%s' --config '%s' --serviceID '%s' --jobID '%s'",
		jobInput.Command, jobInput.UserID, l.ConfigPath, l.SvcID, jobID)

	if len(jobInput.InExtFiles) != len(jobInput.InExtNames) {
		return "", errors.New("Number of input file names and URLs did not match")
	}

	commandParts := []string{workerCommand}

	for i := range jobInput.InExtNames {
		inputPair := fmt.Sprintf("%s:%s", jobInput.InExtNames[i], jobInput.InExtFiles[i])
		commandParts = append(commandParts, "-i", inputPair)
	}

	for _, outputFile := range jobInput.OutGeoJs { // TODO: non-geojson outputs?
		commandParts = append(commandParts, "-o", outputFile)
	}

	return strings.Join(commandParts, " "), nil
}

func (l Loop) calculateAWSInputFileSizeMB(jobInput *pzsvc.InpStruct) (total int) {
	for _, url := range jobInput.InExtFiles {
		if strings.Contains(url, "amazonaws") {
			fileSize, err := pzsvcGetS3FileSizeInMegabytes(url)
			if err == nil {
				pzsvc.LogInfo(*l.PzSession, fmt.Sprintf("S3 File Size for %s found to be %d", url, fileSize))
				total += fileSize
			} else {
				err.Log(*l.PzSession, "Tried to get File Size from S3 File "+url+" but encountered an error; giving up on calculating input sizes")
				return 0
			}
		} else {
			pzsvc.LogInfo(*l.PzSession, fmt.Sprintf("Input file %s is not AWS; giving up on calculating input sizes", url))
			return 0
		}
	}
	return
}

func (l Loop) calculateDiskAndMemoryLimits(jobInput *pzsvc.InpStruct) (diskMB int, memoryMB int) {
	diskMB = defaultTaskDiskMB
	memoryMB = defaultTaskMemoryMB

	if inputSize := l.calculateAWSInputFileSizeMB(jobInput); inputSize > 0 {
		// Allocate 2G for the filesystem and executables (with some buffer), then add the image sizes
		memoryMB = memoryMB + (inputSize * 5)
		pzsvc.LogInfo(*l.PzSession, fmt.Sprintf("Obtained S3 File Sizes for input files; will use Dynamic Disk Space of %d in Task container and Dynamic Memory Size of %d", diskMB, memoryMB))
	} else {
		pzsvc.LogInfo(*l.PzSession, "Could not get the S3 File Sizes for input files. Will use the default Disk and Memory Space when running Task.")
	}
	return
}
<|endoftext|>


<commit_before>// +build !js

package webrtc

// Configuration defines a set of parameters to configure how the
// peer-to-peer communication via PeerConnection is established or
// re-established.
type Configuration struct {
	// ICEServers defines a slice describing servers available to be used by
	// ICE, such as STUN and TURN servers.
	ICEServers []ICEServer

	// ICETransportPolicy indicates which candidates the ICEAgent is allowed
	// to use.
	ICETransportPolicy ICETransportPolicy

	// BundlePolicy indicates which media-bundling policy to use when gathering
	// ICE candidates.
	BundlePolicy BundlePolicy

	// RTCPMuxPolicy indicates which rtcp-mux policy to use when gathering ICE
	// candidates.
	RTCPMuxPolicy RTCPMuxPolicy

	// PeerIdentity sets the target peer identity for the PeerConnection.
	// The PeerConnection will not establish a connection to a remote peer
	// unless it can be successfully authenticated with the provided name.
	PeerIdentity string

	// Certificates describes a set of certificates that the PeerConnection
	// uses to authenticate. Valid values for this parameter are created
	// through calls to the GenerateCertificate function. Although any given
	// DTLS connection will use only one certificate, this attribute allows the
	// caller to provide multiple certificates that support different
	// algorithms. The final certificate will be selected based on the DTLS
	// handshake, which establishes which certificates are allowed. The
	// PeerConnection implementation selects which of the certificates is
	// used for a given connection; how certificates are selected is outside
	// the scope of this specification. If this value is absent, then a default
	// set of certificates is generated for each PeerConnection instance.
	Certificates []Certificate

	// ICECandidatePoolSize describes the size of the prefetched ICE pool.
	ICECandidatePoolSize uint8

	// SDPSemantics controls the type of SDP offers accepted by and
	// SDP answers generated by the PeerConnection.
	SDPSemantics SDPSemantics
}
<commit_msg>Document that Configurations may be re-used<commit_after>// +build !js

package webrtc

// A Configuration defines how peer-to-peer communication via PeerConnection
// is established or re-established.
// Configurations may be set up once and reused across multiple connections.
// Configurations are treated as readonly. As long as they are unmodified,
// they are safe for concurrent use.
type Configuration struct {
	// ICEServers defines a slice describing servers available to be used by
	// ICE, such as STUN and TURN servers.
	ICEServers []ICEServer

	// ICETransportPolicy indicates which candidates the ICEAgent is allowed
	// to use.
	ICETransportPolicy ICETransportPolicy

	// BundlePolicy indicates which media-bundling policy to use when gathering
	// ICE candidates.
	BundlePolicy BundlePolicy

	// RTCPMuxPolicy indicates which rtcp-mux policy to use when gathering ICE
	// candidates.
	RTCPMuxPolicy RTCPMuxPolicy

	// PeerIdentity sets the target peer identity for the PeerConnection.
	// The PeerConnection will not establish a connection to a remote peer
	// unless it can be successfully authenticated with the provided name.
	PeerIdentity string

	// Certificates describes a set of certificates that the PeerConnection
	// uses to authenticate. Valid values for this parameter are created
	// through calls to the GenerateCertificate function. Although any given
	// DTLS connection will use only one certificate, this attribute allows the
	// caller to provide multiple certificates that support different
	// algorithms. The final certificate will be selected based on the DTLS
	// handshake, which establishes which certificates are allowed. The
	// PeerConnection implementation selects which of the certificates is
	// used for a given connection; how certificates are selected is outside
	// the scope of this specification. If this value is absent, then a default
	// set of certificates is generated for each PeerConnection instance.
	Certificates []Certificate

	// ICECandidatePoolSize describes the size of the prefetched ICE pool.
	ICECandidatePoolSize uint8

	// SDPSemantics controls the type of SDP offers accepted by and
	// SDP answers generated by the PeerConnection.
	SDPSemantics SDPSemantics
}
<|endoftext|>


<commit_before>package connpass

import (
	"io/ioutil"
	"testing"
)

func TestParse(t *testing.T) {
	file := "sample.json"
	jsonBlob, err := ioutil.ReadFile(file)
	if err != nil {
		t.Fatalf("Failed to open %v. Reason:%s.", file, err)
	}
	result, err := parse(jsonBlob)
	if err != nil {
		t.Fatalf("Failed to parse the JSON. Reason:%s.", err)
	}

	if result.Returned != 10 {
		t.Errorf("Unexpected number of returned events: %v.", result.Returned)
	}
}
<commit_msg>Add test cases.<commit_after>package connpass

import (
	"io/ioutil"
	"testing"
	"net/url"
)

func TestParse(t *testing.T) {
	file := "sample.json"
	jsonBlob, err := ioutil.ReadFile(file)
	if err != nil {
		t.Fatalf("Failed to open %v. Reason:%s.", file, err)
	}
	result, err := parse(jsonBlob)
	if err != nil {
		t.Fatalf("Failed to parse the JSON. Reason:%s.", err)
	}

	if result.Returned != 10 {
		t.Errorf("Unexpected number of returned events: %v.", result.Returned)
	}
}

func TestDefaultQuery(t *testing.T) {
	query := Query{}
	s := query.buildURL()
	u, err := url.Parse(s)
	if err != nil {
		t.Fatalf("Invalid URL: %s.", s, err)
	}
	if u.RawQuery != "" {
		t.Errorf("Query should be empty: %s", s)
	}
}

func TestBasicQuery(t *testing.T) {
	query := Query{Start: 10, Count: 100, Order: CREATE}
	s := query.buildURL()
	u, err := url.Parse(s)
	if err != nil {
		t.Fatalf("Invalid URL: %s.", s, err)
	}
	assertParam(t, u, "start", "10")
	assertParam(t, u, "count", "100")
	assertParam(t, u, "order", "3")
}

func TestAdvancedQuery(t *testing.T) {
	query := Query{}
	query.KeywordAnd = []string{"test", "http"}
	query.KeywordOr = []string{"go", "golang"}
	query.Time = []Time{Time{Year: 2015, Month: 4}, Time{Year: 2015, Month: 3}, Time{Year: 2015, Month: 6, Date: 26}}
	query.Participant = []string{"hoge", "fuga"}
	query.Owner = []string{"foo"}
	query.SeriesId = []int{999}
	query.EventId = []int{42, 88}

	s := query.buildURL()
	u, err := url.Parse(s)
	if err != nil {
		t.Fatalf("Invalid URL: %s.", s, err)
	}
	assertParam(t, u, "keyword", "test", "http")
	assertParam(t, u, "keyword_or", "go", "golang")
	assertParam(t, u, "ym", "201504,201503")
	assertParam(t, u, "ymd", "20150626")
	assertParam(t, u, "nickname", "hoge", "fuga")
	assertParam(t, u, "owner_nickname", "foo")
	assertParam(t, u, "series_id", "999")
	assertParam(t, u, "event_id", "42", "88")
}

func assertParam(t *testing.T, u *url.URL, k string, e ...string) {
	v := u.Query()[k]
	if !equalStrings(v, e) {
		t.Errorf("Value for the Query param %s is invalid. '%s' ≠ '%s'.", u, v, e)
	}
}

func equalStrings(s1 []string, s2 []string) bool {
	if len(s1) != len(s2) {
		return false
	}
	for i := range s1 {
		if s1[i] != s2[i] {
			return false
		}
	}
	return true
}<|endoftext|>


<commit_before>package action

import (
    "github.com/spf13/cobra"
    "net/http"
    "net"
    "context"
    "fmt"
    "io/ioutil"
    "log"
)

var VersionCmd = &cobra.Command{
    Use: "version",
    Short: "show the Jwt version information",
    Long: "show the Jwt version information",
    RunE: func(cmd *cobra.Command, args []string) error {
        client := &http.Client{
            Transport: &http.Transport{
                DialContext:func(ctx context.Context, network, addr string) (net.Conn, error) {
                    return net.Dial("unix", RootCmd.Args.SockFile + "x")
                },
            },
        }

        resp, err := client.Get("http://unix/v1/version")
        if err != nil {
            log.Fatalf(err)
        }
        version, err := ioutil.ReadAll(resp.Body)
        resp.Body.Close()
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s", version)
        return nil
    },
}<commit_msg>debug<commit_after>package action

import (
    "github.com/spf13/cobra"
    "net/http"
    "net"
    "context"
    "fmt"
    "io/ioutil"
    "log"
)

var VersionCmd = &cobra.Command{
    Use: "version",
    Short: "show the Jwt version information",
    Long: "show the Jwt version information",
    RunE: func(cmd *cobra.Command, args []string) error {
        client := &http.Client{
            Transport: &http.Transport{
                DialContext:func(ctx context.Context, network, addr string) (net.Conn, error) {
                    return net.Dial("unix", RootCmd.Args.SockFile + "x")
                },
            },
        }

        resp, err := client.Get("http://unix/v1/version")
        if err != nil {
            log.Fatal(err)
        }
        version, err := ioutil.ReadAll(resp.Body)
        resp.Body.Close()
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s", version)
        return nil
    },
}<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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 topologymanager

import (
	"testing"
)

func TestPolicySingleNumaNodeCanAdmitPodResult(t *testing.T) {
	tcases := []struct {
		name     string
		hint     TopologyHint
		expected bool
	}{
		{
			name:     "Preferred is set to false in topology hints",
			hint:     TopologyHint{nil, false},
			expected: false,
		},
	}

	for _, tc := range tcases {
		numaNodes := []int{0, 1}
		policy := NewSingleNumaNodePolicy(numaNodes)
		result := policy.(*singleNumaNodePolicy).canAdmitPodResult(&tc.hint)

		if result.Admit != tc.expected {
			t.Errorf("Expected Admit field in result to be %t, got %t", tc.expected, result.Admit)
		}

		if tc.expected == false {
			if len(result.Reason) == 0 {
				t.Errorf("Expected Reason field to be not empty")
			}
			if len(result.Message) == 0 {
				t.Errorf("Expected Message field to be not empty")
			}
		}
	}
}

func TestSingleNumaNodePolicyMerge(t *testing.T) {
	numaNodes := []int{0, 1}
	policy := NewSingleNumaNodePolicy(numaNodes)

	tcases := commonPolicyMergeTestCases(numaNodes)
	tcases = append(tcases, policy.(*singleNumaNodePolicy).mergeTestCases(numaNodes)...)

	testPolicyMerge(policy, tcases, t)
}
<commit_msg>Update single-numa-node policy unit tests<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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 topologymanager

import (
	"reflect"
	"testing"
)

func TestPolicySingleNumaNodeCanAdmitPodResult(t *testing.T) {
	tcases := []struct {
		name     string
		hint     TopologyHint
		expected bool
	}{
		{
			name:     "Preferred is set to false in topology hints",
			hint:     TopologyHint{nil, false},
			expected: false,
		},
	}

	for _, tc := range tcases {
		numaNodes := []int{0, 1}
		policy := NewSingleNumaNodePolicy(numaNodes)
		result := policy.(*singleNumaNodePolicy).canAdmitPodResult(&tc.hint)

		if result.Admit != tc.expected {
			t.Errorf("Expected Admit field in result to be %t, got %t", tc.expected, result.Admit)
		}

		if tc.expected == false {
			if len(result.Reason) == 0 {
				t.Errorf("Expected Reason field to be not empty")
			}
			if len(result.Message) == 0 {
				t.Errorf("Expected Message field to be not empty")
			}
		}
	}
}

func TestPolicySingleNumaNodeFilterHints(t *testing.T) {
	tcases := []struct {
		name              string
		allResources      [][]TopologyHint
		expectedResources [][]TopologyHint
	}{
		{
			name:              "filter empty resources",
			allResources:      [][]TopologyHint{},
			expectedResources: [][]TopologyHint(nil),
		},
		{
			name: "filter hints with nil socket mask",
			allResources: [][]TopologyHint{
				{
					{NUMANodeAffinity: nil, Preferred: false},
				},
				{
					{NUMANodeAffinity: nil, Preferred: true},
				},
			},
			expectedResources: [][]TopologyHint{
				[]TopologyHint(nil),
				[]TopologyHint(nil),
			},
		},
		{
			name: "filter hints with nil socket mask",
			allResources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
					{NUMANodeAffinity: nil, Preferred: false},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
					{NUMANodeAffinity: nil, Preferred: true},
				},
			},
			expectedResources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
				},
			},
		},
		{
			name: "filter hints with empty resource socket mask",
			allResources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
					{NUMANodeAffinity: nil, Preferred: false},
				},
				{},
			},
			expectedResources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
				},
				[]TopologyHint(nil),
			},
		},
		{
			name: "filter hints with wide sockemask",
			allResources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1, 2), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(0, 1, 2), Preferred: false},
					{NUMANodeAffinity: nil, Preferred: false},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(1, 2), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(0, 1, 2), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(0, 2), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: false},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(1, 2), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(0, 1, 2), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(0, 2), Preferred: false},
				},
			},
			expectedResources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: false},
				},
				[]TopologyHint(nil),
			},
		},
	}

	numaNodes := []int{0, 1, 2, 3}
	for _, tc := range tcases {
		policy := NewSingleNumaNodePolicy(numaNodes)
		actual := policy.(*singleNumaNodePolicy).filterHints(tc.allResources)
		if !reflect.DeepEqual(tc.expectedResources, actual) {
			t.Errorf("Test Case: %s", tc.name)
			t.Errorf("Expected result to be %v, got %v", tc.expectedResources, actual)
		}
	}
}

func TestPolicySingleNumaNodeGetHintMatch(t *testing.T) {
	tcases := []struct {
		name          string
		resources     [][]TopologyHint
		expectedFound bool
		expectedMatch TopologyHint
	}{
		{
			name: "match single resource single hint",
			resources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: true},
				},
			},
			expectedFound: true,
			expectedMatch: TopologyHint{
				NUMANodeAffinity: NewTestBitMask(3),
				Preferred:        true,
			},
		},
		{
			name: "match single resource multiple hints (Selected hint preferred is true) 1/2",
			resources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(5), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(2), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
				},
			},
			expectedFound: true,
			expectedMatch: TopologyHint{
				NUMANodeAffinity: NewTestBitMask(1),
				Preferred:        true,
			},
		},
		{
			name: "match single resource multiple hints (Selected hint preferred is false) 2/2",
			resources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(5), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(2), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: false},
				},
			},
			expectedFound: true,
			expectedMatch: TopologyHint{
				NUMANodeAffinity: NewTestBitMask(1),
				Preferred:        true,
			},
		},
		{
			name: "match multiple resource single hint",
			resources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(2), Preferred: true},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(2), Preferred: true},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(2), Preferred: false},
				},
			},
			expectedFound: true,
			expectedMatch: TopologyHint{
				NUMANodeAffinity: NewTestBitMask(2),
				Preferred:        true,
			},
		},
		{
			name: "match multiple resource single hint no match",
			resources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(2), Preferred: false},
				},
			},
			expectedFound: false,
			expectedMatch: TopologyHint{},
		},
		{
			name: "multiple resources no match",
			resources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(4), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(2), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: false},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(5), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: false},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(5), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(4), Preferred: true},
				},
			},
			expectedFound: false,
			expectedMatch: TopologyHint{},
		},
		{
			name: "multiple resources with match",
			resources: [][]TopologyHint{
				{
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(4), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(2), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: true},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(5), Preferred: false},
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(1), Preferred: false},
				},
				{
					{NUMANodeAffinity: NewTestBitMask(0), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(5), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(4), Preferred: true},
					{NUMANodeAffinity: NewTestBitMask(3), Preferred: true},
				},
			},
			expectedFound: true,
			expectedMatch: TopologyHint{
				NUMANodeAffinity: NewTestBitMask(3),
				Preferred:        true,
			},
		},
	}

	numaNodes := []int{0, 1, 2, 3, 4, 5}
	for _, tc := range tcases {
		policy := NewSingleNumaNodePolicy(numaNodes)
		found, match := policy.(*singleNumaNodePolicy).getHintMatch(tc.resources)
		if found != tc.expectedFound {
			t.Errorf("Test Case: %s", tc.name)
			t.Errorf("Expected found to be %v, got %v", tc.expectedFound, found)
		}
		if found {
			if !match.IsEqual(tc.expectedMatch) {
				t.Errorf("Test Case: %s", tc.name)
				t.Errorf("Expected match to be %v, got %v", tc.expectedMatch, match)
			}
		}
	}
}

func TestPolicySingleNumaNodeMerge(t *testing.T) {
	numaNodes := []int{0, 1}
	policy := NewSingleNumaNodePolicy(numaNodes)

	tcases := commonPolicyMergeTestCases(numaNodes)
	tcases = append(tcases, policy.(*singleNumaNodePolicy).mergeTestCases(numaNodes)...)

	testPolicyMerge(policy, tcases, t)
}
<|endoftext|>


<commit_before>//go:generate go run cmd/generate-activity-types/generate-activity-types.go -o activity_types.go
package doarama

const (
	BOAT_CANOE             = 10
	BOAT_KAYAK             = 10
	BOAT_MOTOR             = 9
	BOAT_ROW               = 10
	BOAT_SAIL              = 8
	CYCLE_MOUNTAIN         = 6
	CYCLE_OFF_ROAD         = 6
	CYCLE_ROAD             = 4
	CYCLE_SPORT            = 4
	CYCLE_TRANSPORT        = 5
	DRIVE_BUS              = 24
	DRIVE_CAR              = 24
	DRIVE_TRUCK            = 24
	FLY_AIRCRAFT           = 12
	FLY_AVES               = 31
	FLY_BALLOON            = 34
	FLY_BIRD               = 31
	FLY_DRONE              = 30
	FLY_GLIDE              = 11
	FLY_GLIDER             = 28
	FLY_HANG_GLIDE         = 27
	FLY_PARAGLIDE          = 29
	FLY_SAILPLANE          = 28
	FLY_UAV                = 30
	MOTORCYCLE             = 7
	RAIL_TRAIN             = 25
	RIDE_CAMEL             = 26
	RIDE_EQUESTRIAN        = 26
	RUN_FITNESS            = 3
	SKATE_ICE              = 18
	SKATE_ROLLER           = 19
	SKATE_SCOOTER          = 19
	SKATE_SKATEBOARD       = 19
	SKATE_WINDSKATE        = 32
	SKI_CROSS_COUNTRY      = 13
	SKI_DOWNHILL           = 14
	SKI_ROLLER             = 15
	SKI_WAKEBOARD          = 16
	SKI_WATERSKI           = 16
	SNOWBOARD              = 17
	SURF_KITE              = 21
	SURF_WAVE              = 20
	SURF_WINDSURF          = 22
	SWIM                   = 23
	UNDEFINED_AERIAL       = 33
	UNDEFINED_GROUND_BASED = 0
	WALK_FITNESS           = 1
	WALK_HIKE              = 2
	WALK_TREK              = 2
)

var (
	ActivityTypes = map[string]int{
		"Boat - Kayak/Canoe/Row etc":            10,
		"Boat - Motor":                          9,
		"Boat - Sail":                           8,
		"Cycle - Mountain/Off Road etc":         6,
		"Cycle - Sport/Road etc":                4,
		"Cycle - Transport":                     5,
		"Drive - Car/Truck/Bus etc":             24,
		"Fly - Aircraft":                        12,
		"Fly - Balloon":                         34,
		"Fly - Bird / Aves":                     31,
		"Fly - Glide":                           11,
		"Fly - Hang Glide":                      27,
		"Fly - Paraglide":                       29,
		"Fly - Sailplane / Glider":              28,
		"Fly - UAV / Drone":                     30,
		"Motorcycle":                            7,
		"Rail - Train":                          25,
		"Ride - Equestrian/Camel etc":           26,
		"Run - Fitness":                         3,
		"Skate - Ice":                           18,
		"Skate - Roller/Skateboard/Scooter etc": 19,
		"Skate - Windskate":                     32,
		"Ski - Cross Country":                   13,
		"Ski - Downhill":                        14,
		"Ski - Roller":                          15,
		"Ski - Waterski/Wakeboard etc":          16,
		"Snowboard":                             17,
		"Surf - Kite":                           21,
		"Surf - Wave":                           20,
		"Surf - Windsurf":                       22,
		"Swim":                                  23,
		"Undefined - Aerial":                    33,
		"Undefined - Ground Based":              0,
		"Walk - Fitness":                        1,
		"Walk - Hike/Trek etc":                  2,
	}
)
<commit_msg>Add new Hike + Glide activity type<commit_after>//go:generate go run cmd/generate-activity-types/generate-activity-types.go -o activity_types.go
package doarama

const (
	BOAT_CANOE             = 10
	BOAT_KAYAK             = 10
	BOAT_MOTOR             = 9
	BOAT_ROW               = 10
	BOAT_SAIL              = 8
	CYCLE_MOUNTAIN         = 6
	CYCLE_OFF_ROAD         = 6
	CYCLE_ROAD             = 4
	CYCLE_SPORT            = 4
	CYCLE_TRANSPORT        = 5
	DRIVE_BUS              = 24
	DRIVE_CAR              = 24
	DRIVE_TRUCK            = 24
	FLY_AIRCRAFT           = 12
	FLY_AVES               = 31
	FLY_BALLOON            = 34
	FLY_BIRD               = 31
	FLY_DRONE              = 30
	FLY_GLIDE              = 11
	FLY_GLIDER             = 28
	FLY_HANG_GLIDE         = 27
	FLY_HIKE_AND_GLIDE     = 35
	FLY_PARAGLIDE          = 29
	FLY_SAILPLANE          = 28
	FLY_UAV                = 30
	MOTORCYCLE             = 7
	RAIL_TRAIN             = 25
	RIDE_CAMEL             = 26
	RIDE_EQUESTRIAN        = 26
	RUN_FITNESS            = 3
	SKATE_ICE              = 18
	SKATE_ROLLER           = 19
	SKATE_SCOOTER          = 19
	SKATE_SKATEBOARD       = 19
	SKATE_WINDSKATE        = 32
	SKI_CROSS_COUNTRY      = 13
	SKI_DOWNHILL           = 14
	SKI_ROLLER             = 15
	SKI_WAKEBOARD          = 16
	SKI_WATERSKI           = 16
	SNOWBOARD              = 17
	SURF_KITE              = 21
	SURF_WAVE              = 20
	SURF_WINDSURF          = 22
	SWIM                   = 23
	UNDEFINED_AERIAL       = 33
	UNDEFINED_GROUND_BASED = 0
	WALK_FITNESS           = 1
	WALK_HIKE              = 2
	WALK_TREK              = 2
)

var (
	ActivityTypes = map[string]int{
		"Boat - Kayak/Canoe/Row etc":            10,
		"Boat - Motor":                          9,
		"Boat - Sail":                           8,
		"Cycle - Mountain/Off Road etc":         6,
		"Cycle - Sport/Road etc":                4,
		"Cycle - Transport":                     5,
		"Drive - Car/Truck/Bus etc":             24,
		"Fly - Aircraft":                        12,
		"Fly - Balloon":                         34,
		"Fly - Bird / Aves":                     31,
		"Fly - Glide":                           11,
		"Fly - Hang Glide":                      27,
		"Fly - Hike + Glide":                    35,
		"Fly - Paraglide":                       29,
		"Fly - Sailplane / Glider":              28,
		"Fly - UAV / Drone":                     30,
		"Motorcycle":                            7,
		"Rail - Train":                          25,
		"Ride - Equestrian/Camel etc":           26,
		"Run - Fitness":                         3,
		"Skate - Ice":                           18,
		"Skate - Roller/Skateboard/Scooter etc": 19,
		"Skate - Windskate":                     32,
		"Ski - Cross Country":                   13,
		"Ski - Downhill":                        14,
		"Ski - Roller":                          15,
		"Ski - Waterski/Wakeboard etc":          16,
		"Snowboard":                             17,
		"Surf - Kite":                           21,
		"Surf - Wave":                           20,
		"Surf - Windsurf":                       22,
		"Swim":                                  23,
		"Undefined - Aerial":                    33,
		"Undefined - Ground Based":              0,
		"Walk - Fitness":                        1,
		"Walk - Hike/Trek etc":                  2,
	}
)
<|endoftext|>


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

package ui

import (
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/notification/base"
)

type (
	notificationService struct {
		base.NullNotifier
		issueQueue chan issueNotificationOpts
	}

	issueNotificationOpts struct {
		issueID              int64
		commentID            int64
		notificationAuthorID int64
	}
)

var (
	_ base.Notifier = &notificationService{}
)

// NewNotifier create a new notificationService notifier
func NewNotifier() base.Notifier {
	return &notificationService{
		issueQueue: make(chan issueNotificationOpts, 100),
	}
}

func (ns *notificationService) Run() {
	for opts := range ns.issueQueue {
		if err := models.CreateOrUpdateIssueNotifications(opts.issueID, opts.commentID, opts.notificationAuthorID); err != nil {
			log.Error("Was unable to create issue notification: %v", err)
		}
	}
}

func (ns *notificationService) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
	issue *models.Issue, comment *models.Comment) {
	var opts = issueNotificationOpts{
		issueID:              issue.ID,
		notificationAuthorID: doer.ID,
	}
	if comment != nil {
		opts.commentID = comment.ID
	}
	ns.issueQueue <- opts
}

func (ns *notificationService) NotifyNewIssue(issue *models.Issue) {
	ns.issueQueue <- issueNotificationOpts{
		issueID:              issue.ID,
		notificationAuthorID: issue.Poster.ID,
	}
}

func (ns *notificationService) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
	ns.issueQueue <- issueNotificationOpts{
		issueID:              issue.ID,
		notificationAuthorID: doer.ID,
	}
}

func (ns *notificationService) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User) {
	ns.issueQueue <- issueNotificationOpts{
		issueID:              pr.Issue.ID,
		notificationAuthorID: doer.ID,
	}
}

func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest) {
	ns.issueQueue <- issueNotificationOpts{
		issueID:              pr.Issue.ID,
		notificationAuthorID: pr.Issue.PosterID,
	}
}

func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, c *models.Comment) {
	var opts = issueNotificationOpts{
		issueID:              pr.Issue.ID,
		notificationAuthorID: r.Reviewer.ID,
	}
	if c != nil {
		opts.commentID = c.ID
	}
	ns.issueQueue <- opts
}
<commit_msg>Notification: queue ui.go notification-service (#10281)<commit_after>// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package ui

import (
	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/graceful"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/notification/base"
	"code.gitea.io/gitea/modules/queue"
)

type (
	notificationService struct {
		base.NullNotifier
		issueQueue queue.Queue
	}

	issueNotificationOpts struct {
		issueID              int64
		commentID            int64
		notificationAuthorID int64
	}
)

var (
	_ base.Notifier = &notificationService{}
)

// NewNotifier create a new notificationService notifier
func NewNotifier() base.Notifier {
	ns := &notificationService{}
	ns.issueQueue = queue.CreateQueue("notification-service", ns.handle, issueNotificationOpts{})
	return ns
}

func (ns *notificationService) handle(data ...queue.Data) {
	for _, datum := range data {
		opts := datum.(issueNotificationOpts)
		if err := models.CreateOrUpdateIssueNotifications(opts.issueID, opts.commentID, opts.notificationAuthorID); err != nil {
			log.Error("Was unable to create issue notification: %v", err)
		}
	}
}

func (ns *notificationService) Run() {
	graceful.GetManager().RunWithShutdownFns(ns.issueQueue.Run)
}

func (ns *notificationService) NotifyCreateIssueComment(doer *models.User, repo *models.Repository,
	issue *models.Issue, comment *models.Comment) {
	var opts = issueNotificationOpts{
		issueID:              issue.ID,
		notificationAuthorID: doer.ID,
	}
	if comment != nil {
		opts.commentID = comment.ID
	}
	_ = ns.issueQueue.Push(opts)
}

func (ns *notificationService) NotifyNewIssue(issue *models.Issue) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		issueID:              issue.ID,
		notificationAuthorID: issue.Poster.ID,
	})
}

func (ns *notificationService) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, actionComment *models.Comment, isClosed bool) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		issueID:              issue.ID,
		notificationAuthorID: doer.ID,
	})
}

func (ns *notificationService) NotifyMergePullRequest(pr *models.PullRequest, doer *models.User) {
	_ = ns.issueQueue.Push(issueNotificationOpts{
		issueID:              pr.Issue.ID,
		notificationAuthorID: doer.ID,
	})
}

func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest) {
	if err := pr.LoadIssue(); err != nil {
		log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
		return
	}
	_ = ns.issueQueue.Push(issueNotificationOpts{
		issueID:              pr.Issue.ID,
		notificationAuthorID: pr.Issue.PosterID,
	})
}

func (ns *notificationService) NotifyPullRequestReview(pr *models.PullRequest, r *models.Review, c *models.Comment) {
	var opts = issueNotificationOpts{
		issueID:              pr.Issue.ID,
		notificationAuthorID: r.Reviewer.ID,
	}
	if c != nil {
		opts.commentID = c.ID
	}
	_ = ns.issueQueue.Push(opts)
}
<|endoftext|>


<commit_before>// +build linux
// +build cgo

package shared

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

/*
#include "../shared/netns_getifaddrs.c"
*/
// #cgo CFLAGS: -std=gnu11 -Wvla
import "C"

func NetnsGetifaddrs(initPID int32) (map[string]api.ContainerStateNetwork, error) {
	var netnsid_aware C.bool
	var ifaddrs *C.struct_netns_ifaddrs
	var netnsID C.__s32

	if initPID > 0 {
		f, err := os.Open(fmt.Sprintf("/proc/%d/ns/net", initPID))
		if err != nil {
			return nil, err
		}
		defer f.Close()

		netnsID = C.netns_get_nsid(C.__s32(f.Fd()))
		if netnsID < 0 {
			return nil, fmt.Errorf("Failed to retrieve network namespace id")
		}
	} else {
		netnsID = -1
	}

	ret := C.netns_getifaddrs(&ifaddrs, netnsID, &netnsid_aware)
	if ret < 0 {
		return nil, fmt.Errorf("Failed to retrieve network interfaces and addresses")
	}
	defer C.netns_freeifaddrs(ifaddrs)

	if netnsID >= 0 && !netnsid_aware {
		return nil, fmt.Errorf("Netlink requests are not fully network namespace id aware")
	}

	// We're using the interface name as key here but we should really
	// switch to the ifindex at some point to handle ip aliasing correctly.
	networks := map[string]api.ContainerStateNetwork{}

	for addr := ifaddrs; addr != nil; addr = addr.ifa_next {
		var address [C.INET6_ADDRSTRLEN]C.char
		addNetwork, networkExists := networks[C.GoString(addr.ifa_name)]
		if !networkExists {
			addNetwork = api.ContainerStateNetwork{
				Addresses: []api.ContainerStateNetworkAddress{},
				Counters:  api.ContainerStateNetworkCounters{},
			}
		}

		// Interface flags
		netState := "down"
		netType := "unknown"

		if (addr.ifa_flags & C.IFF_BROADCAST) > 0 {
			netType = "broadcast"
		}

		if (addr.ifa_flags & C.IFF_LOOPBACK) > 0 {
			netType = "loopback"
		}

		if (addr.ifa_flags & C.IFF_POINTOPOINT) > 0 {
			netType = "point-to-point"
		}

		if (addr.ifa_flags & C.IFF_UP) > 0 {
			netState = "up"
		}
		addNetwork.State = netState
		addNetwork.Type = netType
		addNetwork.Mtu = int(addr.ifa_mtu)

		// Addresses
		if addr.ifa_addr != nil && (addr.ifa_addr.sa_family == C.AF_INET || addr.ifa_addr.sa_family == C.AF_INET6) {
			family := "inet"
			if addr.ifa_addr.sa_family == C.AF_INET6 {
				family = "inet6"
			}

			addr_ptr := C.get_addr_ptr(addr.ifa_addr)
			if addr_ptr == nil {
				return nil, fmt.Errorf("Failed to retrieve valid address pointer")
			}

			address_str := C.inet_ntop(C.int(addr.ifa_addr.sa_family), addr_ptr, &address[0], C.INET6_ADDRSTRLEN)
			if address_str == nil {
				return nil, fmt.Errorf("Failed to retrieve address string")
			}

			if addNetwork.Addresses == nil {
				addNetwork.Addresses = []api.ContainerStateNetworkAddress{}
			}

			goAddrString := C.GoString(address_str)
			scope := "global"
			if strings.HasPrefix(goAddrString, "127") {
				scope = "local"
			}

			if goAddrString == "::1" {
				scope = "local"
			}

			if strings.HasPrefix(goAddrString, "169.254") {
				scope = "link"
			}

			if strings.HasPrefix(goAddrString, "fe80:") {
				scope = "link"
			}

			address := api.ContainerStateNetworkAddress{}
			address.Family = family
			address.Address = goAddrString
			address.Netmask = fmt.Sprintf("%d", int(addr.ifa_prefixlen))
			address.Scope = scope

			addNetwork.Addresses = append(addNetwork.Addresses, address)
		} else if addr.ifa_addr != nil && addr.ifa_addr.sa_family == C.AF_PACKET {
			if (addr.ifa_flags & C.IFF_LOOPBACK) == 0 {
				var buf [1024]C.char

				hwaddr := C.get_packet_address(addr.ifa_addr, &buf[0], 1024)
				if hwaddr == nil {
					return nil, fmt.Errorf("Failed to retrieve hardware address")
				}

				addNetwork.Hwaddr = C.GoString(hwaddr)
			}
		}

		if addr.ifa_stats_type == C.IFLA_STATS64 {
			addNetwork.Counters.BytesReceived = int64(addr.ifa_stats64.rx_bytes)
			addNetwork.Counters.BytesSent = int64(addr.ifa_stats64.tx_bytes)
			addNetwork.Counters.PacketsReceived = int64(addr.ifa_stats64.rx_packets)
			addNetwork.Counters.PacketsSent = int64(addr.ifa_stats64.tx_packets)
		}
		ifName := C.GoString(addr.ifa_name)

		networks[ifName] = addNetwork
	}

	return networks, nil
}

func WebsocketExecMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser, exited chan bool, fd int) (chan bool, chan bool) {
	readDone := make(chan bool, 1)
	writeDone := make(chan bool, 1)

	go defaultWriter(conn, w, writeDone)

	go func(conn *websocket.Conn, r io.ReadCloser) {
		in := ExecReaderToChannel(r, -1, exited, fd)
		for {
			buf, ok := <-in
			if !ok {
				r.Close()
				logger.Debugf("sending write barrier")
				conn.WriteMessage(websocket.TextMessage, []byte{})
				readDone <- true
				return
			}
			w, err := conn.NextWriter(websocket.BinaryMessage)
			if err != nil {
				logger.Debugf("Got error getting next writer %s", err)
				break
			}

			_, err = w.Write(buf)
			w.Close()
			if err != nil {
				logger.Debugf("Got err writing %s", err)
				break
			}
		}
		closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
		conn.WriteMessage(websocket.CloseMessage, closeMsg)
		readDone <- true
		r.Close()
	}(conn, r)

	return readDone, writeDone
}
<commit_msg>shared/network: Get HostName field when possible<commit_after>// +build linux
// +build cgo

package shared

import (
	"fmt"
	"io"
	"net"
	"os"
	"strings"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/logger"
)

/*
#include "../shared/netns_getifaddrs.c"
*/
// #cgo CFLAGS: -std=gnu11 -Wvla
import "C"

func NetnsGetifaddrs(initPID int32) (map[string]api.ContainerStateNetwork, error) {
	var netnsid_aware C.bool
	var ifaddrs *C.struct_netns_ifaddrs
	var netnsID C.__s32

	if initPID > 0 {
		f, err := os.Open(fmt.Sprintf("/proc/%d/ns/net", initPID))
		if err != nil {
			return nil, err
		}
		defer f.Close()

		netnsID = C.netns_get_nsid(C.__s32(f.Fd()))
		if netnsID < 0 {
			return nil, fmt.Errorf("Failed to retrieve network namespace id")
		}
	} else {
		netnsID = -1
	}

	ret := C.netns_getifaddrs(&ifaddrs, netnsID, &netnsid_aware)
	if ret < 0 {
		return nil, fmt.Errorf("Failed to retrieve network interfaces and addresses")
	}
	defer C.netns_freeifaddrs(ifaddrs)

	if netnsID >= 0 && !netnsid_aware {
		return nil, fmt.Errorf("Netlink requests are not fully network namespace id aware")
	}

	// We're using the interface name as key here but we should really
	// switch to the ifindex at some point to handle ip aliasing correctly.
	networks := map[string]api.ContainerStateNetwork{}

	for addr := ifaddrs; addr != nil; addr = addr.ifa_next {
		var address [C.INET6_ADDRSTRLEN]C.char
		addNetwork, networkExists := networks[C.GoString(addr.ifa_name)]
		if !networkExists {
			addNetwork = api.ContainerStateNetwork{
				Addresses: []api.ContainerStateNetworkAddress{},
				Counters:  api.ContainerStateNetworkCounters{},
			}
		}

		// Interface flags
		netState := "down"
		netType := "unknown"

		if (addr.ifa_flags & C.IFF_BROADCAST) > 0 {
			netType = "broadcast"
		}

		if (addr.ifa_flags & C.IFF_LOOPBACK) > 0 {
			netType = "loopback"
		}

		if (addr.ifa_flags & C.IFF_POINTOPOINT) > 0 {
			netType = "point-to-point"
		}

		if (addr.ifa_flags & C.IFF_UP) > 0 {
			netState = "up"
		}
		addNetwork.State = netState
		addNetwork.Type = netType
		addNetwork.Mtu = int(addr.ifa_mtu)

		if initPID != 0 && int(addr.ifa_ifindex_peer) > 0 {
			hostInterface, err := net.InterfaceByIndex(int(addr.ifa_ifindex_peer))
			if err == nil {
				addNetwork.HostName = hostInterface.Name
			}
		}

		// Addresses
		if addr.ifa_addr != nil && (addr.ifa_addr.sa_family == C.AF_INET || addr.ifa_addr.sa_family == C.AF_INET6) {
			family := "inet"
			if addr.ifa_addr.sa_family == C.AF_INET6 {
				family = "inet6"
			}

			addr_ptr := C.get_addr_ptr(addr.ifa_addr)
			if addr_ptr == nil {
				return nil, fmt.Errorf("Failed to retrieve valid address pointer")
			}

			address_str := C.inet_ntop(C.int(addr.ifa_addr.sa_family), addr_ptr, &address[0], C.INET6_ADDRSTRLEN)
			if address_str == nil {
				return nil, fmt.Errorf("Failed to retrieve address string")
			}

			if addNetwork.Addresses == nil {
				addNetwork.Addresses = []api.ContainerStateNetworkAddress{}
			}

			goAddrString := C.GoString(address_str)
			scope := "global"
			if strings.HasPrefix(goAddrString, "127") {
				scope = "local"
			}

			if goAddrString == "::1" {
				scope = "local"
			}

			if strings.HasPrefix(goAddrString, "169.254") {
				scope = "link"
			}

			if strings.HasPrefix(goAddrString, "fe80:") {
				scope = "link"
			}

			address := api.ContainerStateNetworkAddress{}
			address.Family = family
			address.Address = goAddrString
			address.Netmask = fmt.Sprintf("%d", int(addr.ifa_prefixlen))
			address.Scope = scope

			addNetwork.Addresses = append(addNetwork.Addresses, address)
		} else if addr.ifa_addr != nil && addr.ifa_addr.sa_family == C.AF_PACKET {
			if (addr.ifa_flags & C.IFF_LOOPBACK) == 0 {
				var buf [1024]C.char

				hwaddr := C.get_packet_address(addr.ifa_addr, &buf[0], 1024)
				if hwaddr == nil {
					return nil, fmt.Errorf("Failed to retrieve hardware address")
				}

				addNetwork.Hwaddr = C.GoString(hwaddr)
			}
		}

		if addr.ifa_stats_type == C.IFLA_STATS64 {
			addNetwork.Counters.BytesReceived = int64(addr.ifa_stats64.rx_bytes)
			addNetwork.Counters.BytesSent = int64(addr.ifa_stats64.tx_bytes)
			addNetwork.Counters.PacketsReceived = int64(addr.ifa_stats64.rx_packets)
			addNetwork.Counters.PacketsSent = int64(addr.ifa_stats64.tx_packets)
		}
		ifName := C.GoString(addr.ifa_name)

		networks[ifName] = addNetwork
	}

	return networks, nil
}

func WebsocketExecMirror(conn *websocket.Conn, w io.WriteCloser, r io.ReadCloser, exited chan bool, fd int) (chan bool, chan bool) {
	readDone := make(chan bool, 1)
	writeDone := make(chan bool, 1)

	go defaultWriter(conn, w, writeDone)

	go func(conn *websocket.Conn, r io.ReadCloser) {
		in := ExecReaderToChannel(r, -1, exited, fd)
		for {
			buf, ok := <-in
			if !ok {
				r.Close()
				logger.Debugf("sending write barrier")
				conn.WriteMessage(websocket.TextMessage, []byte{})
				readDone <- true
				return
			}
			w, err := conn.NextWriter(websocket.BinaryMessage)
			if err != nil {
				logger.Debugf("Got error getting next writer %s", err)
				break
			}

			_, err = w.Write(buf)
			w.Close()
			if err != nil {
				logger.Debugf("Got err writing %s", err)
				break
			}
		}
		closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
		conn.WriteMessage(websocket.CloseMessage, closeMsg)
		readDone <- true
		r.Close()
	}(conn, r)

	return readDone, writeDone
}
<|endoftext|>


<commit_before>package util

import (
	"encoding/json"
	"fmt"
	"net/http"

	"mariadb.com/shared/models"
)

func SendOK(w http.ResponseWriter, data interface{}) {
	result, err := json.Marshal(data)
	if err != nil {
		SendBadRequest(w, err)
	} else {
		w.WriteHeader(http.StatusOK)
		w.Header().Set("Content-Type", "application/json")
		w.Write(result)
	}
}

// SendBadRequest writes a Bad Request to the ResponseWrite
func SendBadRequest(w http.ResponseWriter, err error) {
	e := &models.Error{Message: err.Error()}
	var errJSON, _ = json.Marshal(e)
	fmt.Printf("Error: %v \n", string(errJSON))

	w.WriteHeader(http.StatusBadRequest)
	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(string(errJSON)))
}

func SendImage(w http.ResponseWriter, filename string, contentType string, image []byte) {
	w.Header().Set("Content-Disposition", "inline; filename="+filename)
	w.Header().Set("Content-Type", contentType)
	w.Write(image)
}
<commit_msg>fix wrong import<commit_after>package util

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/bstaijen/mariadb-for-microservices/shared/models"
)

func SendOK(w http.ResponseWriter, data interface{}) {
	result, err := json.Marshal(data)
	if err != nil {
		SendBadRequest(w, err)
	} else {
		w.WriteHeader(http.StatusOK)
		w.Header().Set("Content-Type", "application/json")
		w.Write(result)
	}
}

// SendBadRequest writes a Bad Request to the ResponseWrite
func SendBadRequest(w http.ResponseWriter, err error) {
	e := &models.Error{Message: err.Error()}
	var errJSON, _ = json.Marshal(e)
	fmt.Printf("Error: %v \n", string(errJSON))

	w.WriteHeader(http.StatusBadRequest)
	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(string(errJSON)))
}

func SendImage(w http.ResponseWriter, filename string, contentType string, image []byte) {
	w.Header().Set("Content-Disposition", "inline; filename="+filename)
	w.Header().Set("Content-Type", contentType)
	w.Write(image)
}
<|endoftext|>


<commit_before>package shell

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"github.com/zetamatta/go-texts/mbcs"

	"github.com/zetamatta/nyagos/dos"
)

func readEnv(scan *bufio.Scanner, verbose io.Writer) (int, error) {
	errorlevel := -1
	for scan.Scan() {
		line := strings.TrimSpace(scan.Text())
		eqlPos := strings.Index(line, "=")
		if eqlPos > 0 {
			left := line[:eqlPos]
			right := line[eqlPos+1:]
			if left == "ERRORLEVEL_" {
				value, err := strconv.ParseInt(right, 10, 32)
				if err != nil {
					if verbose != nil {
						fmt.Fprintf(verbose, "Could not read ERRORLEVEL(%s)\n", right)
					}
				} else {
					errorlevel = int(value)
				}
			} else {
				orig := os.Getenv(left)
				if verbose != nil {
					fmt.Fprintf(verbose, "%s=%s\n", left, right)
				}
				if orig != right {
					// fmt.Fprintf(os.Stderr, "%s:=%s\n", left, right)
					os.Setenv(left, right)
				}
			}
		}
	}
	return errorlevel, scan.Err()
}

func readPwd(scan *bufio.Scanner, verbose io.Writer) error {
	if !scan.Scan() {
		if err := scan.Err(); err != nil {
			return err
		} else {
			return io.EOF
		}
	}
	line := strings.TrimSpace(scan.Text())
	if verbose != nil {
		fmt.Fprintf(verbose, "cd \"%s\"\n", line)
	}
	os.Chdir(line)
	return nil
}

// loadTmpFile - read update the current-directory and environment-variables from tmp-file.
func loadTmpFile(fname string, verbose io.Writer) (int, error) {
	fp, err := os.Open(fname)
	if err != nil {
		return -1, err
	}
	defer fp.Close()

	scan := bufio.NewScanner(mbcs.NewAtoUReader(fp, mbcs.ConsoleCP()))
	if err := readPwd(scan, verbose); err != nil {
		return -1, err
	}
	return readEnv(scan, verbose)
}

func CmdExe(cmdline string, stdin io.Reader, stdout, stderr io.Writer, env []string) (int, error) {

	if wd, err := os.Getwd(); err == nil && strings.HasPrefix(wd, `\\`) {
		netdrive, closer := dos.UNCtoNetDrive(wd)
		defer closer()
		if netdrive != "" {
			if err := os.Chdir(netdrive); err == nil {
				defer os.Chdir(wd)
			}
		}
	}

	cmdexe := os.Getenv("COMSPEC")

	if cmdexe == "" {
		cmdexe = "cmd.exe"
	}

	var buffer strings.Builder
	buffer.WriteString(`/S /C "`)
	buffer.WriteString(cmdline)
	buffer.WriteString(` "`)

	cmd := exec.Cmd{
		Path:        cmdexe,
		Stdin:       stdin,
		Stdout:      stdout,
		Stderr:      stderr,
		Env:         env,
		SysProcAttr: &syscall.SysProcAttr{CmdLine: buffer.String()},
	}
	if err := cmd.Run(); err != nil {
		return -1, err
	}
	return cmd.ProcessState.ExitCode(), nil
}

func callBatch(
	args []string,
	tmpfile string,
	verbose io.Writer,
	stdin io.Reader,
	stdout io.Writer,
	stderr io.Writer,
	env []string) (int, error) {

	var cmdline strings.Builder

	cmdline.WriteString(`call`)
	for _, arg1 := range args {
		cmdline.WriteByte(' ')
		cmdline.WriteString(arg1)
	}
	cmdline.WriteString(` & call set ERRORLEVEL_=%^ERRORLEVEL% & (cd & set) > "`)
	cmdline.WriteString(tmpfile)
	cmdline.WriteString(`"`)

	return CmdExe(cmdline.String(), stdin, stdout, stderr, env)
}

// RawSource calls the batchfiles and load the changed variable the batchfile has done.
func RawSource(args []string, verbose io.Writer, debug bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, env []string) (int, error) {
	tempDir := os.TempDir()
	pid := os.Getpid()
	tmpfile := filepath.Join(tempDir, fmt.Sprintf("nyagos-%d.tmp", pid))

	errorlevel, err := callBatch(
		args,
		tmpfile,
		verbose,
		stdin,
		stdout,
		stderr,
		env)

	if err != nil {
		return errorlevel, err
	}

	if !debug {
		defer os.Remove(tmpfile)
	}

	if errorlevel, err = loadTmpFile(tmpfile, verbose); err != nil {
		if os.IsNotExist(err) {
			return 1, fmt.Errorf("%s: the batch file may use `exit` without `/b` option. Could not find the change of the environment variables", args[0])
		}
		return 1, err
	}
	return errorlevel, err
}
<commit_msg>Fix confict of temporary file on executing batchfile<commit_after>package shell

import (
	"bufio"
	"fmt"
	"io"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"github.com/zetamatta/go-texts/mbcs"

	"github.com/zetamatta/nyagos/dos"
)

func readEnv(scan *bufio.Scanner, verbose io.Writer) (int, error) {
	errorlevel := -1
	for scan.Scan() {
		line := strings.TrimSpace(scan.Text())
		eqlPos := strings.Index(line, "=")
		if eqlPos > 0 {
			left := line[:eqlPos]
			right := line[eqlPos+1:]
			if left == "ERRORLEVEL_" {
				value, err := strconv.ParseInt(right, 10, 32)
				if err != nil {
					if verbose != nil {
						fmt.Fprintf(verbose, "Could not read ERRORLEVEL(%s)\n", right)
					}
				} else {
					errorlevel = int(value)
				}
			} else {
				orig := os.Getenv(left)
				if verbose != nil {
					fmt.Fprintf(verbose, "%s=%s\n", left, right)
				}
				if orig != right {
					// fmt.Fprintf(os.Stderr, "%s:=%s\n", left, right)
					os.Setenv(left, right)
				}
			}
		}
	}
	return errorlevel, scan.Err()
}

func readPwd(scan *bufio.Scanner, verbose io.Writer) error {
	if !scan.Scan() {
		if err := scan.Err(); err != nil {
			return err
		} else {
			return io.EOF
		}
	}
	line := strings.TrimSpace(scan.Text())
	if verbose != nil {
		fmt.Fprintf(verbose, "cd \"%s\"\n", line)
	}
	os.Chdir(line)
	return nil
}

// loadTmpFile - read update the current-directory and environment-variables from tmp-file.
func loadTmpFile(fname string, verbose io.Writer) (int, error) {
	fp, err := os.Open(fname)
	if err != nil {
		return -1, err
	}
	defer fp.Close()

	scan := bufio.NewScanner(mbcs.NewAtoUReader(fp, mbcs.ConsoleCP()))
	if err := readPwd(scan, verbose); err != nil {
		return -1, err
	}
	return readEnv(scan, verbose)
}

func CmdExe(cmdline string, stdin io.Reader, stdout, stderr io.Writer, env []string) (int, error) {

	if wd, err := os.Getwd(); err == nil && strings.HasPrefix(wd, `\\`) {
		netdrive, closer := dos.UNCtoNetDrive(wd)
		defer closer()
		if netdrive != "" {
			if err := os.Chdir(netdrive); err == nil {
				defer os.Chdir(wd)
			}
		}
	}

	cmdexe := os.Getenv("COMSPEC")

	if cmdexe == "" {
		cmdexe = "cmd.exe"
	}

	var buffer strings.Builder
	buffer.WriteString(`/S /C "`)
	buffer.WriteString(cmdline)
	buffer.WriteString(` "`)

	cmd := exec.Cmd{
		Path:        cmdexe,
		Stdin:       stdin,
		Stdout:      stdout,
		Stderr:      stderr,
		Env:         env,
		SysProcAttr: &syscall.SysProcAttr{CmdLine: buffer.String()},
	}
	if err := cmd.Run(); err != nil {
		return -1, err
	}
	return cmd.ProcessState.ExitCode(), nil
}

func callBatch(
	args []string,
	tmpfile string,
	verbose io.Writer,
	stdin io.Reader,
	stdout io.Writer,
	stderr io.Writer,
	env []string) (int, error) {

	var cmdline strings.Builder

	cmdline.WriteString(`call`)
	for _, arg1 := range args {
		cmdline.WriteByte(' ')
		cmdline.WriteString(arg1)
	}
	cmdline.WriteString(` & call set ERRORLEVEL_=%^ERRORLEVEL% & (cd & set) > "`)
	cmdline.WriteString(tmpfile)
	cmdline.WriteString(`"`)

	return CmdExe(cmdline.String(), stdin, stdout, stderr, env)
}

// RawSource calls the batchfiles and load the changed variable the batchfile has done.
func RawSource(args []string, verbose io.Writer, debug bool, stdin io.Reader, stdout io.Writer, stderr io.Writer, env []string) (int, error) {
	tempDir := os.TempDir()
	pid := os.Getpid()
	tmpfile := filepath.Join(tempDir, fmt.Sprintf("nyagos-%d-%d.tmp", pid, rand.Int()))

	errorlevel, err := callBatch(
		args,
		tmpfile,
		verbose,
		stdin,
		stdout,
		stderr,
		env)

	if err != nil {
		return errorlevel, err
	}

	if !debug {
		defer os.Remove(tmpfile)
	}

	if errorlevel, err = loadTmpFile(tmpfile, verbose); err != nil {
		if os.IsNotExist(err) {
			return 1, fmt.Errorf("%s: the batch file may use `exit` without `/b` option. Could not find the change of the environment variables", args[0])
		}
		return 1, err
	}
	return errorlevel, err
}
<|endoftext|>


<commit_before>package terraform

import (
	"sync"
	"testing"
)

func TestNodeRefreshableManagedResourceDynamicExpand_scaleOut(t *testing.T) {
	var stateLock sync.RWMutex

	addr, err := ParseResourceAddress("aws_instance.foo")
	if err != nil {
		t.Fatalf("bad: %s", err)
	}

	m := testModule(t, "refresh-resource-scale-inout")

	state := &State{
		Modules: []*ModuleState{
			&ModuleState{
				Path: rootModulePath,
				Resources: map[string]*ResourceState{
					"aws_instance.foo.0": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "foo",
							},
						},
					},
					"aws_instance.foo.1": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "bar",
							},
						},
					},
				},
			},
		},
	}

	n := &NodeRefreshableManagedResource{
		NodeAbstractCountResource: &NodeAbstractCountResource{
			NodeAbstractResource: &NodeAbstractResource{
				Addr:   addr,
				Config: m.Config().Resources[0],
			},
		},
	}

	g, err := n.DynamicExpand(&MockEvalContext{
		PathPath:   []string{"root"},
		StateState: state,
		StateLock:  &stateLock,
	})

	actual := g.StringWithNodeTypes()
	expected := `aws_instance.foo[0] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[1] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[2] - *terraform.NodeRefreshableManagedResourceInstance
root - terraform.graphNodeRoot
  aws_instance.foo[0] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[1] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[2] - *terraform.NodeRefreshableManagedResourceInstance
`
	if expected != actual {
		t.Fatalf("Expected:\n%s\nGot:\n%s", expected, actual)
	}
}

func TestNodeRefreshableManagedResourceDynamicExpand_scaleIn(t *testing.T) {
	var stateLock sync.RWMutex

	addr, err := ParseResourceAddress("aws_instance.foo")
	if err != nil {
		t.Fatalf("bad: %s", err)
	}

	m := testModule(t, "refresh-resource-scale-inout")

	state := &State{
		Modules: []*ModuleState{
			&ModuleState{
				Path: rootModulePath,
				Resources: map[string]*ResourceState{
					"aws_instance.foo.0": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "foo",
							},
						},
					},
					"aws_instance.foo.1": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "bar",
							},
						},
					},
					"aws_instance.foo.2": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "baz",
							},
						},
					},
					"aws_instance.foo.3": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "qux",
							},
						},
					},
				},
			},
		},
	}

	n := &NodeRefreshableManagedResource{
		NodeAbstractCountResource: &NodeAbstractCountResource{
			NodeAbstractResource: &NodeAbstractResource{
				Addr:   addr,
				Config: m.Config().Resources[0],
			},
		},
	}

	g, err := n.DynamicExpand(&MockEvalContext{
		PathPath:   []string{"root"},
		StateState: state,
		StateLock:  &stateLock,
	})

	actual := g.StringWithNodeTypes()
	expected := `aws_instance.foo[0] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[1] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[2] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[3] - *terraform.NodeRefreshableManagedResourceInstance
root - terraform.graphNodeRoot
  aws_instance.foo[0] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[1] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[2] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[3] - *terraform.NodeRefreshableManagedResourceInstance
`
	if expected != actual {
		t.Fatalf("Expected:\n%s\nGot:\n%s", expected, actual)
	}
}
<commit_msg>core: Add resource count scale-out EvalTree test<commit_after>package terraform

import (
	"reflect"
	"sync"
	"testing"

	"github.com/davecgh/go-spew/spew"
)

func TestNodeRefreshableManagedResourceDynamicExpand_scaleOut(t *testing.T) {
	var stateLock sync.RWMutex

	addr, err := ParseResourceAddress("aws_instance.foo")
	if err != nil {
		t.Fatalf("bad: %s", err)
	}

	m := testModule(t, "refresh-resource-scale-inout")

	state := &State{
		Modules: []*ModuleState{
			&ModuleState{
				Path: rootModulePath,
				Resources: map[string]*ResourceState{
					"aws_instance.foo.0": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "foo",
							},
						},
					},
					"aws_instance.foo.1": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "bar",
							},
						},
					},
				},
			},
		},
	}

	n := &NodeRefreshableManagedResource{
		NodeAbstractCountResource: &NodeAbstractCountResource{
			NodeAbstractResource: &NodeAbstractResource{
				Addr:   addr,
				Config: m.Config().Resources[0],
			},
		},
	}

	g, err := n.DynamicExpand(&MockEvalContext{
		PathPath:   []string{"root"},
		StateState: state,
		StateLock:  &stateLock,
	})

	actual := g.StringWithNodeTypes()
	expected := `aws_instance.foo[0] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[1] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[2] - *terraform.NodeRefreshableManagedResourceInstance
root - terraform.graphNodeRoot
  aws_instance.foo[0] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[1] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[2] - *terraform.NodeRefreshableManagedResourceInstance
`
	if expected != actual {
		t.Fatalf("Expected:\n%s\nGot:\n%s", expected, actual)
	}
}

func TestNodeRefreshableManagedResourceDynamicExpand_scaleIn(t *testing.T) {
	var stateLock sync.RWMutex

	addr, err := ParseResourceAddress("aws_instance.foo")
	if err != nil {
		t.Fatalf("bad: %s", err)
	}

	m := testModule(t, "refresh-resource-scale-inout")

	state := &State{
		Modules: []*ModuleState{
			&ModuleState{
				Path: rootModulePath,
				Resources: map[string]*ResourceState{
					"aws_instance.foo.0": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "foo",
							},
						},
					},
					"aws_instance.foo.1": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "bar",
							},
						},
					},
					"aws_instance.foo.2": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "baz",
							},
						},
					},
					"aws_instance.foo.3": &ResourceState{
						Type: "aws_instance",
						Deposed: []*InstanceState{
							&InstanceState{
								ID: "qux",
							},
						},
					},
				},
			},
		},
	}

	n := &NodeRefreshableManagedResource{
		NodeAbstractCountResource: &NodeAbstractCountResource{
			NodeAbstractResource: &NodeAbstractResource{
				Addr:   addr,
				Config: m.Config().Resources[0],
			},
		},
	}

	g, err := n.DynamicExpand(&MockEvalContext{
		PathPath:   []string{"root"},
		StateState: state,
		StateLock:  &stateLock,
	})

	actual := g.StringWithNodeTypes()
	expected := `aws_instance.foo[0] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[1] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[2] - *terraform.NodeRefreshableManagedResourceInstance
aws_instance.foo[3] - *terraform.NodeRefreshableManagedResourceInstance
root - terraform.graphNodeRoot
  aws_instance.foo[0] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[1] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[2] - *terraform.NodeRefreshableManagedResourceInstance
  aws_instance.foo[3] - *terraform.NodeRefreshableManagedResourceInstance
`
	if expected != actual {
		t.Fatalf("Expected:\n%s\nGot:\n%s", expected, actual)
	}
}

func TestNodeRefreshableManagedResourceEvalTree_scaleOut(t *testing.T) {
	var provider ResourceProvider
	var state *InstanceState
	var resourceConfig *ResourceConfig

	addr, err := ParseResourceAddress("aws_instance.foo[2]")
	if err != nil {
		t.Fatalf("bad: %s", err)
	}

	m := testModule(t, "refresh-resource-scale-inout")

	n := &NodeRefreshableManagedResourceInstance{
		NodeAbstractResource: &NodeAbstractResource{
			Addr:   addr,
			Config: m.Config().Resources[0],
		},
	}

	actual := n.EvalTree()

	expected := &EvalSequence{
		Nodes: []EvalNode{
			&EvalInterpolate{
				Config: n.Config.RawConfig.Copy(),
				Resource: &Resource{
					Name:       addr.Name,
					Type:       addr.Type,
					CountIndex: addr.Index,
				},
				Output: &resourceConfig,
			},
			&EvalGetProvider{
				Name:   n.ProvidedBy()[0],
				Output: &provider,
			},
			&EvalValidateResource{
				Provider:       &provider,
				Config:         &resourceConfig,
				ResourceName:   n.Config.Name,
				ResourceType:   n.Config.Type,
				ResourceMode:   n.Config.Mode,
				IgnoreWarnings: true,
			},
			&EvalReadState{
				Name:   addr.stateId(),
				Output: &state,
			},
			&EvalDiff{
				Name: addr.stateId(),
				Info: &InstanceInfo{
					Id:         addr.stateId(),
					Type:       addr.Type,
					ModulePath: normalizeModulePath(addr.Path),
				},
				Config:      &resourceConfig,
				Resource:    n.Config,
				Provider:    &provider,
				State:       &state,
				OutputState: &state,
				Stub:        true,
			},
			&EvalWriteState{
				Name:         addr.stateId(),
				ResourceType: n.Config.Type,
				Provider:     n.Config.Provider,
				Dependencies: n.StateReferences(),
				State:        &state,
			},
		},
	}

	if !reflect.DeepEqual(expected, actual) {
		t.Fatalf("Expected:\n\n%s\nGot:\n\n%s\n", spew.Sdump(expected), spew.Sdump(actual))
	}
}
<|endoftext|>


<commit_before>package mithril

import (
	"fmt"
	"mithril/log"
	"mithril/message"

	"github.com/streadway/amqp"
)

type amqpAdaptedRequest struct {
	Publishing *amqp.Publishing
	Exchange   string
	RoutingKey string
	Mandatory  bool
	Immediate  bool
}

type AMQPPublisher struct {
	amqpUri         string
	amqpConn        *amqp.Connection
	handlingChannel *amqp.Channel
	confirmAck      chan uint64
	confirmNack     chan uint64
	notifyClose     chan *amqp.Error
}

func NewAMQPPublisher(amqpUri string) (*AMQPPublisher, error) {
	publisher := &AMQPPublisher{
		amqpUri: amqpUri,
	}

	if err := publisher.establishConnection(); err != nil {
		return nil, err
	}
	return publisher, nil
}

func (me *AMQPPublisher) Publish(req *message.Message) error {
	var (
		amqpReq *amqpAdaptedRequest
		err     error
	)

	amqpReq = me.adaptHttpRequest(req)
	if err = me.publishAdaptedRequest(amqpReq); err != nil {
		log.Println("amqp - Failed to publish request:", err)
		return err
	}
	return nil
}

func (me *AMQPPublisher) establishConnection() (err error) {

	if me.amqpConn != nil {
		return
	}

	log.Printf("amqp - connecting to rabbitmq...")
	me.amqpConn, err = amqp.Dial(me.amqpUri)
	if err != nil {
		return err
	}
	log.Printf("amqp - connected to rabbitmq")

	log.Printf("amqp - creating channel...")
	me.handlingChannel, err = me.amqpConn.Channel()
	if err != nil {
		return err
	}
	log.Printf("amqp - channel created")

	log.Printf("amqp - setting confirm mode...")
	if err = me.handlingChannel.Confirm(false); err != nil {
		return err
	}
	log.Printf("amqp - confirm mode set")

	me.confirmAck, me.confirmNack = me.handlingChannel.NotifyConfirm(make(chan uint64, 1), make(chan uint64, 1))
	log.Printf("amqp - notify confirm channels created.")
	go func() {
		closeChan := me.amqpConn.NotifyClose(make(chan *amqp.Error))
		select {
		case e := <-closeChan:
			log.Printf("amqp - The connection to rabbitmq has been closed. %d: %s", e.Code, e.Reason)
			me.disconnect()
		}
	}()

	log.Printf("amqp - Ready to publish messages!")
	return nil
}

func (me *AMQPPublisher) disconnect() {
	if me.handlingChannel != nil {
		me.handlingChannel.Close()
		me.handlingChannel = nil
	}

	if me.amqpConn != nil {
		me.amqpConn.Close()
		me.amqpConn = nil
	}
}

func (me *AMQPPublisher) adaptHttpRequest(req *message.Message) *amqpAdaptedRequest {
	return &amqpAdaptedRequest{
		Publishing: &amqp.Publishing{
			MessageId:     req.MessageId,
			CorrelationId: req.CorrelationId,
			Timestamp:     req.Timestamp,
			AppId:         req.AppId,
			ContentType:   req.ContentType,
			Body:          req.BodyBytes,
		},
		Exchange:   req.Exchange,
		RoutingKey: req.RoutingKey,
		Mandatory:  req.Mandatory,
		Immediate:  req.Immediate,
	}
}

func (me *AMQPPublisher) publishAdaptedRequest(amqpReq *amqpAdaptedRequest) (err error) {
	err = me.establishConnection()
	if err != nil {
		return err
	}
	err = me.handlingChannel.Publish(amqpReq.Exchange,
		amqpReq.RoutingKey, amqpReq.Mandatory,
		amqpReq.Immediate, *amqpReq.Publishing)

	if err != nil {
		return err
	}

	select {
	case _ = <-me.confirmAck:
		return nil
	case _ = <-me.confirmNack:
		return fmt.Errorf("amqp - RabbitMQ nack'd message")
	}
}
<commit_msg>Making log message a little more explicit<commit_after>package mithril

import (
	"fmt"
	"mithril/log"
	"mithril/message"

	"github.com/streadway/amqp"
)

type amqpAdaptedRequest struct {
	Publishing *amqp.Publishing
	Exchange   string
	RoutingKey string
	Mandatory  bool
	Immediate  bool
}

type AMQPPublisher struct {
	amqpUri         string
	amqpConn        *amqp.Connection
	handlingChannel *amqp.Channel
	confirmAck      chan uint64
	confirmNack     chan uint64
	notifyClose     chan *amqp.Error
}

func NewAMQPPublisher(amqpUri string) (*AMQPPublisher, error) {
	publisher := &AMQPPublisher{
		amqpUri: amqpUri,
	}

	if err := publisher.establishConnection(); err != nil {
		return nil, err
	}
	return publisher, nil
}

func (me *AMQPPublisher) Publish(req *message.Message) error {
	var (
		amqpReq *amqpAdaptedRequest
		err     error
	)

	amqpReq = me.adaptHttpRequest(req)
	if err = me.publishAdaptedRequest(amqpReq); err != nil {
		log.Println("amqp - Failed to publish request:", err)
		return err
	}
	return nil
}

func (me *AMQPPublisher) establishConnection() (err error) {

	if me.amqpConn != nil {
		return
	}

	log.Printf("amqp - no rabbitmq connection found, establishing new connection...")
	me.amqpConn, err = amqp.Dial(me.amqpUri)
	if err != nil {
		return err
	}
	log.Printf("amqp - connected to rabbitmq")

	log.Printf("amqp - creating channel...")
	me.handlingChannel, err = me.amqpConn.Channel()
	if err != nil {
		return err
	}
	log.Printf("amqp - channel created")

	log.Printf("amqp - setting confirm mode...")
	if err = me.handlingChannel.Confirm(false); err != nil {
		return err
	}
	log.Printf("amqp - confirm mode set")

	me.confirmAck, me.confirmNack = me.handlingChannel.NotifyConfirm(make(chan uint64, 1), make(chan uint64, 1))
	log.Printf("amqp - notify confirm channels created.")
	go func() {
		closeChan := me.amqpConn.NotifyClose(make(chan *amqp.Error))
		select {
		case e := <-closeChan:
			log.Printf("amqp - The connection to rabbitmq has been closed. %d: %s", e.Code, e.Reason)
			me.disconnect()
		}
	}()

	log.Printf("amqp - Ready to publish messages!")
	return nil
}

func (me *AMQPPublisher) disconnect() {
	if me.handlingChannel != nil {
		me.handlingChannel.Close()
		me.handlingChannel = nil
	}

	if me.amqpConn != nil {
		me.amqpConn.Close()
		me.amqpConn = nil
	}
}

func (me *AMQPPublisher) adaptHttpRequest(req *message.Message) *amqpAdaptedRequest {
	return &amqpAdaptedRequest{
		Publishing: &amqp.Publishing{
			MessageId:     req.MessageId,
			CorrelationId: req.CorrelationId,
			Timestamp:     req.Timestamp,
			AppId:         req.AppId,
			ContentType:   req.ContentType,
			Body:          req.BodyBytes,
		},
		Exchange:   req.Exchange,
		RoutingKey: req.RoutingKey,
		Mandatory:  req.Mandatory,
		Immediate:  req.Immediate,
	}
}

func (me *AMQPPublisher) publishAdaptedRequest(amqpReq *amqpAdaptedRequest) (err error) {
	err = me.establishConnection()
	if err != nil {
		return err
	}
	err = me.handlingChannel.Publish(amqpReq.Exchange,
		amqpReq.RoutingKey, amqpReq.Mandatory,
		amqpReq.Immediate, *amqpReq.Publishing)

	if err != nil {
		return err
	}

	select {
	case _ = <-me.confirmAck:
		return nil
	case _ = <-me.confirmNack:
		return fmt.Errorf("amqp - RabbitMQ nack'd message")
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The etcd Authors
//
// 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.

// the file is borrowed from github.com/rakyll/boom/boomer/print.go

package report

import (
	"fmt"
	"math"
	"sort"
	"strings"
	"time"
)

const (
	barChar = "∎"
)

// Result describes the timings for an operation.
type Result struct {
	Start time.Time
	End   time.Time
	Err   error
}

func (res *Result) Duration() time.Duration { return res.End.Sub(res.Start) }

type report struct {
	results   chan Result
	precision string

	avgTotal float64
	fastest  float64
	slowest  float64
	average  float64
	stddev   float64
	rps      float64
	total    time.Duration

	errorDist map[string]int
	lats      []float64

	sps *secondPoints
}

// Stats exposes results raw data.
type Stats struct {
	AvgTotal   float64
	Fastest    float64
	Slowest    float64
	Average    float64
	Stddev     float64
	RPS        float64
	Total      time.Duration
	ErrorDist  map[string]int
	Lats       []float64
	TimeSeries TimeSeries
}

// Report processes a result stream until it is closed, then produces a
// string with information about the consumed result data.
type Report interface {
	Results() chan<- Result

	// Stats returns results in raw data.
	Stats() <-chan Stats
}

func NewReport(precision string) Report {
	return &report{
		results:   make(chan Result, 16),
		precision: precision,
		errorDist: make(map[string]int),
	}
}

func NewReportSample(precision string) Report {
	r := NewReport(precision).(*report)
	r.sps = newSecondPoints()
	return r
}

func (r *report) Results() chan<- Result { return r.results }

func (r *report) Stats() <-chan Stats {
	donec := make(chan Stats, 1)
	go func() {
		defer close(donec)
		r.processResults()
		donec <- Stats{
			AvgTotal:   r.avgTotal,
			Fastest:    r.fastest,
			Slowest:    r.slowest,
			Average:    r.average,
			Stddev:     r.stddev,
			RPS:        r.rps,
			Total:      r.total,
			ErrorDist:  copyMap(r.errorDist),
			Lats:       copyFloats(r.lats),
			TimeSeries: r.sps.getTimeSeries(),
		}
	}()
	return donec
}

func copyMap(m map[string]int) (c map[string]int) {
	c = make(map[string]int, len(m))
	for k, v := range m {
		c[k] = v
	}
	return
}

func copyFloats(s []float64) (c []float64) {
	c = make([]float64, len(s))
	copy(c, s)
	return
}

func (r *report) String() (s string) {
	if len(r.lats) > 0 {
		s += fmt.Sprintf("\nSummary:\n")
		s += fmt.Sprintf("  Total:\t%s.\n", r.sec2str(r.total.Seconds()))
		s += fmt.Sprintf("  Slowest:\t%s.\n", r.sec2str(r.slowest))
		s += fmt.Sprintf("  Fastest:\t%s.\n", r.sec2str(r.fastest))
		s += fmt.Sprintf("  Average:\t%s.\n", r.sec2str(r.average))
		s += fmt.Sprintf("  Stddev:\t%s.\n", r.sec2str(r.stddev))
		s += fmt.Sprintf("  Requests/sec:\t"+r.precision+"\n", r.rps)
		s += r.histogram()
		s += r.sprintLatencies()
		if r.sps != nil {
			s += fmt.Sprintf("%v\n", r.sps.getTimeSeries())
		}
	}
	if len(r.errorDist) > 0 {
		s += r.errors()
	}
	return s
}

func (r *report) sec2str(sec float64) string { return fmt.Sprintf(r.precision+" secs", sec) }

type reportRate struct{ *report }

func NewReportRate(precision string) Report {
	return &reportRate{NewReport(precision).(*report)}
}

func (r *reportRate) String() string {
	return fmt.Sprintf(" Requests/sec:\t"+r.precision+"\n", r.rps)
}

func (r *report) processResult(res *Result) {
	if res.Err != nil {
		fmt.Println(res.Err.Error())
		// r.errorDist[res.Err.Error()]++
		return
	}
	dur := res.Duration()
	r.lats = append(r.lats, dur.Seconds())
	r.avgTotal += dur.Seconds()
	if r.sps != nil {
		r.sps.Add(res.Start, dur)
	}
}

func (r *report) processResults() {
	st := time.Now()
	for res := range r.results {
		r.processResult(&res)
	}
	r.total = time.Since(st)

	r.rps = float64(len(r.lats)) / r.total.Seconds()
	r.average = r.avgTotal / float64(len(r.lats))
	for i := range r.lats {
		dev := r.lats[i] - r.average
		r.stddev += dev * dev
	}
	r.stddev = math.Sqrt(r.stddev / float64(len(r.lats)))
	sort.Float64s(r.lats)
	if len(r.lats) > 0 {
		r.fastest = r.lats[0]
		r.slowest = r.lats[len(r.lats)-1]
	}
}

var pctls = []float64{10, 25, 50, 75, 90, 95, 99, 99.9}

// Percentiles returns percentile distribution of float64 slice.
func Percentiles(nums []float64) (pcs []float64, data []float64) {
	return pctls, percentiles(nums)
}

func percentiles(nums []float64) (data []float64) {
	data = make([]float64, len(pctls))
	j := 0
	n := len(nums)
	for i := 0; i < n && j < len(pctls); i++ {
		current := float64(i) * 100.0 / float64(n)
		if current >= pctls[j] {
			data[j] = nums[i]
			j++
		}
	}
	return
}

func (r *report) sprintLatencies() string {
	data := percentiles(r.lats)
	s := fmt.Sprintf("\nLatency distribution:\n")
	for i := 0; i < len(pctls); i++ {
		if data[i] > 0 {
			s += fmt.Sprintf("  %v%% in %s.\n", pctls[i], r.sec2str(data[i]))
		}
	}
	return s
}

func (r *report) histogram() string {
	bc := 10
	buckets := make([]float64, bc+1)
	counts := make([]int, bc+1)
	bs := (r.slowest - r.fastest) / float64(bc)
	for i := 0; i < bc; i++ {
		buckets[i] = r.fastest + bs*float64(i)
	}
	buckets[bc] = r.slowest
	var bi int
	var max int
	for i := 0; i < len(r.lats); {
		if r.lats[i] <= buckets[bi] {
			i++
			counts[bi]++
			if max < counts[bi] {
				max = counts[bi]
			}
		} else if bi < len(buckets)-1 {
			bi++
		}
	}
	s := fmt.Sprintf("\nResponse time histogram:\n")
	for i := 0; i < len(buckets); i++ {
		// Normalize bar lengths.
		var barLen int
		if max > 0 {
			barLen = counts[i] * 40 / max
		}
		s += fmt.Sprintf("  "+r.precision+" [%v]\t|%v\n", buckets[i], counts[i], strings.Repeat(barChar, barLen))
	}
	return s
}

func (r *report) errors() string {
	s := fmt.Sprintf("\nError distribution:\n")
	for err, num := range r.errorDist {
		s += fmt.Sprintf("  [%d]\t%s\n", num, err)
	}
	return s
}
<commit_msg>pkg/report: revert to etcd master<commit_after>// Copyright 2014 The etcd Authors
//
// 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.

// the file is borrowed from github.com/rakyll/boom/boomer/print.go

package report

import (
	"fmt"
	"math"
	"sort"
	"strings"
	"time"
)

const (
	barChar = "∎"
)

// Result describes the timings for an operation.
type Result struct {
	Start time.Time
	End   time.Time
	Err   error
}

func (res *Result) Duration() time.Duration { return res.End.Sub(res.Start) }

type report struct {
	results   chan Result
	precision string

	avgTotal float64
	fastest  float64
	slowest  float64
	average  float64
	stddev   float64
	rps      float64
	total    time.Duration

	errorDist map[string]int
	lats      []float64

	sps *secondPoints
}

// Stats exposes results raw data.
type Stats struct {
	AvgTotal   float64
	Fastest    float64
	Slowest    float64
	Average    float64
	Stddev     float64
	RPS        float64
	Total      time.Duration
	ErrorDist  map[string]int
	Lats       []float64
	TimeSeries TimeSeries
}

// Report processes a result stream until it is closed, then produces a
// string with information about the consumed result data.
type Report interface {
	Results() chan<- Result

	// Run returns results in print-friendly format.
	Run() <-chan string

	// Stats returns results in raw data.
	Stats() <-chan Stats
}

func NewReport(precision string) Report {
	return &report{
		results:   make(chan Result, 16),
		precision: precision,
		errorDist: make(map[string]int),
	}
}

func NewReportSample(precision string) Report {
	r := NewReport(precision).(*report)
	r.sps = newSecondPoints()
	return r
}

func (r *report) Results() chan<- Result { return r.results }

func (r *report) Run() <-chan string {
	donec := make(chan string, 1)
	go func() {
		defer close(donec)
		r.processResults()
		donec <- r.String()
	}()
	return donec
}

func (r *report) Stats() <-chan Stats {
	donec := make(chan Stats, 1)
	go func() {
		defer close(donec)
		r.processResults()
		donec <- Stats{
			AvgTotal:   r.avgTotal,
			Fastest:    r.fastest,
			Slowest:    r.slowest,
			Average:    r.average,
			Stddev:     r.stddev,
			RPS:        r.rps,
			Total:      r.total,
			ErrorDist:  copyMap(r.errorDist),
			Lats:       copyFloats(r.lats),
			TimeSeries: r.sps.getTimeSeries(),
		}
	}()
	return donec
}

func copyMap(m map[string]int) (c map[string]int) {
	c = make(map[string]int, len(m))
	for k, v := range m {
		c[k] = v
	}
	return
}

func copyFloats(s []float64) (c []float64) {
	c = make([]float64, len(s))
	copy(c, s)
	return
}

func (r *report) String() (s string) {
	if len(r.lats) > 0 {
		s += fmt.Sprintf("\nSummary:\n")
		s += fmt.Sprintf("  Total:\t%s.\n", r.sec2str(r.total.Seconds()))
		s += fmt.Sprintf("  Slowest:\t%s.\n", r.sec2str(r.slowest))
		s += fmt.Sprintf("  Fastest:\t%s.\n", r.sec2str(r.fastest))
		s += fmt.Sprintf("  Average:\t%s.\n", r.sec2str(r.average))
		s += fmt.Sprintf("  Stddev:\t%s.\n", r.sec2str(r.stddev))
		s += fmt.Sprintf("  Requests/sec:\t"+r.precision+"\n", r.rps)
		s += r.histogram()
		s += r.sprintLatencies()
		if r.sps != nil {
			s += fmt.Sprintf("%v\n", r.sps.getTimeSeries())
		}
	}
	if len(r.errorDist) > 0 {
		s += r.errors()
	}
	return s
}

func (r *report) sec2str(sec float64) string { return fmt.Sprintf(r.precision+" secs", sec) }

type reportRate struct{ *report }

func NewReportRate(precision string) Report {
	return &reportRate{NewReport(precision).(*report)}
}

func (r *reportRate) String() string {
	return fmt.Sprintf(" Requests/sec:\t"+r.precision+"\n", r.rps)
}

func (r *report) processResult(res *Result) {
	if res.Err != nil {
		r.errorDist[res.Err.Error()]++
		return
	}
	dur := res.Duration()
	r.lats = append(r.lats, dur.Seconds())
	r.avgTotal += dur.Seconds()
	if r.sps != nil {
		r.sps.Add(res.Start, dur)
	}
}

func (r *report) processResults() {
	st := time.Now()
	for res := range r.results {
		r.processResult(&res)
	}
	r.total = time.Since(st)

	r.rps = float64(len(r.lats)) / r.total.Seconds()
	r.average = r.avgTotal / float64(len(r.lats))
	for i := range r.lats {
		dev := r.lats[i] - r.average
		r.stddev += dev * dev
	}
	r.stddev = math.Sqrt(r.stddev / float64(len(r.lats)))
	sort.Float64s(r.lats)
	if len(r.lats) > 0 {
		r.fastest = r.lats[0]
		r.slowest = r.lats[len(r.lats)-1]
	}
}

var pctls = []float64{10, 25, 50, 75, 90, 95, 99, 99.9}

// Percentiles returns percentile distribution of float64 slice.
func Percentiles(nums []float64) (pcs []float64, data []float64) {
	return pctls, percentiles(nums)
}

func percentiles(nums []float64) (data []float64) {
	data = make([]float64, len(pctls))
	j := 0
	n := len(nums)
	for i := 0; i < n && j < len(pctls); i++ {
		current := float64(i) * 100.0 / float64(n)
		if current >= pctls[j] {
			data[j] = nums[i]
			j++
		}
	}
	return
}

func (r *report) sprintLatencies() string {
	data := percentiles(r.lats)
	s := fmt.Sprintf("\nLatency distribution:\n")
	for i := 0; i < len(pctls); i++ {
		if data[i] > 0 {
			s += fmt.Sprintf("  %v%% in %s.\n", pctls[i], r.sec2str(data[i]))
		}
	}
	return s
}

func (r *report) histogram() string {
	bc := 10
	buckets := make([]float64, bc+1)
	counts := make([]int, bc+1)
	bs := (r.slowest - r.fastest) / float64(bc)
	for i := 0; i < bc; i++ {
		buckets[i] = r.fastest + bs*float64(i)
	}
	buckets[bc] = r.slowest
	var bi int
	var max int
	for i := 0; i < len(r.lats); {
		if r.lats[i] <= buckets[bi] {
			i++
			counts[bi]++
			if max < counts[bi] {
				max = counts[bi]
			}
		} else if bi < len(buckets)-1 {
			bi++
		}
	}
	s := fmt.Sprintf("\nResponse time histogram:\n")
	for i := 0; i < len(buckets); i++ {
		// Normalize bar lengths.
		var barLen int
		if max > 0 {
			barLen = counts[i] * 40 / max
		}
		s += fmt.Sprintf("  "+r.precision+" [%v]\t|%v\n", buckets[i], counts[i], strings.Repeat(barChar, barLen))
	}
	return s
}

func (r *report) errors() string {
	s := fmt.Sprintf("\nError distribution:\n")
	for err, num := range r.errorDist {
		s += fmt.Sprintf("  [%d]\t%s\n", num, err)
	}
	return s
}
<|endoftext|>