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

package lsp

import (
	"context"
	"fmt"
	"strings"
	"sync"

	"golang.org/x/tools/internal/lsp/debug/tag"
	"golang.org/x/tools/internal/lsp/mod"
	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/telemetry/event"
	"golang.org/x/tools/internal/xcontext"
)

type diagnosticKey struct {
	id           source.FileIdentity
	withAnalysis bool
}

func (s *Server) diagnoseDetached(snapshot source.Snapshot) {
	ctx := snapshot.View().BackgroundContext()
	ctx = xcontext.Detach(ctx)

	reports := s.diagnose(ctx, snapshot, false)
	s.publishReports(ctx, snapshot, reports)
}

func (s *Server) diagnoseSnapshot(snapshot source.Snapshot) {
	ctx := snapshot.View().BackgroundContext()

	reports := s.diagnose(ctx, snapshot, false)
	s.publishReports(ctx, snapshot, reports)
}

// diagnose is a helper function for running diagnostics with a given context.
// Do not call it directly.
func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, alwaysAnalyze bool) map[diagnosticKey][]source.Diagnostic {
	ctx, done := event.StartSpan(ctx, "lsp:background-worker")
	defer done()

	// Wait for a free diagnostics slot.
	select {
	case <-ctx.Done():
		return nil
	case s.diagnosticsSema <- struct{}{}:
	}
	defer func() { <-s.diagnosticsSema }()

	allReports := make(map[diagnosticKey][]source.Diagnostic)
	var reportsMu sync.Mutex
	var wg sync.WaitGroup

	// Diagnose the go.mod file.
	reports, missingModules, err := mod.Diagnostics(ctx, snapshot)
	if ctx.Err() != nil {
		return nil
	}
	if err != nil {
		event.Error(ctx, "diagnose: could not generate diagnostics for go.mod file", err)
	}
	// Ensure that the reports returned from mod.Diagnostics are only related to the
	// go.mod file for the module.
	if len(reports) > 1 {
		panic("unexpected reports from mod.Diagnostics")
	}
	modURI, _ := snapshot.View().ModFiles()
	for id, diags := range reports {
		if id.URI != modURI {
			panic("unexpected reports from mod.Diagnostics")
		}
		key := diagnosticKey{
			id: id,
		}
		allReports[key] = diags
	}

	// Diagnose all of the packages in the workspace.
	wsPackages, err := snapshot.WorkspacePackages(ctx)
	if ctx.Err() != nil {
		return nil
	}
	if err != nil {
		// If we encounter a genuine error when getting workspace packages,
		// notify the user.
		s.showedInitialErrorMu.Lock()
		if !s.showedInitialError {
			err := s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
				Type:    protocol.Error,
				Message: fmt.Sprintf("Your workspace is misconfigured: %s. Please see https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md for more information or file an issue (https://github.com/golang/go/issues/new) if you believe this is a mistake.", err.Error()),
			})
			s.showedInitialError = err == nil
		}
		s.showedInitialErrorMu.Unlock()

		event.Error(ctx, "diagnose: no workspace packages", err, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder))
		return nil
	}
	for _, ph := range wsPackages {
		wg.Add(1)
		go func(ph source.PackageHandle) {
			defer wg.Done()
			// Only run analyses for packages with open files.
			withAnalyses := alwaysAnalyze
			for _, fh := range ph.CompiledGoFiles() {
				if snapshot.IsOpen(fh.File().Identity().URI) {
					withAnalyses = true
				}
			}
			reports, warn, err := source.Diagnostics(ctx, snapshot, ph, missingModules, withAnalyses)
			// Check if might want to warn the user about their build configuration.
			if warn && !snapshot.View().ValidBuildConfiguration() {
				s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
					Type:    protocol.Warning,
					Message: `You are neither in a module nor in your GOPATH. If you are using modules, please open your editor at the directory containing the go.mod. If you believe this warning is incorrect, please file an issue: https://github.com/golang/go/issues/new.`,
				})
			}
			if ctx.Err() != nil {
				return
			}
			if err != nil {
				event.Error(ctx, "diagnose: could not generate diagnostics for package", err, tag.Snapshot.Of(snapshot.ID()), tag.Package.Of(ph.ID()))
				return
			}
			reportsMu.Lock()
			for id, diags := range reports {
				key := diagnosticKey{
					id:           id,
					withAnalysis: withAnalyses,
				}
				allReports[key] = diags
			}
			reportsMu.Unlock()
		}(ph)
	}
	wg.Wait()
	return allReports
}

func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, reports map[diagnosticKey][]source.Diagnostic) {
	// Check for context cancellation before publishing diagnostics.
	if ctx.Err() != nil {
		return
	}

	s.deliveredMu.Lock()
	defer s.deliveredMu.Unlock()

	for key, diagnostics := range reports {
		// Don't deliver diagnostics if the context has already been canceled.
		if ctx.Err() != nil {
			break
		}

		// Pre-sort diagnostics to avoid extra work when we compare them.
		source.SortDiagnostics(diagnostics)
		toSend := sentDiagnostics{
			version:      key.id.Version,
			identifier:   key.id.Identifier,
			sorted:       diagnostics,
			withAnalysis: key.withAnalysis,
			snapshotID:   snapshot.ID(),
		}

		// We use the zero values if this is an unknown file.
		delivered := s.delivered[key.id.URI]

		// Snapshot IDs are always increasing, so we use them instead of file
		// versions to create the correct order for diagnostics.

		// If we've already delivered diagnostics for a future snapshot for this file,
		// do not deliver them.
		if delivered.snapshotID > toSend.snapshotID {
			// Do not update the delivered map since it already contains newer diagnostics.
			continue
		}

		// Check if we should reuse the cached diagnostics.
		if equalDiagnostics(delivered.sorted, diagnostics) {
			// Make sure to update the delivered map.
			s.delivered[key.id.URI] = toSend
			continue
		}

		// If we've already delivered diagnostics for this file, at this
		// snapshot, with analyses, do not send diagnostics without analyses.
		if delivered.snapshotID == toSend.snapshotID && delivered.version == toSend.version &&
			delivered.withAnalysis && !toSend.withAnalysis {
			// Do not update the delivered map since it already contains better diagnostics.
			continue
		}

		if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
			Diagnostics: toProtocolDiagnostics(diagnostics),
			URI:         protocol.URIFromSpanURI(key.id.URI),
			Version:     key.id.Version,
		}); err != nil {
			if ctx.Err() == nil {
				event.Error(ctx, "publishReports: failed to deliver diagnostic", err, tag.URI.Of(key.id.URI))
			}
			continue
		}
		// Update the delivered map.
		s.delivered[key.id.URI] = toSend
	}
}

// equalDiagnostics returns true if the 2 lists of diagnostics are equal.
// It assumes that both a and b are already sorted.
func equalDiagnostics(a, b []source.Diagnostic) bool {
	if len(a) != len(b) {
		return false
	}
	for i := 0; i < len(a); i++ {
		if source.CompareDiagnostic(a[i], b[i]) != 0 {
			return false
		}
	}
	return true
}

func toProtocolDiagnostics(diagnostics []source.Diagnostic) []protocol.Diagnostic {
	reports := []protocol.Diagnostic{}
	for _, diag := range diagnostics {
		related := make([]protocol.DiagnosticRelatedInformation, 0, len(diag.Related))
		for _, rel := range diag.Related {
			related = append(related, protocol.DiagnosticRelatedInformation{
				Location: protocol.Location{
					URI:   protocol.URIFromSpanURI(rel.URI),
					Range: rel.Range,
				},
				Message: rel.Message,
			})
		}
		reports = append(reports, protocol.Diagnostic{
			Message:            strings.TrimSpace(diag.Message), // go list returns errors prefixed by newline
			Range:              diag.Range,
			Severity:           diag.Severity,
			Source:             diag.Source,
			Tags:               diag.Tags,
			RelatedInformation: related,
		})
	}
	return reports
}
<commit_msg>internal/lsp: be more careful about showing workspace misconfig message<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lsp

import (
	"context"
	"fmt"
	"strings"
	"sync"

	"golang.org/x/tools/internal/lsp/debug/tag"
	"golang.org/x/tools/internal/lsp/mod"
	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/telemetry/event"
	"golang.org/x/tools/internal/xcontext"
)

type diagnosticKey struct {
	id           source.FileIdentity
	withAnalysis bool
}

func (s *Server) diagnoseDetached(snapshot source.Snapshot) {
	ctx := snapshot.View().BackgroundContext()
	ctx = xcontext.Detach(ctx)

	reports := s.diagnose(ctx, snapshot, false)
	s.publishReports(ctx, snapshot, reports)
}

func (s *Server) diagnoseSnapshot(snapshot source.Snapshot) {
	ctx := snapshot.View().BackgroundContext()

	reports := s.diagnose(ctx, snapshot, false)
	s.publishReports(ctx, snapshot, reports)
}

// diagnose is a helper function for running diagnostics with a given context.
// Do not call it directly.
func (s *Server) diagnose(ctx context.Context, snapshot source.Snapshot, alwaysAnalyze bool) map[diagnosticKey][]source.Diagnostic {
	ctx, done := event.StartSpan(ctx, "lsp:background-worker")
	defer done()

	// Wait for a free diagnostics slot.
	select {
	case <-ctx.Done():
		return nil
	case s.diagnosticsSema <- struct{}{}:
	}
	defer func() { <-s.diagnosticsSema }()

	allReports := make(map[diagnosticKey][]source.Diagnostic)
	var reportsMu sync.Mutex
	var wg sync.WaitGroup

	// Diagnose the go.mod file.
	reports, missingModules, err := mod.Diagnostics(ctx, snapshot)
	if ctx.Err() != nil {
		return nil
	}
	if err != nil {
		event.Error(ctx, "diagnose: could not generate diagnostics for go.mod file", err)
	}
	// Ensure that the reports returned from mod.Diagnostics are only related to the
	// go.mod file for the module.
	if len(reports) > 1 {
		panic("unexpected reports from mod.Diagnostics")
	}
	modURI, _ := snapshot.View().ModFiles()
	for id, diags := range reports {
		if id.URI != modURI {
			panic("unexpected reports from mod.Diagnostics")
		}
		key := diagnosticKey{
			id: id,
		}
		allReports[key] = diags
	}

	// Diagnose all of the packages in the workspace.
	wsPackages, err := snapshot.WorkspacePackages(ctx)
	if ctx.Err() != nil {
		return nil
	}
	// If we encounter a genuine error when getting workspace packages,
	// notify the user that their workspace may be misconfigured.
	if err != nil {
		// TODO(golang/go#37971): Remove this guard.
		if !snapshot.View().ValidBuildConfiguration() {
			s.showedInitialErrorMu.Lock()
			if !s.showedInitialError {
				err := s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
					Type:    protocol.Error,
					Message: fmt.Sprintf("Your workspace is misconfigured: %s. Please see https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md for more information or file an issue (https://github.com/golang/go/issues/new) if you believe this is a mistake.", err.Error()),
				})
				s.showedInitialError = err == nil
			}
			s.showedInitialErrorMu.Unlock()
		}
		event.Error(ctx, "diagnose: no workspace packages", err, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder))
		return nil
	}
	for _, ph := range wsPackages {
		wg.Add(1)
		go func(ph source.PackageHandle) {
			defer wg.Done()
			// Only run analyses for packages with open files.
			withAnalyses := alwaysAnalyze
			for _, fh := range ph.CompiledGoFiles() {
				if snapshot.IsOpen(fh.File().Identity().URI) {
					withAnalyses = true
				}
			}
			reports, warn, err := source.Diagnostics(ctx, snapshot, ph, missingModules, withAnalyses)
			// Check if might want to warn the user about their build configuration.
			if warn && !snapshot.View().ValidBuildConfiguration() {
				s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
					Type:    protocol.Warning,
					Message: `You are neither in a module nor in your GOPATH. If you are using modules, please open your editor at the directory containing the go.mod. If you believe this warning is incorrect, please file an issue: https://github.com/golang/go/issues/new.`,
				})
			}
			if ctx.Err() != nil {
				return
			}
			if err != nil {
				event.Error(ctx, "diagnose: could not generate diagnostics for package", err, tag.Snapshot.Of(snapshot.ID()), tag.Package.Of(ph.ID()))
				return
			}
			reportsMu.Lock()
			for id, diags := range reports {
				key := diagnosticKey{
					id:           id,
					withAnalysis: withAnalyses,
				}
				allReports[key] = diags
			}
			reportsMu.Unlock()
		}(ph)
	}
	wg.Wait()
	return allReports
}

func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, reports map[diagnosticKey][]source.Diagnostic) {
	// Check for context cancellation before publishing diagnostics.
	if ctx.Err() != nil {
		return
	}

	s.deliveredMu.Lock()
	defer s.deliveredMu.Unlock()

	for key, diagnostics := range reports {
		// Don't deliver diagnostics if the context has already been canceled.
		if ctx.Err() != nil {
			break
		}

		// Pre-sort diagnostics to avoid extra work when we compare them.
		source.SortDiagnostics(diagnostics)
		toSend := sentDiagnostics{
			version:      key.id.Version,
			identifier:   key.id.Identifier,
			sorted:       diagnostics,
			withAnalysis: key.withAnalysis,
			snapshotID:   snapshot.ID(),
		}

		// We use the zero values if this is an unknown file.
		delivered := s.delivered[key.id.URI]

		// Snapshot IDs are always increasing, so we use them instead of file
		// versions to create the correct order for diagnostics.

		// If we've already delivered diagnostics for a future snapshot for this file,
		// do not deliver them.
		if delivered.snapshotID > toSend.snapshotID {
			// Do not update the delivered map since it already contains newer diagnostics.
			continue
		}

		// Check if we should reuse the cached diagnostics.
		if equalDiagnostics(delivered.sorted, diagnostics) {
			// Make sure to update the delivered map.
			s.delivered[key.id.URI] = toSend
			continue
		}

		// If we've already delivered diagnostics for this file, at this
		// snapshot, with analyses, do not send diagnostics without analyses.
		if delivered.snapshotID == toSend.snapshotID && delivered.version == toSend.version &&
			delivered.withAnalysis && !toSend.withAnalysis {
			// Do not update the delivered map since it already contains better diagnostics.
			continue
		}

		if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
			Diagnostics: toProtocolDiagnostics(diagnostics),
			URI:         protocol.URIFromSpanURI(key.id.URI),
			Version:     key.id.Version,
		}); err != nil {
			if ctx.Err() == nil {
				event.Error(ctx, "publishReports: failed to deliver diagnostic", err, tag.URI.Of(key.id.URI))
			}
			continue
		}
		// Update the delivered map.
		s.delivered[key.id.URI] = toSend
	}
}

// equalDiagnostics returns true if the 2 lists of diagnostics are equal.
// It assumes that both a and b are already sorted.
func equalDiagnostics(a, b []source.Diagnostic) bool {
	if len(a) != len(b) {
		return false
	}
	for i := 0; i < len(a); i++ {
		if source.CompareDiagnostic(a[i], b[i]) != 0 {
			return false
		}
	}
	return true
}

func toProtocolDiagnostics(diagnostics []source.Diagnostic) []protocol.Diagnostic {
	reports := []protocol.Diagnostic{}
	for _, diag := range diagnostics {
		related := make([]protocol.DiagnosticRelatedInformation, 0, len(diag.Related))
		for _, rel := range diag.Related {
			related = append(related, protocol.DiagnosticRelatedInformation{
				Location: protocol.Location{
					URI:   protocol.URIFromSpanURI(rel.URI),
					Range: rel.Range,
				},
				Message: rel.Message,
			})
		}
		reports = append(reports, protocol.Diagnostic{
			Message:            strings.TrimSpace(diag.Message), // go list returns errors prefixed by newline
			Range:              diag.Range,
			Severity:           diag.Severity,
			Source:             diag.Source,
			Tags:               diag.Tags,
			RelatedInformation: related,
		})
	}
	return reports
}
<|endoftext|>


<commit_before>package network

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"github.com/araframework/aradg/internal/consts"
	"github.com/araframework/aradg/internal/utils/conf"
	"log"
	"net"
	"time"
)

type Cluster struct {
	listener  net.Listener
	option    *conf.ClusterOption
	leader    bool
	startTime int64
}

type Data struct {
	Magic  uint16
	Leader bool
}

func NewCluster() *Cluster {
	c := &Cluster{}
	c.option = conf.LoadCluster()
	if c.option == nil {
		log.Fatal("Initialize conf failed.")
	}
	c.leader = false
	c.startTime = time.Now().UnixNano()
	return c
}

func (c *Cluster) Start() {
	go c.listen()
	time.Sleep(time.Second)
	go c.join()
}

func (c *Cluster) listen() {
	listener, err := net.Listen("tcp", c.option.Network.Interface)
	if err != nil {
		log.Fatal(err)
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}
		go c.handleConnection(conn)
	}
}

func (c *Cluster) join() {
	for _, value := range c.option.Network.Join["tcp-ip"] {
		if value == c.option.Network.Interface {
			//continue
		}
		conn, err := net.Dial("tcp", value)
		if err != nil {
			log.Fatal(err)
		}

		buf := new(bytes.Buffer)
		err = binary.Write(buf, binary.LittleEndian, Data{consts.CmdMagic, true})
		if err != nil {
			log.Fatal(err)
		}
		conn.Write(buf.Bytes())
	}
}

func (c *Cluster) Stop() {
	if c.listener != nil {
		c.listener.Close()
	}
}

func (c *Cluster) handleConnection(conn net.Conn) {
	//d := Data{}
	d := make([]byte, 8)
	i, err := conn.Read(d)
	fmt.Println(i, err)
	//err := binary.Read(conn, binary.LittleEndian, d)
	//fmt.Println("read done")
	//if err != nil {
	//	fmt.Println("binary.Read failed:", err)
	//}

	fmt.Printf("bin:% x\n", d)
	conn.Close()
}
<commit_msg>cluster<commit_after>package network

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"github.com/araframework/aradg/internal/consts"
	"github.com/araframework/aradg/internal/utils/conf"
	"log"
	"net"
	"time"
)

type Cluster struct {
	listener  net.Listener
	option    *conf.ClusterOption
	leader    bool
	startTime int64
}

// request for join and cluster members
type Data struct {
	Magic     uint16
	Leader    bool
	StartTime int64
	Members   []Member
}

type Member struct {
	Leader    bool
	StartTime int64
	Interface string
}

// new Cluster instance
func NewCluster() *Cluster {
	c := &Cluster{}
	c.option = conf.LoadCluster()
	if c.option == nil {
		log.Fatal("Initialize conf failed.")
	}
	c.leader = false
	c.startTime = time.Now().UnixNano()
	return c
}

// start this Cluster
func (c *Cluster) Start() {
	go c.listen()
	time.Sleep(time.Second)
	go c.join()
}

// stop this cluster
func (c *Cluster) Stop() {
	if c.listener != nil {
		c.listener.Close()
	}
}

func (c *Cluster) listen() {
	listener, err := net.Listen("tcp", c.option.Network.Interface)
	if err != nil {
		log.Fatal(err)
	}
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}
		go c.handleConnection(conn)
	}
}

func (c *Cluster) join() {
	for _, value := range c.option.Network.Join["tcp-ip"] {
		// skip self
		if value == c.option.Network.Interface {
			//continue
		}
		conn, err := net.Dial("tcp", value)
		if err != nil {
			log.Fatal(err)
		}

		var buf bytes.Buffer
		memberSelf := Member{false, c.startTime, c.option.Network.Interface}
		data := Data{consts.CmdMagic, false, c.startTime, []Member{memberSelf}}
		enc := gob.NewEncoder(&buf) // Will write to network.

		// Encode (send) some values.
		err = enc.Encode(data)
		if err != nil {
			log.Fatal("encode error:", err)
		}
		conn.Write(buf.Bytes())
	}
}

func (c *Cluster) handleConnection(conn net.Conn) {
	d := Data{}
	dec := gob.NewDecoder(conn) // Will read from network.
	err := dec.Decode(&d)
	if err != nil {
		log.Fatal("decode error 1:", err)
	}
	fmt.Printf("%q: {%d, %d}\n", d.StartTime, d.Leader, d.Magic)

	fmt.Printf("bin:%v\n", d)
	conn.Close()
}
<|endoftext|>


<commit_before>// Package util contains common functionality for "utilities" required by the
// bot.
//
// This file is for processing the application's configuration from a YAML file.
package util

import (
	"fmt"
	"io/ioutil"
	"time"

	"github.com/shibukawa/configdir"
	"github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
)

const (
	configFilename  = "config.yaml" // These default values are used to create a
	vendorName      = "netsplit"    // filename for loading a file from the
	applicationName = "metal"       // platform's standard config location.

	defaultPort     = 6667
	defaultNickname = "metalbot"
	defaultLogLevel = "info"

	defaultCommandTrigger = "!"
)

// pluginConfig contains plugin-specific configuration.
type pluginConfig struct {
	Name    string
	Options map[string]interface{}
}

// ircConfig contains config items specific to the IRC bot itself.
type ircConfig struct {
	Channels         []string      `yaml:"channels"`
	CommandTrigger   string        `yaml:"command_trigger"`
	Debug            bool          `yaml:"debug"`
	Ident            string        `yaml:"ident"`
	MaxReconnect     int           `yaml:"max_reconnect"`
	ReconnectDelay   time.Duration `yaml:"reconnect_delay"`
	Modes            string        `yaml:"modes"`
	Nickname         string        `yaml:"nickname"`
	NickservAccount  string        `yaml:"nickserv_account"`
	NickservPassword string        `yaml:"nickserv_password"`
	Port             int           `yaml:"port"`
	RealName         string        `yaml:"real_name"`
	Server           string        `yaml:"server"`
	ServerPassword   string        `yaml:"server_password"`
	UseTLS           bool          `yaml:"use_tls"`
	Verbose          bool          `yaml:"verbose"`

	Hostname              string
	ReconnectDelayMinutes time.Duration
}

// Config contains the entire application's configuration.
type Config struct {
	IRC              *ircConfig               `yaml:"irc"`
	Plugins          map[string]*pluginConfig `yaml:"plugins"`
	UnparsedLogLevel string                   `yaml:"log_level"`

	LogLevel logrus.Level
}

// NewConfig sets up the application's configuration.
func NewConfig(params ...string) *Config {
	config := &Config{}
	config.Plugins = make(map[string]*pluginConfig)

	data, err := loadConfigData(params)

	if err != nil {
		panic(err)
	}

	err = yaml.Unmarshal(data, config)

	if err != nil {
		panic(err)
	}

	config.applyDefaults()

	return config
}

// loadConfigData retrieves bytes from the config file. An optional filename can
// be provided to load configuration from a specific file rather than the
// default set for configdir.
func loadConfigData(params []string) ([]byte, error) {
	var (
		err      error
		data     []byte
		filename string
	)

	if len(params) > 0 {
		filename = params[0]

		data, err = ioutil.ReadFile(filename)
	} else {
		configDirs := configdir.New(vendorName, applicationName)
		folder := configDirs.QueryFolderContainsFile(configFilename)

		if folder != nil {
			data, err = folder.ReadFile(configFilename)
		}
	}

	if err != nil {
		panic(err)
	}

	return data, err
}

// applyDefaults sets default configuration values for items which are missing.
func (c *Config) applyDefaults() {
	if c.IRC == nil {
		c.IRC = &ircConfig{}
	}

	if c.IRC.Port == 0 {
		c.IRC.Port = defaultPort
	}

	if c.IRC.Nickname == "" {
		c.IRC.Nickname = defaultNickname
	}

	if c.IRC.Ident == "" {
		c.IRC.Ident = c.IRC.Nickname
	}

	if c.IRC.RealName == "" {
		c.IRC.RealName = c.IRC.Nickname
	}

	if c.IRC.NickservAccount == "" {
		c.IRC.NickservAccount = c.IRC.Nickname
	}

	if c.IRC.ReconnectDelay == 0 {
		c.IRC.ReconnectDelay = time.Duration(600 * time.Second)
	}

	if c.IRC.CommandTrigger == "" {
		c.IRC.CommandTrigger = defaultCommandTrigger
	}

	c.IRC.Hostname = fmt.Sprintf("%s:%d", c.IRC.Server, c.IRC.Port)

	c.setLogLevel()
}

// setLogLevel parses the configured logging level into one understood by
// logrus.
func (c *Config) setLogLevel() {
	level, err := logrus.ParseLevel(c.UnparsedLogLevel)

	if err != nil {
		level = logrus.InfoLevel
	}

	c.LogLevel = level
}
<commit_msg>Add default value for config.IRC.MaxReconnect (3)<commit_after>// Package util contains common functionality for "utilities" required by the
// bot.
//
// This file is for processing the application's configuration from a YAML file.
package util

import (
	"fmt"
	"io/ioutil"
	"time"

	"github.com/shibukawa/configdir"
	"github.com/sirupsen/logrus"
	"gopkg.in/yaml.v2"
)

const (
	configFilename  = "config.yaml" // These default values are used to create a
	vendorName      = "netsplit"    // filename for loading a file from the
	applicationName = "metal"       // platform's standard config location.

	defaultPort           = 6667
	defaultNickname       = "metalbot"
	defaultLogLevel       = "info"
	defaultCommandTrigger = "!"
	defaultMaxReconnect   = 3
)

// pluginConfig contains plugin-specific configuration.
type pluginConfig struct {
	Name    string
	Options map[string]interface{}
}

// ircConfig contains config items specific to the IRC bot itself.
type ircConfig struct {
	Channels         []string      `yaml:"channels"`
	CommandTrigger   string        `yaml:"command_trigger"`
	Debug            bool          `yaml:"debug"`
	Ident            string        `yaml:"ident"`
	MaxReconnect     int           `yaml:"max_reconnect"`
	ReconnectDelay   time.Duration `yaml:"reconnect_delay"`
	Modes            string        `yaml:"modes"`
	Nickname         string        `yaml:"nickname"`
	NickservAccount  string        `yaml:"nickserv_account"`
	NickservPassword string        `yaml:"nickserv_password"`
	Port             int           `yaml:"port"`
	RealName         string        `yaml:"real_name"`
	Server           string        `yaml:"server"`
	ServerPassword   string        `yaml:"server_password"`
	UseTLS           bool          `yaml:"use_tls"`
	Verbose          bool          `yaml:"verbose"`

	Hostname              string
	ReconnectDelayMinutes time.Duration
}

// Config contains the entire application's configuration.
type Config struct {
	IRC              *ircConfig               `yaml:"irc"`
	Plugins          map[string]*pluginConfig `yaml:"plugins"`
	UnparsedLogLevel string                   `yaml:"log_level"`

	LogLevel logrus.Level
}

// NewConfig sets up the application's configuration.
func NewConfig(params ...string) *Config {
	config := &Config{}
	config.Plugins = make(map[string]*pluginConfig)

	data, err := loadConfigData(params)

	if err != nil {
		panic(err)
	}

	err = yaml.Unmarshal(data, config)

	if err != nil {
		panic(err)
	}

	config.applyDefaults()

	return config
}

// loadConfigData retrieves bytes from the config file. An optional filename can
// be provided to load configuration from a specific file rather than the
// default set for configdir.
func loadConfigData(params []string) ([]byte, error) {
	var (
		err      error
		data     []byte
		filename string
	)

	if len(params) > 0 {
		filename = params[0]

		data, err = ioutil.ReadFile(filename)
	} else {
		configDirs := configdir.New(vendorName, applicationName)
		folder := configDirs.QueryFolderContainsFile(configFilename)

		if folder != nil {
			data, err = folder.ReadFile(configFilename)
		}
	}

	if err != nil {
		panic(err)
	}

	return data, err
}

// applyDefaults sets default configuration values for items which are missing.
func (c *Config) applyDefaults() {
	if c.IRC == nil {
		c.IRC = &ircConfig{}
	}

	if c.IRC.Port == 0 {
		c.IRC.Port = defaultPort
	}

	if c.IRC.Nickname == "" {
		c.IRC.Nickname = defaultNickname
	}

	if c.IRC.Ident == "" {
		c.IRC.Ident = c.IRC.Nickname
	}

	if c.IRC.RealName == "" {
		c.IRC.RealName = c.IRC.Nickname
	}

	if c.IRC.NickservAccount == "" {
		c.IRC.NickservAccount = c.IRC.Nickname
	}

	if c.IRC.ReconnectDelay == 0 {
		c.IRC.ReconnectDelay = time.Duration(600 * time.Second)
	}

	if c.IRC.CommandTrigger == "" {
		c.IRC.CommandTrigger = defaultCommandTrigger
	}

	if c.IRC.MaxReconnect == 0 {
		c.IRC.MaxReconnect = defaultMaxReconnect
	}

	c.IRC.Hostname = fmt.Sprintf("%s:%d", c.IRC.Server, c.IRC.Port)

	c.setLogLevel()
}

// setLogLevel parses the configured logging level into one understood by
// logrus.
func (c *Config) setLogLevel() {
	level, err := logrus.ParseLevel(c.UnparsedLogLevel)

	if err != nil {
		level = logrus.InfoLevel
	}

	c.LogLevel = level
}
<|endoftext|>


<commit_before>package version

// Version describes module version
const Version = "1.3.1"
<commit_msg>bump up version: 1.4.1<commit_after>package version

// Version describes module version
const Version = "1.4.1"
<|endoftext|>


<commit_before>package xwindow

import (
	"image"
	"image/color"
	"github.com/kbinani/screenshot/internal/util"
	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/xproto"
	"github.com/BurntSushi/xgb/xinerama"
)

func Capture(x, y, width, height int) (*image.RGBA, error) {
	c, err := xgb.NewConn()
	if err != nil {
		return nil, err
	}
	defer c.Close()

	err = xinerama.Init(c)
	reply, err := xinerama.QueryScreens(c).Reply()
	if err != nil {
		return nil, err
	}

	primary := reply.ScreenInfo[0]
	x0 := int(primary.XOrg)
	y0 := int(primary.YOrg)

	screen := xproto.Setup(c).DefaultScreen(c)
	wholeScreenBounds := image.Rect(0, 0, int(screen.WidthInPixels), int(screen.HeightInPixels))
	targetBounds := image.Rect(x + x0, y + y0, x + x0 + width, y + y0 + height)
	intersect := wholeScreenBounds.Intersect(targetBounds)

	rect := image.Rect(0, 0, width, height)
	img, err := util.CreateImage(rect)
	if err != nil {
		return nil, err
	}

	// Paint with opaque black
	index := 0
	for iy := 0; iy < height; iy++ {
		j := index
		for ix := 0; ix < width; ix++ {
			img.Pix[j + 3] = 255
			j += 4
		}
		index += img.Stride
	}

	if !intersect.Empty() {
		xImg, err := xproto.GetImage(c, xproto.ImageFormatZPixmap, xproto.Drawable(screen.Root),
					     int16(intersect.Min.X), int16(intersect.Min.Y),
					     uint16(intersect.Dx()), uint16(intersect.Dy()), 0xffffffff).Reply()
		if err != nil {
			return nil, err
		}

		// BitBlt by hand
		offset := 0
		for iy := intersect.Min.Y; iy < intersect.Max.Y; iy++ {
			for ix := intersect.Min.X; ix < intersect.Max.X; ix++ {
				r := xImg.Data[offset + 2]
				g := xImg.Data[offset + 1]
				b := xImg.Data[offset]
				img.SetRGBA(ix - (x + x0), iy - (y + y0), color.RGBA{r, g, b, 255})
				offset += 4
			}
		}
	}

	return img, nil
}

func NumActiveDisplays() int {
	c, err := xgb.NewConn()
	if err != nil {
		return 0
	}
	defer c.Close()

	err = xinerama.Init(c)
	if err != nil {
		return 0
	}

	reply, err := xinerama.QueryScreens(c).Reply()
	if err != nil {
		return 0
	}

	return int(reply.Number)
}

func GetDisplayBounds(displayIndex int) image.Rectangle {
	c, err := xgb.NewConn()
	if err != nil {
		return image.ZR
	}
	defer c.Close()

	err = xinerama.Init(c)

	reply, err := xinerama.QueryScreens(c).Reply()
	if err != nil {
		return image.ZR
	}

	if displayIndex >= int(reply.Number) {
		return image.ZR
	}

	primary := reply.ScreenInfo[0]
	x0 := int(primary.XOrg)
	y0 := int(primary.YOrg)

	screen := reply.ScreenInfo[displayIndex]
	x := int(screen.XOrg) - x0
	y := int(screen.YOrg) - y0
	w := int(screen.Width)
	h := int(screen.Height)
	return image.Rect(x, y, x + w, y + h)
}
<commit_msg>Recover from panic from xgb<commit_after>package xwindow

import (
	"fmt"
	"errors"
	"image"
	"image/color"
	"github.com/kbinani/screenshot/internal/util"
	"github.com/BurntSushi/xgb"
	"github.com/BurntSushi/xgb/xproto"
	"github.com/BurntSushi/xgb/xinerama"
)

func Capture(x, y, width, height int) (img *image.RGBA, e error) {
	defer func () {
		err := recover()
		if err != nil {
			img = nil
			e = errors.New(fmt.Sprintf("%v", err))
		}
	} ()
	c, err := xgb.NewConn()
	if err != nil {
		return nil, err
	}
	defer c.Close()

	err = xinerama.Init(c)
	reply, err := xinerama.QueryScreens(c).Reply()
	if err != nil {
		return nil, err
	}

	primary := reply.ScreenInfo[0]
	x0 := int(primary.XOrg)
	y0 := int(primary.YOrg)

	screen := xproto.Setup(c).DefaultScreen(c)
	wholeScreenBounds := image.Rect(0, 0, int(screen.WidthInPixels), int(screen.HeightInPixels))
	targetBounds := image.Rect(x + x0, y + y0, x + x0 + width, y + y0 + height)
	intersect := wholeScreenBounds.Intersect(targetBounds)

	rect := image.Rect(0, 0, width, height)
	img, err = util.CreateImage(rect)
	if err != nil {
		return nil, err
	}

	// Paint with opaque black
	index := 0
	for iy := 0; iy < height; iy++ {
		j := index
		for ix := 0; ix < width; ix++ {
			img.Pix[j + 3] = 255
			j += 4
		}
		index += img.Stride
	}

	if !intersect.Empty() {
		xImg, err := xproto.GetImage(c, xproto.ImageFormatZPixmap, xproto.Drawable(screen.Root),
					     int16(intersect.Min.X), int16(intersect.Min.Y),
					     uint16(intersect.Dx()), uint16(intersect.Dy()), 0xffffffff).Reply()
		if err != nil {
			return nil, err
		}

		// BitBlt by hand
		offset := 0
		for iy := intersect.Min.Y; iy < intersect.Max.Y; iy++ {
			for ix := intersect.Min.X; ix < intersect.Max.X; ix++ {
				r := xImg.Data[offset + 2]
				g := xImg.Data[offset + 1]
				b := xImg.Data[offset]
				img.SetRGBA(ix - (x + x0), iy - (y + y0), color.RGBA{r, g, b, 255})
				offset += 4
			}
		}
	}

	return img, e
}

func NumActiveDisplays() (num int) {
	defer func () {
		e := recover()
		if e != nil {
			num = 0
		}
	} ()

	c, err := xgb.NewConn()
	if err != nil {
		return 0
	}
	defer c.Close()

	err = xinerama.Init(c)
	if err != nil {
		return 0
	}

	reply, err := xinerama.QueryScreens(c).Reply()
	if err != nil {
		return 0
	}

	num = int(reply.Number)
	return num
}

func GetDisplayBounds(displayIndex int) (rect image.Rectangle) {
	defer func () {
		e := recover()
		if e != nil {
			rect = image.ZR
		}
	} ()

	c, err := xgb.NewConn()
	if err != nil {
		return image.ZR
	}
	defer c.Close()

	err = xinerama.Init(c)

	reply, err := xinerama.QueryScreens(c).Reply()
	if err != nil {
		return image.ZR
	}

	if displayIndex >= int(reply.Number) {
		return image.ZR
	}

	primary := reply.ScreenInfo[0]
	x0 := int(primary.XOrg)
	y0 := int(primary.YOrg)

	screen := reply.ScreenInfo[displayIndex]
	x := int(screen.XOrg) - x0
	y := int(screen.YOrg) - y0
	w := int(screen.Width)
	h := int(screen.Height)
	rect = image.Rect(x, y, x + w, y + h)
	return rect
}

<|endoftext|>


<commit_before>package eth

import (
	"context"
	"fmt"
	"math/big"
	"strings"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/golang/glog"
	"github.com/livepeer/go-livepeer/eth/contracts"
)

var SubscribeRetry = uint64(3)

type logCallback func(types.Log) (bool, error)
type headerCallback func(*types.Header) (bool, error)

type EventMonitor interface {
	SubscribeNewJob(context.Context, string, chan types.Log, common.Address, logCallback) (ethereum.Subscription, error)
	SubscribeNewRound(context.Context, string, chan types.Log, logCallback) (ethereum.Subscription, error)
	SubscribeNewBlock(context.Context, string, chan *types.Header, headerCallback) (ethereum.Subscription, error)
	EventSubscriptions() map[string]bool
}

type EventSubscription struct {
	sub       ethereum.Subscription
	logsCh    chan types.Log
	headersCh chan *types.Header
	active    bool
}

type eventMonitor struct {
	backend         *ethclient.Client
	contractAddrMap map[string]common.Address
	eventSubMap     map[string]*EventSubscription
	latestBlock     *big.Int
}

func NewEventMonitor(backend *ethclient.Client, contractAddrMap map[string]common.Address) EventMonitor {
	return &eventMonitor{
		backend:         backend,
		contractAddrMap: contractAddrMap,
		eventSubMap:     make(map[string]*EventSubscription),
	}
}

func (em *eventMonitor) EventSubscriptions() map[string]bool {
	activeSubMap := make(map[string]bool)

	for k, v := range em.eventSubMap {
		if v.active {
			activeSubMap[k] = true
		}
	}

	return activeSubMap
}

func (em *eventMonitor) SubscribeNewRound(ctx context.Context, subName string, logsCh chan types.Log, cb logCallback) (ethereum.Subscription, error) {
	if _, ok := em.eventSubMap[subName]; ok {
		return nil, fmt.Errorf("Event subscription already registered as active with name: %v", subName)
	}

	abiJSON, err := abi.JSON(strings.NewReader(contracts.RoundsManagerABI))
	if err != nil {
		return nil, err
	}

	eventId := abiJSON.Events["NewRound"].Id()
	roundsManagerAddr := em.contractAddrMap["RoundsManager"]

	q := ethereum.FilterQuery{
		Addresses: []common.Address{roundsManagerAddr},
		Topics:    [][]common.Hash{[]common.Hash{eventId}},
	}

	subscribe := func() error {
		sub, err := em.backend.SubscribeFilterLogs(ctx, q, logsCh)
		if err != nil {
			glog.Errorf("SubscribeNewRound error: %v. Retrying...", err)
			return err
		} else {
			glog.Infof("SubscribeNewRound successful.")
		}

		em.eventSubMap[subName] = &EventSubscription{
			sub:    sub,
			logsCh: logsCh,
			active: true,
		}

		return nil
	}

	if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
		glog.Infof("SubscribeNewRound error: %v", err)
		return nil, err
	}

	go em.watchLogs(subName, cb, func() {
		glog.Infof("Trying to resubscribe for %v", subName)
		if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
			glog.Infof("Resubscription error: %v", err)
			return
		}
	})

	return em.eventSubMap[subName].sub, nil
}

func (em *eventMonitor) SubscribeNewJob(ctx context.Context, subName string, logsCh chan types.Log, broadcasterAddr common.Address, cb logCallback) (ethereum.Subscription, error) {
	if _, ok := em.eventSubMap[subName]; ok {
		return nil, fmt.Errorf("Event subscription already registered as active with name: %v", subName)
	}

	abiJSON, err := abi.JSON(strings.NewReader(contracts.JobsManagerABI))
	if err != nil {
		return nil, err
	}

	eventId := abiJSON.Events["NewJob"].Id()
	jobsManagerAddr := em.contractAddrMap["JobsManager"]

	var q ethereum.FilterQuery
	if !IsNullAddress(broadcasterAddr) {
		q = ethereum.FilterQuery{
			Addresses: []common.Address{jobsManagerAddr},
			Topics:    [][]common.Hash{[]common.Hash{eventId}, []common.Hash{}, []common.Hash{common.BytesToHash(common.LeftPadBytes(broadcasterAddr[:], 32))}},
		}
	} else {
		q = ethereum.FilterQuery{
			Addresses: []common.Address{jobsManagerAddr},
			Topics:    [][]common.Hash{[]common.Hash{eventId}},
		}
	}

	subscribe := func() error {
		sub, err := em.backend.SubscribeFilterLogs(ctx, q, logsCh)
		if err != nil {
			glog.Errorf("SubscribeNewJob error: %v. retrying...", err)
			return err
		} else {
			glog.Infof("SubscribedNewJob successful.")
		}

		em.eventSubMap[subName] = &EventSubscription{
			sub:    sub,
			logsCh: logsCh,
			active: true,
		}
		return nil
	}

	if err = backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
		glog.Errorf("SubscribeNewJob failed: %v", err)
		return nil, err
	}

	go em.watchLogs(subName, cb, func() {
		glog.Infof("Trying to resubscribe for %v", subName)
		if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
			glog.Errorf("Resubscribe failed: %v", err)
			return
		}
	})

	return em.eventSubMap[subName].sub, nil
}

func (em *eventMonitor) SubscribeNewBlock(ctx context.Context, subName string, headersCh chan *types.Header, cb headerCallback) (ethereum.Subscription, error) {
	if _, ok := em.eventSubMap[subName]; ok {
		return nil, fmt.Errorf("Event subscription already registered as active with name: %v", subName)
	}

	subscribe := func() error {
		sub, err := em.backend.SubscribeNewHead(ctx, headersCh)
		if err != nil {
			glog.Errorf("SubscribeNewHead error: %v. retrying...", err)
			return err
		} else {
			glog.Infof("SubscribeNewHead successful.")
		}

		em.eventSubMap[subName] = &EventSubscription{
			sub:       sub,
			headersCh: headersCh,
			active:    true,
		}
		return nil
	}
	if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
		glog.Errorf("SubscribeNewHead failed: %v", err)
		return nil, err
	}

	go em.watchBlocks(subName, em.eventSubMap[subName].sub, headersCh, cb, func() {
		glog.Infof("Trying to resubscribe for %v", subName)
		if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
			glog.Errorf("Resubscribe failed: %v", err)
			return
		}
	})

	return em.eventSubMap[subName].sub, nil
}

func (em *eventMonitor) setSubActive(subName string) {
	em.eventSubMap[subName].active = true
}

func (em *eventMonitor) setSubInactive(subName string) {
	em.eventSubMap[subName].active = false
}

func (em *eventMonitor) watchLogs(subName string, eventCb logCallback, errCb func()) {
	em.setSubActive(subName)
	defer em.setSubInactive(subName)

	for {
		select {
		case l, ok := <-em.eventSubMap[subName].logsCh:
			if !ok {
				glog.Errorf("Logs channel closed")
				return
			}

			watch, err := eventCb(l)
			if err != nil {
				glog.Errorf("Error with log callback: %v", err)
			}

			if !watch {
				glog.Infof("Done watching for logs")
				return
			}
		case err := <-em.eventSubMap[subName].sub.Err():
			glog.Errorf("Error with log subscription: %v", err)

			errCb()
		}
	}
}

func (em *eventMonitor) watchBlocks(subName string, sub ethereum.Subscription, headersCh chan *types.Header, eventCb headerCallback, errCb func()) {
	em.setSubActive(subName)
	defer em.setSubInactive(subName)

	for {
		select {
		case h, ok := <-em.eventSubMap[subName].headersCh:
			if !ok {
				glog.Errorf("Logs channel closed")
				return
			}

			watch, err := eventCb(h)
			if err != nil {
				glog.Errorf("Error with header callback: %v", err)
			}

			if !watch {
				glog.Infof("Done watching")
				return
			}
		case err := <-em.eventSubMap[subName].sub.Err():
			glog.Errorf("Error with header subscription: %v", err)

			errCb()
		}
	}
}
<commit_msg>remove unused variable<commit_after>package eth

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/golang/glog"
	"github.com/livepeer/go-livepeer/eth/contracts"
)

var SubscribeRetry = uint64(3)

type logCallback func(types.Log) (bool, error)
type headerCallback func(*types.Header) (bool, error)

type EventMonitor interface {
	SubscribeNewJob(context.Context, string, chan types.Log, common.Address, logCallback) (ethereum.Subscription, error)
	SubscribeNewRound(context.Context, string, chan types.Log, logCallback) (ethereum.Subscription, error)
	SubscribeNewBlock(context.Context, string, chan *types.Header, headerCallback) (ethereum.Subscription, error)
	EventSubscriptions() map[string]bool
}

type EventSubscription struct {
	sub       ethereum.Subscription
	logsCh    chan types.Log
	headersCh chan *types.Header
	active    bool
}

type eventMonitor struct {
	backend         *ethclient.Client
	contractAddrMap map[string]common.Address
	eventSubMap     map[string]*EventSubscription
}

func NewEventMonitor(backend *ethclient.Client, contractAddrMap map[string]common.Address) EventMonitor {
	return &eventMonitor{
		backend:         backend,
		contractAddrMap: contractAddrMap,
		eventSubMap:     make(map[string]*EventSubscription),
	}
}

func (em *eventMonitor) EventSubscriptions() map[string]bool {
	activeSubMap := make(map[string]bool)

	for k, v := range em.eventSubMap {
		if v.active {
			activeSubMap[k] = true
		}
	}

	return activeSubMap
}

func (em *eventMonitor) SubscribeNewRound(ctx context.Context, subName string, logsCh chan types.Log, cb logCallback) (ethereum.Subscription, error) {
	if _, ok := em.eventSubMap[subName]; ok {
		return nil, fmt.Errorf("Event subscription already registered as active with name: %v", subName)
	}

	abiJSON, err := abi.JSON(strings.NewReader(contracts.RoundsManagerABI))
	if err != nil {
		return nil, err
	}

	eventId := abiJSON.Events["NewRound"].Id()
	roundsManagerAddr := em.contractAddrMap["RoundsManager"]

	q := ethereum.FilterQuery{
		Addresses: []common.Address{roundsManagerAddr},
		Topics:    [][]common.Hash{[]common.Hash{eventId}},
	}

	subscribe := func() error {
		sub, err := em.backend.SubscribeFilterLogs(ctx, q, logsCh)
		if err != nil {
			glog.Errorf("SubscribeNewRound error: %v. Retrying...", err)
			return err
		} else {
			glog.Infof("SubscribeNewRound successful.")
		}

		em.eventSubMap[subName] = &EventSubscription{
			sub:    sub,
			logsCh: logsCh,
			active: true,
		}

		return nil
	}

	if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
		glog.Infof("SubscribeNewRound error: %v", err)
		return nil, err
	}

	go em.watchLogs(subName, cb, func() {
		glog.Infof("Trying to resubscribe for %v", subName)
		if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
			glog.Infof("Resubscription error: %v", err)
			return
		}
	})

	return em.eventSubMap[subName].sub, nil
}

func (em *eventMonitor) SubscribeNewJob(ctx context.Context, subName string, logsCh chan types.Log, broadcasterAddr common.Address, cb logCallback) (ethereum.Subscription, error) {
	if _, ok := em.eventSubMap[subName]; ok {
		return nil, fmt.Errorf("Event subscription already registered as active with name: %v", subName)
	}

	abiJSON, err := abi.JSON(strings.NewReader(contracts.JobsManagerABI))
	if err != nil {
		return nil, err
	}

	eventId := abiJSON.Events["NewJob"].Id()
	jobsManagerAddr := em.contractAddrMap["JobsManager"]

	var q ethereum.FilterQuery
	if !IsNullAddress(broadcasterAddr) {
		q = ethereum.FilterQuery{
			Addresses: []common.Address{jobsManagerAddr},
			Topics:    [][]common.Hash{[]common.Hash{eventId}, []common.Hash{}, []common.Hash{common.BytesToHash(common.LeftPadBytes(broadcasterAddr[:], 32))}},
		}
	} else {
		q = ethereum.FilterQuery{
			Addresses: []common.Address{jobsManagerAddr},
			Topics:    [][]common.Hash{[]common.Hash{eventId}},
		}
	}

	subscribe := func() error {
		sub, err := em.backend.SubscribeFilterLogs(ctx, q, logsCh)
		if err != nil {
			glog.Errorf("SubscribeNewJob error: %v. retrying...", err)
			return err
		} else {
			glog.Infof("SubscribedNewJob successful.")
		}

		em.eventSubMap[subName] = &EventSubscription{
			sub:    sub,
			logsCh: logsCh,
			active: true,
		}
		return nil
	}

	if err = backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
		glog.Errorf("SubscribeNewJob failed: %v", err)
		return nil, err
	}

	go em.watchLogs(subName, cb, func() {
		glog.Infof("Trying to resubscribe for %v", subName)
		if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
			glog.Errorf("Resubscribe failed: %v", err)
			return
		}
	})

	return em.eventSubMap[subName].sub, nil
}

func (em *eventMonitor) SubscribeNewBlock(ctx context.Context, subName string, headersCh chan *types.Header, cb headerCallback) (ethereum.Subscription, error) {
	if _, ok := em.eventSubMap[subName]; ok {
		return nil, fmt.Errorf("Event subscription already registered as active with name: %v", subName)
	}

	subscribe := func() error {
		sub, err := em.backend.SubscribeNewHead(ctx, headersCh)
		if err != nil {
			glog.Errorf("SubscribeNewHead error: %v. retrying...", err)
			return err
		} else {
			glog.Infof("SubscribeNewHead successful.")
		}

		em.eventSubMap[subName] = &EventSubscription{
			sub:       sub,
			headersCh: headersCh,
			active:    true,
		}
		return nil
	}
	if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
		glog.Errorf("SubscribeNewHead failed: %v", err)
		return nil, err
	}

	go em.watchBlocks(subName, em.eventSubMap[subName].sub, headersCh, cb, func() {
		glog.Infof("Trying to resubscribe for %v", subName)
		if err := backoff.Retry(subscribe, backoff.NewConstantBackOff(time.Second*2)); err != nil {
			glog.Errorf("Resubscribe failed: %v", err)
			return
		}
	})

	return em.eventSubMap[subName].sub, nil
}

func (em *eventMonitor) setSubActive(subName string) {
	em.eventSubMap[subName].active = true
}

func (em *eventMonitor) setSubInactive(subName string) {
	em.eventSubMap[subName].active = false
}

func (em *eventMonitor) watchLogs(subName string, eventCb logCallback, errCb func()) {
	em.setSubActive(subName)
	defer em.setSubInactive(subName)

	for {
		select {
		case l, ok := <-em.eventSubMap[subName].logsCh:
			if !ok {
				glog.Errorf("Logs channel closed")
				return
			}

			watch, err := eventCb(l)
			if err != nil {
				glog.Errorf("Error with log callback: %v", err)
			}

			if !watch {
				glog.Infof("Done watching for logs")
				return
			}
		case err := <-em.eventSubMap[subName].sub.Err():
			glog.Errorf("Error with log subscription: %v", err)

			errCb()
		}
	}
}

func (em *eventMonitor) watchBlocks(subName string, sub ethereum.Subscription, headersCh chan *types.Header, eventCb headerCallback, errCb func()) {
	em.setSubActive(subName)
	defer em.setSubInactive(subName)

	for {
		select {
		case h, ok := <-em.eventSubMap[subName].headersCh:
			if !ok {
				glog.Errorf("Logs channel closed")
				return
			}

			watch, err := eventCb(h)
			if err != nil {
				glog.Errorf("Error with header callback: %v", err)
			}

			if !watch {
				glog.Infof("Done watching")
				return
			}
		case err := <-em.eventSubMap[subName].sub.Err():
			glog.Errorf("Error with header subscription: %v", err)

			errCb()
		}
	}
}
<|endoftext|>


<commit_before>package jsonpatch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"testing"
)

func reformatJSON(j string) string {
	buf := new(bytes.Buffer)

	json.Indent(buf, []byte(j), "", "  ")

	return buf.String()
}

func compareJSON(a, b string) bool {
	// return Equal([]byte(a), []byte(b))

	var objA, objB map[string]interface{}
	json.Unmarshal([]byte(a), &objA)
	json.Unmarshal([]byte(b), &objB)

	// fmt.Printf("Comparing %#v\nagainst %#v\n", objA, objB)
	return reflect.DeepEqual(objA, objB)
}

func applyPatch(doc, patch string) (string, error) {
	obj, err := DecodePatch([]byte(patch))

	if err != nil {
		panic(err)
	}

	out, err := obj.Apply([]byte(doc))

	if err != nil {
		return "", err
	}

	return string(out), nil
}

type Case struct {
	doc, patch, result string
}

var Cases = []Case{
	{
		`{ "foo": "bar"}`,
		`[
         { "op": "add", "path": "/baz", "value": "qux" }
     ]`,
		`{
       "baz": "qux",
       "foo": "bar"
     }`,
	},
	{
		`{ "foo": [ "bar", "baz" ] }`,
		`[
     { "op": "add", "path": "/foo/1", "value": "qux" }
    ]`,
		`{ "foo": [ "bar", "qux", "baz" ] }`,
	},
	{
		`{ "foo": [ "bar", "baz" ] }`,
		`[
     { "op": "add", "path": "/foo/-1", "value": "qux" }
    ]`,
		`{ "foo": [ "bar", "baz", "qux" ] }`,
	},
	{
		`{ "baz": "qux", "foo": "bar" }`,
		`[ { "op": "remove", "path": "/baz" } ]`,
		`{ "foo": "bar" }`,
	},
	{
		`{ "foo": [ "bar", "qux", "baz" ] }`,
		`[ { "op": "remove", "path": "/foo/1" } ]`,
		`{ "foo": [ "bar", "baz" ] }`,
	},
	{
		`{ "baz": "qux", "foo": "bar" }`,
		`[ { "op": "replace", "path": "/baz", "value": "boo" } ]`,
		`{ "baz": "boo", "foo": "bar" }`,
	},
	{
		`{
     "foo": {
       "bar": "baz",
       "waldo": "fred"
     },
     "qux": {
       "corge": "grault"
     }
   }`,
		`[ { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" } ]`,
		`{
     "foo": {
       "bar": "baz"
     },
     "qux": {
       "corge": "grault",
       "thud": "fred"
     }
   }`,
	},
	{
		`{ "foo": [ "all", "grass", "cows", "eat" ] }`,
		`[ { "op": "move", "from": "/foo/1", "path": "/foo/3" } ]`,
		`{ "foo": [ "all", "cows", "eat", "grass" ] }`,
	},
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "path": "/child", "value": { "grandchild": { } } } ]`,
		`{ "foo": "bar", "child": { "grandchild": { } } }`,
	},
	{
		`{ "foo": ["bar"] }`,
		`[ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] } ]`,
		`{ "foo": ["bar", ["abc", "def"]] }`,
	},
	{
		`{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`,
		`[ { "op": "remove", "path": "/qux/bar" } ]`,
		`{ "foo": "bar", "qux": { "baz": 1 } }`,
	},
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "path": "/baz", "value": null } ]`,
		`{ "baz": null, "foo": "bar" }`,
	},
	{
		`{ "foo": ["bar"]}`,
		`[ { "op": "replace", "path": "/foo/0", "value": "baz"}]`,
		`{ "foo": ["baz"]}`,
	},
	{
		`{ "foo": ["bar","baz"]}`,
		`[ { "op": "replace", "path": "/foo/0", "value": "bum"}]`,
		`{ "foo": ["bum","baz"]}`,
	},
	{
		`{ "foo": ["bar","qux","baz"]}`,
		`[ { "op": "replace", "path": "/foo/1", "value": "bum"}]`,
		`{ "foo": ["bar", "bum","baz"]}`,
	},
	{
		`[ {"foo": ["bar","qux","baz"]}]`,
		`[ { "op": "replace", "path": "/0/foo/0", "value": "bum"}]`,
		`[ {"foo": ["bum","qux","baz"]}]`,
	},
	{
		`[ {"foo": ["bar","qux","baz"], "bar": ["qux","baz"]}]`,
		`[ { "op": "copy", "from": "/0/foo/0", "path": "/0/bar/0"}]`,
		`[ {"foo": ["bar","qux","baz"], "bar": ["bar", "baz"]}]`,
	},
	{
		`[ {"foo": ["bar","qux","baz"], "bar": ["qux","baz"]}]`,
		`[ { "op": "copy", "from": "/0/foo/0", "path": "/0/bar"}]`,
		`[ {"foo": ["bar","qux","baz"], "bar": ["bar", "qux", "baz"]}]`,
	},
	{
		`[ { "foo": {"bar": ["qux","baz"]}, "baz": {"qux": "bum"}}]`,
		`[ { "op": "copy", "from": "/0/foo/bar", "path": "/0/baz/bar"}]`,
		`[ { "baz": {"bar": ["qux","baz"], "qux":"bum"}, "foo": {"bar": ["qux","baz"]}}]`,
	},
	{
		`{ "foo": ["bar","qux","baz"]}`,
		`[ { "op": "remove", "path": "/foo/-2"}]`,
		`{ "foo": ["bar", "baz"]}`,
	},
	{
		`{ "foo": []}`,
		`[ { "op": "add", "path": "/foo/-1", "value": "qux"}]`,
		`{ "foo": ["qux"]}`,
  },
  {
    `{ "bar": [{"baz": null}]}`,
		`[ { "op": "replace", "path": "/bar/0/baz", "value": 1 } ]`,
		`{ "bar": [{"baz": 1}]}`,
	},
	{
		`{ "bar": [{"baz": 1}]}`,
		`[ { "op": "replace", "path": "/bar/0/baz", "value": null } ]`,
		`{ "bar": [{"baz": null}]}`,
	},
	{
		`{ "bar": [null]}`,
		`[ { "op": "replace", "path": "/bar/0", "value": 1 } ]`,
		`{ "bar": [1]}`,
	},
	{
		`{ "bar": [1]}`,
		`[ { "op": "replace", "path": "/bar/0", "value": null } ]`,
		`{ "bar": [null]}`,
	},
}

type BadCase struct {
	doc, patch string
}

var MutationTestCases = []BadCase{
	{
		`{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`,
		`[ { "op": "remove", "path": "/qux/bar" } ]`,
	},
	{
		`{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`,
		`[ { "op": "replace", "path": "/qux/baz", "value": null } ]`,
	},
}

var BadCases = []BadCase{
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "path": "/baz/bat", "value": "qux" } ]`,
	},
	{
		`{ "a": { "b": { "d": 1 } } }`,
		`[ { "op": "remove", "path": "/a/b/c" } ]`,
	},
	{
		`{ "a": { "b": { "d": 1 } } }`,
		`[ { "op": "move", "from": "/a/b/c", "path": "/a/b/e" } ]`,
	},
	{
		`{ "a": { "b": [1] } }`,
		`[ { "op": "remove", "path": "/a/b/1" } ]`,
	},
	{
		`{ "a": { "b": [1] } }`,
		`[ { "op": "move", "from": "/a/b/1", "path": "/a/b/2" } ]`,
	},
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "pathz": "/baz", "value": "qux" } ]`,
	},
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "path": "", "value": "qux" } ]`,
	},
	{
		`{ "foo": ["bar","baz"]}`,
		`[ { "op": "replace", "path": "/foo/2", "value": "bum"}]`,
	},
	{
		`{ "foo": ["bar","baz"]}`,
		`[ { "op": "add", "path": "/foo/-4", "value": "bum"}]`,
	},
	{
		`{ "name":{ "foo": "bat", "qux": "bum"}}`,
		`[ { "op": "replace", "path": "/foo/bar", "value":"baz"}]`,
	},
	{
		`{ "foo": ["bar"]}`,
		`[ {"op": "add", "path": "/foo/2", "value": "bum"}]`,
	},
	{
		`{ "foo": []}`,
		`[ {"op": "remove", "path": "/foo/-"}]`,
	},
	{
		`{ "foo": []}`,
		`[ {"op": "remove", "path": "/foo/-1"}]`,
	},
	{
		`{ "foo": ["bar"]}`,
		`[ {"op": "remove", "path": "/foo/-2"}]`,
	},
}

func TestAllCases(t *testing.T) {
	for _, c := range Cases {
		out, err := applyPatch(c.doc, c.patch)

		if err != nil {
			t.Errorf("Unable to apply patch: %s", err)
		}

		if !compareJSON(out, c.result) {
			t.Errorf("Patch did not apply. Expected:\n%s\n\nActual:\n%s",
				reformatJSON(c.result), reformatJSON(out))
		}
	}

	for _, c := range MutationTestCases {
		out, err := applyPatch(c.doc, c.patch)

		if err != nil {
			t.Errorf("Unable to apply patch: %s", err)
		}

		if compareJSON(out, c.doc) {
			t.Errorf("Patch did not apply. Original:\n%s\n\nPatched:\n%s",
				reformatJSON(c.doc), reformatJSON(out))
		}
	}

	for _, c := range BadCases {
		_, err := applyPatch(c.doc, c.patch)

		if err == nil {
			t.Errorf("Patch should have failed to apply but it did not")
		}
	}
}

type TestCase struct {
	doc, patch string
	result     bool
	failedPath string
}

var TestCases = []TestCase{
	{
		`{
      "baz": "qux",
      "foo": [ "a", 2, "c" ]
    }`,
		`[
      { "op": "test", "path": "/baz", "value": "qux" },
      { "op": "test", "path": "/foo/1", "value": 2 }
    ]`,
		true,
		"",
	},
	{
		`{ "baz": "qux" }`,
		`[ { "op": "test", "path": "/baz", "value": "bar" } ]`,
		false,
		"/baz",
	},
	{
		`{
      "baz": "qux",
      "foo": ["a", 2, "c"]
    }`,
		`[
      { "op": "test", "path": "/baz", "value": "qux" },
      { "op": "test", "path": "/foo/1", "value": "c" }
    ]`,
		false,
		"/foo/1",
	},
	{
		`{ "baz": "qux" }`,
		`[ { "op": "test", "path": "/foo", "value": 42 } ]`,
		false,
		"/foo",
	},
	{
		`{ "baz": "qux" }`,
		`[ { "op": "test", "path": "/foo", "value": null } ]`,
		true,
		"",
	},
	{
		`{ "foo": null }`,
		`[ { "op": "test", "path": "/foo", "value": null } ]`,
		true,
		"",
	},
	{
		`{ "foo": {} }`,
		`[ { "op": "test", "path": "/foo", "value": null } ]`,
		false,
		"/foo",
	},
	{
		`{ "foo": [] }`,
		`[ { "op": "test", "path": "/foo", "value": null } ]`,
		false,
		"/foo",
	},
	{
		`{ "baz/foo": "qux" }`,
		`[ { "op": "test", "path": "/baz~1foo", "value": "qux"} ]`,
		true,
		"",
	},
}

func TestAllTest(t *testing.T) {
	for _, c := range TestCases {
		_, err := applyPatch(c.doc, c.patch)

		if c.result && err != nil {
			t.Errorf("Testing failed when it should have passed: %s", err)
		} else if !c.result && err == nil {
			t.Errorf("Testing passed when it should have faild: %s", err)
		} else if !c.result {
			expected := fmt.Sprintf("Testing value %s failed", c.failedPath)
			if err.Error() != expected {
				t.Errorf("Testing failed as expected but invalid message: expected [%s], got [%s]", expected, err)
			}
		}
	}
}
<commit_msg>Fix tabs<commit_after>package jsonpatch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"testing"
)

func reformatJSON(j string) string {
	buf := new(bytes.Buffer)

	json.Indent(buf, []byte(j), "", "  ")

	return buf.String()
}

func compareJSON(a, b string) bool {
	// return Equal([]byte(a), []byte(b))

	var objA, objB map[string]interface{}
	json.Unmarshal([]byte(a), &objA)
	json.Unmarshal([]byte(b), &objB)

	// fmt.Printf("Comparing %#v\nagainst %#v\n", objA, objB)
	return reflect.DeepEqual(objA, objB)
}

func applyPatch(doc, patch string) (string, error) {
	obj, err := DecodePatch([]byte(patch))

	if err != nil {
		panic(err)
	}

	out, err := obj.Apply([]byte(doc))

	if err != nil {
		return "", err
	}

	return string(out), nil
}

type Case struct {
	doc, patch, result string
}

var Cases = []Case{
	{
		`{ "foo": "bar"}`,
		`[
         { "op": "add", "path": "/baz", "value": "qux" }
     ]`,
		`{
       "baz": "qux",
       "foo": "bar"
     }`,
	},
	{
		`{ "foo": [ "bar", "baz" ] }`,
		`[
     { "op": "add", "path": "/foo/1", "value": "qux" }
    ]`,
		`{ "foo": [ "bar", "qux", "baz" ] }`,
	},
	{
		`{ "foo": [ "bar", "baz" ] }`,
		`[
     { "op": "add", "path": "/foo/-1", "value": "qux" }
    ]`,
		`{ "foo": [ "bar", "baz", "qux" ] }`,
	},
	{
		`{ "baz": "qux", "foo": "bar" }`,
		`[ { "op": "remove", "path": "/baz" } ]`,
		`{ "foo": "bar" }`,
	},
	{
		`{ "foo": [ "bar", "qux", "baz" ] }`,
		`[ { "op": "remove", "path": "/foo/1" } ]`,
		`{ "foo": [ "bar", "baz" ] }`,
	},
	{
		`{ "baz": "qux", "foo": "bar" }`,
		`[ { "op": "replace", "path": "/baz", "value": "boo" } ]`,
		`{ "baz": "boo", "foo": "bar" }`,
	},
	{
		`{
     "foo": {
       "bar": "baz",
       "waldo": "fred"
     },
     "qux": {
       "corge": "grault"
     }
   }`,
		`[ { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" } ]`,
		`{
     "foo": {
       "bar": "baz"
     },
     "qux": {
       "corge": "grault",
       "thud": "fred"
     }
   }`,
	},
	{
		`{ "foo": [ "all", "grass", "cows", "eat" ] }`,
		`[ { "op": "move", "from": "/foo/1", "path": "/foo/3" } ]`,
		`{ "foo": [ "all", "cows", "eat", "grass" ] }`,
	},
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "path": "/child", "value": { "grandchild": { } } } ]`,
		`{ "foo": "bar", "child": { "grandchild": { } } }`,
	},
	{
		`{ "foo": ["bar"] }`,
		`[ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] } ]`,
		`{ "foo": ["bar", ["abc", "def"]] }`,
	},
	{
		`{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`,
		`[ { "op": "remove", "path": "/qux/bar" } ]`,
		`{ "foo": "bar", "qux": { "baz": 1 } }`,
	},
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "path": "/baz", "value": null } ]`,
		`{ "baz": null, "foo": "bar" }`,
	},
	{
		`{ "foo": ["bar"]}`,
		`[ { "op": "replace", "path": "/foo/0", "value": "baz"}]`,
		`{ "foo": ["baz"]}`,
	},
	{
		`{ "foo": ["bar","baz"]}`,
		`[ { "op": "replace", "path": "/foo/0", "value": "bum"}]`,
		`{ "foo": ["bum","baz"]}`,
	},
	{
		`{ "foo": ["bar","qux","baz"]}`,
		`[ { "op": "replace", "path": "/foo/1", "value": "bum"}]`,
		`{ "foo": ["bar", "bum","baz"]}`,
	},
	{
		`[ {"foo": ["bar","qux","baz"]}]`,
		`[ { "op": "replace", "path": "/0/foo/0", "value": "bum"}]`,
		`[ {"foo": ["bum","qux","baz"]}]`,
	},
	{
		`[ {"foo": ["bar","qux","baz"], "bar": ["qux","baz"]}]`,
		`[ { "op": "copy", "from": "/0/foo/0", "path": "/0/bar/0"}]`,
		`[ {"foo": ["bar","qux","baz"], "bar": ["bar", "baz"]}]`,
	},
	{
		`[ {"foo": ["bar","qux","baz"], "bar": ["qux","baz"]}]`,
		`[ { "op": "copy", "from": "/0/foo/0", "path": "/0/bar"}]`,
		`[ {"foo": ["bar","qux","baz"], "bar": ["bar", "qux", "baz"]}]`,
	},
	{
		`[ { "foo": {"bar": ["qux","baz"]}, "baz": {"qux": "bum"}}]`,
		`[ { "op": "copy", "from": "/0/foo/bar", "path": "/0/baz/bar"}]`,
		`[ { "baz": {"bar": ["qux","baz"], "qux":"bum"}, "foo": {"bar": ["qux","baz"]}}]`,
	},
	{
		`{ "foo": ["bar","qux","baz"]}`,
		`[ { "op": "remove", "path": "/foo/-2"}]`,
		`{ "foo": ["bar", "baz"]}`,
	},
	{
		`{ "foo": []}`,
		`[ { "op": "add", "path": "/foo/-1", "value": "qux"}]`,
		`{ "foo": ["qux"]}`,
	},
	{
		`{ "bar": [{"baz": null}]}`,
		`[ { "op": "replace", "path": "/bar/0/baz", "value": 1 } ]`,
		`{ "bar": [{"baz": 1}]}`,
	},
	{
		`{ "bar": [{"baz": 1}]}`,
		`[ { "op": "replace", "path": "/bar/0/baz", "value": null } ]`,
		`{ "bar": [{"baz": null}]}`,
	},
	{
		`{ "bar": [null]}`,
		`[ { "op": "replace", "path": "/bar/0", "value": 1 } ]`,
		`{ "bar": [1]}`,
	},
	{
		`{ "bar": [1]}`,
		`[ { "op": "replace", "path": "/bar/0", "value": null } ]`,
		`{ "bar": [null]}`,
	},
}

type BadCase struct {
	doc, patch string
}

var MutationTestCases = []BadCase{
	{
		`{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`,
		`[ { "op": "remove", "path": "/qux/bar" } ]`,
	},
	{
		`{ "foo": "bar", "qux": { "baz": 1, "bar": null } }`,
		`[ { "op": "replace", "path": "/qux/baz", "value": null } ]`,
	},
}

var BadCases = []BadCase{
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "path": "/baz/bat", "value": "qux" } ]`,
	},
	{
		`{ "a": { "b": { "d": 1 } } }`,
		`[ { "op": "remove", "path": "/a/b/c" } ]`,
	},
	{
		`{ "a": { "b": { "d": 1 } } }`,
		`[ { "op": "move", "from": "/a/b/c", "path": "/a/b/e" } ]`,
	},
	{
		`{ "a": { "b": [1] } }`,
		`[ { "op": "remove", "path": "/a/b/1" } ]`,
	},
	{
		`{ "a": { "b": [1] } }`,
		`[ { "op": "move", "from": "/a/b/1", "path": "/a/b/2" } ]`,
	},
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "pathz": "/baz", "value": "qux" } ]`,
	},
	{
		`{ "foo": "bar" }`,
		`[ { "op": "add", "path": "", "value": "qux" } ]`,
	},
	{
		`{ "foo": ["bar","baz"]}`,
		`[ { "op": "replace", "path": "/foo/2", "value": "bum"}]`,
	},
	{
		`{ "foo": ["bar","baz"]}`,
		`[ { "op": "add", "path": "/foo/-4", "value": "bum"}]`,
	},
	{
		`{ "name":{ "foo": "bat", "qux": "bum"}}`,
		`[ { "op": "replace", "path": "/foo/bar", "value":"baz"}]`,
	},
	{
		`{ "foo": ["bar"]}`,
		`[ {"op": "add", "path": "/foo/2", "value": "bum"}]`,
	},
	{
		`{ "foo": []}`,
		`[ {"op": "remove", "path": "/foo/-"}]`,
	},
	{
		`{ "foo": []}`,
		`[ {"op": "remove", "path": "/foo/-1"}]`,
	},
	{
		`{ "foo": ["bar"]}`,
		`[ {"op": "remove", "path": "/foo/-2"}]`,
	},
}

func TestAllCases(t *testing.T) {
	for _, c := range Cases {
		out, err := applyPatch(c.doc, c.patch)

		if err != nil {
			t.Errorf("Unable to apply patch: %s", err)
		}

		if !compareJSON(out, c.result) {
			t.Errorf("Patch did not apply. Expected:\n%s\n\nActual:\n%s",
				reformatJSON(c.result), reformatJSON(out))
		}
	}

	for _, c := range MutationTestCases {
		out, err := applyPatch(c.doc, c.patch)

		if err != nil {
			t.Errorf("Unable to apply patch: %s", err)
		}

		if compareJSON(out, c.doc) {
			t.Errorf("Patch did not apply. Original:\n%s\n\nPatched:\n%s",
				reformatJSON(c.doc), reformatJSON(out))
		}
	}

	for _, c := range BadCases {
		_, err := applyPatch(c.doc, c.patch)

		if err == nil {
			t.Errorf("Patch should have failed to apply but it did not")
		}
	}
}

type TestCase struct {
	doc, patch string
	result     bool
	failedPath string
}

var TestCases = []TestCase{
	{
		`{
      "baz": "qux",
      "foo": [ "a", 2, "c" ]
    }`,
		`[
      { "op": "test", "path": "/baz", "value": "qux" },
      { "op": "test", "path": "/foo/1", "value": 2 }
    ]`,
		true,
		"",
	},
	{
		`{ "baz": "qux" }`,
		`[ { "op": "test", "path": "/baz", "value": "bar" } ]`,
		false,
		"/baz",
	},
	{
		`{
      "baz": "qux",
      "foo": ["a", 2, "c"]
    }`,
		`[
      { "op": "test", "path": "/baz", "value": "qux" },
      { "op": "test", "path": "/foo/1", "value": "c" }
    ]`,
		false,
		"/foo/1",
	},
	{
		`{ "baz": "qux" }`,
		`[ { "op": "test", "path": "/foo", "value": 42 } ]`,
		false,
		"/foo",
	},
	{
		`{ "baz": "qux" }`,
		`[ { "op": "test", "path": "/foo", "value": null } ]`,
		true,
		"",
	},
	{
		`{ "foo": null }`,
		`[ { "op": "test", "path": "/foo", "value": null } ]`,
		true,
		"",
	},
	{
		`{ "foo": {} }`,
		`[ { "op": "test", "path": "/foo", "value": null } ]`,
		false,
		"/foo",
	},
	{
		`{ "foo": [] }`,
		`[ { "op": "test", "path": "/foo", "value": null } ]`,
		false,
		"/foo",
	},
	{
		`{ "baz/foo": "qux" }`,
		`[ { "op": "test", "path": "/baz~1foo", "value": "qux"} ]`,
		true,
		"",
	},
}

func TestAllTest(t *testing.T) {
	for _, c := range TestCases {
		_, err := applyPatch(c.doc, c.patch)

		if c.result && err != nil {
			t.Errorf("Testing failed when it should have passed: %s", err)
		} else if !c.result && err == nil {
			t.Errorf("Testing passed when it should have faild: %s", err)
		} else if !c.result {
			expected := fmt.Sprintf("Testing value %s failed", c.failedPath)
			if err.Error() != expected {
				t.Errorf("Testing failed as expected but invalid message: expected [%s], got [%s]", expected, err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package via

import (
	"fmt"
	"github.com/mrosset/util/file"
	"github.com/mrosset/util/json"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

const (
	ERR_BRANCH_MISMATCH = "Branches do not Match"
)

var (
	cache   Cache
	gopath  = filepath.Join(os.Getenv("GOPATH"), "src/github.com/mrosset/via")
	cfile   = filepath.Join(gopath, "plans/config.json")
	viaUrl  = "https://github.com/mrosset/via"
	planUrl = "https://github.com/mrosset/plans"
	config  = new(Config)
)

func init() {
	// TODO rework this to error and suggest user use 'via init'
	pdir := filepath.Dir(cfile)
	if !file.Exists(pdir) {
		err := Clone(pdir, "refs/heads/linux-x86_64", planUrl)
		if err != nil {
			elog.Fatal(err)
		}
	}
	err := json.Read(&config, cfile)
	if err != nil {
		elog.Fatal(err)
	}
	// TODO: provide Lint for master config
	sort.Strings([]string(config.Flags))
	sort.Strings(config.Remove)
	err = json.Write(&config, cfile)
	if err != nil {
		elog.Fatal(err)
	}

	cache = Cache(os.ExpandEnv(string(config.Cache)))
	cache.Init()
	config.Plans = os.ExpandEnv(config.Plans)
	config.Repo = os.ExpandEnv(config.Repo)
	err = os.MkdirAll(config.Repo, 0755)
	if err != nil {
		elog.Fatal(err)
	}
	for i, j := range config.Env {
		os.Setenv(i, os.ExpandEnv(j))
	}
	for i, j := range config.Env {
		os.Setenv(i, os.ExpandEnv(j))
	}
}

type Config struct {
	Branch    string
	Identity  string
	Arch      string
	OS        string
	Root      string
	PlansRepo string

	// Paths
	Cache  Cache
	DB     DB
	Plans  string
	Repo   string
	Binary string
	Prefix string

	// Toolchain
	Flags Flags

	Env         map[string]string
	Remove      []string
	PostInstall []string

	// Internal Fields
	template *Config
}

func (c *Config) Expand() *Config {
	if c.template != nil {
		return c.template
	}
	o := new(Config)
	err := json.Parse(o, c)
	if err != nil {
		panic(err)
	}
	c.template = o
	return o
}

// Checks all branches match the Config branch
func (c Config) CheckBranches() error {
	rb := c.RepoBranch()
	pb := c.PlanBranch()
	if pb != config.Branch || rb != config.Branch {
		return fmt.Errorf("%s: repo:%s plan:%s", ERR_BRANCH_MISMATCH, rb, pb)
	}
	return nil
}

// Returns the checked out branch for repo directory
func (c Config) RepoBranch() string {
	b, err := Branch(c.Repo)
	if err != nil {
		elog.Fatalf("%s %s", c.Repo, err)
	}
	return b
}

// Returns the checked out branch for plans directory
func (c Config) PlanBranch() string {
	p := filepath.Join(c.Plans)
	b, err := Branch(p)
	if err != nil {
		elog.Fatal(err)
	}
	return b
}

type Flags []string

func (f Flags) String() string {
	return strings.Join(f, " ")
}

type DB string

func (d DB) Installed() string {
	return join(config.Root, string(d), "installed")
}

func (d DB) Plans() string {
	return join(config.Root, string(d), "plans")
}
<commit_msg>do not check publish branch when building.<commit_after>package via

import (
	"fmt"
	"github.com/mrosset/util/file"
	"github.com/mrosset/util/json"
	"os"
	"path/filepath"
	"sort"
	"strings"
)

const (
	ERR_BRANCH_MISMATCH = "Branches do not Match"
)

var (
	cache   Cache
	gopath  = filepath.Join(os.Getenv("GOPATH"), "src/github.com/mrosset/via")
	cfile   = filepath.Join(gopath, "plans/config.json")
	viaUrl  = "https://github.com/mrosset/via"
	planUrl = "https://github.com/mrosset/plans"
	config  = new(Config)
)

func init() {
	// TODO rework this to error and suggest user use 'via init'
	pdir := filepath.Dir(cfile)
	if !file.Exists(pdir) {
		err := Clone(pdir, "refs/heads/linux-x86_64", planUrl)
		if err != nil {
			elog.Fatal(err)
		}
	}
	err := json.Read(&config, cfile)
	if err != nil {
		elog.Fatal(err)
	}
	// TODO: provide Lint for master config
	sort.Strings([]string(config.Flags))
	sort.Strings(config.Remove)
	err = json.Write(&config, cfile)
	if err != nil {
		elog.Fatal(err)
	}

	cache = Cache(os.ExpandEnv(string(config.Cache)))
	cache.Init()
	config.Plans = os.ExpandEnv(config.Plans)
	config.Repo = os.ExpandEnv(config.Repo)
	err = os.MkdirAll(config.Repo, 0755)
	if err != nil {
		elog.Fatal(err)
	}
	for i, j := range config.Env {
		os.Setenv(i, os.ExpandEnv(j))
	}
	for i, j := range config.Env {
		os.Setenv(i, os.ExpandEnv(j))
	}
}

type Config struct {
	Branch    string
	Identity  string
	Arch      string
	OS        string
	Root      string
	PlansRepo string

	// Paths
	Cache  Cache
	DB     DB
	Plans  string
	Repo   string
	Binary string
	Prefix string

	// Toolchain
	Flags Flags

	Env         map[string]string
	Remove      []string
	PostInstall []string

	// Internal Fields
	template *Config
}

func (c *Config) Expand() *Config {
	if c.template != nil {
		return c.template
	}
	o := new(Config)
	err := json.Parse(o, c)
	if err != nil {
		panic(err)
	}
	c.template = o
	return o
}

// Checks all branches match the Config branch
func (c Config) CheckBranches() error {
	pb := c.PlanBranch()
	if pb != config.Branch {
		return fmt.Errorf("%s: plan:%s", ERR_BRANCH_MISMATCH, pb)
	}
	return nil
}

// Returns the checked out branch for repo directory
func (c Config) RepoBranch() string {
	b, err := Branch(c.Repo)
	if err != nil {
		elog.Fatalf("%s %s", c.Repo, err)
	}
	return b
}

// Returns the checked out branch for plans directory
func (c Config) PlanBranch() string {
	p := filepath.Join(c.Plans)
	b, err := Branch(p)
	if err != nil {
		elog.Fatal(err)
	}
	return b
}

type Flags []string

func (f Flags) String() string {
	return strings.Join(f, " ")
}

type DB string

func (d DB) Installed() string {
	return join(config.Root, string(d), "installed")
}

func (d DB) Plans() string {
	return join(config.Root, string(d), "plans")
}
<|endoftext|>


<commit_before>package goevolve

import (
	"bytes"
	"crypto/sha256"
	"encoding/gob"
	"fmt"
	"github.com/TSavo/GoVirtual"
	"io"
	"log"
	"os"
	"time"
)

type Population struct {
	Id, RegisterLength   int
	InstructionSet       *govirtual.InstructionSet
	Breeder              *Breeder
	Evaluator            *Evaluator
	Selector             *Selector
	TerminationCondition *govirtual.TerminationCondition
	ControlChan          chan bool
	PopulationReportChan chan *PopulationReport
	Heap                 *govirtual.Memory
}

var SolutionCache map[string]*Solution

func init() {
	SolutionCache = make(map[string]*Solution)
	go func() {
		for {
			time.Sleep(60 * time.Second)
			WriteSolutionCache(EncodeSolutionCache())
		}
	}()

	defer recover()
	cache := ReadSolutionCache()
	if(cache != nil) {
		SolutionCache = *DecodeSolutionCache(cache)
	}
}

func EncodeSolutionCache() (b *bytes.Buffer) {
	b = new(bytes.Buffer)
	e := gob.NewEncoder(b)

	// Encoding the map
	err := e.Encode(&SolutionCache)
	if err != nil {
		panic(err)
	}
	return
}

func DecodeSolutionCache(b *bytes.Buffer) *map[string]*Solution {
	s := make(map[string]*Solution)
	d := gob.NewDecoder(b)

	// Decoding the serialized data
	err := d.Decode(&s)
	if err != nil {
		return nil
	}
	return &s
}

func WriteSolutionCache(b *bytes.Buffer) {
	f, er := os.OpenFile("SolutionCache.gob", os.O_RDWR | os.O_CREATE | os.O_TRUNC, 0777  )
	f.Write(b.Bytes()) // Error handling elided for brevity.
	f.Close()
}

func ReadSolutionCache() *bytes.Buffer {
	buf := bytes.NewBuffer(nil)
	f, _ := os.Open("SolutionCache.gob") // Error handling elided for brevity.
	written, err := io.Copy(buf, f)      // Error handling elided for brevity.
	f.Close()
	if err == nil && written > 0 {
		return buf
	}
	return nil
}

type Solution struct {
	Reward  int
	Program string
}

type SolutionList []*Solution

func (sol *SolutionList) GetPrograms() []string {
	x := make([]string, len(*sol))
	for i, solution := range *sol {
		x[i] = solution.Program
	}
	return x
}

type PopulationReport struct {
	Id int
	SolutionList
}

func (s SolutionList) Len() int           { return len(s) }
func (s SolutionList) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s SolutionList) Less(i, j int) bool { return s[i].Reward > s[j].Reward }

func NewPopulation(id int, sharedMemory *govirtual.Memory, rl int, is *govirtual.InstructionSet, term govirtual.TerminationCondition, gen Breeder, eval Evaluator, selector Selector) *Population {
	return &Population{id, rl, is, &gen, &eval, &selector, &term, make(chan bool, 1), make(chan *PopulationReport, 1), sharedMemory}
}

func (s *Population) Run() {
	programs := (*s.Breeder).Breed((*s.Breeder).Breed(nil))
	processors := make([]*govirtual.Processor, 0)
	for {
		solutions := make(SolutionList, len(programs))
		for len(processors) < len(solutions) {
			c := govirtual.NewProcessor(s.Id, s.RegisterLength, s.InstructionSet, s.Heap, s.TerminationCondition)
			processors = append(processors, c)
		}
		if len(processors) > len(solutions) {
			processors = processors[:len(solutions)]
		}

		for x, pro := range processors {
			select {
			case <-s.ControlChan:
				return
			default:
			}
			log.Printf("#%d: %d\n", s.Id, x)
			sha := fmt.Sprintf("%x", sha256.Sum256([]byte(programs[x])))
			sol, notNeeded := SolutionCache[sha]
			if notNeeded {
				solutions[x] = sol
			} else {
				pro.Reset()
				pro.CompileAndLoad(programs[x])
				pro.Run()
				solutions[x] = &Solution{(*s.Evaluator).Evaluate(pro), programs[x]}
				potential, present := SolutionCache[sha]
				if !present || potential.Reward > solutions[x].Reward {
					SolutionCache[sha] = solutions[x]
				}
			}
		}
		select {
		case s.PopulationReportChan <- &PopulationReport{s.Id, solutions}:
		default:
		}
		programs = (*s.Breeder).Breed((*s.Selector).Select(&solutions).GetPrograms())
	}
}
<commit_msg>Fixing compile error<commit_after>package goevolve

import (
	"bytes"
	"crypto/sha256"
	"encoding/gob"
	"fmt"
	"github.com/TSavo/GoVirtual"
	"io"
	"log"
	"os"
	"time"
)

type Population struct {
	Id, RegisterLength   int
	InstructionSet       *govirtual.InstructionSet
	Breeder              *Breeder
	Evaluator            *Evaluator
	Selector             *Selector
	TerminationCondition *govirtual.TerminationCondition
	ControlChan          chan bool
	PopulationReportChan chan *PopulationReport
	Heap                 *govirtual.Memory
}

var SolutionCache map[string]*Solution

func init() {
	SolutionCache = make(map[string]*Solution)
	go func() {
		for {
			time.Sleep(60 * time.Second)
			WriteSolutionCache(EncodeSolutionCache())
		}
	}()

	defer recover()
	cache := ReadSolutionCache()
	if(cache != nil) {
		SolutionCache = *DecodeSolutionCache(cache)
	}
}

func EncodeSolutionCache() (b *bytes.Buffer) {
	b = new(bytes.Buffer)
	e := gob.NewEncoder(b)

	// Encoding the map
	err := e.Encode(&SolutionCache)
	if err != nil {
		panic(err)
	}
	return
}

func DecodeSolutionCache(b *bytes.Buffer) *map[string]*Solution {
	s := make(map[string]*Solution)
	d := gob.NewDecoder(b)

	// Decoding the serialized data
	err := d.Decode(&s)
	if err != nil {
		return nil
	}
	return &s
}

func WriteSolutionCache(b *bytes.Buffer) {
	f, _ := os.OpenFile("SolutionCache.gob", os.O_RDWR | os.O_CREATE | os.O_TRUNC, 0777  )
	f.Write(b.Bytes()) // Error handling elided for brevity.
	f.Close()
}

func ReadSolutionCache() *bytes.Buffer {
	buf := bytes.NewBuffer(nil)
	f, _ := os.Open("SolutionCache.gob") // Error handling elided for brevity.
	written, err := io.Copy(buf, f)      // Error handling elided for brevity.
	f.Close()
	if err == nil && written > 0 {
		return buf
	}
	return nil
}

type Solution struct {
	Reward  int
	Program string
}

type SolutionList []*Solution

func (sol *SolutionList) GetPrograms() []string {
	x := make([]string, len(*sol))
	for i, solution := range *sol {
		x[i] = solution.Program
	}
	return x
}

type PopulationReport struct {
	Id int
	SolutionList
}

func (s SolutionList) Len() int           { return len(s) }
func (s SolutionList) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s SolutionList) Less(i, j int) bool { return s[i].Reward > s[j].Reward }

func NewPopulation(id int, sharedMemory *govirtual.Memory, rl int, is *govirtual.InstructionSet, term govirtual.TerminationCondition, gen Breeder, eval Evaluator, selector Selector) *Population {
	return &Population{id, rl, is, &gen, &eval, &selector, &term, make(chan bool, 1), make(chan *PopulationReport, 1), sharedMemory}
}

func (s *Population) Run() {
	programs := (*s.Breeder).Breed((*s.Breeder).Breed(nil))
	processors := make([]*govirtual.Processor, 0)
	for {
		solutions := make(SolutionList, len(programs))
		for len(processors) < len(solutions) {
			c := govirtual.NewProcessor(s.Id, s.RegisterLength, s.InstructionSet, s.Heap, s.TerminationCondition)
			processors = append(processors, c)
		}
		if len(processors) > len(solutions) {
			processors = processors[:len(solutions)]
		}

		for x, pro := range processors {
			select {
			case <-s.ControlChan:
				return
			default:
			}
			log.Printf("#%d: %d\n", s.Id, x)
			sha := fmt.Sprintf("%x", sha256.Sum256([]byte(programs[x])))
			sol, notNeeded := SolutionCache[sha]
			if notNeeded {
				solutions[x] = sol
			} else {
				pro.Reset()
				pro.CompileAndLoad(programs[x])
				pro.Run()
				solutions[x] = &Solution{(*s.Evaluator).Evaluate(pro), programs[x]}
				potential, present := SolutionCache[sha]
				if !present || potential.Reward > solutions[x].Reward {
					SolutionCache[sha] = solutions[x]
				}
			}
		}
		select {
		case s.PopulationReportChan <- &PopulationReport{s.Id, solutions}:
		default:
		}
		programs = (*s.Breeder).Breed((*s.Selector).Select(&solutions).GetPrograms())
	}
}
<|endoftext|>


<commit_before>//  Copyright 2020 Google Inc. All Rights Reserved.
//
//  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 utils contains e2e tests utils for cli tools e2e tests
package utils

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"sort"
	"strings"
	"sync"

	"github.com/GoogleCloudPlatform/compute-image-tools/go/e2e_test_utils/junitxml"
	"github.com/GoogleCloudPlatform/compute-image-tools/go/e2e_test_utils/test_config"
)

// CLITestType defines which type of test is going to be executed
type CLITestType string

// List all test types here
const (
	Wrapper                       CLITestType = "1 wrapper"
	GcloudBetaProdWrapperLatest   CLITestType = "2 gcloud(beta)-prod wrapper-latest"
	GcloudBetaLatestWrapperLatest CLITestType = "3 gcloud(beta)-latest wrapper-latest"
	GcloudGaLatestWrapperRelease  CLITestType = "4 gcloud(ga)-latest wrapper-release"
)

var (
	gcloudUpdateLock = sync.Mutex{}
)

// CLITestSuite executes given test suite.
func CLITestSuite(ctx context.Context, tswg *sync.WaitGroup, testSuites chan *junitxml.TestSuite,
	logger *log.Logger, testSuiteRegex, testCaseRegex *regexp.Regexp,
	testProjectConfig *testconfig.Project, testSuiteName string, testsMap map[CLITestType]map[*junitxml.TestCase]func(
		context.Context, *junitxml.TestCase, *log.Logger, *testconfig.Project, CLITestType)) {

	defer tswg.Done()

	if testSuiteRegex != nil && !testSuiteRegex.MatchString(testSuiteName) {
		return
	}

	testSuite := junitxml.NewTestSuite(testSuiteName)
	defer testSuite.Finish(testSuites)
	logger.Printf("Running CLITestSuite %q", testSuite.Name)
	tests := runTestCases(ctx, logger, testCaseRegex, testProjectConfig, testSuite.Name, testsMap)

	for ret := range tests {
		testSuite.TestCase = append(testSuite.TestCase, ret)
	}

	logger.Printf("Finished CLITestSuite %q", testSuite.Name)
}

func runTestCases(ctx context.Context, logger *log.Logger, regex *regexp.Regexp,
	testProjectConfig *testconfig.Project, testSuiteName string, testsMap map[CLITestType]map[*junitxml.TestCase]func(
		context.Context, *junitxml.TestCase, *log.Logger, *testconfig.Project, CLITestType)) chan *junitxml.TestCase {

	tests := make(chan *junitxml.TestCase)
	var ttwg sync.WaitGroup
	ttwg.Add(len(testsMap))
	tts := make([]string, 0, len(testsMap))
	for tt := range testsMap {
		tts = append(tts, string(tt))
	}
	sort.Strings(tts)
	go func() {
		for _, ttStr := range tts {
			tt := CLITestType(ttStr)
			m := testsMap[tt]
			logger.Printf("=== Running CLITestSuite %v for test type %v ===", testSuiteName, tt)

			var wg sync.WaitGroup
			for tc, f := range m {
				wg.Add(1)
				go func(ctx context.Context, wg *sync.WaitGroup, tc *junitxml.TestCase, tt CLITestType, f func(
					context.Context, *junitxml.TestCase, *log.Logger, *testconfig.Project, CLITestType)) {

					defer wg.Done()
					if tc.FilterTestCase(regex) {
						tc.Finish(tests)
					} else {
						defer logger.Printf("TestCase %s.%q finished in %fs", tc.Classname, tc.Name, tc.Time)
						defer tc.Finish(tests)
						logger.Printf("Running TestCase %s.%q", tc.Classname, tc.Name)
						f(ctx, tc, logger, testProjectConfig, tt)
					}
				}(ctx, &wg, tc, tt, f)
			}
			wg.Wait()

			ttwg.Done()
			logger.Printf("=== Finished running CLITestSuite %v for test type %v ===", testSuiteName, tt)
		}
	}()

	go func() {
		ttwg.Wait()
		close(tests)
	}()

	return tests
}

// RunCliTool runs a cli tool with given args
func RunCliTool(logger *log.Logger, testCase *junitxml.TestCase, cmdString string, args []string) error {
	prefix := "Test Env"
	if testCase != nil {
		prefix = testCase.Name
	}
	logger.Printf("[%v] Running command: '%s %s'", prefix, cmdString, strings.Join(args, " "))
	cmd := exec.Command(cmdString, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// RunTestCommand runs given test command
func RunTestCommand(cmd string, args []string, logger *log.Logger, testCase *junitxml.TestCase) bool {
	if err := RunCliTool(logger, testCase, cmd, args); err != nil {
		Failure(testCase, logger, fmt.Sprintf("Error running cmd: %v\n", err))
		return false
	}
	return true
}

// RunTestCommandIgnoringError runs given test command. The test case won't be marked as fail even error happens.
func RunTestCommandIgnoringError(cmd string, args []string, logger *log.Logger, testCase *junitxml.TestCase) bool {
	if err := RunCliTool(logger, testCase, cmd, args); err != nil {
		logger.Printf("[%v] %v", testCase.Name, fmt.Sprintf("Error running cmd: %v\n", err))
		return false
	}
	return true
}

func runCliToolAsync(logger *log.Logger, testCase *junitxml.TestCase, cmdString string, args []string) (*exec.Cmd, error) {
	logger.Printf("[%v] Running command: '%s %s'", testCase.Name, cmdString, strings.Join(args, " "))
	cmd := exec.Command(cmdString, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	return cmd, err
}

// RunTestCommandAsync runs given test command asynchronously
func RunTestCommandAsync(cmd string, args []string, logger *log.Logger, testCase *junitxml.TestCase) *exec.Cmd {
	cmdPtr, err := runCliToolAsync(logger, testCase, cmd, args)
	if err != nil {
		Failure(testCase, logger, fmt.Sprintf("Error starting cmd: %v\n", err))
		return nil
	}
	return cmdPtr
}

// GcloudAuth runs "gcloud auth"
func GcloudAuth(logger *log.Logger, testCase *junitxml.TestCase) bool {
	// This file exists in test env. For local testing, download a creds file from project
	// compute-image-tools-test.
	credsPath := "/etc/compute-image-tools-test-service-account/creds.json"
	cmd := "gcloud"
	args := []string{"auth", "activate-service-account", "--key-file=" + credsPath}
	if err := RunCliTool(logger, testCase, cmd, args); err != nil {
		Failure(testCase, logger, fmt.Sprintf("Error running cmd: %v\n", err))
		return false
	}
	return true
}

// GcloudUpdate runs "gcloud update" to pull either latest or prod version
func GcloudUpdate(logger *log.Logger, testCase *junitxml.TestCase, latest bool) bool {
	gcloudUpdateLock.Lock()
	defer gcloudUpdateLock.Unlock()

	// auth is required for gcloud updates
	if !GcloudAuth(logger, testCase) {
		return false
	}

	cmd := "gcloud"

	if latest {
		args := []string{"components", "repositories", "add",
			"https://storage.googleapis.com/cloud-sdk-testing/ci/staging/components-2.json", "--quiet"}
		if err := RunCliTool(logger, testCase, cmd, args); err != nil {
			logger.Printf("Error running cmd: %v\n", err)
			testCase.WriteFailure("Error running cmd: %v", err)
			return false
		}
	} else {
		args := []string{"components", "repositories", "remove", "--all"}
		if err := RunCliTool(logger, testCase, cmd, args); err != nil {
			logger.Printf("Error running cmd: %v\n", err)
			testCase.WriteFailure("Error running cmd: %v", err)
			return false
		}
	}

	args := []string{"components", "update", "--quiet"}
	if err := RunCliTool(logger, testCase, cmd, args); err != nil {
		logger.Printf("Error running cmd: %v\n", err)
		testCase.WriteFailure("Error running cmd: %v", err)
		return false
	}

	// an additional auth is required if updated through a different repository
	if !GcloudAuth(logger, testCase) {
		return false
	}

	return true
}

// RunTestForTestType runs test for given test type
func RunTestForTestType(cmd string, args []string, testType CLITestType, logger *log.Logger, testCase *junitxml.TestCase) bool {
	switch testType {
	case Wrapper:
		if !RunTestCommand(cmd, args, logger, testCase) {
			return false
		}
	case GcloudBetaProdWrapperLatest:
		if !GcloudUpdate(logger, testCase, false) {
			return false
		}
		if !RunTestCommand(cmd, args, logger, testCase) {
			return false
		}
	case GcloudBetaLatestWrapperLatest:
	case GcloudGaLatestWrapperRelease:
		if !GcloudUpdate(logger, testCase, true) {
			return false
		}
		if !RunTestCommand(cmd, args, logger, testCase) {
			return false
		}
	}
	return true
}

// Failure logs failure message to both test case output and logger.
func Failure(testCase *junitxml.TestCase, logger *log.Logger, msg string) {
	prefix := "Test Env"
	if testCase != nil {
		prefix = testCase.Name
		testCase.WriteFailure(msg)
	}
	logger.Printf("[%v] %v", prefix, msg)
}

// ContainsSubString checks whether the string slice contains a substring anywhere.
func ContainsSubString(strs []string, s string) bool {
	for _, str := range strs {
		if strings.Contains(str, s) {
			return true
		}
	}
	return false
}
<commit_msg>Fixed GcloudGaLatestWrapperRelease E2E tests not running (#1363)<commit_after>//  Copyright 2020 Google Inc. All Rights Reserved.
//
//  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 utils contains e2e tests utils for cli tools e2e tests
package utils

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/exec"
	"regexp"
	"sort"
	"strings"
	"sync"

	"github.com/GoogleCloudPlatform/compute-image-tools/go/e2e_test_utils/junitxml"
	"github.com/GoogleCloudPlatform/compute-image-tools/go/e2e_test_utils/test_config"
)

// CLITestType defines which type of test is going to be executed
type CLITestType string

// List all test types here
const (
	Wrapper                       CLITestType = "1 wrapper"
	GcloudBetaProdWrapperLatest   CLITestType = "2 gcloud(beta)-prod wrapper-latest"
	GcloudBetaLatestWrapperLatest CLITestType = "3 gcloud(beta)-latest wrapper-latest"
	GcloudGaLatestWrapperRelease  CLITestType = "4 gcloud(ga)-latest wrapper-release"
)

var (
	gcloudUpdateLock = sync.Mutex{}
)

// CLITestSuite executes given test suite.
func CLITestSuite(ctx context.Context, tswg *sync.WaitGroup, testSuites chan *junitxml.TestSuite,
	logger *log.Logger, testSuiteRegex, testCaseRegex *regexp.Regexp,
	testProjectConfig *testconfig.Project, testSuiteName string, testsMap map[CLITestType]map[*junitxml.TestCase]func(
		context.Context, *junitxml.TestCase, *log.Logger, *testconfig.Project, CLITestType)) {

	defer tswg.Done()

	if testSuiteRegex != nil && !testSuiteRegex.MatchString(testSuiteName) {
		return
	}

	testSuite := junitxml.NewTestSuite(testSuiteName)
	defer testSuite.Finish(testSuites)
	logger.Printf("Running CLITestSuite %q", testSuite.Name)
	tests := runTestCases(ctx, logger, testCaseRegex, testProjectConfig, testSuite.Name, testsMap)

	for ret := range tests {
		testSuite.TestCase = append(testSuite.TestCase, ret)
	}

	logger.Printf("Finished CLITestSuite %q", testSuite.Name)
}

func runTestCases(ctx context.Context, logger *log.Logger, regex *regexp.Regexp,
	testProjectConfig *testconfig.Project, testSuiteName string, testsMap map[CLITestType]map[*junitxml.TestCase]func(
		context.Context, *junitxml.TestCase, *log.Logger, *testconfig.Project, CLITestType)) chan *junitxml.TestCase {

	tests := make(chan *junitxml.TestCase)
	var ttwg sync.WaitGroup
	ttwg.Add(len(testsMap))
	tts := make([]string, 0, len(testsMap))
	for tt := range testsMap {
		tts = append(tts, string(tt))
	}
	sort.Strings(tts)
	go func() {
		for _, ttStr := range tts {
			tt := CLITestType(ttStr)
			m := testsMap[tt]
			logger.Printf("=== Running CLITestSuite %v for test type %v ===", testSuiteName, tt)

			var wg sync.WaitGroup
			for tc, f := range m {
				wg.Add(1)
				go func(ctx context.Context, wg *sync.WaitGroup, tc *junitxml.TestCase, tt CLITestType, f func(
					context.Context, *junitxml.TestCase, *log.Logger, *testconfig.Project, CLITestType)) {

					defer wg.Done()
					if tc.FilterTestCase(regex) {
						tc.Finish(tests)
					} else {
						defer logger.Printf("TestCase %s.%q finished in %fs", tc.Classname, tc.Name, tc.Time)
						defer tc.Finish(tests)
						logger.Printf("Running TestCase %s.%q", tc.Classname, tc.Name)
						f(ctx, tc, logger, testProjectConfig, tt)
					}
				}(ctx, &wg, tc, tt, f)
			}
			wg.Wait()

			ttwg.Done()
			logger.Printf("=== Finished running CLITestSuite %v for test type %v ===", testSuiteName, tt)
		}
	}()

	go func() {
		ttwg.Wait()
		close(tests)
	}()

	return tests
}

// RunCliTool runs a cli tool with given args
func RunCliTool(logger *log.Logger, testCase *junitxml.TestCase, cmdString string, args []string) error {
	prefix := "Test Env"
	if testCase != nil {
		prefix = testCase.Name
	}
	logger.Printf("[%v] Running command: '%s %s'", prefix, cmdString, strings.Join(args, " "))
	cmd := exec.Command(cmdString, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// RunTestCommand runs given test command
func RunTestCommand(cmd string, args []string, logger *log.Logger, testCase *junitxml.TestCase) bool {
	if err := RunCliTool(logger, testCase, cmd, args); err != nil {
		Failure(testCase, logger, fmt.Sprintf("Error running cmd: %v\n", err))
		return false
	}
	return true
}

// RunTestCommandIgnoringError runs given test command. The test case won't be marked as fail even error happens.
func RunTestCommandIgnoringError(cmd string, args []string, logger *log.Logger, testCase *junitxml.TestCase) bool {
	if err := RunCliTool(logger, testCase, cmd, args); err != nil {
		logger.Printf("[%v] %v", testCase.Name, fmt.Sprintf("Error running cmd: %v\n", err))
		return false
	}
	return true
}

func runCliToolAsync(logger *log.Logger, testCase *junitxml.TestCase, cmdString string, args []string) (*exec.Cmd, error) {
	logger.Printf("[%v] Running command: '%s %s'", testCase.Name, cmdString, strings.Join(args, " "))
	cmd := exec.Command(cmdString, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	return cmd, err
}

// RunTestCommandAsync runs given test command asynchronously
func RunTestCommandAsync(cmd string, args []string, logger *log.Logger, testCase *junitxml.TestCase) *exec.Cmd {
	cmdPtr, err := runCliToolAsync(logger, testCase, cmd, args)
	if err != nil {
		Failure(testCase, logger, fmt.Sprintf("Error starting cmd: %v\n", err))
		return nil
	}
	return cmdPtr
}

// GcloudAuth runs "gcloud auth"
func GcloudAuth(logger *log.Logger, testCase *junitxml.TestCase) bool {
	// This file exists in test env. For local testing, download a creds file from project
	// compute-image-tools-test.
	credsPath := "/etc/compute-image-tools-test-service-account/creds.json"
	cmd := "gcloud"
	args := []string{"auth", "activate-service-account", "--key-file=" + credsPath}
	if err := RunCliTool(logger, testCase, cmd, args); err != nil {
		Failure(testCase, logger, fmt.Sprintf("Error running cmd: %v\n", err))
		return false
	}
	return true
}

// GcloudUpdate runs "gcloud update" to pull either latest or prod version
func GcloudUpdate(logger *log.Logger, testCase *junitxml.TestCase, latest bool) bool {
	gcloudUpdateLock.Lock()
	defer gcloudUpdateLock.Unlock()

	// auth is required for gcloud updates
	if !GcloudAuth(logger, testCase) {
		return false
	}

	cmd := "gcloud"

	if latest {
		args := []string{"components", "repositories", "add",
			"https://storage.googleapis.com/cloud-sdk-testing/ci/staging/components-2.json", "--quiet"}
		if err := RunCliTool(logger, testCase, cmd, args); err != nil {
			logger.Printf("Error running cmd: %v\n", err)
			testCase.WriteFailure("Error running cmd: %v", err)
			return false
		}
	} else {
		args := []string{"components", "repositories", "remove", "--all"}
		if err := RunCliTool(logger, testCase, cmd, args); err != nil {
			logger.Printf("Error running cmd: %v\n", err)
			testCase.WriteFailure("Error running cmd: %v", err)
			return false
		}
	}

	args := []string{"components", "update", "--quiet"}
	if err := RunCliTool(logger, testCase, cmd, args); err != nil {
		logger.Printf("Error running cmd: %v\n", err)
		testCase.WriteFailure("Error running cmd: %v", err)
		return false
	}

	// an additional auth is required if updated through a different repository
	if !GcloudAuth(logger, testCase) {
		return false
	}

	return true
}

// RunTestForTestType runs test for given test type
func RunTestForTestType(cmd string, args []string, testType CLITestType, logger *log.Logger, testCase *junitxml.TestCase) bool {
	switch testType {
	case Wrapper:
		if !RunTestCommand(cmd, args, logger, testCase) {
			return false
		}
	case GcloudBetaProdWrapperLatest:
		if !GcloudUpdate(logger, testCase, false) {
			return false
		}
		if !RunTestCommand(cmd, args, logger, testCase) {
			return false
		}
	case GcloudBetaLatestWrapperLatest:
		fallthrough
	case GcloudGaLatestWrapperRelease:
		if !GcloudUpdate(logger, testCase, true) {
			return false
		}
		if !RunTestCommand(cmd, args, logger, testCase) {
			return false
		}
	}
	return true
}

// Failure logs failure message to both test case output and logger.
func Failure(testCase *junitxml.TestCase, logger *log.Logger, msg string) {
	prefix := "Test Env"
	if testCase != nil {
		prefix = testCase.Name
		testCase.WriteFailure(msg)
	}
	logger.Printf("[%v] %v", prefix, msg)
}

// ContainsSubString checks whether the string slice contains a substring anywhere.
func ContainsSubString(strs []string, s string) bool {
	for _, str := range strs {
		if strings.Contains(str, s) {
			return true
		}
	}
	return false
}
<|endoftext|>