<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

type Command struct {
	Delay   int
	Timeout int
	Command string
}

type Config struct {
	Workers  int
	Commands []*Command
	disabled bool
}

const CONFIG_WRAPPER = `
workers=5
default_timeout=0
commands=$(jq -n '[]')

command() {
    delay=$1; shift
    commands=$(echo "$commands" | \
        jq --arg delay "$delay" --arg cmd "$*" \
           --arg timeout "${timeout:-$default_timeout}" \
           '. + [{Timeout: ($timeout|tonumber), Delay: ($delay|tonumber), Command: $cmd}]')
    timeout=
}

. %s

echo "$commands" | jq --arg workers "$workers" '{Workers: ($workers|tonumber), Commands: .}'
`

type loggerWriter struct {
	log         *log.Logger
	cmd         *exec.Cmd
	buf         []byte
}

func (w *loggerWriter) Write(data []byte) (int, error) {
	sz := len(data)
	data = append(w.buf, data...)
	lines := bytes.Split(data, []byte("\n"))
	if len(lines[len(lines)-1]) == 0 {
		w.buf = nil
	} else {
		w.buf = lines[len(lines)-1]
	}
	lines = lines[:len(lines)-1]
	for _, line := range lines {
		w.log.Printf("[%d] %s", w.cmd.Process.Pid, string(line))
	}
	return sz, nil
}

func (w *loggerWriter) Close() {
	if w.buf != nil {
		w.log.Printf("[%d] %s", w.cmd.Process.Pid, string(w.buf))
		w.buf = nil
	}
}

func readConfig(cfgFile string) (cfg *Config, err error) {
	sp := exec.Command("sh")
	sp.Stderr = os.Stderr
	sp.Stdin = bytes.NewBuffer([]byte(fmt.Sprintf(CONFIG_WRAPPER, cfgFile)))
	out, err := sp.Output()
	if err != nil {
		return nil, err
	}

	cfg = new(Config)
	err = json.Unmarshal(out, cfg)
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func process(cmd *Command) {
	var timer *time.Timer
	var err error

	sp := exec.Command("sh", "-c", cmd.Command)
	stdout := &loggerWriter{log: log.Default(), cmd: sp}
	stderr := &loggerWriter{log: log.Default(), cmd: sp}
	sp.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	sp.Stdout = stdout
	sp.Stderr = stderr

	if err = sp.Start(); err != nil {
		log.Printf("%s failed: %s", cmd.Command, err.Error())
		return
	}
	log.Printf("[%d] %s", sp.Process.Pid, cmd.Command)

	if cmd.Timeout > 0 {
		timer = time.AfterFunc(time.Duration(cmd.Timeout)*time.Second, func() {
			if sp.ProcessState == nil {
				syscall.Kill(-sp.Process.Pid, syscall.SIGTERM)
			}
		})
	}

	err = sp.Wait()
	stdout.Close()
	stderr.Close()

	if err != nil {
		log.Printf("[%d] %s failed: %s", sp.Process.Pid, cmd.Command, err.Error())
	} else {
		log.Printf("[%d] done", sp.Process.Pid)
	}

	timer.Stop()
}

func reload(cfgFile string, oldConfig *Config, runOnce bool) (config *Config, err error) {
	// loopGroup is the number of (pending) writers on the command channel.
	// After disabling a configuration, we have to wait for it to fall to 0 before
	// closing the channel (otherwise, they will write to the closed channel).
	//
	// onceGroup is the number of unprocessed commands in the initial batch.
	var loopGroup, onceGroup sync.WaitGroup

	var closeChannel sync.Once

	config, err = readConfig(cfgFile)
	if err != nil {
		return nil, err
	}

	ch := make(chan *Command, len(config.Commands))

	for i := 0; i < config.Workers; i++ {
		go func() {
			for !config.disabled {
				var cmd *Command
				if cmd = <-ch; cmd == nil {
					continue
				}

				process(cmd)

				if runOnce {
					onceGroup.Done()
				} else {
					loopGroup.Add(1)
					time.AfterFunc(time.Duration(cmd.Delay)*time.Second, func() {
						if !config.disabled {
							ch <- cmd
						}
						loopGroup.Done()
					})
				}
			}

			loopGroup.Wait()
			closeChannel.Do(func() { close(ch) })
		}()
	}

	for _, cmd := range config.Commands {
		ch <- cmd
		if runOnce {
			onceGroup.Add(1)
		}
	}

	if runOnce {
		onceGroup.Wait()
		os.Exit(0)
	}

	if oldConfig != nil {
		oldConfig.disabled = true
	}

	return config, nil
}

func main() {
	var runOnce bool
	var cfgFile string

	flag.BoolVar(&runOnce, "once", false, "Process commands once, and then exit")
	flag.Parse()

	if cfgFile = flag.Arg(0); cfgFile == "" {
		cfgFile = os.ExpandEnv("$HOME/.config/ggsrc")
	}

	config, err := reload(cfgFile, nil, runOnce)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while reading configuration: %s", err)
		os.Exit(1)
	}

	// wait for signals (interrupt, reload)
	sigChan := make(chan os.Signal, 2)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGUSR1)
	for sig := range sigChan {
		switch sig {
		case syscall.SIGINT:
			return
		case syscall.SIGUSR1:
			config, err = reload(cfgFile, config, runOnce)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error while reloading configuration: %s", err)
			}
		}
	}
}
<commit_msg>gofmt<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

type Command struct {
	Delay   int
	Timeout int
	Command string
}

type Config struct {
	Workers  int
	Commands []*Command
	disabled bool
}

const CONFIG_WRAPPER = `
workers=5
default_timeout=0
commands=$(jq -n '[]')

command() {
    delay=$1; shift
    commands=$(echo "$commands" | \
        jq --arg delay "$delay" --arg cmd "$*" \
           --arg timeout "${timeout:-$default_timeout}" \
           '. + [{Timeout: ($timeout|tonumber), Delay: ($delay|tonumber), Command: $cmd}]')
    timeout=
}

. %s

echo "$commands" | jq --arg workers "$workers" '{Workers: ($workers|tonumber), Commands: .}'
`

type loggerWriter struct {
	log *log.Logger
	cmd *exec.Cmd
	buf []byte
}

func (w *loggerWriter) Write(data []byte) (int, error) {
	sz := len(data)
	data = append(w.buf, data...)
	lines := bytes.Split(data, []byte("\n"))
	if len(lines[len(lines)-1]) == 0 {
		w.buf = nil
	} else {
		w.buf = lines[len(lines)-1]
	}
	lines = lines[:len(lines)-1]
	for _, line := range lines {
		w.log.Printf("[%d] %s", w.cmd.Process.Pid, string(line))
	}
	return sz, nil
}

func (w *loggerWriter) Close() {
	if w.buf != nil {
		w.log.Printf("[%d] %s", w.cmd.Process.Pid, string(w.buf))
		w.buf = nil
	}
}

func readConfig(cfgFile string) (cfg *Config, err error) {
	sp := exec.Command("sh")
	sp.Stderr = os.Stderr
	sp.Stdin = bytes.NewBuffer([]byte(fmt.Sprintf(CONFIG_WRAPPER, cfgFile)))
	out, err := sp.Output()
	if err != nil {
		return nil, err
	}

	cfg = new(Config)
	err = json.Unmarshal(out, cfg)
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func process(cmd *Command) {
	var timer *time.Timer
	var err error

	sp := exec.Command("sh", "-c", cmd.Command)
	stdout := &loggerWriter{log: log.Default(), cmd: sp}
	stderr := &loggerWriter{log: log.Default(), cmd: sp}
	sp.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	sp.Stdout = stdout
	sp.Stderr = stderr

	if err = sp.Start(); err != nil {
		log.Printf("%s failed: %s", cmd.Command, err.Error())
		return
	}
	log.Printf("[%d] %s", sp.Process.Pid, cmd.Command)

	if cmd.Timeout > 0 {
		timer = time.AfterFunc(time.Duration(cmd.Timeout)*time.Second, func() {
			if sp.ProcessState == nil {
				syscall.Kill(-sp.Process.Pid, syscall.SIGTERM)
			}
		})
	}

	err = sp.Wait()
	stdout.Close()
	stderr.Close()

	if err != nil {
		log.Printf("[%d] %s failed: %s", sp.Process.Pid, cmd.Command, err.Error())
	} else {
		log.Printf("[%d] done", sp.Process.Pid)
	}

	timer.Stop()
}

func reload(cfgFile string, oldConfig *Config, runOnce bool) (config *Config, err error) {
	// loopGroup is the number of (pending) writers on the command channel.
	// After disabling a configuration, we have to wait for it to fall to 0 before
	// closing the channel (otherwise, they will write to the closed channel).
	//
	// onceGroup is the number of unprocessed commands in the initial batch.
	var loopGroup, onceGroup sync.WaitGroup

	var closeChannel sync.Once

	config, err = readConfig(cfgFile)
	if err != nil {
		return nil, err
	}

	ch := make(chan *Command, len(config.Commands))

	for i := 0; i < config.Workers; i++ {
		go func() {
			for !config.disabled {
				var cmd *Command
				if cmd = <-ch; cmd == nil {
					continue
				}

				process(cmd)

				if runOnce {
					onceGroup.Done()
				} else {
					loopGroup.Add(1)
					time.AfterFunc(time.Duration(cmd.Delay)*time.Second, func() {
						if !config.disabled {
							ch <- cmd
						}
						loopGroup.Done()
					})
				}
			}

			loopGroup.Wait()
			closeChannel.Do(func() { close(ch) })
		}()
	}

	for _, cmd := range config.Commands {
		ch <- cmd
		if runOnce {
			onceGroup.Add(1)
		}
	}

	if runOnce {
		onceGroup.Wait()
		os.Exit(0)
	}

	if oldConfig != nil {
		oldConfig.disabled = true
	}

	return config, nil
}

func main() {
	var runOnce bool
	var cfgFile string

	flag.BoolVar(&runOnce, "once", false, "Process commands once, and then exit")
	flag.Parse()

	if cfgFile = flag.Arg(0); cfgFile == "" {
		cfgFile = os.ExpandEnv("$HOME/.config/ggsrc")
	}

	config, err := reload(cfgFile, nil, runOnce)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while reading configuration: %s", err)
		os.Exit(1)
	}

	// wait for signals (interrupt, reload)
	sigChan := make(chan os.Signal, 2)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGUSR1)
	for sig := range sigChan {
		switch sig {
		case syscall.SIGINT:
			return
		case syscall.SIGUSR1:
			config, err = reload(cfgFile, config, runOnce)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error while reloading configuration: %s", err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"os"
	"sort"
	"strings"

	"github.com/google/go-github/github"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"golang.org/x/oauth2"
)

var (
	ghreposCmd = &cobra.Command{
		Use:   "ghrepos",
		Short: "ghrepos prints a filtered list of GitHub repositories",
		Long:  "TODO",
		RunE:  run,
	}
)

func init() {
	ghreposCmd.PersistentFlags().String("token", "", "GitHub token to use for API authentication")
	must(viper.BindPFlag("token", ghreposCmd.PersistentFlags().Lookup("token")))
	must(viper.BindEnv("token", "GITHUB_TOKEN"))

	ghreposCmd.PersistentFlags().StringP("owner", "o", "", "User or organization filter")
	must(viper.BindPFlag("owner", ghreposCmd.PersistentFlags().Lookup("owner")))
	must(viper.BindEnv("owner", "GITHUB_USER"))

	ghreposCmd.PersistentFlags().Bool("json", false, "Print JSON array instead of human readable list")
	must(viper.BindPFlag("json", ghreposCmd.PersistentFlags().Lookup("json")))
}

func run(cmd *cobra.Command, args []string) error {
	var httpClient *http.Client
	if token := viper.GetString("token"); token != "" {
		ts := oauth2.StaticTokenSource(
			&oauth2.Token{AccessToken: viper.GetString("token")},
		)
		httpClient = oauth2.NewClient(oauth2.NoContext, ts)
	}
	c := github.NewClient(httpClient)

	if len(args) < 1 {
		return errors.New("You need to provide a topic")
	}
	topic := args[0]

	query := []string{fmt.Sprintf("topic:%s", topic)}
	if owner := viper.GetString("owner"); owner != "" {
		query = append(query, fmt.Sprintf("user:%s", owner))
	}

	var result []github.Repository
	opt := &github.SearchOptions{}
	for {
		repos, resp, err := c.Search.Repositories(context.Background(), strings.Join(query, " "), opt)
		if err != nil {
			return fmt.Errorf("Could not perform search: %s", err)
		}
		result = append(result, repos.Repositories...)
		if resp.NextPage == 0 {
			break
		}
		opt.ListOptions.Page = resp.NextPage
	}

	sort.Sort(byName(result))

	output := []string{}
	for _, repo := range result {
		output = append(output, fmt.Sprintf("%s/%s", *repo.Owner.Login, *repo.Name))
	}

	switch {
	case viper.GetBool("json"):
		return json.NewEncoder(os.Stdout).Encode(output)
	default:
		fmt.Println(strings.Join(output, "\n"))
	}

	return nil
}

func must(err error) {
	if err != nil {
		abort(err)
	}
}

type byName []github.Repository

func (bn byName) Len() int      { return len(bn) }
func (bn byName) Swap(i, j int) { bn[i], bn[j] = bn[j], bn[i] }
func (bn byName) Less(i, j int) bool {
	if *bn[i].Owner.Login < *bn[j].Owner.Login {
		return true
	}
	if *bn[i].Owner.Login == *bn[j].Owner.Login && *bn[i].Name < *bn[j].Name {
		return true
	}
	return false
}
<commit_msg>Support querying intersection of multiple topics<commit_after>package main

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"os"
	"sort"
	"strings"

	"github.com/google/go-github/github"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"golang.org/x/oauth2"
)

var (
	ghreposCmd = &cobra.Command{
		Use:   "ghrepos",
		Short: "ghrepos prints a filtered list of GitHub repositories",
		Long:  "TODO",
		RunE:  run,
	}
)

func init() {
	ghreposCmd.PersistentFlags().String("token", "", "GitHub token to use for API authentication")
	must(viper.BindPFlag("token", ghreposCmd.PersistentFlags().Lookup("token")))
	must(viper.BindEnv("token", "GITHUB_TOKEN"))

	ghreposCmd.PersistentFlags().StringP("owner", "o", "", "User or organization filter")
	must(viper.BindPFlag("owner", ghreposCmd.PersistentFlags().Lookup("owner")))
	must(viper.BindEnv("owner", "GITHUB_USER"))

	ghreposCmd.PersistentFlags().Bool("json", false, "Print JSON array instead of human readable list")
	must(viper.BindPFlag("json", ghreposCmd.PersistentFlags().Lookup("json")))
}

func run(cmd *cobra.Command, args []string) error {
	var httpClient *http.Client
	if token := viper.GetString("token"); token != "" {
		ts := oauth2.StaticTokenSource(
			&oauth2.Token{AccessToken: viper.GetString("token")},
		)
		httpClient = oauth2.NewClient(oauth2.NoContext, ts)
	}
	c := github.NewClient(httpClient)

	if len(args) < 1 {
		return errors.New("You need to provide a topic")
	}

	query := []string{}

	for _, topic := range args {
		query = append(query, fmt.Sprintf("topic:%s", topic))
	}

	if owner := viper.GetString("owner"); owner != "" {
		query = append(query, fmt.Sprintf("user:%s", owner))
	}

	var result []github.Repository
	opt := &github.SearchOptions{}
	for {
		repos, resp, err := c.Search.Repositories(context.Background(), strings.Join(query, " "), opt)
		if err != nil {
			return fmt.Errorf("Could not perform search: %s", err)
		}
		result = append(result, repos.Repositories...)
		if resp.NextPage == 0 {
			break
		}
		opt.ListOptions.Page = resp.NextPage
	}

	sort.Sort(byName(result))

	output := []string{}
	for _, repo := range result {
		output = append(output, fmt.Sprintf("%s/%s", *repo.Owner.Login, *repo.Name))
	}

	switch {
	case viper.GetBool("json"):
		return json.NewEncoder(os.Stdout).Encode(output)
	default:
		fmt.Println(strings.Join(output, "\n"))
	}

	return nil
}

func must(err error) {
	if err != nil {
		abort(err)
	}
}

type byName []github.Repository

func (bn byName) Len() int      { return len(bn) }
func (bn byName) Swap(i, j int) { bn[i], bn[j] = bn[j], bn[i] }
func (bn byName) Less(i, j int) bool {
	if *bn[i].Owner.Login < *bn[j].Owner.Login {
		return true
	}
	if *bn[i].Owner.Login == *bn[j].Owner.Login && *bn[i].Name < *bn[j].Name {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package packetserializers

import (
	"bytes"
	"encoding/binary"

	"github.com/piot/hasty-protocol/channel"
	"github.com/piot/hasty-protocol/packet"
)

// LoginResultToOctets : todo
func LoginResultToOctets(channelID channel.ID) []byte {
	buf := new(bytes.Buffer)
	buf.WriteByte(byte(packet.LoginResult))
	buf.WriteByte(byte(1))
	binary.Write(buf, binary.BigEndian, channelID.Raw())
	return buf.Bytes()
}
<commit_msg>Returning proper login result<commit_after>package packetserializers

import (
	"bytes"
	"encoding/binary"

	"github.com/piot/hasty-protocol/channel"
	"github.com/piot/hasty-protocol/packet"
)

// LoginResultToOctets : todo
func LoginResultToOctets(successful bool, channelID channel.ID) []byte {
	buf := new(bytes.Buffer)
	buf.WriteByte(byte(packet.LoginResult))
	var loginSuccessfulOctet uint8
	if successful {
		loginSuccessfulOctet = 1
	}
	buf.WriteByte(loginSuccessfulOctet)
	binary.Write(buf, binary.BigEndian, channelID.Raw())
	return buf.Bytes()
}
<|endoftext|>


<commit_before>package agent

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

	"github.com/hashicorp/consul/logger"
)

// extra endpoints that should be tested, and their allowed methods
var extraTestEndpoints = map[string][]string{
	"/v1/query":             []string{"GET", "POST"},
	"/v1/query/":            []string{"GET", "PUT", "DELETE"},
	"/v1/query/xxx/execute": []string{"GET"},
	"/v1/query/xxx/explain": []string{"GET"},
}

// These endpoints are ignored in unit testing for response codes
var ignoredEndpoints = []string{"/v1/status/peers", "/v1/agent/monitor", "/v1/agent/reload"}

// These have custom logic
var customEndpoints = []string{"/v1/query", "/v1/query/"}

// includePathInTest returns whether this path should be ignored for the purpose of testing its response code
func includePathInTest(path string) bool {
	ignored := false
	for _, p := range ignoredEndpoints {
		if p == path {
			ignored = true
			break
		}
	}
	for _, p := range customEndpoints {
		if p == path {
			ignored = true
			break
		}
	}

	return !ignored
}

func TestHTTPAPI_MethodNotAllowed_OSS(t *testing.T) {

	a := NewTestAgent(t.Name(), `acl_datacenter = "dc1"`)
	a.Agent.LogWriter = logger.NewLogWriter(512)
	defer a.Shutdown()

	all := []string{"GET", "PUT", "POST", "DELETE", "HEAD", "OPTIONS"}
	client := http.Client{}

	testMethodNotAllowed := func(method string, path string, allowedMethods []string) {
		t.Run(method+" "+path, func(t *testing.T) {
			uri := fmt.Sprintf("http://%s%s", a.HTTPAddr(), path)
			req, _ := http.NewRequest(method, uri, nil)
			resp, err := client.Do(req)
			if err != nil {
				t.Fatal("client.Do failed: ", err)
			}

			allowed := method == "OPTIONS"
			for _, allowedMethod := range allowedMethods {
				if allowedMethod == method {
					allowed = true
					break
				}
			}

			if allowed && resp.StatusCode == http.StatusMethodNotAllowed {
				t.Fatalf("method allowed: got status code %d want any other code", resp.StatusCode)
			}
			if !allowed && resp.StatusCode != http.StatusMethodNotAllowed {
				t.Fatalf("method not allowed: got status code %d want %d", resp.StatusCode, http.StatusMethodNotAllowed)
			}
		})
	}

	for path, methods := range extraTestEndpoints {
		for _, method := range all {
			testMethodNotAllowed(method, path, methods)
		}
	}

	for path, methods := range allowedMethods {
		if includePathInTest(path) {
			for _, method := range all {
				testMethodNotAllowed(method, path, methods)
			}
		}
	}
}

func TestHTTPAPI_OptionMethod_OSS(t *testing.T) {
	a := NewTestAgent(t.Name(), `acl_datacenter = "dc1"`)
	a.Agent.LogWriter = logger.NewLogWriter(512)
	defer a.Shutdown()

	testOptionMethod := func(path string, methods []string) {
		t.Run("OPTIONS "+path, func(t *testing.T) {
			uri := fmt.Sprintf("http://%s%s", a.HTTPAddr(), path)
			req, _ := http.NewRequest("OPTIONS", uri, nil)
			resp := httptest.NewRecorder()
			a.srv.Handler.ServeHTTP(resp, req)
			allMethods := append([]string{"OPTIONS"}, methods...)

			if resp.Code != http.StatusOK {
				t.Fatalf("options request: got status code %d want %d", resp.Code, http.StatusOK)
			}

			optionsStr := resp.Header().Get("Allow")
			if optionsStr == "" {
				t.Fatalf("options request: got empty 'Allow' header")
			} else if optionsStr != strings.Join(allMethods, ",") {
				t.Fatalf("options request: got 'Allow' header value of %s want %s", optionsStr, allMethods)
			}
		})
	}

	for path, methods := range extraTestEndpoints {
		testOptionMethod(path, methods)
	}
	for path, methods := range allowedMethods {
		if includePathInTest(path) {
			testOptionMethod(path, methods)
		}
	}
}
<commit_msg>Close HTTP response in Agent test (HTTPAPI_MethodNotAllowed_OSS)<commit_after>package agent

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

	"github.com/hashicorp/consul/logger"
)

// extra endpoints that should be tested, and their allowed methods
var extraTestEndpoints = map[string][]string{
	"/v1/query":             []string{"GET", "POST"},
	"/v1/query/":            []string{"GET", "PUT", "DELETE"},
	"/v1/query/xxx/execute": []string{"GET"},
	"/v1/query/xxx/explain": []string{"GET"},
}

// These endpoints are ignored in unit testing for response codes
var ignoredEndpoints = []string{"/v1/status/peers", "/v1/agent/monitor", "/v1/agent/reload"}

// These have custom logic
var customEndpoints = []string{"/v1/query", "/v1/query/"}

// includePathInTest returns whether this path should be ignored for the purpose of testing its response code
func includePathInTest(path string) bool {
	ignored := false
	for _, p := range ignoredEndpoints {
		if p == path {
			ignored = true
			break
		}
	}
	for _, p := range customEndpoints {
		if p == path {
			ignored = true
			break
		}
	}

	return !ignored
}

func TestHTTPAPI_MethodNotAllowed_OSS(t *testing.T) {

	a := NewTestAgent(t.Name(), `acl_datacenter = "dc1"`)
	a.Agent.LogWriter = logger.NewLogWriter(512)
	defer a.Shutdown()

	all := []string{"GET", "PUT", "POST", "DELETE", "HEAD", "OPTIONS"}
	client := http.Client{}

	testMethodNotAllowed := func(method string, path string, allowedMethods []string) {
		t.Run(method+" "+path, func(t *testing.T) {
			uri := fmt.Sprintf("http://%s%s", a.HTTPAddr(), path)
			req, _ := http.NewRequest(method, uri, nil)
			resp, err := client.Do(req)
			if err != nil {
				t.Fatal("client.Do failed: ", err)
			}
			defer resp.Body.Close()

			allowed := method == "OPTIONS"
			for _, allowedMethod := range allowedMethods {
				if allowedMethod == method {
					allowed = true
					break
				}
			}

			if allowed && resp.StatusCode == http.StatusMethodNotAllowed {
				t.Fatalf("method allowed: got status code %d want any other code", resp.StatusCode)
			}
			if !allowed && resp.StatusCode != http.StatusMethodNotAllowed {
				t.Fatalf("method not allowed: got status code %d want %d", resp.StatusCode, http.StatusMethodNotAllowed)
			}
		})
	}

	for path, methods := range extraTestEndpoints {
		for _, method := range all {
			testMethodNotAllowed(method, path, methods)
		}
	}

	for path, methods := range allowedMethods {
		if includePathInTest(path) {
			for _, method := range all {
				testMethodNotAllowed(method, path, methods)
			}
		}
	}
}

func TestHTTPAPI_OptionMethod_OSS(t *testing.T) {
	a := NewTestAgent(t.Name(), `acl_datacenter = "dc1"`)
	a.Agent.LogWriter = logger.NewLogWriter(512)
	defer a.Shutdown()

	testOptionMethod := func(path string, methods []string) {
		t.Run("OPTIONS "+path, func(t *testing.T) {
			uri := fmt.Sprintf("http://%s%s", a.HTTPAddr(), path)
			req, _ := http.NewRequest("OPTIONS", uri, nil)
			resp := httptest.NewRecorder()
			a.srv.Handler.ServeHTTP(resp, req)
			allMethods := append([]string{"OPTIONS"}, methods...)

			if resp.Code != http.StatusOK {
				t.Fatalf("options request: got status code %d want %d", resp.Code, http.StatusOK)
			}

			optionsStr := resp.Header().Get("Allow")
			if optionsStr == "" {
				t.Fatalf("options request: got empty 'Allow' header")
			} else if optionsStr != strings.Join(allMethods, ",") {
				t.Fatalf("options request: got 'Allow' header value of %s want %s", optionsStr, allMethods)
			}
		})
	}

	for path, methods := range extraTestEndpoints {
		testOptionMethod(path, methods)
	}
	for path, methods := range allowedMethods {
		if includePathInTest(path) {
			testOptionMethod(path, methods)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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 grpctrace

import (
	"context"
	"fmt"
	"testing"

	"google.golang.org/grpc"

	"go.opentelemetry.io/otel/api/core"
	export "go.opentelemetry.io/otel/sdk/export/trace"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

type testExporter struct {
	spanMap map[string][]*export.SpanData
}

func (t *testExporter) ExportSpan(ctx context.Context, s *export.SpanData) {
	t.spanMap[s.Name] = append(t.spanMap[s.Name], s)
}

type mockUICInvoker struct {
	ctx context.Context
}

func (mcuici *mockUICInvoker) invoker(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error {
	mcuici.ctx = ctx
	return nil
}

type mockProtoMessage struct{}

func (mm *mockProtoMessage) Reset() {
}

func (mm *mockProtoMessage) String() string {
	return "mock"
}

func (mm *mockProtoMessage) ProtoMessage() {
}

func TestUnaryClientInterceptor(t *testing.T) {
	exp := &testExporter{make(map[string][]*export.SpanData)}
	tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp),
		sdktrace.WithConfig(sdktrace.Config{
			DefaultSampler: sdktrace.AlwaysSample(),
		},
		))

	clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure())
	if err != nil {
		t.Fatalf("failed to create client connection: %v", err)
	}

	tracer := tp.Tracer("grpctrace/client")
	unaryInterceptor := UnaryClientInterceptor(tracer)

	req := &mockProtoMessage{}
	reply := &mockProtoMessage{}
	uniInterceptorInvoker := &mockUICInvoker{}

	checks := []struct {
		name         string
		expectedAttr map[core.Key]core.Value
		eventsAttr   []map[core.Key]core.Value
	}{
		{
			name: "/github.com.serviceName/bar",
			expectedAttr: map[core.Key]core.Value{
				rpcServiceKey:  core.String("serviceName"),
				netPeerIPKey:   core.String("fake"),
				netPeerPortKey: core.String("connection"),
			},
			eventsAttr: []map[core.Key]core.Value{
				{
					messageTypeKey: core.String("SENT"),
					messageIDKey:   core.Int(1),
				},
				{
					messageTypeKey: core.String("RECEIVED"),
					messageIDKey:   core.Int(1),
				},
			},
		},
		{
			name: "/serviceName/bar",
			expectedAttr: map[core.Key]core.Value{
				rpcServiceKey: core.String("serviceName"),
			},
			eventsAttr: []map[core.Key]core.Value{
				{
					messageTypeKey: core.String("SENT"),
					messageIDKey:   core.Int(1),
				},
				{
					messageTypeKey: core.String("RECEIVED"),
					messageIDKey:   core.Int(1),
				},
			},
		},
		{
			name:         "serviceName/bar",
			expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("serviceName")},
		},
		{
			name:         "invalidName",
			expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("")},
		},
		{
			name:         "/github.com.foo.serviceName_123/method",
			expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("serviceName_123")},
		},
	}

	for idx, check := range checks {
		fmt.Println("================", idx, "==================")
		err = unaryInterceptor(context.Background(), check.name, req, reply, clientConn, uniInterceptorInvoker.invoker)
		if err != nil {
			t.Fatalf("failed to run unary interceptor: %v", err)
		}

		spanData, ok := exp.spanMap[check.name]
		if !ok || len(spanData) == 0 {
			t.Fatalf("no span data found for name < %s >", check.name)
		}

		attrs := spanData[0].Attributes
		for _, attr := range attrs {
			expectedAttr, ok := check.expectedAttr[attr.Key]
			if ok {
				if expectedAttr != attr.Value {
					t.Errorf("name: %s invalid %s found. expected %s, actual %s", check.name, string(attr.Key),
						expectedAttr.AsString(), attr.Value.AsString())
				}
				delete(check.expectedAttr, attr.Key)
			}
		}

		// Check if any expected attr not seen
		if len(check.expectedAttr) > 0 {
			for attr := range check.expectedAttr {
				t.Errorf("missing attribute %s in span", string(attr))
			}
		}

		events := spanData[0].MessageEvents
		for event := 0; event < len(check.eventsAttr); event++ {
			for _, attr := range events[event].Attributes {
				expectedAttr, ok := check.eventsAttr[event][attr.Key]
				if ok {
					if attr.Value != expectedAttr {
						t.Errorf("invalid value for attribute %s in events, expected %s actual %s",
							string(attr.Key), attr.Value.AsString(), expectedAttr.AsString())
					}
					delete(check.eventsAttr[event], attr.Key)
				}
			}
			if len(check.eventsAttr[event]) > 0 {
				for attr := range check.eventsAttr[event] {
					t.Errorf("missing attribute %s in span event", string(attr))
				}
			}
		}
	}
}
<commit_msg>Added grpc stream interceptor client<commit_after>// Copyright The OpenTelemetry 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 grpctrace

import (
	"context"
	"sync"
	"testing"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"

	"go.opentelemetry.io/otel/api/core"
	export "go.opentelemetry.io/otel/sdk/export/trace"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

type testExporter struct {
	mu      sync.Mutex
	spanMap map[string][]*export.SpanData
}

func (t *testExporter) ExportSpan(ctx context.Context, s *export.SpanData) {
	t.mu.Lock()
	defer t.mu.Unlock()
	t.spanMap[s.Name] = append(t.spanMap[s.Name], s)
}

type mockUICInvoker struct {
	ctx context.Context
}

func (mcuici *mockUICInvoker) invoker(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error {
	mcuici.ctx = ctx
	return nil
}

type mockProtoMessage struct{}

func (mm *mockProtoMessage) Reset() {
}

func (mm *mockProtoMessage) String() string {
	return "mock"
}

func (mm *mockProtoMessage) ProtoMessage() {
}

func TestUnaryClientInterceptor(t *testing.T) {
	exp := &testExporter{spanMap: make(map[string][]*export.SpanData)}
	tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp),
		sdktrace.WithConfig(sdktrace.Config{
			DefaultSampler: sdktrace.AlwaysSample(),
		},
		))

	clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure())
	if err != nil {
		t.Fatalf("failed to create client connection: %v", err)
	}

	tracer := tp.Tracer("grpctrace/client")
	unaryInterceptor := UnaryClientInterceptor(tracer)

	req := &mockProtoMessage{}
	reply := &mockProtoMessage{}
	uniInterceptorInvoker := &mockUICInvoker{}

	checks := []struct {
		name         string
		expectedAttr map[core.Key]core.Value
		eventsAttr   []map[core.Key]core.Value
	}{
		{
			name: "/github.com.serviceName/bar",
			expectedAttr: map[core.Key]core.Value{
				rpcServiceKey:  core.String("serviceName"),
				netPeerIPKey:   core.String("fake"),
				netPeerPortKey: core.String("connection"),
			},
			eventsAttr: []map[core.Key]core.Value{
				{
					messageTypeKey: core.String("SENT"),
					messageIDKey:   core.Int(1),
				},
				{
					messageTypeKey: core.String("RECEIVED"),
					messageIDKey:   core.Int(1),
				},
			},
		},
		{
			name: "/serviceName/bar",
			expectedAttr: map[core.Key]core.Value{
				rpcServiceKey: core.String("serviceName"),
			},
			eventsAttr: []map[core.Key]core.Value{
				{
					messageTypeKey: core.String("SENT"),
					messageIDKey:   core.Int(1),
				},
				{
					messageTypeKey: core.String("RECEIVED"),
					messageIDKey:   core.Int(1),
				},
			},
		},
		{
			name:         "serviceName/bar",
			expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("serviceName")},
		},
		{
			name:         "invalidName",
			expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("")},
		},
		{
			name:         "/github.com.foo.serviceName_123/method",
			expectedAttr: map[core.Key]core.Value{rpcServiceKey: core.String("serviceName_123")},
		},
	}

	for _, check := range checks {
		err = unaryInterceptor(context.Background(), check.name, req, reply, clientConn, uniInterceptorInvoker.invoker)
		if err != nil {
			t.Fatalf("failed to run unary interceptor: %v", err)
		}

		spanData, ok := exp.spanMap[check.name]
		if !ok || len(spanData) == 0 {
			t.Fatalf("no span data found for name < %s >", check.name)
		}

		attrs := spanData[0].Attributes
		for _, attr := range attrs {
			expectedAttr, ok := check.expectedAttr[attr.Key]
			if ok {
				if expectedAttr != attr.Value {
					t.Errorf("name: %s invalid %s found. expected %s, actual %s", check.name, string(attr.Key),
						expectedAttr.AsString(), attr.Value.AsString())
				}
				delete(check.expectedAttr, attr.Key)
			}
		}

		// Check if any expected attr not seen
		if len(check.expectedAttr) > 0 {
			for attr := range check.expectedAttr {
				t.Errorf("missing attribute %s in span", string(attr))
			}
		}

		events := spanData[0].MessageEvents
		for event := 0; event < len(check.eventsAttr); event++ {
			for _, attr := range events[event].Attributes {
				expectedAttr, ok := check.eventsAttr[event][attr.Key]
				if ok {
					if attr.Value != expectedAttr {
						t.Errorf("invalid value for attribute %s in events, expected %s actual %s",
							string(attr.Key), attr.Value.AsString(), expectedAttr.AsString())
					}
					delete(check.eventsAttr[event], attr.Key)
				}
			}
			if len(check.eventsAttr[event]) > 0 {
				for attr := range check.eventsAttr[event] {
					t.Errorf("missing attribute %s in span event", string(attr))
				}
			}
		}
	}
}

type mockClientStream struct {
	Desc *grpc.StreamDesc
	Ctx  context.Context
}

func (mockClientStream) SendMsg(m interface{}) error  { return nil }
func (mockClientStream) RecvMsg(m interface{}) error  { return nil }
func (mockClientStream) CloseSend() error             { return nil }
func (c mockClientStream) Context() context.Context   { return c.Ctx }
func (mockClientStream) Header() (metadata.MD, error) { return nil, nil }
func (mockClientStream) Trailer() metadata.MD         { return nil }

func TestStreamClientInterceptor(t *testing.T) {
	exp := &testExporter{spanMap: make(map[string][]*export.SpanData)}
	tp, _ := sdktrace.NewProvider(sdktrace.WithSyncer(exp),
		sdktrace.WithConfig(sdktrace.Config{
			DefaultSampler: sdktrace.AlwaysSample(),
		},
		))
	clientConn, err := grpc.Dial("fake:connection", grpc.WithInsecure())
	if err != nil {
		t.Fatalf("failed to create client connection: %v", err)
	}

	// tracer
	tracer := tp.Tracer("grpctrace/Server")
	streamCI := StreamClientInterceptor(tracer)

	var mockClStr mockClientStream
	methodName := "/github.com.serviceName/bar"

	streamClient, err := streamCI(context.Background(),
		&grpc.StreamDesc{ServerStreams: true},
		clientConn,
		methodName,
		func(ctx context.Context,
			desc *grpc.StreamDesc,
			cc *grpc.ClientConn,
			method string,
			opts ...grpc.CallOption) (grpc.ClientStream, error) {
			mockClStr = mockClientStream{Desc: desc, Ctx: ctx}
			return mockClStr, nil
		})

	if err != nil {
		t.Fatalf("failed to initialize grpc stream client: %v", err)
	}

	// no span exported while stream is open
	if _, ok := exp.spanMap[methodName]; ok {
		t.Fatalf("span shouldn't end while stream is open")
	}

	req := &mockProtoMessage{}
	reply := &mockProtoMessage{}

	// send and receive fake data
	for i := 0; i < 10; i++ {
		_ = streamClient.SendMsg(req)
		_ = streamClient.RecvMsg(reply)
	}

	// close client and server stream
	_ = streamClient.CloseSend()
	mockClStr.Desc.ServerStreams = false
	_ = streamClient.RecvMsg(reply)

	// added retry because span end is called in separate go routine
	var spanData []*export.SpanData
	for retry := 0; retry < 5; retry++ {
		ok := false
		exp.mu.Lock()
		spanData, ok = exp.spanMap[methodName]
		exp.mu.Unlock()
		if ok {
			break
		}
		time.Sleep(time.Second * 1)
	}
	if len(spanData) == 0 {
		t.Fatalf("no span data found for name < %s >", methodName)
	}

	attrs := spanData[0].Attributes
	expectedAttr := map[core.Key]string{
		rpcServiceKey:  "serviceName",
		netPeerIPKey:   "fake",
		netPeerPortKey: "connection",
	}

	for _, attr := range attrs {
		expected, ok := expectedAttr[attr.Key]
		if ok {
			if expected != attr.Value.AsString() {
				t.Errorf("name: %s invalid %s found. expected %s, actual %s", methodName, string(attr.Key),
					expected, attr.Value.AsString())
			}
		}
	}

	events := spanData[0].MessageEvents
	if len(events) != 20 {
		t.Fatalf("incorrect number of events expected 20 got %d", len(events))
	}
	for i := 0; i < 20; i += 2 {
		msgID := i/2 + 1
		validate := func(eventName string, attrs []core.KeyValue) {
			for _, attr := range attrs {
				if attr.Key == messageTypeKey && attr.Value.AsString() != eventName {
					t.Errorf("invalid event on index: %d expecting %s event, receive %s event", i, eventName, attr.Value.AsString())
				}
				if attr.Key == messageIDKey && attr.Value != core.Int(msgID) {
					t.Errorf("invalid id for message event expected %d received %d", msgID, attr.Value.AsInt32())
				}
			}
		}
		validate("SENT", events[i].Attributes)
		validate("RECEIVED", events[i+1].Attributes)
	}
}
<|endoftext|>


<commit_before>package agentlogger_test

import (
	"bytes"
	"fmt"
	"os"
	"syscall"

	"github.com/cloudfoundry/bosh-agent/infrastructure/agentlogger"
	"github.com/cloudfoundry/bosh-utils/logger"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Signalable logger debug", func() {
	Describe("when SIGSEGV is recieved", func() {
		It("it dumps all goroutines to stderr", func() {
			errBuf := new(bytes.Buffer)
			outBuf := new(bytes.Buffer)
			signalChannel := make(chan os.Signal, 1)
			writerLogger := logger.NewWriterLogger(logger.LevelError, outBuf, errBuf)
			_, doneChannel := agentlogger.NewSignalableLogger(writerLogger, signalChannel)

			signalChannel <- syscall.SIGSEGV
			<-doneChannel

			fmt.Println(errBuf)
			Expect(errBuf).To(ContainSubstring("Dumping goroutines"))
			Expect(errBuf).To(MatchRegexp(`goroutine (\d+) \[(syscall|running)\]`))
		})
	})
})
<commit_msg>Remove println from signalablelogger test<commit_after>package agentlogger_test

import (
	"bytes"
	"os"
	"syscall"

	"github.com/cloudfoundry/bosh-agent/infrastructure/agentlogger"
	"github.com/cloudfoundry/bosh-utils/logger"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Signalable logger debug", func() {
	Describe("when SIGSEGV is recieved", func() {
		It("it dumps all goroutines to stderr", func() {
			errBuf := new(bytes.Buffer)
			outBuf := new(bytes.Buffer)
			signalChannel := make(chan os.Signal, 1)
			writerLogger := logger.NewWriterLogger(logger.LevelError, outBuf, errBuf)
			_, doneChannel := agentlogger.NewSignalableLogger(writerLogger, signalChannel)

			signalChannel <- syscall.SIGSEGV
			<-doneChannel

			Expect(errBuf).To(ContainSubstring("Dumping goroutines"))
			Expect(errBuf).To(MatchRegexp(`goroutine (\d+) \[(syscall|running)\]`))
		})
	})
})
<|endoftext|>


<commit_before>package servers

import (
	"net/http"
	"testing"

	"github.com/rackspace/gophercloud/pagination"
	th "github.com/rackspace/gophercloud/testhelper"
	"github.com/rackspace/gophercloud/testhelper/client"
)

func TestListServers(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerListSuccessfully(t)

	pages := 0
	err := List(client.ServiceClient(), ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
		pages++

		actual, err := ExtractServers(page)
		if err != nil {
			return false, err
		}

		if len(actual) != 2 {
			t.Fatalf("Expected 2 servers, got %d", len(actual))
		}
		th.CheckDeepEquals(t, ServerHerp, actual[0])
		th.CheckDeepEquals(t, ServerDerp, actual[1])

		return true, nil
	})

	th.AssertNoErr(t, err)

	if pages != 1 {
		t.Errorf("Expected 1 page, saw %d", pages)
	}
}

func TestCreateServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerCreationSuccessfully(t, SingleServerBody)

	actual, err := Create(client.ServiceClient(), CreateOpts{
		Name:      "derp",
		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
		FlavorRef: "1",
	}).Extract()
	th.AssertNoErr(t, err)

	th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestDeleteServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerDeletionSuccessfully(t)

	res := Delete(client.ServiceClient(), "asdfasdfasdf")
	th.AssertNoErr(t, res.Err)
}

func TestGetServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerGetSuccessfully(t)

	client := client.ServiceClient()
	actual, err := Get(client, "1234asdf").Extract()
	if err != nil {
		t.Fatalf("Unexpected Get error: %v", err)
	}

	th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestUpdateServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerUpdateSuccessfully(t)

	client := client.ServiceClient()
	actual, err := Update(client, "1234asdf", UpdateOpts{Name: "new-name"}).Extract()
	if err != nil {
		t.Fatalf("Unexpected Update error: %v", err)
	}

	th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestChangeServerAdminPassword(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleAdminPasswordChangeSuccessfully(t)

	res := ChangeAdminPassword(client.ServiceClient(), "1234asdf", "new-password")
	th.AssertNoErr(t, res.Err)
}

func TestRebootServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleRebootSuccessfully(t)

	res := Reboot(client.ServiceClient(), "1234asdf", SoftReboot)
	th.AssertNoErr(t, res.Err)
}

func TestRebuildServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleRebuildSuccessfully(t, SingleServerBody)

	opts := RebuildOpts{
		Name:       "new-name",
		AdminPass:  "swordfish",
		ImageID:    "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
		AccessIPv4: "1.2.3.4",
	}

	actual, err := Rebuild(client.ServiceClient(), "1234asdf", opts).Extract()
	th.AssertNoErr(t, err)

	th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestResizeServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()

	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
		th.TestMethod(t, r, "POST")
		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
		th.TestJSONRequest(t, r, `{ "resize": { "flavorRef": "2" } }`)

		w.WriteHeader(http.StatusAccepted)
	})

	res := Resize(client.ServiceClient(), "1234asdf", ResizeOpts{FlavorRef: "2"})
	th.AssertNoErr(t, res.Err)
}

func TestConfirmResize(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()

	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
		th.TestMethod(t, r, "POST")
		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
		th.TestJSONRequest(t, r, `{ "confirmResize": null }`)

		w.WriteHeader(http.StatusNoContent)
	})

	res := ConfirmResize(client.ServiceClient(), "1234asdf")
	th.AssertNoErr(t, res.Err)
}

func TestRevertResize(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()

	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
		th.TestMethod(t, r, "POST")
		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
		th.TestJSONRequest(t, r, `{ "revertResize": null }`)

		w.WriteHeader(http.StatusAccepted)
	})

	res := RevertResize(client.ServiceClient(), "1234asdf")
	th.AssertNoErr(t, res.Err)
}

func TestRescue(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()

	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
		th.TestMethod(t, r, "POST")
		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
		th.TestJSONRequest(t, r, `{ "rescue": { "adminPass": "1234567890" } }`)

		w.WriteHeader(http.StatusAccepted)
		w.Write(`{ "adminPass": "1234567890" }`)
	})

	res = Rescue(client.ServiceClient(), "1234asdf", RescueOpts{
		adminPass: "1234567890",
	})
	th.AssertNoErr(t, res.Err)
	th.AssertEquals(t, "1234567890", res.AdminPass)
}
<commit_msg>whoops<commit_after>package servers

import (
	"net/http"
	"testing"

	"github.com/rackspace/gophercloud/pagination"
	th "github.com/rackspace/gophercloud/testhelper"
	"github.com/rackspace/gophercloud/testhelper/client"
)

func TestListServers(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerListSuccessfully(t)

	pages := 0
	err := List(client.ServiceClient(), ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
		pages++

		actual, err := ExtractServers(page)
		if err != nil {
			return false, err
		}

		if len(actual) != 2 {
			t.Fatalf("Expected 2 servers, got %d", len(actual))
		}
		th.CheckDeepEquals(t, ServerHerp, actual[0])
		th.CheckDeepEquals(t, ServerDerp, actual[1])

		return true, nil
	})

	th.AssertNoErr(t, err)

	if pages != 1 {
		t.Errorf("Expected 1 page, saw %d", pages)
	}
}

func TestCreateServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerCreationSuccessfully(t, SingleServerBody)

	actual, err := Create(client.ServiceClient(), CreateOpts{
		Name:      "derp",
		ImageRef:  "f90f6034-2570-4974-8351-6b49732ef2eb",
		FlavorRef: "1",
	}).Extract()
	th.AssertNoErr(t, err)

	th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestDeleteServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerDeletionSuccessfully(t)

	res := Delete(client.ServiceClient(), "asdfasdfasdf")
	th.AssertNoErr(t, res.Err)
}

func TestGetServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerGetSuccessfully(t)

	client := client.ServiceClient()
	actual, err := Get(client, "1234asdf").Extract()
	if err != nil {
		t.Fatalf("Unexpected Get error: %v", err)
	}

	th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestUpdateServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleServerUpdateSuccessfully(t)

	client := client.ServiceClient()
	actual, err := Update(client, "1234asdf", UpdateOpts{Name: "new-name"}).Extract()
	if err != nil {
		t.Fatalf("Unexpected Update error: %v", err)
	}

	th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestChangeServerAdminPassword(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleAdminPasswordChangeSuccessfully(t)

	res := ChangeAdminPassword(client.ServiceClient(), "1234asdf", "new-password")
	th.AssertNoErr(t, res.Err)
}

func TestRebootServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleRebootSuccessfully(t)

	res := Reboot(client.ServiceClient(), "1234asdf", SoftReboot)
	th.AssertNoErr(t, res.Err)
}

func TestRebuildServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()
	HandleRebuildSuccessfully(t, SingleServerBody)

	opts := RebuildOpts{
		Name:       "new-name",
		AdminPass:  "swordfish",
		ImageID:    "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/images/f90f6034-2570-4974-8351-6b49732ef2eb",
		AccessIPv4: "1.2.3.4",
	}

	actual, err := Rebuild(client.ServiceClient(), "1234asdf", opts).Extract()
	th.AssertNoErr(t, err)

	th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestResizeServer(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()

	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
		th.TestMethod(t, r, "POST")
		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
		th.TestJSONRequest(t, r, `{ "resize": { "flavorRef": "2" } }`)

		w.WriteHeader(http.StatusAccepted)
	})

	res := Resize(client.ServiceClient(), "1234asdf", ResizeOpts{FlavorRef: "2"})
	th.AssertNoErr(t, res.Err)
}

func TestConfirmResize(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()

	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
		th.TestMethod(t, r, "POST")
		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
		th.TestJSONRequest(t, r, `{ "confirmResize": null }`)

		w.WriteHeader(http.StatusNoContent)
	})

	res := ConfirmResize(client.ServiceClient(), "1234asdf")
	th.AssertNoErr(t, res.Err)
}

func TestRevertResize(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()

	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
		th.TestMethod(t, r, "POST")
		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
		th.TestJSONRequest(t, r, `{ "revertResize": null }`)

		w.WriteHeader(http.StatusAccepted)
	})

	res := RevertResize(client.ServiceClient(), "1234asdf")
	th.AssertNoErr(t, res.Err)
}

func TestRescue(t *testing.T) {
	th.SetupHTTP()
	defer th.TeardownHTTP()

	th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
		th.TestMethod(t, r, "POST")
		th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
		th.TestJSONRequest(t, r, `{ "rescue": { "adminPass": "1234567890" } }`)

		w.WriteHeader(http.StatusAccepted)
		w.Write(`{ "adminPass": "1234567890" }`)
	})

	res = Rescue(client.ServiceClient(), "1234asdf", RescueOpts{
		AdminPass: "1234567890",
	})
	th.AssertNoErr(t, res.Err)
	th.AssertEquals(t, "1234567890", res.AdminPass)
}
<|endoftext|>


<commit_before>package felixcheck

import (
	"fmt"
	"log"

	"encoding/json"

	"github.com/aleasoluciones/simpleamqp"
	"github.com/bigdatadev/goryman"
)

type CheckPublisher interface {
	PublishCheckResult(Event)
}

type LogPublisher struct {
}

func NewLogPublisher() LogPublisher {
	return LogPublisher{}
}

func (p LogPublisher) PublishCheckResult(event Event) {
	log.Println(event)
}

type RabbitMqPublisher struct {
	publisher *simpleamqp.AmqpPublisher
}

func NewRabbitMqPublisher(amqpuri, exchange string) RabbitMqPublisher {
	p := RabbitMqPublisher{simpleamqp.NewAmqpPublisher(amqpuri, exchange)}
	return p
}

func (p RabbitMqPublisher) PublishCheckResult(event Event) {
	topic := fmt.Sprintf("check.%s.%s", event.Host, event.Service)
	serialized, _ := json.Marshal(event)
	p.publisher.Publish(topic, serialized)
}

type RiemannPublisher struct {
	client *goryman.GorymanClient
}

func NewRiemannPublisher(addr string) RiemannPublisher {
	p := RiemannPublisher{goryman.NewGorymanClient(addr)}
	return p
}

func (p RiemannPublisher) PublishCheckResult(event Event) {
	err := p.client.Connect()
	if err != nil {
		log.Printf("[error] publishing check %s", event)
		return
	}
	defer p.client.Close()
	riemannEvent := goryman.Event{Description: event.Description, Host: event.Host, Service: event.Service, State: event.State, Metric: event.Metric}

	err = p.client.SendEvent(&riemannEvent)
	if err != nil {
		log.Printf("[error] sending check %s", event)
		return
	}
}
<commit_msg>missed attributes added at riemann publisher event conversion<commit_after>package felixcheck

import (
	"fmt"
	"log"

	"encoding/json"

	"github.com/aleasoluciones/simpleamqp"
	"github.com/bigdatadev/goryman"
)

type CheckPublisher interface {
	PublishCheckResult(Event)
}

type LogPublisher struct {
}

func NewLogPublisher() LogPublisher {
	return LogPublisher{}
}

func (p LogPublisher) PublishCheckResult(event Event) {
	log.Println(event)
}

type RabbitMqPublisher struct {
	publisher *simpleamqp.AmqpPublisher
}

func NewRabbitMqPublisher(amqpuri, exchange string) RabbitMqPublisher {
	p := RabbitMqPublisher{simpleamqp.NewAmqpPublisher(amqpuri, exchange)}
	return p
}

func (p RabbitMqPublisher) PublishCheckResult(event Event) {
	topic := fmt.Sprintf("check.%s.%s", event.Host, event.Service)
	serialized, _ := json.Marshal(event)
	p.publisher.Publish(topic, serialized)
}

type RiemannPublisher struct {
	client *goryman.GorymanClient
}

func NewRiemannPublisher(addr string) RiemannPublisher {
	p := RiemannPublisher{goryman.NewGorymanClient(addr)}
	return p
}

func (p RiemannPublisher) PublishCheckResult(event Event) {
	err := p.client.Connect()
	if err != nil {
		log.Printf("[error] publishing check %s", event)
		return
	}
	defer p.client.Close()
	riemannEvent := goryman.Event{Description: event.Description, Host: event.Host, Service: event.Service, State: event.State, Metric: event.Metric, Tags: event.Tags, Attributes: event.Attributes, Ttl: event.Ttl}

	err = p.client.SendEvent(&riemannEvent)
	if err != nil {
		log.Printf("[error] sending check %s", event)
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"net/rpc"
	"strconv"
	"time"

	"github.com/nanobox-core/scribble"
)

//
type (

	//
	Status struct {
		CRole    	string
		DBRole   	string
		State    	string
		UpdatedAt time.Time
	}
)

var (
	client *rpc.Client
	status *Status
	store  *scribble.Driver
)

//
func StatusStart() error {

	//
	port := strconv.FormatInt(int64(conf.ClusterPort+1), 10)

	//
	s := Status{CRole: conf.Role, State: "booting"}

	//
	store = scribble.New("./status", log)
	t := scribble.Transaction{Operation: "write", Collection: "cluster", RecordID: "node", Container: &s}
	if err := store.Transact(t); err != nil {
		return err
	}

	//
	rpc.Register(s)

	// RPC SERVER
	l, err := net.Listen("tcp", port)
	if err != nil {
		return err
	}

	//
	go func(l net.Listener) {
		for {
			if conn, err := l.Accept(); err != nil {
				fmt.Println("accept error: " + err.Error())
			} else {
				fmt.Printf("new connection established\n")
				go rpc.ServeConn(conn)
			}
		}
	}(l)

	// RPC CLIENT
	client, err = rpc.Dial("tcp", port)
	if err != nil {
		return err
	}

	return nil
}

// 'public' methods

//
func (s *Status) SetCRole(role string) {
	s.CRole = role
	if err := save(s); err != nil {
		log.Fatal("BONK!", err)
		panic("Unable to set set cluster role! " + err.Error())
	}
}

//
func (s *Status) SetDBRole(role string) {
	s.DBRole = role
	if err := save(s); err != nil {
		log.Fatal("BONK!", err)
		panic("Unable to set db role! " + err.Error())
	}
}

//
func (s *Status) SetState(state string) {
	s.State = state
	if err := save(s); err != nil {
		log.Fatal("BONK!", err)
		panic("Unable to set state! " + err.Error())
	}
}

// 'public' (RPC mapped) function

//
func Whoami() (*Status, error) {
	fmt.Println("WHAT IS THIS", list.LocalNode())

	s := &Status{}

	if err := client.Call("Status.whoami", nil, s); err != nil {
		return nil, err
	}

	return s, nil
}

//
func Whois(role string) (*Status, error) {
	s := &Status{}

	if err := client.Call("Status.whois", role, s); err != nil {
		return nil, err
	}

	return s, nil
}

//
func Cluster() ([]*Status, error) {
	var members = []*Status{}

	if err := client.Call("Status.cluster", nil, &members); err != nil {
		return nil, err
	}

	return members, nil
}

//
func Demote() error {
	if err := client.Call("Status.demote", nil, nil); err != nil {
		return err
	}

	return nil
}

// 'private' (RPC) methods

//
func (s *Status) whoami(v interface{}) error {

	//
	if err := get(s.CRole, v); err != nil {
		return err
	}

	return nil
}

//
func (s *Status) whois(role string, v interface{}) error {

	//
	for _, m := range list.Members() {
		if m.Name == role {
			if err := get(role, v); err != nil {
				return err
			}
		}
	}

	return nil
}

//
func (s *Status) cluster(v []*Status) error {

	//
	for range list.Members() {

		//
		status, err := Whoami()
		if err != nil {
			return err
		}

		//
		v = append(v, status)
	}

	return nil
}

//
func (s *Status) demote() error {
	return nil
}

// 'private' functions

//
func get(role string, v interface{}) error {
	t := scribble.Transaction{Operation: "read", Collection: "cluster", RecordID: role, Container: &v}
	if err := store.Transact(t); err != nil {
		return err
	}

	return nil
}

//
func save(v interface{}) error {
	t := scribble.Transaction{Operation: "write", Collection: "cluster", RecordID: "node", Container: &v}
	if err := store.Transact(t); err != nil {
		return err
	}

	return nil
}
<commit_msg>removing setcrole<commit_after>package main

import (
	"fmt"
	"net"
	"net/rpc"
	"strconv"
	"time"

	"github.com/nanobox-core/scribble"
)

//
type (

	//
	Status struct {
		CRole    	string
		DBRole   	string
		State    	string
		UpdatedAt time.Time
	}
)

var (
	client *rpc.Client
	status *Status
	store  *scribble.Driver
)

//
func StatusStart() error {

	//
	port := strconv.FormatInt(int64(conf.ClusterPort+1), 10)

	//
	s := Status{CRole: conf.Role, State: "booting"}

	//
	store = scribble.New("./status", log)
	t := scribble.Transaction{Operation: "write", Collection: "cluster", RecordID: "node", Container: &s}
	if err := store.Transact(t); err != nil {
		return err
	}

	//
	rpc.Register(s)

	// RPC SERVER
	l, err := net.Listen("tcp", port)
	if err != nil {
		return err
	}

	//
	go func(l net.Listener) {
		for {
			if conn, err := l.Accept(); err != nil {
				fmt.Println("accept error: " + err.Error())
			} else {
				fmt.Printf("new connection established\n")
				go rpc.ServeConn(conn)
			}
		}
	}(l)

	// RPC CLIENT
	client, err = rpc.Dial("tcp", port)
	if err != nil {
		return err
	}

	return nil
}

// 'public' methods

//
// func (s *Status) SetCRole(role string) {
// 	s.CRole = role
// 	if err := save(s); err != nil {
// 		log.Fatal("BONK!", err)
// 		panic("Unable to set set cluster role! " + err.Error())
// 	}
// }

//
func (s *Status) SetDBRole(role string) {
	s.DBRole = role
	if err := save(s); err != nil {
		log.Fatal("BONK!", err)
		panic("Unable to set db role! " + err.Error())
	}
}

//
func (s *Status) SetState(state string) {
	s.State = state
	if err := save(s); err != nil {
		log.Fatal("BONK!", err)
		panic("Unable to set state! " + err.Error())
	}
}

// 'public' (RPC mapped) function

//
func Whoami() (*Status, error) {
	fmt.Println("WHAT IS THIS", list.LocalNode())

	s := &Status{}

	if err := client.Call("Status.whoami", nil, s); err != nil {
		return nil, err
	}

	return s, nil
}

//
func Whois(role string) (*Status, error) {
	s := &Status{}

	if err := client.Call("Status.whois", role, s); err != nil {
		return nil, err
	}

	return s, nil
}

//
func Cluster() ([]*Status, error) {
	var members = []*Status{}

	if err := client.Call("Status.cluster", nil, &members); err != nil {
		return nil, err
	}

	return members, nil
}

//
func Demote() error {
	if err := client.Call("Status.demote", nil, nil); err != nil {
		return err
	}

	return nil
}

// 'private' (RPC) methods

//
func (s *Status) whoami(v interface{}) error {

	//
	if err := get(s.CRole, v); err != nil {
		return err
	}

	return nil
}

//
func (s *Status) whois(role string, v interface{}) error {

	//
	for _, m := range list.Members() {
		if m.Name == role {
			if err := get(role, v); err != nil {
				return err
			}
		}
	}

	return nil
}

//
func (s *Status) cluster(v []*Status) error {

	//
	for range list.Members() {

		//
		status, err := Whoami()
		if err != nil {
			return err
		}

		//
		v = append(v, status)
	}

	return nil
}

//
func (s *Status) demote() error {
	return nil
}

// 'private' functions

//
func get(role string, v interface{}) error {
	t := scribble.Transaction{Operation: "read", Collection: "cluster", RecordID: role, Container: &v}
	if err := store.Transact(t); err != nil {
		return err
	}

	return nil
}

//
func save(v interface{}) error {
	t := scribble.Transaction{Operation: "write", Collection: "cluster", RecordID: "node", Container: &v}
	if err := store.Transact(t); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package git

/*
#include <git2.h>
#include <git2/errors.h>

int _go_git_status_foreach(git_repository *repo, void *data);
*/
import "C"

import (
	"runtime"
	"unsafe"
)

type Status int

const (
	StatusCurrent         Status = C.GIT_STATUS_CURRENT
	StatusIndexNew               = C.GIT_STATUS_INDEX_NEW
	StatusIndexModified          = C.GIT_STATUS_INDEX_MODIFIED
	StatusIndexDeleted           = C.GIT_STATUS_INDEX_DELETED
	StatusIndexRenamed           = C.GIT_STATUS_INDEX_RENAMED
	StatusIndexTypeChange        = C.GIT_STATUS_INDEX_TYPECHANGE
	StatusWtNew                  = C.GIT_STATUS_WT_NEW
	StatusWtModified             = C.GIT_STATUS_WT_MODIFIED
	StatusWtDeleted              = C.GIT_STATUS_WT_DELETED
	StatusWtTypeChange           = C.GIT_STATUS_WT_TYPECHANGE
	StatusWtRenamed              = C.GIT_STATUS_WT_RENAMED
	StatusIgnored                = C.GIT_STATUS_IGNORED
)

type StatusEntry struct {
	Status         Status
	HeadToIndex    DiffDelta
	IndexToWorkdir DiffDelta
}

func statusEntryFromC(statusEntry *C.git_status_entry) StatusEntry {
	return StatusEntry {
		Status:         Status(statusEntry.status),
		HeadToIndex:    diffDeltaFromC(statusEntry.head_to_index),
		IndexToWorkdir: diffDeltaFromC(statusEntry.index_to_workdir),
	}
}

type StatusList struct {
	ptr *C.git_status_list
}

func newStatusListFromC(ptr *C.git_status_list) *StatusList {
	if ptr == nil {
		return nil
	}

	statusList := &StatusList{
		ptr: ptr,
	}

	runtime.SetFinalizer(statusList, (*StatusList).Free)
	return statusList
}

func (statusList *StatusList) Free() error {
	if statusList.ptr == nil {
		return ErrInvalid
	}
	runtime.SetFinalizer(statusList, nil)
	C.git_status_list_free(statusList.ptr)
	statusList.ptr = nil
	return nil
}

func (statusList *StatusList) ByIndex(index int) (StatusEntry, error) {
	if statusList.ptr == nil {
		return StatusEntry{}, ErrInvalid
	}
	ptr := C.git_status_byindex(statusList.ptr, C.size_t(index))
	return statusEntryFromC(ptr), nil
}

func (statusList *StatusList) EntryCount() (int, error) {
	if statusList.ptr == nil {
		return -1, ErrInvalid
	}
	return int(C.git_status_list_entrycount(statusList.ptr)), nil
}

const (
	StatusOptIncludeUntracked             = C.GIT_STATUS_OPT_INCLUDE_UNTRACKED
	StatusOptIncludeIgnored               = C.GIT_STATUS_OPT_INCLUDE_IGNORED
	StatusOptIncludeUnmodified            = C.GIT_STATUS_OPT_INCLUDE_UNMODIFIED
	StatusOptExcludeSubmodules            = C.GIT_STATUS_OPT_EXCLUDE_SUBMODULES
	StatusOptRecurseUntrackedDirs         = C.GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
	StatusOptDisablePathspecMatch         = C.GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
	StatusOptRecurseIgnoredDirs           = C.GIT_STATUS_OPT_RECURSE_IGNORED_DIRS
	StatusOptRenamesHeadToIndex           = C.GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
	StatusOptRenamesIndexToWorkdir        = C.GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
	StatusOptSortCaseSensitively          = C.GIT_STATUS_OPT_SORT_CASE_SENSITIVELY
	StatusOptSortCaseInsensitively        = C.GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
	StatusOptRenamesFromRewrites          = C.GIT_STATUS_OPT_RENAMES_FROM_REWRITES
	StatusOptNoRefresh                    = C.GIT_STATUS_OPT_NO_REFRESH
	StatusOptUpdateIndex                  = C.GIT_STATUS_OPT_UPDATE_INDEX
)

type StatusShow int

const (
	StatusShowIndexAndWorkdir StatusShow = C.GIT_STATUS_SHOW_INDEX_AND_WORKDIR
	StatusShowIndexOnly                  = C.GIT_STATUS_SHOW_INDEX_ONLY
	StatusShowWorkdirOnly                = C.GIT_STATUS_SHOW_WORKDIR_ONLY
)

type StatusOptions struct {
	Version  int
	Show     StatusShow
	Flags    int
	Pathspec []string
}

func (opts *StatusOptions) toC() *C.git_status_options {
	if opts == nil {
		return nil
	}

	cpathspec := C.git_strarray{}
	if opts.Pathspec != nil {
		cpathspec.count = C.size_t(len(opts.Pathspec))
		cpathspec.strings = makeCStringsFromStrings(opts.Pathspec)
		defer freeStrarray(&cpathspec)
	}

	copts := &C.git_status_options{
		version:  C.GIT_STATUS_OPTIONS_VERSION,
		show:     C.git_status_show_t(opts.Show),
		flags:    C.uint(opts.Flags),
		pathspec: cpathspec,
	}

	return copts
}

func (v *Repository) StatusList(opts *StatusOptions) (*StatusList, error) {
	var ptr *C.git_status_list
	var copts *C.git_status_options

	if opts != nil {
		copts = opts.toC()
	} else {
		copts = &C.git_status_options{}
		ret := C.git_status_init_options(copts, C.GIT_STATUS_OPTIONS_VERSION)
		if ret < 0 {
			return nil, MakeGitError(ret)
		}
	}

	ret := C.git_status_list_new(&ptr, v.ptr, copts)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}
	return newStatusListFromC(ptr), nil
}

func (v *Repository) StatusFile(path string) (Status, error) {
	var statusFlags C.uint
	cPath := C.CString(path)
	ret := C.git_status_file(&statusFlags, v.ptr, cPath)
	if ret < 0 {
		return 0, MakeGitError(ret)
	}
	return Status(statusFlags), nil
}

type StatusCallback func(path string, status Status) int

//export fileStatusForeach
func fileStatusForeach(_path *C.char, _flags C.uint, _payload unsafe.Pointer) C.int {
	path := C.GoString(_path)
	flags := Status(_flags)

	cb := (*StatusCallback)(_payload)
	return C.int((*cb)(path, flags))
}

func (v *Repository) StatusForeach(callback StatusCallback) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C._go_git_status_foreach(v.ptr, unsafe.Pointer(&callback))

	if ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}
<commit_msg>don't return anything from StatusList.Free<commit_after>package git

/*
#include <git2.h>
#include <git2/errors.h>

int _go_git_status_foreach(git_repository *repo, void *data);
*/
import "C"

import (
	"runtime"
	"unsafe"
)

type Status int

const (
	StatusCurrent         Status = C.GIT_STATUS_CURRENT
	StatusIndexNew               = C.GIT_STATUS_INDEX_NEW
	StatusIndexModified          = C.GIT_STATUS_INDEX_MODIFIED
	StatusIndexDeleted           = C.GIT_STATUS_INDEX_DELETED
	StatusIndexRenamed           = C.GIT_STATUS_INDEX_RENAMED
	StatusIndexTypeChange        = C.GIT_STATUS_INDEX_TYPECHANGE
	StatusWtNew                  = C.GIT_STATUS_WT_NEW
	StatusWtModified             = C.GIT_STATUS_WT_MODIFIED
	StatusWtDeleted              = C.GIT_STATUS_WT_DELETED
	StatusWtTypeChange           = C.GIT_STATUS_WT_TYPECHANGE
	StatusWtRenamed              = C.GIT_STATUS_WT_RENAMED
	StatusIgnored                = C.GIT_STATUS_IGNORED
)

type StatusEntry struct {
	Status         Status
	HeadToIndex    DiffDelta
	IndexToWorkdir DiffDelta
}

func statusEntryFromC(statusEntry *C.git_status_entry) StatusEntry {
	return StatusEntry {
		Status:         Status(statusEntry.status),
		HeadToIndex:    diffDeltaFromC(statusEntry.head_to_index),
		IndexToWorkdir: diffDeltaFromC(statusEntry.index_to_workdir),
	}
}

type StatusList struct {
	ptr *C.git_status_list
}

func newStatusListFromC(ptr *C.git_status_list) *StatusList {
	if ptr == nil {
		return nil
	}

	statusList := &StatusList{
		ptr: ptr,
	}

	runtime.SetFinalizer(statusList, (*StatusList).Free)
	return statusList
}

func (statusList *StatusList) Free() {
	if statusList.ptr == nil {
		return
	}
	runtime.SetFinalizer(statusList, nil)
	C.git_status_list_free(statusList.ptr)
	statusList.ptr = nil
}

func (statusList *StatusList) ByIndex(index int) (StatusEntry, error) {
	if statusList.ptr == nil {
		return StatusEntry{}, ErrInvalid
	}
	ptr := C.git_status_byindex(statusList.ptr, C.size_t(index))
	return statusEntryFromC(ptr), nil
}

func (statusList *StatusList) EntryCount() (int, error) {
	if statusList.ptr == nil {
		return -1, ErrInvalid
	}
	return int(C.git_status_list_entrycount(statusList.ptr)), nil
}

const (
	StatusOptIncludeUntracked             = C.GIT_STATUS_OPT_INCLUDE_UNTRACKED
	StatusOptIncludeIgnored               = C.GIT_STATUS_OPT_INCLUDE_IGNORED
	StatusOptIncludeUnmodified            = C.GIT_STATUS_OPT_INCLUDE_UNMODIFIED
	StatusOptExcludeSubmodules            = C.GIT_STATUS_OPT_EXCLUDE_SUBMODULES
	StatusOptRecurseUntrackedDirs         = C.GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
	StatusOptDisablePathspecMatch         = C.GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH
	StatusOptRecurseIgnoredDirs           = C.GIT_STATUS_OPT_RECURSE_IGNORED_DIRS
	StatusOptRenamesHeadToIndex           = C.GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX
	StatusOptRenamesIndexToWorkdir        = C.GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR
	StatusOptSortCaseSensitively          = C.GIT_STATUS_OPT_SORT_CASE_SENSITIVELY
	StatusOptSortCaseInsensitively        = C.GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY
	StatusOptRenamesFromRewrites          = C.GIT_STATUS_OPT_RENAMES_FROM_REWRITES
	StatusOptNoRefresh                    = C.GIT_STATUS_OPT_NO_REFRESH
	StatusOptUpdateIndex                  = C.GIT_STATUS_OPT_UPDATE_INDEX
)

type StatusShow int

const (
	StatusShowIndexAndWorkdir StatusShow = C.GIT_STATUS_SHOW_INDEX_AND_WORKDIR
	StatusShowIndexOnly                  = C.GIT_STATUS_SHOW_INDEX_ONLY
	StatusShowWorkdirOnly                = C.GIT_STATUS_SHOW_WORKDIR_ONLY
)

type StatusOptions struct {
	Version  int
	Show     StatusShow
	Flags    int
	Pathspec []string
}

func (opts *StatusOptions) toC() *C.git_status_options {
	if opts == nil {
		return nil
	}

	cpathspec := C.git_strarray{}
	if opts.Pathspec != nil {
		cpathspec.count = C.size_t(len(opts.Pathspec))
		cpathspec.strings = makeCStringsFromStrings(opts.Pathspec)
		defer freeStrarray(&cpathspec)
	}

	copts := &C.git_status_options{
		version:  C.GIT_STATUS_OPTIONS_VERSION,
		show:     C.git_status_show_t(opts.Show),
		flags:    C.uint(opts.Flags),
		pathspec: cpathspec,
	}

	return copts
}

func (v *Repository) StatusList(opts *StatusOptions) (*StatusList, error) {
	var ptr *C.git_status_list
	var copts *C.git_status_options

	if opts != nil {
		copts = opts.toC()
	} else {
		copts = &C.git_status_options{}
		ret := C.git_status_init_options(copts, C.GIT_STATUS_OPTIONS_VERSION)
		if ret < 0 {
			return nil, MakeGitError(ret)
		}
	}

	ret := C.git_status_list_new(&ptr, v.ptr, copts)
	if ret < 0 {
		return nil, MakeGitError(ret)
	}
	return newStatusListFromC(ptr), nil
}

func (v *Repository) StatusFile(path string) (Status, error) {
	var statusFlags C.uint
	cPath := C.CString(path)
	ret := C.git_status_file(&statusFlags, v.ptr, cPath)
	if ret < 0 {
		return 0, MakeGitError(ret)
	}
	return Status(statusFlags), nil
}

type StatusCallback func(path string, status Status) int

//export fileStatusForeach
func fileStatusForeach(_path *C.char, _flags C.uint, _payload unsafe.Pointer) C.int {
	path := C.GoString(_path)
	flags := Status(_flags)

	cb := (*StatusCallback)(_payload)
	return C.int((*cb)(path, flags))
}

func (v *Repository) StatusForeach(callback StatusCallback) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	ret := C._go_git_status_foreach(v.ptr, unsafe.Pointer(&callback))

	if ret < 0 {
		return MakeGitError(ret)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014, Jeremy Bingham (<jbingham@gmail.com>)
 *
 * 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 main

import (
	"github.com/ctdk/goiardi/actor"
	"github.com/ctdk/goiardi/node"
	"net/http"
	"encoding/json"
)

func statusHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	opUser, oerr := actor.GetReqUser(r.Header.Get("X-OPS-USERID"))
	if oerr != nil {
		jsonErrorReport(w, r, oerr.Error(), oerr.Status())
		return
	}
	if !opUser.IsAdmin() {
		jsonErrorReport(w, r, "You must be an admin to do that", http.StatusForbidden)
		return
	}
	pathArray := splitPath(r.URL.Path)

	if len(pathArray) < 3 {
		jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
		return
	}

	var statusResponse interface{}

	switch r.Method {
	case "GET":
		/* pathArray[1] will tell us what operation we're doing */
		switch pathArray[1] {
			case "all":

			case "node":
				if len(pathArray) != 4 {
					jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
					return
				}
				nodeName := pathArray[2]
				op := pathArray[3]
				n, gerr := node.Get(nodeName)
				if gerr != nil {
					jsonErrorReport(w, r, gerr.Error(), gerr.Status())
					return
				}
				switch op {
				case "latest":
					ns, err := n.LatestStatus()
					if err != nil {
						jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
						return
					}
					statusResponse = ns.ToJSON()
				case "all":
					ns, err := n.AllStatuses()
					if err != nil {
						jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
						return
					}
					sr := make([]map[string]string, len(ns))
					for i, v := range ns {
						sr[i] = v.ToJSON()
					}
					statusResponse = sr
				default:
					jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
					return
				}
			default:
				jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
				return
		}
	default:
		jsonErrorReport(w, r, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	enc := json.NewEncoder(w)
	if err := enc.Encode(&statusResponse); err != nil {
		jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>node status available over http<commit_after>/*
 * Copyright (c) 2013-2014, Jeremy Bingham (<jbingham@gmail.com>)
 *
 * 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 main

import (
	"github.com/ctdk/goiardi/actor"
	"github.com/ctdk/goiardi/node"
	"github.com/ctdk/goiardi/util"
	"net/http"
	"encoding/json"
	"fmt"
)

func statusHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	opUser, oerr := actor.GetReqUser(r.Header.Get("X-OPS-USERID"))
	if oerr != nil {
		jsonErrorReport(w, r, oerr.Error(), oerr.Status())
		return
	}
	if !opUser.IsAdmin() {
		jsonErrorReport(w, r, "You must be an admin to do that", http.StatusForbidden)
		return
	}
	pathArray := splitPath(r.URL.Path)

	if len(pathArray) < 3 {
		jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
		return
	}

	var statusResponse interface{}

	switch r.Method {
	case "GET":
		/* pathArray[1] will tell us what operation we're doing */
		switch pathArray[1] {
			// /status/all/nodes
			case "all":
				if len(pathArray) != 3 {
					jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
					return
				}
				if pathArray[2] != "nodes" {
					jsonErrorReport(w, r, "Invalid object to get status for", http.StatusBadRequest)
					return
				}
				nodes := node.AllNodes()
				sr := make([]map[string]string, len(nodes))
				for i, n := range nodes {
					ns, err := n.LatestStatus()
					if err != nil {
						nsbad := make(map[string]string)
						nsbad["node_name"] = n.Name
						nsbad["status"] = "no record"
						sr[i] = nsbad
						continue
					}
					sr[i] = ns.ToJSON()
					nsurl := fmt.Sprintf("/status/node/%s/latest", n.Name)
					sr[i]["url"] = util.CustomURL(nsurl)
				}
				statusResponse = sr
			// /status/node/<nodeName>/(all|latest)
			case "node":
				if len(pathArray) != 4 {
					jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
					return
				}
				nodeName := pathArray[2]
				op := pathArray[3]
				n, gerr := node.Get(nodeName)
				if gerr != nil {
					jsonErrorReport(w, r, gerr.Error(), gerr.Status())
					return
				}
				switch op {
				case "latest":
					ns, err := n.LatestStatus()
					if err != nil {
						jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
						return
					}
					statusResponse = ns.ToJSON()
				case "all":
					ns, err := n.AllStatuses()
					if err != nil {
						jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
						return
					}
					sr := make([]map[string]string, len(ns))
					for i, v := range ns {
						sr[i] = v.ToJSON()
					}
					statusResponse = sr
				default:
					jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
					return
				}
			default:
				jsonErrorReport(w, r, "Bad request", http.StatusBadRequest)
				return
		}
	default:
		jsonErrorReport(w, r, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}
	enc := json.NewEncoder(w)
	if err := enc.Encode(&statusResponse); err != nil {
		jsonErrorReport(w, r, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package agent

import (
	"errors"
	"fmt"
	"github.com/hashicorp/consul/testutil"
	"github.com/hashicorp/serf/serf"
	"io"
	"net"
	"os"
	"strings"
	"testing"
	"time"
)

type rpcParts struct {
	dir    string
	client *RPCClient
	agent  *Agent
	rpc    *AgentRPC
}

func (r *rpcParts) Close() {
	r.client.Close()
	r.rpc.Shutdown()
	r.agent.Shutdown()
	os.RemoveAll(r.dir)
}

// testRPCClient returns an RPCClient connected to an RPC server that
// serves only this connection.
func testRPCClient(t *testing.T) *rpcParts {
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	lw := NewLogWriter(512)
	mult := io.MultiWriter(os.Stderr, lw)

	conf := nextConfig()
	dir, agent := makeAgentLog(t, conf, mult)
	rpc := NewAgentRPC(agent, l, mult, lw)

	rpcClient, err := NewRPCClient(l.Addr().String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	return &rpcParts{
		dir:    dir,
		client: rpcClient,
		agent:  agent,
		rpc:    rpc,
	}
}

func TestRPCClientForceLeave(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfLan)
	if _, err := p1.agent.JoinLAN([]string{s2Addr}); err != nil {
		t.Fatalf("err: %s", err)
	}

	if err := p2.agent.Shutdown(); err != nil {
		t.Fatalf("err: %s", err)
	}

	if err := p1.client.ForceLeave(p2.agent.config.NodeName); err != nil {
		t.Fatalf("err: %s", err)
	}

	m := p1.agent.LANMembers()
	if len(m) != 2 {
		t.Fatalf("should have 2 members: %#v", m)
	}

	testutil.WaitForResult(func() (bool, error) {
		m := p1.agent.LANMembers()
		success := m[1].Status == serf.StatusLeft
		return success, errors.New(m[1].Status.String())
	}, func(err error) {
		t.Fatalf("member status is %v, should be left", err)
	})
}

func TestRPCClientJoinLAN(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfLan)
	n, err := p1.client.Join([]string{s2Addr}, false)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if n != 1 {
		t.Fatalf("n != 1: %d", n)
	}
}

func TestRPCClientJoinWAN(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfWan)
	n, err := p1.client.Join([]string{s2Addr}, true)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if n != 1 {
		t.Fatalf("n != 1: %d", n)
	}
}

func TestRPCClientLANMembers(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	mem, err := p1.client.LANMembers()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(mem) != 1 {
		t.Fatalf("bad: %#v", mem)
	}

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfLan)
	_, err = p1.client.Join([]string{s2Addr}, false)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	mem, err = p1.client.LANMembers()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(mem) != 2 {
		t.Fatalf("bad: %#v", mem)
	}
}

func TestRPCClientWANMembers(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	mem, err := p1.client.WANMembers()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(mem) != 1 {
		t.Fatalf("bad: %#v", mem)
	}

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfWan)
	_, err = p1.client.Join([]string{s2Addr}, true)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	mem, err = p1.client.WANMembers()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(mem) != 2 {
		t.Fatalf("bad: %#v", mem)
	}
}

func TestRPCClientStats(t *testing.T) {
	p1 := testRPCClient(t)
	defer p1.Close()

	stats, err := p1.client.Stats()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if _, ok := stats["agent"]; !ok {
		t.Fatalf("bad: %#v", stats)
	}

	if _, ok := stats["consul"]; !ok {
		t.Fatalf("bad: %#v", stats)
	}
}

func TestRPCClientLeave(t *testing.T) {
	p1 := testRPCClient(t)
	defer p1.Close()

	if err := p1.client.Leave(); err != nil {
		t.Fatalf("err: %s", err)
	}

	time.Sleep(1 * time.Second)

	select {
	case <-p1.agent.ShutdownCh():
	default:
		t.Fatalf("agent should be shutdown!")
	}
}

func TestRPCClientMonitor(t *testing.T) {
	p1 := testRPCClient(t)
	defer p1.Close()

	eventCh := make(chan string, 64)
	if handle, err := p1.client.Monitor("debug", eventCh); err != nil {
		t.Fatalf("err: %s", err)
	} else {
		defer p1.client.Stop(handle)
	}

	found := false
OUTER1:
	for {
		select {
		case e := <-eventCh:
			if strings.Contains(e, "Accepted client") {
				found = true
			}
		default:
			break OUTER1
		}
	}
	if !found {
		t.Fatalf("should log client accept")
	}

	// Join a bad thing to generate more events
	p1.agent.JoinLAN(nil)

	time.Sleep(1 * time.Second)

	found = false
OUTER2:
	for {
		select {
		case e := <-eventCh:
			if strings.Contains(e, "joining") {
				found = true
			}
		default:
			break OUTER2
		}
	}
	if !found {
		t.Fatalf("should log joining")
	}
}
<commit_msg>agent: fix failing monitor test<commit_after>package agent

import (
	"errors"
	"fmt"
	"github.com/hashicorp/consul/testutil"
	"github.com/hashicorp/serf/serf"
	"io"
	"net"
	"os"
	"strings"
	"testing"
	"time"
)

type rpcParts struct {
	dir    string
	client *RPCClient
	agent  *Agent
	rpc    *AgentRPC
}

func (r *rpcParts) Close() {
	r.client.Close()
	r.rpc.Shutdown()
	r.agent.Shutdown()
	os.RemoveAll(r.dir)
}

// testRPCClient returns an RPCClient connected to an RPC server that
// serves only this connection.
func testRPCClient(t *testing.T) *rpcParts {
	l, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	lw := NewLogWriter(512)
	mult := io.MultiWriter(os.Stderr, lw)

	conf := nextConfig()
	dir, agent := makeAgentLog(t, conf, mult)
	rpc := NewAgentRPC(agent, l, mult, lw)

	rpcClient, err := NewRPCClient(l.Addr().String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	return &rpcParts{
		dir:    dir,
		client: rpcClient,
		agent:  agent,
		rpc:    rpc,
	}
}

func TestRPCClientForceLeave(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfLan)
	if _, err := p1.agent.JoinLAN([]string{s2Addr}); err != nil {
		t.Fatalf("err: %s", err)
	}

	if err := p2.agent.Shutdown(); err != nil {
		t.Fatalf("err: %s", err)
	}

	if err := p1.client.ForceLeave(p2.agent.config.NodeName); err != nil {
		t.Fatalf("err: %s", err)
	}

	m := p1.agent.LANMembers()
	if len(m) != 2 {
		t.Fatalf("should have 2 members: %#v", m)
	}

	testutil.WaitForResult(func() (bool, error) {
		m := p1.agent.LANMembers()
		success := m[1].Status == serf.StatusLeft
		return success, errors.New(m[1].Status.String())
	}, func(err error) {
		t.Fatalf("member status is %v, should be left", err)
	})
}

func TestRPCClientJoinLAN(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfLan)
	n, err := p1.client.Join([]string{s2Addr}, false)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if n != 1 {
		t.Fatalf("n != 1: %d", n)
	}
}

func TestRPCClientJoinWAN(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfWan)
	n, err := p1.client.Join([]string{s2Addr}, true)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if n != 1 {
		t.Fatalf("n != 1: %d", n)
	}
}

func TestRPCClientLANMembers(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	mem, err := p1.client.LANMembers()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(mem) != 1 {
		t.Fatalf("bad: %#v", mem)
	}

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfLan)
	_, err = p1.client.Join([]string{s2Addr}, false)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	mem, err = p1.client.LANMembers()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(mem) != 2 {
		t.Fatalf("bad: %#v", mem)
	}
}

func TestRPCClientWANMembers(t *testing.T) {
	p1 := testRPCClient(t)
	p2 := testRPCClient(t)
	defer p1.Close()
	defer p2.Close()

	mem, err := p1.client.WANMembers()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(mem) != 1 {
		t.Fatalf("bad: %#v", mem)
	}

	s2Addr := fmt.Sprintf("127.0.0.1:%d", p2.agent.config.Ports.SerfWan)
	_, err = p1.client.Join([]string{s2Addr}, true)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	mem, err = p1.client.WANMembers()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(mem) != 2 {
		t.Fatalf("bad: %#v", mem)
	}
}

func TestRPCClientStats(t *testing.T) {
	p1 := testRPCClient(t)
	defer p1.Close()

	stats, err := p1.client.Stats()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if _, ok := stats["agent"]; !ok {
		t.Fatalf("bad: %#v", stats)
	}

	if _, ok := stats["consul"]; !ok {
		t.Fatalf("bad: %#v", stats)
	}
}

func TestRPCClientLeave(t *testing.T) {
	p1 := testRPCClient(t)
	defer p1.Close()

	if err := p1.client.Leave(); err != nil {
		t.Fatalf("err: %s", err)
	}

	time.Sleep(1 * time.Second)

	select {
	case <-p1.agent.ShutdownCh():
	default:
		t.Fatalf("agent should be shutdown!")
	}
}

func TestRPCClientMonitor(t *testing.T) {
	p1 := testRPCClient(t)
	defer p1.Close()

	eventCh := make(chan string, 64)
	if handle, err := p1.client.Monitor("debug", eventCh); err != nil {
		t.Fatalf("err: %s", err)
	} else {
		defer p1.client.Stop(handle)
	}

	found := false
OUTER1:
	for {
		select {
		case e := <-eventCh:
			if strings.Contains(e, "Accepted client") {
				found = true
				break OUTER1
			}
		default:
		}
	}
	if !found {
		t.Fatalf("should log client accept")
	}

	// Join a bad thing to generate more events
	p1.agent.JoinLAN(nil)

	time.Sleep(1 * time.Second)

	found = false
OUTER2:
	for {
		select {
		case e := <-eventCh:
			if strings.Contains(e, "joining") {
				found = true
			}
		default:
			break OUTER2
		}
	}
	if !found {
		t.Fatalf("should log joining")
	}
}
<|endoftext|>


<commit_before>/* status.dat handling */

package nagios

import (
	"bufio"
	"io"
	"regexp"
	"sync"
)

var blockStartRegex = regexp.MustCompile(`^(contactstatus|hoststatus|info|programstatus|servicecomment|servicestatus)\s\{`)
var blockEndRegex = regexp.MustCompile(`^\s}$`)
var kvRegex = regexp.MustCompile(`^\s*(\S+?)=(.*)$`)

type Status struct {
	Host    map[string]Host               `json:"host,omitempty"`
	Service map[string]map[string]Service `json:"service,omitempty"`
	Summary Summary                       `json:"summary,omitempty"`
	sync.RWMutex
}

func LoadStatus(r io.Reader) (Status, error) {
	var status Status
	var err error
	scanner := bufio.NewScanner(r)
	status.Host = make(map[string]Host)
	status.Service = make(map[string]map[string]Service)
	block_type := ""
	block_content := make(map[string]string)
	for scanner.Scan() {
		t := scanner.Text()
		match := blockStartRegex.FindStringSubmatch(t)
		if len(match) > 1 {
			block_type = match[1]
			continue
		}
		match = kvRegex.FindStringSubmatch(t)
		if len(match) > 1 {
			block_content[match[1]] = match[2]
			continue
		}
		if blockEndRegex.MatchString(t) {
			if block_type == "servicestatus" {
				s, err := NewServiceFromMap(block_content)
				if err == nil {
					if status.Service[s.Hostname] == nil {
						status.Service[s.Hostname] = make(map[string]Service)
					}
					status.Service[s.Hostname][s.Description] = s

				} else {
					return status, err
				}

			} else if block_type == "hoststatus" {
				h, err := NewHostFromMap(block_content)
				if err == nil {
					status.Host[h.Hostname] = h
				} else {
					return status, err
				}

			}
			//end of block summary ,cleanup vars
			block_type = ""
			block_content = make(map[string]string)
			continue
		}
	}
	status.Summary.UpdateHost(status.Host)
	status.Summary.UpdateService(status.Service)
	return status, err
}

func (s *Status) UpdateStatus(r io.Reader) error {
	status, err := LoadStatus(r)
	s.Lock()
	s.Host = status.Host
	s.Service = status.Service
	s.Unlock()
	return err
}
<commit_msg>fix update<commit_after>/* status.dat handling */

package nagios

import (
	"bufio"
	"io"
	"regexp"
	"sync"
)

var blockStartRegex = regexp.MustCompile(`^(contactstatus|hoststatus|info|programstatus|servicecomment|servicestatus)\s\{`)
var blockEndRegex = regexp.MustCompile(`^\s}$`)
var kvRegex = regexp.MustCompile(`^\s*(\S+?)=(.*)$`)

type Status struct {
	Host    map[string]Host               `json:"host,omitempty"`
	Service map[string]map[string]Service `json:"service,omitempty"`
	Summary Summary                       `json:"summary,omitempty"`
	sync.RWMutex
}

func LoadStatus(r io.Reader) (Status, error) {
	var status Status
	var err error
	scanner := bufio.NewScanner(r)
	status.Host = make(map[string]Host)
	status.Service = make(map[string]map[string]Service)
	block_type := ""
	block_content := make(map[string]string)
	for scanner.Scan() {
		t := scanner.Text()
		match := blockStartRegex.FindStringSubmatch(t)
		if len(match) > 1 {
			block_type = match[1]
			continue
		}
		match = kvRegex.FindStringSubmatch(t)
		if len(match) > 1 {
			block_content[match[1]] = match[2]
			continue
		}
		if blockEndRegex.MatchString(t) {
			if block_type == "servicestatus" {
				s, err := NewServiceFromMap(block_content)
				if err == nil {
					if status.Service[s.Hostname] == nil {
						status.Service[s.Hostname] = make(map[string]Service)
					}
					status.Service[s.Hostname][s.Description] = s

				} else {
					return status, err
				}

			} else if block_type == "hoststatus" {
				h, err := NewHostFromMap(block_content)
				if err == nil {
					status.Host[h.Hostname] = h
				} else {
					return status, err
				}

			}
			//end of block summary ,cleanup vars
			block_type = ""
			block_content = make(map[string]string)
			continue
		}
	}
	status.Summary.UpdateHost(status.Host)
	status.Summary.UpdateService(status.Service)
	return status, err
}

func (s *Status) UpdateStatus(r io.Reader) error {
	status, err := LoadStatus(r)
	s.Lock()
	s.Host = status.Host
	s.Service = status.Service
	s.Summary = status.Summary
	s.Unlock()
	return err
}
<|endoftext|>


<commit_before>package eventemitter

import (
	"testing"
	"time"
)

func TestEmitterSynced(t *testing.T) {
	testEmitter(t, false)
}

func TestEmitterAsync(t *testing.T) {
	testEmitter(t, true)
}

func testEmitter(t *testing.T, async bool) {
	var em EventEmitter
	var ob Observable

	e := NewEmitter(async)
	em = e
	ob = e

	var ASingle, AListener, capture int

	listener := ob.AddListener("test event A", func(args ...interface{}) {
		verifyArgs(t, args)
		AListener++
	})

	ob.ListenOnce("test event A", func(args ...interface{}) {
		verifyArgs(t, args)
		ASingle++
	})

	capturer := ob.AddCapturer(func(event EventType, args ...interface{}) {
		verifyArgs(t, args)
		capture++
	})

	em.EmitEvent("test event A", "test", 123, true)
	em.EmitEvent("test event B", "test", 123, true)
	em.EmitEvent("test event C", "test", 123, true)
	em.EmitEvent("test event A", "test", 123, true)
	em.EmitEvent("test event A", "test", 123, true)

	ob.RemoveListener("test event A", listener)
	ob.RemoveCapturer(capturer)

	em.EmitEvent("Testing 123", 1)
	em.EmitEvent("test event A", 1)
	em.EmitEvent("Wow", 2)

	if async {
		// Events are async, so wait a bit for them to finish
		time.Sleep(time.Millisecond * 100)
	}

	if ASingle != 1 {
		t.Log("Single A event not triggered right", ASingle)
		t.Fail()
	}
	if AListener != 3 {
		t.Log("A event not triggered right", AListener)
		t.Fail()
	}
	if capture != 5 {
		t.Log("Capture all not triggered right", capture)
		t.Fail()
	}
}

func verifyArgs(t *testing.T, args []interface{}) {
	if len(args) != 3 {
		t.Logf("Too few arguments (%d) %#v", len(args), args)
		t.Fail()
		return
	}

	s, ok := args[0].(string)
	if !ok || s != "test" {
		t.Log("Wrong argument for 1:test!")
		t.Fail()
	}

	i, ok := args[1].(int)
	if !ok || i != 123 {
		t.Log("Wrong argument for 2:123!")
		t.Fail()
	}

	b, ok := args[2].(bool)
	if !ok || b != true {
		t.Log("Wrong argument for 3:true!")
		t.Fail()
	}
}

func TestEmitNonAsyncRecursive(t *testing.T) {
	e := NewEmitter(false)

	var rootFired int
	e.AddListener("rootevent", func(args ...interface{}) {
		rootFired++
		e.EmitEvent("subevent", 1, 2, 3)
		e.EmitEvent("subevent", 1, 2, 3)
	})

	var subFired int
	e.AddListener("subevent", func(args ...interface{}) {
		if len(args) != 3 {
			t.Logf("Too few arguments (%d) %#v", len(args), args)
			t.Fail()
			return
		}
		subFired++
	})

	e.EmitEvent("rootevent", "test")

	if rootFired != 1 {
		t.Log("Root event all not triggered right", rootFired)
		t.Fail()
	}

	if subFired != 2 {
		t.Log("Sub event all not triggered right", subFired)
		t.Fail()
	}
}
<commit_msg>Fix dataraces in go test<commit_after>package eventemitter

import (
	"sync/atomic"
	"testing"
	"time"
)

func TestEmitterSynced(t *testing.T) {
	testEmitter(t, false)
}

func TestEmitterAsync(t *testing.T) {
	testEmitter(t, true)
}

func testEmitter(t *testing.T, async bool) {
	var em EventEmitter
	var ob Observable

	e := NewEmitter(async)
	em = e
	ob = e

	var ASingle, AListener, capture int32

	listener := ob.AddListener("test event A", func(args ...interface{}) {
		verifyArgs(t, args)
		atomic.AddInt32(&AListener, 1)
	})

	ob.ListenOnce("test event A", func(args ...interface{}) {
		verifyArgs(t, args)
		atomic.AddInt32(&ASingle, 1)
	})

	capturer := ob.AddCapturer(func(event EventType, args ...interface{}) {
		verifyArgs(t, args)
		atomic.AddInt32(&capture, 1)
	})

	em.EmitEvent("test event A", "test", 123, true)
	em.EmitEvent("test event B", "test", 123, true)
	em.EmitEvent("test event C", "test", 123, true)
	em.EmitEvent("test event A", "test", 123, true)
	em.EmitEvent("test event A", "test", 123, true)

	ob.RemoveListener("test event A", listener)
	ob.RemoveCapturer(capturer)

	em.EmitEvent("Testing 123", 1)
	em.EmitEvent("test event A", 1)
	em.EmitEvent("Wow", 2)

	if async {
		// Events are async, so wait a bit for them to finish
		time.Sleep(time.Millisecond * 200)
	}

	if atomic.LoadInt32(&ASingle) != 1 {
		t.Log("Single A event not triggered right", atomic.LoadInt32(&ASingle))
		t.Fail()
	}
	if atomic.LoadInt32(&AListener) != 3 {
		t.Log("A event not triggered right", atomic.LoadInt32(&AListener))
		t.Fail()
	}
	if atomic.LoadInt32(&capture) != 5 {
		t.Log("Capture all not triggered right", atomic.LoadInt32(&capture))
		t.Fail()
	}
}

func verifyArgs(t *testing.T, args []interface{}) {
	if len(args) != 3 {
		t.Logf("Too few arguments (%d) %#v", len(args), args)
		t.Fail()
		return
	}

	s, ok := args[0].(string)
	if !ok || s != "test" {
		t.Log("Wrong argument for 1:test!")
		t.Fail()
	}

	i, ok := args[1].(int)
	if !ok || i != 123 {
		t.Log("Wrong argument for 2:123!")
		t.Fail()
	}

	b, ok := args[2].(bool)
	if !ok || b != true {
		t.Log("Wrong argument for 3:true!")
		t.Fail()
	}
}

func TestEmitNonAsyncRecursive(t *testing.T) {
	e := NewEmitter(false)

	var rootFired int
	e.AddListener("rootevent", func(args ...interface{}) {
		rootFired++
		e.EmitEvent("subevent", 1, 2, 3)
		e.EmitEvent("subevent", 1, 2, 3)
	})

	var subFired int
	e.AddListener("subevent", func(args ...interface{}) {
		if len(args) != 3 {
			t.Logf("Too few arguments (%d) %#v", len(args), args)
			t.Fail()
			return
		}
		subFired++
	})

	e.EmitEvent("rootevent", "test")

	if rootFired != 1 {
		t.Log("Root event all not triggered right", rootFired)
		t.Fail()
	}

	if subFired != 2 {
		t.Log("Sub event all not triggered right", subFired)
		t.Fail()
	}
}
<|endoftext|>