<commit_before>package panicwrap

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"testing"
)

func helperProcess(s ...string) *exec.Cmd {
	cs := []string{"-test.run=TestHelperProcess", "--"}
	cs = append(cs, s...)
	env := []string{
		"GO_WANT_HELPER_PROCESS=1",
	}

	cmd := exec.Command(os.Args[0], cs...)
	cmd.Env = append(env, os.Environ()...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd
}

// This is executed by `helperProcess` in a separate process in order to
// provider a proper sub-process environment to test some of our functionality.
func TestHelperProcess(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}

	// Find the arguments to our helper, which are the arguments past
	// the "--" in the command line.
	args := os.Args
	for len(args) > 0 {
		if args[0] == "--" {
			args = args[1:]
			break
		}

		args = args[1:]
	}

	if len(args) == 0 {
		fmt.Fprintf(os.Stderr, "No command\n")
		os.Exit(2)
	}

	cmd, args := args[0], args[1:]
	switch cmd {
	case "panic":
		exitStatus, err := BasicWrap(func(string) {
			fmt.Fprint(os.Stdout, "wrapped")
			os.Exit(0)
		})

		if err != nil {
			fmt.Fprintf(os.Stderr, "wrap error: %s", err)
			os.Exit(1)
		}

		if exitStatus < 0 {
			panic("uh oh")
		}

		os.Exit(exitStatus)
	default:
		fmt.Fprintf(os.Stderr, "Unknown command: %q\n", cmd)
		os.Exit(2)
	}
}

func TestPanicWrap(t *testing.T) {
	stdout := new(bytes.Buffer)

	p := helperProcess("panic")
	p.Stdout = stdout
	if err := p.Run(); err != nil {
		t.Fatalf("err: %s", err)
	}

	if !strings.Contains(stdout.String(), "wrapped") {
		t.Fatalf("didn't wrap: %#v", stdout.String())
	}
}
<commit_msg>test that output is shuttled through<commit_after>package panicwrap

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"testing"
)

func helperProcess(s ...string) *exec.Cmd {
	cs := []string{"-test.run=TestHelperProcess", "--"}
	cs = append(cs, s...)
	env := []string{
		"GO_WANT_HELPER_PROCESS=1",
	}

	cmd := exec.Command(os.Args[0], cs...)
	cmd.Env = append(env, os.Environ()...)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd
}

// This is executed by `helperProcess` in a separate process in order to
// provider a proper sub-process environment to test some of our functionality.
func TestHelperProcess(*testing.T) {
	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
		return
	}

	// Find the arguments to our helper, which are the arguments past
	// the "--" in the command line.
	args := os.Args
	for len(args) > 0 {
		if args[0] == "--" {
			args = args[1:]
			break
		}

		args = args[1:]
	}

	if len(args) == 0 {
		fmt.Fprintf(os.Stderr, "No command\n")
		os.Exit(2)
	}

	cmd, args := args[0], args[1:]
	switch cmd {
	case "no-panic-output":
		fmt.Fprint(os.Stdout, "i am output")
		fmt.Fprint(os.Stderr, "stderr out")
		os.Exit(0)
	case "panic":
		exitStatus, err := BasicWrap(func(string) {
			fmt.Fprint(os.Stdout, "wrapped")
			os.Exit(0)
		})

		if err != nil {
			fmt.Fprintf(os.Stderr, "wrap error: %s", err)
			os.Exit(1)
		}

		if exitStatus < 0 {
			panic("uh oh")
		}

		os.Exit(exitStatus)
	default:
		fmt.Fprintf(os.Stderr, "Unknown command: %q\n", cmd)
		os.Exit(2)
	}
}

func TestPanicWrap_Output(t *testing.T) {
	stderr := new(bytes.Buffer)
	stdout := new(bytes.Buffer)

	p := helperProcess("no-panic-output")
	p.Stdout = stdout
	p.Stderr = stderr
	if err := p.Run(); err != nil {
		t.Fatalf("err: %s", err)
	}

	if !strings.Contains(stdout.String(), "i am output") {
		t.Fatalf("didn't forward: %#v", stdout.String())
	}

	if !strings.Contains(stderr.String(), "stderr out") {
		t.Fatalf("didn't forward: %#v", stderr.String())
	}
}

func TestPanicWrap_Wrap(t *testing.T) {
	stdout := new(bytes.Buffer)

	p := helperProcess("panic")
	p.Stdout = stdout
	if err := p.Run(); err != nil {
		t.Fatalf("err: %s", err)
	}

	if !strings.Contains(stdout.String(), "wrapped") {
		t.Fatalf("didn't wrap: %#v", stdout.String())
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Google, Inc. All rights reserved.

// +build ignore

// This benchmark reads in file <tempdir>/gopacket_benchmark.pcap and measures
// the time it takes to decode all packets from that file.  If the file doesn't
// exist, it's pulled down from a publicly available location.  However, you can
// feel free to substitute your own file at that location, in which case the
// benchmark will run on your own data.
// It's also useful for figuring out which packets may be causing errors.  Pass
// in the --printErrors flag, and it'll print out error layers for each packet
// that has them.
package main

import (
	"compress/gzip"
  "encoding/hex"
	"flag"
	"fmt"
	"github.com/gconnell/gopacket/pcap"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

var decodeLazy *bool = flag.Bool("lazy", false, "If true, use lazy decoding")
var decodeNoCopy *bool = flag.Bool("nocopy", false, "If true, avoid an extra copy when decoding packets")
var printErrors *bool = flag.Bool("printErrors", false, "If true, check for and print error layers.")
var printLayers *bool = flag.Bool("printLayers", false, "If true, print out the layers of each packet")
var repeat *int = flag.Int("repeat", 1, "Read over the file N times")

func main() {
	flag.Parse()
	filename := os.TempDir() + string(os.PathSeparator) + "gopacket_benchmark.pcap"
	if _, err := os.Stat(filename); err != nil {
		// This URL points to a publicly available packet data set from a DARPA
		// intrusion detection evaluation.  See
		// http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/1999/training/week1/index.html
		// for more details.
		url := "http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/1999/training/week1/tuesday/inside.tcpdump.gz"
		fmt.Println("Local pcap file", filename, "doesn't exist, reading from", url)
		if resp, err := http.Get(url); err != nil {
			panic(err)
		} else if out, err := os.Create(filename); err != nil {
			panic(err)
		} else if gz, err := gzip.NewReader(resp.Body); err != nil {
			panic(err)
		} else if n, err := io.Copy(out, gz); err != nil {
			panic(err)
		} else if err := gz.Close(); err != nil {
			panic(err)
		} else if err := out.Close(); err != nil {
			panic(err)
		} else {
			fmt.Println("Successfully read", n, "bytes from url, unzipped to local storage")
		}
	}
	fmt.Println("Reading file once through to hopefully cache most of it")
	if f, err := os.Open(filename); err != nil {
		panic(err)
	} else if n, err := io.Copy(ioutil.Discard, f); err != nil {
		panic(err)
	} else if err := f.Close(); err != nil {
		panic(err)
	} else {
		fmt.Println("Read in file", filename, ", total of", n, "bytes")
	}
	for i := 0; i < *repeat; i++ {
		fmt.Println("Opening file", filename, "for read")
		if h, err := pcap.OpenOffline(filename); err != nil {
			panic(err)
		} else {
			h.DecodeOptions.Lazy = *decodeLazy
			h.DecodeOptions.NoCopy = *decodeNoCopy
			count, errors := 0, 0
			start := time.Now()
			for packet, err := h.Next(); err != pcap.NextErrorNoMorePackets; packet, err = h.Next() {
				if err != nil {
					fmt.Println("Error reading in packet:", err)
				}
				count++
        var hasError bool
				if *printErrors && packet.ErrorLayer() != nil {
					fmt.Println("Error decoding packet:", packet.ErrorLayer().Error())
          fmt.Println(hex.Dump(packet.Data()))
					errors++
          hasError = true
				}
        if *printLayers || hasError {
          fmt.Printf("=== PACKET %d ===\n", count)
          for _, l := range packet.Layers() {
            fmt.Printf("--- LAYER %v ---\n%#v\n", l.LayerType(), l)
          }
          fmt.Println()
        }
			}
			duration := time.Since(start)
			fmt.Printf("Read in %v packets in %v, %v per packet\n", count, duration, duration/time.Duration(count))
			if *printErrors {
				fmt.Printf("%v errors, successfully decoded %.02f%%\n", errors, float64(count-errors)*100.0/float64(count))
			}
		}
	}
}
<commit_msg>Added CPU profiling to benchmark.<commit_after>// Copyright 2012 Google, Inc. All rights reserved.

// +build ignore

// This benchmark reads in file <tempdir>/gopacket_benchmark.pcap and measures
// the time it takes to decode all packets from that file.  If the file doesn't
// exist, it's pulled down from a publicly available location.  However, you can
// feel free to substitute your own file at that location, in which case the
// benchmark will run on your own data.
// It's also useful for figuring out which packets may be causing errors.  Pass
// in the --printErrors flag, and it'll print out error layers for each packet
// that has them.
package main

import (
	"compress/gzip"
	"encoding/hex"
	"flag"
	"fmt"
	"github.com/gconnell/gopacket/pcap"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"runtime/pprof"
	"time"
)

var decodeLazy *bool = flag.Bool("lazy", false, "If true, use lazy decoding")
var decodeNoCopy *bool = flag.Bool("nocopy", false, "If true, avoid an extra copy when decoding packets")
var printErrors *bool = flag.Bool("printErrors", false, "If true, check for and print error layers.")
var printLayers *bool = flag.Bool("printLayers", false, "If true, print out the layers of each packet")
var repeat *int = flag.Int("repeat", 1, "Read over the file N times")
var cpuProfile *string = flag.String("cpuprofile", "", "If set, write CPU profile to filename")

func main() {
	flag.Parse()
	filename := os.TempDir() + string(os.PathSeparator) + "gopacket_benchmark.pcap"
	if _, err := os.Stat(filename); err != nil {
		// This URL points to a publicly available packet data set from a DARPA
		// intrusion detection evaluation.  See
		// http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/1999/training/week1/index.html
		// for more details.
		url := "http://www.ll.mit.edu/mission/communications/cyber/CSTcorpora/ideval/data/1999/training/week1/tuesday/inside.tcpdump.gz"
		fmt.Println("Local pcap file", filename, "doesn't exist, reading from", url)
		if resp, err := http.Get(url); err != nil {
			panic(err)
		} else if out, err := os.Create(filename); err != nil {
			panic(err)
		} else if gz, err := gzip.NewReader(resp.Body); err != nil {
			panic(err)
		} else if n, err := io.Copy(out, gz); err != nil {
			panic(err)
		} else if err := gz.Close(); err != nil {
			panic(err)
		} else if err := out.Close(); err != nil {
			panic(err)
		} else {
			fmt.Println("Successfully read", n, "bytes from url, unzipped to local storage")
		}
	}
	fmt.Println("Reading file once through to hopefully cache most of it")
	if f, err := os.Open(filename); err != nil {
		panic(err)
	} else if n, err := io.Copy(ioutil.Discard, f); err != nil {
		panic(err)
	} else if err := f.Close(); err != nil {
		panic(err)
	} else {
		fmt.Println("Read in file", filename, ", total of", n, "bytes")
	}
	if *cpuProfile != "" {
		if cpu, err := os.Create(*cpuProfile); err != nil {
			panic(err)
		} else if err := pprof.StartCPUProfile(cpu); err != nil {
			panic(err)
		} else {
			defer func() {
				pprof.StopCPUProfile()
				cpu.Close()
			}()
		}
	}
	for i := 0; i < *repeat; i++ {
		fmt.Println("Opening file", filename, "for read")
		if h, err := pcap.OpenOffline(filename); err != nil {
			panic(err)
		} else {
			h.DecodeOptions.Lazy = *decodeLazy
			h.DecodeOptions.NoCopy = *decodeNoCopy
			count, errors := 0, 0
			start := time.Now()
			for packet, err := h.Next(); err != pcap.NextErrorNoMorePackets; packet, err = h.Next() {
				if err != nil {
					fmt.Println("Error reading in packet:", err)
				}
				count++
				var hasError bool
				if *printErrors && packet.ErrorLayer() != nil {
					fmt.Println("Error decoding packet:", packet.ErrorLayer().Error())
					fmt.Println(hex.Dump(packet.Data()))
					errors++
					hasError = true
				}
				if *printLayers || hasError {
					fmt.Printf("=== PACKET %d ===\n", count)
					for _, l := range packet.Layers() {
						fmt.Printf("--- LAYER %v ---\n%#v\n", l.LayerType(), l)
					}
					fmt.Println()
				}
			}
			duration := time.Since(start)
			fmt.Printf("Read in %v packets in %v, %v per packet\n", count, duration, duration/time.Duration(count))
			if *printErrors {
				fmt.Printf("%v errors, successfully decoded %.02f%%\n", errors, float64(count-errors)*100.0/float64(count))
			}
		}
	}
}
<|endoftext|>


<commit_before>package gitmedia

import (
	"errors"
	"fmt"
	"github.com/github/git-media/git"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

const Version = "0.2.3"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	LocalLinkDir       string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func LocalLinkPath(sha string) (string, error) {
	if len(sha) == 0 {
		return "", fmt.Errorf("Error trying to create local object directory, invalid sha: '%s'", sha)
	}
	path := filepath.Join(LocalLinkDir, sha[0:2])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local object directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha[2:len(sha)]), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

var shaMatcher = regexp.MustCompile(`^[0-9a-f]{40}`)

func CurrentRef() (string, error) {
	head, err := ioutil.ReadFile(filepath.Join(LocalGitDir, "HEAD"))
	if err != nil {
		return "", err
	}

	if shaMatcher.Match(head) {
		return strings.TrimSpace(string(head)), nil
	}

	headString := string(head)
	parts := strings.Split(headString, " ")
	if len(parts) != 2 {
		return "", errors.New("Unable to parse HEAD")
	}

	refFile := strings.TrimSpace(parts[1])
	sha, err := ioutil.ReadFile(filepath.Join(LocalGitDir, refFile))
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(string(sha)), nil
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		LocalLinkDir = filepath.Join(LocalMediaDir, "objects")
		TempDir = filepath.Join(LocalMediaDir, "tmp")

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}

		if err := os.MkdirAll(LocalLinkDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create objects directory in '%s': %s", LocalLinkDir, err))
		}
	}

	gitVersion, err := git.Config.Version()
	if err != nil {
		gitVersion = "unknown"
	}

	UserAgent = fmt.Sprintf("git-media/%s (GitHub; %s %s; git %s; go %s)", Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(gitVersion, "git version ", "", 1),
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

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

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<commit_msg>ラララララ ラー ララララー<commit_after>package gitmedia

import (
	"errors"
	"fmt"
	"github.com/github/git-media/git"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

const Version = "0.3.1"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	UserAgent          string
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	LocalLinkDir       string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func LocalLinkPath(sha string) (string, error) {
	if len(sha) == 0 {
		return "", fmt.Errorf("Error trying to create local object directory, invalid sha: '%s'", sha)
	}
	path := filepath.Join(LocalLinkDir, sha[0:2])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local object directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha[2:len(sha)]), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

var shaMatcher = regexp.MustCompile(`^[0-9a-f]{40}`)

func CurrentRef() (string, error) {
	head, err := ioutil.ReadFile(filepath.Join(LocalGitDir, "HEAD"))
	if err != nil {
		return "", err
	}

	if shaMatcher.Match(head) {
		return strings.TrimSpace(string(head)), nil
	}

	headString := string(head)
	parts := strings.Split(headString, " ")
	if len(parts) != 2 {
		return "", errors.New("Unable to parse HEAD")
	}

	refFile := strings.TrimSpace(parts[1])
	sha, err := ioutil.ReadFile(filepath.Join(LocalGitDir, refFile))
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(string(sha)), nil
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		LocalLinkDir = filepath.Join(LocalMediaDir, "objects")
		TempDir = filepath.Join(LocalMediaDir, "tmp")

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}

		if err := os.MkdirAll(LocalLinkDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create objects directory in '%s': %s", LocalLinkDir, err))
		}
	}

	gitVersion, err := git.Config.Version()
	if err != nil {
		gitVersion = "unknown"
	}

	UserAgent = fmt.Sprintf("git-media/%s (GitHub; %s %s; git %s; go %s)", Version,
		runtime.GOOS,
		runtime.GOARCH,
		strings.Replace(gitVersion, "git version ", "", 1),
		strings.Replace(runtime.Version(), "go", "", 1))
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	var cleanDir = filepath.Clean(dir)
	if cleanDir[len(cleanDir)-1] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

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

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<|endoftext|>


<commit_before>package gitschemalex

import (
	"database/sql"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"testing"

	_ "github.com/go-sql-driver/mysql"
	"github.com/lestrrat/go-test-mysqld"
)

func TestRunner(t *testing.T) {
	var dsn = "root:@127.0.0.1:3306/mysql"
	if ok, _ := strconv.ParseBool(os.Getenv("TRAVIS")); !ok {
		mysqld, err := mysqltest.NewMysqld(nil)
		if err != nil {
			t.Fatal(err)
		}
		defer mysqld.Stop()
		dsn = mysqld.DSN()
	}

	db, err := sql.Open("mysql", dsn)
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec("CREATE DATABASE IF NOT EXISTS `test`"); err != nil {
		t.Fatal(err)
	}

	if _, err := db.Exec("USE `test`"); err != nil {
		t.Fatal(err)
	}

	dir, err := ioutil.TempDir("", "gitschemalex")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	if err := os.Chdir(dir); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "init").Run(); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "config", "user.email", "hoge@example.com").Run(); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "config", "user.name", "hoge").Run(); err != nil {
		t.Fatal(err)
	}

	schema, err := os.Create(filepath.Join(dir, "schema.sql"))
	if err != nil {
		t.Fatal(err)
	}

	// first table

	if _, err := schema.WriteString("CREATE TABLE hoge ( `id` INTEGER NOT NULL, `c` VARCHAR(20) );\n"); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "add", "schema.sql").Run(); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "commit", "-m", "initial commit").Run(); err != nil {
		t.Fatal(err)
	}

	r := &Runner{
		Workspace: dir,
		Deploy:    true,
		DSN:       dsn,
		Table:     "git_schemalex_version",
		Schema:    "schema.sql",
	}
	if err := r.Run(); err != nil {
		t.Fatal(err)
	}

	// deployed

	if _, err := db.Exec("INSERT INTO `hoge` (`id`, `c`) VALUES (1, '2')"); err != nil {
		t.Fatal(err)
	}

	// second table

	if _, err := schema.WriteString("CREATE TABLE fuga ( `id` INTEGER NOT NULL, `c` VARCHAR(20) );\n"); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "add", "schema.sql").Run(); err != nil {
		t.Fatal(err)
	}
	if err := exec.Command("git", "commit", "--author", "hoge <hoge@example.com>", "-m", "second commit").Run(); err != nil {
		t.Fatal(err)
	}

	if err := r.Run(); err != nil {
		t.Fatal(err)
	}

	if _, err := db.Exec("INSERT INTO `fuga` (`id`, `c`) VALUES (1, '2')"); err != nil {
		t.Fatal(err)
	}

	// equal version

	if e, g := ErrEqualVersion, r.Run(); e != g {
		t.Fatal("should %v got %v", e, g)
	}
}
<commit_msg>dangit, tcp()<commit_after>package gitschemalex

import (
	"database/sql"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"testing"

	_ "github.com/go-sql-driver/mysql"
	"github.com/lestrrat/go-test-mysqld"
)

func TestRunner(t *testing.T) {
	var dsn = "root:@tcp(127.0.0.1:3306)/mysql"
	if ok, _ := strconv.ParseBool(os.Getenv("TRAVIS")); !ok {
		mysqld, err := mysqltest.NewMysqld(nil)
		if err != nil {
			t.Fatal(err)
		}
		defer mysqld.Stop()
		dsn = mysqld.DSN()
	}

	db, err := sql.Open("mysql", dsn)
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	if _, err := db.Exec("CREATE DATABASE IF NOT EXISTS `test`"); err != nil {
		t.Fatal(err)
	}

	if _, err := db.Exec("USE `test`"); err != nil {
		t.Fatal(err)
	}

	dir, err := ioutil.TempDir("", "gitschemalex")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	if err := os.Chdir(dir); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "init").Run(); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "config", "user.email", "hoge@example.com").Run(); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "config", "user.name", "hoge").Run(); err != nil {
		t.Fatal(err)
	}

	schema, err := os.Create(filepath.Join(dir, "schema.sql"))
	if err != nil {
		t.Fatal(err)
	}

	// first table

	if _, err := schema.WriteString("CREATE TABLE hoge ( `id` INTEGER NOT NULL, `c` VARCHAR(20) );\n"); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "add", "schema.sql").Run(); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "commit", "-m", "initial commit").Run(); err != nil {
		t.Fatal(err)
	}

	r := &Runner{
		Workspace: dir,
		Deploy:    true,
		DSN:       dsn,
		Table:     "git_schemalex_version",
		Schema:    "schema.sql",
	}
	if err := r.Run(); err != nil {
		t.Fatal(err)
	}

	// deployed

	if _, err := db.Exec("INSERT INTO `hoge` (`id`, `c`) VALUES (1, '2')"); err != nil {
		t.Fatal(err)
	}

	// second table

	if _, err := schema.WriteString("CREATE TABLE fuga ( `id` INTEGER NOT NULL, `c` VARCHAR(20) );\n"); err != nil {
		t.Fatal(err)
	}

	if err := exec.Command("git", "add", "schema.sql").Run(); err != nil {
		t.Fatal(err)
	}
	if err := exec.Command("git", "commit", "--author", "hoge <hoge@example.com>", "-m", "second commit").Run(); err != nil {
		t.Fatal(err)
	}

	if err := r.Run(); err != nil {
		t.Fatal(err)
	}

	if _, err := db.Exec("INSERT INTO `fuga` (`id`, `c`) VALUES (1, '2')"); err != nil {
		t.Fatal(err)
	}

	// equal version

	if e, g := ErrEqualVersion, r.Run(); e != g {
		t.Fatal("should %v got %v", e, g)
	}
}
<|endoftext|>


<commit_before>package objects

import (
	"encoding/big"

type Msg struct {
	AddrHash []byte
	TxidHash []byte
	Timestamp time.Time
	IV []byte
	X big.Int
	Y big.Int
	Encrypted []byte
	MAC []byte
}

func (m *Msg) FromBytes(log chan string, data []byte) {
  var buffer bytes.Buffer
  enc := gob.NewDecoder(&buffer)
  err := enc.Decode(m)
  if err != nil {
    log <- "Decoding error."
    log <- err.Error()
  }
}

func (m *Msg) GetBytes(log chan string) []byte {
  var buffer bytes.Buffer
  enc := gob.NewEncoder(&buffer)
  err := enc.Encode(m)
  if err != nil {
    log <- "Encoding error!"
    log <- err.Error()
    return nil
  } else {
    return buffer.Bytes()
  }
}

type MsgUnencrypted struct {
	Txid []byte
	SendAddr []byte
	Message string
}
<commit_msg>added missing )<commit_after>package objects

import (
	"encoding/big"
)

type Msg struct {
	AddrHash []byte
	TxidHash []byte
	Timestamp time.Time
	IV []byte
	X big.Int
	Y big.Int
	Encrypted []byte
	MAC []byte
}

func (m *Msg) FromBytes(log chan string, data []byte) {
  var buffer bytes.Buffer
  enc := gob.NewDecoder(&buffer)
  err := enc.Decode(m)
  if err != nil {
    log <- "Decoding error."
    log <- err.Error()
  }
}

func (m *Msg) GetBytes(log chan string) []byte {
  var buffer bytes.Buffer
  enc := gob.NewEncoder(&buffer)
  err := enc.Encode(m)
  if err != nil {
    log <- "Encoding error!"
    log <- err.Error()
    return nil
  } else {
    return buffer.Bytes()
  }
}

type MsgUnencrypted struct {
	Txid []byte
	SendAddr []byte
	Message string
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"
	"math/rand"
)

func Sqrt(x float64) float64 {
	var z float64 = rand.Float64() + float64(1)
	var diff float64 = x

	for math.Floor(diff) != 0 {
		diff = (z - ((z*z - x) / 2 * z))
	}
	return diff
}

func main() {
	fmt.Println(Sqrt(2))
}
<commit_msg>day: 2, caught in infinte loop<commit_after>package main

import (
	"fmt"
	"math"
	"math/rand"
)

func Sqrt(x float64) float64 {
	var z float64 = rand.Float64() + float64(1)
	z_next := z + float64(1)

	for diff := z_next - z; math.Floor(diff) != 0; {
		z_next = z - ((z*z - x) / (2 * z))
		diff = z_next - z
	}
	return z_next
}

func main() {
	fmt.Println(Sqrt(2))
}
<|endoftext|>


<commit_before>// Package cas implements an efficient client for Content Addressable Storage.
package cas

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/pkg/errors"
	"golang.org/x/sync/semaphore"
	bspb "google.golang.org/genproto/googleapis/bytestream"
	"google.golang.org/grpc"

	"github.com/bazelbuild/remote-apis-sdks/go/pkg/digest"
	"github.com/bazelbuild/remote-apis-sdks/go/pkg/retry"
	repb "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2"
)

// Client is a client for Content Addressable Storage.
// Create one using NewClient.
//
// Goroutine-safe.
//
// All fields are considered immutable, and should not be changed.
type Client struct {
	conn *grpc.ClientConn
	// InstanceName is the full name of the RBE instance.
	InstanceName string

	// ClientConfig is the configuration that the client was created with.
	ClientConfig

	byteStream bspb.ByteStreamClient
	cas        repb.ContentAddressableStorageClient

	// per-RPC semaphores

	semFindMissingBlobs *semaphore.Weighted
	semBatchUpdateBlobs *semaphore.Weighted

	// TODO(nodir): ensure it does not hurt streaming.
	semFileIO *semaphore.Weighted
	// muLargeFile ensures only one large file is read/written at a time.
	// TODO(nodir): ensure this doesn't hurt performance on SSDs.
	muLargeFile sync.Mutex
	// Pools of []byte slices with the length of ClientConfig.FileIOSize.
	fileIOBufs sync.Pool

	// Mockable functions.

	testScheduleCheck func(ctx context.Context, item *uploadItem) error
}

// ClientConfig is a config for Client.
// See DefaultClientConfig() for the default values.
type ClientConfig struct {
	// FSConcurrency is the maximum number of concurrent file system operations.
	// TODO(nodir): ensure this does not hurt streaming performance
	FSConcurrency int

	// SmallFileThreshold is a size threshold to categorize a file as small.
	// Such files are buffered entirely (read only once).
	SmallFileThreshold int64

	// LargeFileThreshold is a size threshold to categorize a file as large. For
	// such files, IO concurrency limits are much tighter and locality is
	// prioritized: the file is read for the first and second times with minimal
	// delay between the two.
	LargeFileThreshold int64

	// FileIOSize is the size of file reads.
	FileIOSize int64

	// FindMissingBlobs is configuration for FindMissingBlobs RPCs.
	// FindMissingBlobs.MaxSizeBytes is ignored.
	FindMissingBlobs RPCConfig

	// BatchUpdateBlobs is configuration for BatchUpdateBlobs RPCs.
	BatchUpdateBlobs RPCConfig

	// RetryPolicy specifies how to retry requests on transient errors.
	RetryPolicy retry.BackoffPolicy

	// IgnoreCapabilities specifies whether to ignore server-provided capabilities.
	// Capabilities are consulted by default.
	IgnoreCapabilities bool
}

// RPCConfig is configuration for a particular CAS RPC.
// Some of the fields might not apply to certain RPCs.
type RPCConfig struct {
	// Concurrency is the maximum number of RPCs in flight.
	Concurrency int

	// MaxSizeBytes is the maximum size of the request/response, in bytes.
	// Applies only to unary RPCs.
	MaxSizeBytes int

	// MaxItems is the maximum number of blobs/digests per RPC.
	// Applies only to unary batch RPCs, such as FindMissingBlobs.
	MaxItems int

	// Timeout is the maximum duration of the RPC.
	Timeout time.Duration
}

// DefaultClientConfig returns the default config.
//
// To override a specific value:
//   cfg := DefaultClientConfig()
//   ... mutate cfg ...
//   client, err := NewClientWithConfig(ctx, cfg)
func DefaultClientConfig() ClientConfig {
	return ClientConfig{
		// GCE docs recommend at least 32 concurrent IOs.
		// https://cloud.google.com/compute/docs/disks/optimizing-pd-performance#io-queue-depth
		// TODO(nodir): tune this number.
		FSConcurrency: 32,

		SmallFileThreshold: 1024 * 1024,       // 1MiB
		LargeFileThreshold: 256 * 1024 * 1024, // 256MiB

		// GCE docs recommend 4MB IO size for large files.
		// https://cloud.google.com/compute/docs/disks/optimizing-pd-performance#io-size
		FileIOSize: 4 * 1024 * 1024, // 4MiB

		FindMissingBlobs: RPCConfig{
			Concurrency: 64,
			MaxItems:    1000,
			Timeout:     time.Minute,
		},
		BatchUpdateBlobs: RPCConfig{
			Concurrency: 256,

			// This is a suggested approximate limit based on current RBE implementation for writes.
			// Above that BatchUpdateBlobs calls start to exceed a typical minute timeout.
			// This default might not be best for reads though.
			MaxItems: 4000,
			// 4MiB is the default gRPC request size limit.
			MaxSizeBytes: 4 * 1024 * 1024,
			Timeout:      time.Minute,
		},

		RetryPolicy: retry.ExponentialBackoff(225*time.Millisecond, 2*time.Second, retry.Attempts(6)),
	}
}

// Validate returns a non-nil error if the config is invalid.
func (c *ClientConfig) Validate() error {
	switch {
	case c.FSConcurrency <= 0:
		return fmt.Errorf("FSConcurrency must be positive")

	case c.SmallFileThreshold < 0:
		return fmt.Errorf("SmallFileThreshold must be non-negative")
	case c.LargeFileThreshold <= 0:
		return fmt.Errorf("LargeFileThreshold must be positive")
	case c.SmallFileThreshold >= c.LargeFileThreshold:
		return fmt.Errorf("SmallFileThreshold must be smaller than LargeFileThreshold")

	case c.FileIOSize <= 0:
		return fmt.Errorf("FileIOSize must be positive")

	// Checking more than 100K blobs may run into the request size limits.
	// It does not really make sense to check even >10K blobs, so limit to 10k.
	case c.FindMissingBlobs.MaxItems > 10000:
		return fmt.Errorf("FindMissingBlobs.MaxItems must <= 10000")
	}

	if err := c.FindMissingBlobs.validate(); err != nil {
		return errors.Wrap(err, "FindMissingBlobs")
	}
	if err := c.BatchUpdateBlobs.validate(); err != nil {
		return errors.Wrap(err, "BatchUpdateBlobs")
	}
	return nil
}

// validate returns an error if the config is invalid.
func (c *RPCConfig) validate() error {
	switch {
	case c.Concurrency <= 0:
		return fmt.Errorf("Concurrency must be positive")
	case c.Timeout <= 0:
		return fmt.Errorf("Timeout must be positive")
	default:
		return nil
	}
}

// NewClient creates a new client with the default configuration.
// Use client.Dial to create a connection.
func NewClient(ctx context.Context, conn *grpc.ClientConn, instanceName string) (*Client, error) {
	return NewClientWithConfig(ctx, conn, instanceName, DefaultClientConfig())
}

// NewClientWithConfig creates a new client and accepts a configuration.
func NewClientWithConfig(ctx context.Context, conn *grpc.ClientConn, instanceName string, config ClientConfig) (*Client, error) {
	switch err := config.Validate(); {
	case err != nil:
		return nil, errors.Wrap(err, "invalid config")
	case conn == nil:
		return nil, fmt.Errorf("conn is unspecified")
	case instanceName == "":
		return nil, fmt.Errorf("instance name is unspecified")
	}

	client := &Client{
		InstanceName: instanceName,
		ClientConfig: config,
		conn:         conn,
		byteStream:   bspb.NewByteStreamClient(conn),
		cas:          repb.NewContentAddressableStorageClient(conn),
	}
	if !client.IgnoreCapabilities {
		if err := client.checkCapabilities(ctx); err != nil {
			return nil, errors.Wrapf(err, "checking capabilities")
		}
	}

	client.init()

	return client, nil
}

// init is a part of NewClientWithConfig that can be done in tests without
// creating a real gRPC connection. This function exists purely to aid testing,
// and is tightly coupled with NewClientWithConfig.
func (c *Client) init() {
	c.semFindMissingBlobs = semaphore.NewWeighted(int64(c.FindMissingBlobs.Concurrency))
	c.semBatchUpdateBlobs = semaphore.NewWeighted(int64(c.BatchUpdateBlobs.Concurrency))

	c.semFileIO = semaphore.NewWeighted(int64(c.FSConcurrency))
	c.fileIOBufs.New = func() interface{} {
		return make([]byte, c.FileIOSize)
	}
}

// unaryRPC calls f with retries, and with per-RPC timeouts.
// Does not limit concurrency.
// It is useful when f calls an unary RPC.
func (c *Client) unaryRPC(ctx context.Context, cfg *RPCConfig, f func(context.Context) error) error {
	return retry.WithPolicy(ctx, retry.TransientOnly, c.RetryPolicy, func() error {
		ctx, cancel := context.WithTimeout(ctx, cfg.Timeout)
		defer cancel()
		return f(ctx)
	})
}

// checkCapabilities consults with server-side capabilities and potentially
// mutates c.ClientConfig.
func (c *Client) checkCapabilities(ctx context.Context) error {
	caps, err := repb.NewCapabilitiesClient(c.conn).GetCapabilities(ctx, &repb.GetCapabilitiesRequest{InstanceName: c.InstanceName})
	if err != nil {
		return errors.Wrapf(err, "GetCapabilities RPC")
	}

	if err := digest.CheckCapabilities(caps); err != nil {
		return errors.Wrapf(err, "digest function mismatch")
	}

	if c.BatchUpdateBlobs.MaxSizeBytes > int(caps.CacheCapabilities.MaxBatchTotalSizeBytes) {
		c.BatchUpdateBlobs.MaxSizeBytes = int(caps.CacheCapabilities.MaxBatchTotalSizeBytes)
	}
	return nil
}
<commit_msg>[cas] Increase FindMissingBlobs concurrency to 256 (#323)<commit_after>// Package cas implements an efficient client for Content Addressable Storage.
package cas

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/pkg/errors"
	"golang.org/x/sync/semaphore"
	bspb "google.golang.org/genproto/googleapis/bytestream"
	"google.golang.org/grpc"

	"github.com/bazelbuild/remote-apis-sdks/go/pkg/digest"
	"github.com/bazelbuild/remote-apis-sdks/go/pkg/retry"
	repb "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2"
)

// Client is a client for Content Addressable Storage.
// Create one using NewClient.
//
// Goroutine-safe.
//
// All fields are considered immutable, and should not be changed.
type Client struct {
	conn *grpc.ClientConn
	// InstanceName is the full name of the RBE instance.
	InstanceName string

	// ClientConfig is the configuration that the client was created with.
	ClientConfig

	byteStream bspb.ByteStreamClient
	cas        repb.ContentAddressableStorageClient

	// per-RPC semaphores

	semFindMissingBlobs *semaphore.Weighted
	semBatchUpdateBlobs *semaphore.Weighted

	// TODO(nodir): ensure it does not hurt streaming.
	semFileIO *semaphore.Weighted
	// muLargeFile ensures only one large file is read/written at a time.
	// TODO(nodir): ensure this doesn't hurt performance on SSDs.
	muLargeFile sync.Mutex
	// Pools of []byte slices with the length of ClientConfig.FileIOSize.
	fileIOBufs sync.Pool

	// Mockable functions.

	testScheduleCheck func(ctx context.Context, item *uploadItem) error
}

// ClientConfig is a config for Client.
// See DefaultClientConfig() for the default values.
type ClientConfig struct {
	// FSConcurrency is the maximum number of concurrent file system operations.
	// TODO(nodir): ensure this does not hurt streaming performance
	FSConcurrency int

	// SmallFileThreshold is a size threshold to categorize a file as small.
	// Such files are buffered entirely (read only once).
	SmallFileThreshold int64

	// LargeFileThreshold is a size threshold to categorize a file as large. For
	// such files, IO concurrency limits are much tighter and locality is
	// prioritized: the file is read for the first and second times with minimal
	// delay between the two.
	LargeFileThreshold int64

	// FileIOSize is the size of file reads.
	FileIOSize int64

	// FindMissingBlobs is configuration for FindMissingBlobs RPCs.
	// FindMissingBlobs.MaxSizeBytes is ignored.
	FindMissingBlobs RPCConfig

	// BatchUpdateBlobs is configuration for BatchUpdateBlobs RPCs.
	BatchUpdateBlobs RPCConfig

	// RetryPolicy specifies how to retry requests on transient errors.
	RetryPolicy retry.BackoffPolicy

	// IgnoreCapabilities specifies whether to ignore server-provided capabilities.
	// Capabilities are consulted by default.
	IgnoreCapabilities bool
}

// RPCConfig is configuration for a particular CAS RPC.
// Some of the fields might not apply to certain RPCs.
type RPCConfig struct {
	// Concurrency is the maximum number of RPCs in flight.
	Concurrency int

	// MaxSizeBytes is the maximum size of the request/response, in bytes.
	// Applies only to unary RPCs.
	MaxSizeBytes int

	// MaxItems is the maximum number of blobs/digests per RPC.
	// Applies only to unary batch RPCs, such as FindMissingBlobs.
	MaxItems int

	// Timeout is the maximum duration of the RPC.
	Timeout time.Duration
}

// DefaultClientConfig returns the default config.
//
// To override a specific value:
//   cfg := DefaultClientConfig()
//   ... mutate cfg ...
//   client, err := NewClientWithConfig(ctx, cfg)
func DefaultClientConfig() ClientConfig {
	return ClientConfig{
		// GCE docs recommend at least 32 concurrent IOs.
		// https://cloud.google.com/compute/docs/disks/optimizing-pd-performance#io-queue-depth
		// TODO(nodir): tune this number.
		FSConcurrency: 32,

		SmallFileThreshold: 1024 * 1024,       // 1MiB
		LargeFileThreshold: 256 * 1024 * 1024, // 256MiB

		// GCE docs recommend 4MB IO size for large files.
		// https://cloud.google.com/compute/docs/disks/optimizing-pd-performance#io-size
		FileIOSize: 4 * 1024 * 1024, // 4MiB

		FindMissingBlobs: RPCConfig{
			Concurrency: 256, // Should be >= BatchUpdateBlobs.Concurrency.
			MaxItems:    1000,
			Timeout:     time.Minute,
		},
		BatchUpdateBlobs: RPCConfig{
			Concurrency: 256,

			// This is a suggested approximate limit based on current RBE implementation for writes.
			// Above that BatchUpdateBlobs calls start to exceed a typical minute timeout.
			// This default might not be best for reads though.
			MaxItems: 4000,
			// 4MiB is the default gRPC request size limit.
			MaxSizeBytes: 4 * 1024 * 1024,
			Timeout:      time.Minute,
		},

		RetryPolicy: retry.ExponentialBackoff(225*time.Millisecond, 2*time.Second, retry.Attempts(6)),
	}
}

// Validate returns a non-nil error if the config is invalid.
func (c *ClientConfig) Validate() error {
	switch {
	case c.FSConcurrency <= 0:
		return fmt.Errorf("FSConcurrency must be positive")

	case c.SmallFileThreshold < 0:
		return fmt.Errorf("SmallFileThreshold must be non-negative")
	case c.LargeFileThreshold <= 0:
		return fmt.Errorf("LargeFileThreshold must be positive")
	case c.SmallFileThreshold >= c.LargeFileThreshold:
		return fmt.Errorf("SmallFileThreshold must be smaller than LargeFileThreshold")

	case c.FileIOSize <= 0:
		return fmt.Errorf("FileIOSize must be positive")

	// Checking more than 100K blobs may run into the request size limits.
	// It does not really make sense to check even >10K blobs, so limit to 10k.
	case c.FindMissingBlobs.MaxItems > 10000:
		return fmt.Errorf("FindMissingBlobs.MaxItems must <= 10000")
	}

	if err := c.FindMissingBlobs.validate(); err != nil {
		return errors.Wrap(err, "FindMissingBlobs")
	}
	if err := c.BatchUpdateBlobs.validate(); err != nil {
		return errors.Wrap(err, "BatchUpdateBlobs")
	}
	return nil
}

// validate returns an error if the config is invalid.
func (c *RPCConfig) validate() error {
	switch {
	case c.Concurrency <= 0:
		return fmt.Errorf("Concurrency must be positive")
	case c.Timeout <= 0:
		return fmt.Errorf("Timeout must be positive")
	default:
		return nil
	}
}

// NewClient creates a new client with the default configuration.
// Use client.Dial to create a connection.
func NewClient(ctx context.Context, conn *grpc.ClientConn, instanceName string) (*Client, error) {
	return NewClientWithConfig(ctx, conn, instanceName, DefaultClientConfig())
}

// NewClientWithConfig creates a new client and accepts a configuration.
func NewClientWithConfig(ctx context.Context, conn *grpc.ClientConn, instanceName string, config ClientConfig) (*Client, error) {
	switch err := config.Validate(); {
	case err != nil:
		return nil, errors.Wrap(err, "invalid config")
	case conn == nil:
		return nil, fmt.Errorf("conn is unspecified")
	case instanceName == "":
		return nil, fmt.Errorf("instance name is unspecified")
	}

	client := &Client{
		InstanceName: instanceName,
		ClientConfig: config,
		conn:         conn,
		byteStream:   bspb.NewByteStreamClient(conn),
		cas:          repb.NewContentAddressableStorageClient(conn),
	}
	if !client.IgnoreCapabilities {
		if err := client.checkCapabilities(ctx); err != nil {
			return nil, errors.Wrapf(err, "checking capabilities")
		}
	}

	client.init()

	return client, nil
}

// init is a part of NewClientWithConfig that can be done in tests without
// creating a real gRPC connection. This function exists purely to aid testing,
// and is tightly coupled with NewClientWithConfig.
func (c *Client) init() {
	c.semFindMissingBlobs = semaphore.NewWeighted(int64(c.FindMissingBlobs.Concurrency))
	c.semBatchUpdateBlobs = semaphore.NewWeighted(int64(c.BatchUpdateBlobs.Concurrency))

	c.semFileIO = semaphore.NewWeighted(int64(c.FSConcurrency))
	c.fileIOBufs.New = func() interface{} {
		return make([]byte, c.FileIOSize)
	}
}

// unaryRPC calls f with retries, and with per-RPC timeouts.
// Does not limit concurrency.
// It is useful when f calls an unary RPC.
func (c *Client) unaryRPC(ctx context.Context, cfg *RPCConfig, f func(context.Context) error) error {
	return retry.WithPolicy(ctx, retry.TransientOnly, c.RetryPolicy, func() error {
		ctx, cancel := context.WithTimeout(ctx, cfg.Timeout)
		defer cancel()
		return f(ctx)
	})
}

// checkCapabilities consults with server-side capabilities and potentially
// mutates c.ClientConfig.
func (c *Client) checkCapabilities(ctx context.Context) error {
	caps, err := repb.NewCapabilitiesClient(c.conn).GetCapabilities(ctx, &repb.GetCapabilitiesRequest{InstanceName: c.InstanceName})
	if err != nil {
		return errors.Wrapf(err, "GetCapabilities RPC")
	}

	if err := digest.CheckCapabilities(caps); err != nil {
		return errors.Wrapf(err, "digest function mismatch")
	}

	if c.BatchUpdateBlobs.MaxSizeBytes > int(caps.CacheCapabilities.MaxBatchTotalSizeBytes) {
		c.BatchUpdateBlobs.MaxSizeBytes = int(caps.CacheCapabilities.MaxBatchTotalSizeBytes)
	}
	return nil
}
<|endoftext|>


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

package commands

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"time"

	"nvim-go/context"
	"nvim-go/nvim"
	"nvim-go/nvim/profile"
	"nvim-go/nvim/quickfix"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
)

func init() {
	plugin.HandleCommand("Gobuild", &plugin.CommandOptions{Bang: true, Eval: "[getcwd(), expand('%:p:h')]"}, cmdBuild)
}

// CmdBuildEval struct type for Eval of GoBuild command.
type CmdBuildEval struct {
	Cwd string `msgpack:",array"`
	Dir string
}

func cmdBuild(v *vim.Vim, bang bool, eval CmdBuildEval) {
	go Build(v, bang, eval)
}

// Build building the current buffer's package use compile tool of determined
// from the directory structure.
func Build(v *vim.Vim, bang bool, eval CmdBuildEval) error {
	defer profile.Start(time.Now(), "GoBuild")
	ctxt := new(context.Build)
	defer ctxt.SetContext(eval.Dir)()

	cmd, err := compileCmd(ctxt, bang, eval)
	if err != nil {
		return err
	}
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if ctxt.Tool == "gb" {
		cmd.Dir = ctxt.GbProjectDir
	}

	err = cmd.Run()
	if err == nil {
		return nvim.EchoSuccess(v, "GoBuild", fmt.Sprintf("tool: %s", ctxt.Tool))
	}

	if _, ok := err.(*exec.ExitError); ok {
		w, err := v.CurrentWindow()
		if err != nil {
			return err
		}

		loclist, err := quickfix.ParseError(stderr.Bytes(), eval.Cwd, ctxt)
		if err != nil {
			return err
		}
		if err := quickfix.SetLoclist(v, loclist); err != nil {
			return err
		}

		return quickfix.OpenLoclist(v, w, loclist, true)
	}

	return err
}

func compileCmd(ctxt *context.Build, bang bool, eval CmdBuildEval) (*exec.Cmd, error) {
	var (
		compiler = ctxt.Tool
		args     = []string{"build"}
		buildDir string
	)
	if compiler == "go" {
		buildDir = eval.Dir
		if !bang {
			tmpfile, err := ioutil.TempFile(os.TempDir(), "nvim-go")
			if err != nil {
				return nil, err
			}
			defer os.Remove(tmpfile.Name())
			args = append(args, "-o", tmpfile.Name())
		}
	} else if compiler == "gb" {
		buildDir = ctxt.GbProjectDir
	}

	cmd := exec.Command(compiler, args...)
	cmd.Dir = buildDir

	return cmd, nil
}
<commit_msg>cmds/build: Fix BuildForce option error<commit_after>// Copyright 2016 Koichi Shiraishi. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package commands

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"time"

	"nvim-go/config"
	"nvim-go/context"
	"nvim-go/nvim"
	"nvim-go/nvim/profile"
	"nvim-go/nvim/quickfix"

	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
)

func init() {
	plugin.HandleCommand("Gobuild", &plugin.CommandOptions{Bang: true, Eval: "[getcwd(), expand('%:p:h')]"}, cmdBuild)
}

// CmdBuildEval struct type for Eval of GoBuild command.
type CmdBuildEval struct {
	Cwd string `msgpack:",array"`
	Dir string
}

func cmdBuild(v *vim.Vim, bang bool, eval CmdBuildEval) {
	go Build(v, bang, eval)
}

// Build building the current buffer's package use compile tool of determined
// from the directory structure.
func Build(v *vim.Vim, bang bool, eval CmdBuildEval) error {
	defer profile.Start(time.Now(), "GoBuild")
	ctxt := new(context.Build)
	defer ctxt.SetContext(eval.Dir)()

	cmd, err := compileCmd(ctxt, bang, eval)
	if err != nil {
		return err
	}
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	if ctxt.Tool == "gb" {
		cmd.Dir = ctxt.GbProjectDir
	}

	err = cmd.Run()
	if err == nil {
		return nvim.EchoSuccess(v, "GoBuild", fmt.Sprintf("tool: %s", ctxt.Tool))
	}

	if _, ok := err.(*exec.ExitError); ok {
		w, err := v.CurrentWindow()
		if err != nil {
			return err
		}

		loclist, err := quickfix.ParseError(stderr.Bytes(), eval.Cwd, ctxt)
		if err != nil {
			return err
		}
		if err := quickfix.SetLoclist(v, loclist); err != nil {
			return err
		}

		return quickfix.OpenLoclist(v, w, loclist, true)
	}

	return err
}

func compileCmd(ctxt *context.Build, bang bool, eval CmdBuildEval) (*exec.Cmd, error) {
	var (
		compiler = ctxt.Tool
		args     = []string{"build"}
		buildDir string
	)
	if config.BuildForce {
		bang = true
	}
	if compiler == "go" {
		buildDir = eval.Dir
		if !bang {
			tmpfile, err := ioutil.TempFile(os.TempDir(), "nvim-go")
			if err != nil {
				return nil, err
			}
			defer os.Remove(tmpfile.Name())
			args = append(args, "-o", tmpfile.Name())
		}
	} else if compiler == "gb" {
		buildDir = ctxt.GbProjectDir
	}

	cmd := exec.Command(compiler, args...)
	cmd.Dir = buildDir

	return cmd, nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sns"
	"time"
)

const awsSNSPendingConfirmationMessage = "pending confirmation"

func resourceAwsSnsTopicSubscription() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSnsTopicSubscriptionCreate,
		Read:   resourceAwsSnsTopicSubscriptionRead,
		Update: resourceAwsSnsTopicSubscriptionUpdate,
		Delete: resourceAwsSnsTopicSubscriptionDelete,

		Schema: map[string]*schema.Schema{
			"protocol": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(string)
					forbidden := []string{"email", "sms"}
					for _, f := range forbidden {
						if strings.Contains(value, f) {
							errors = append(
								errors,
								fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value),
							)
						}
					}
					return
				},
			},
			"endpoint": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
			"endpoint_auto_confirms": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: false,
				Default:  false,
			},
			"max_fetch_retries": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: false,
				Default:  3,
			},
			"fetch_retry_delay": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: false,
				Default:  1,
			},
			"topic_arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
			"delivery_policy": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},
			"raw_message_delivery": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: false,
				Default:  false,
			},
			"arn": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsSnsTopicSubscriptionCreate(d *schema.ResourceData, meta interface{}) error {
	snsconn := meta.(*AWSClient).snsconn

	output, err := subscribeToSNSTopic(d, snsconn)

	if err != nil {
		return err
	}

	if output.SubscriptionArn != nil && *output.SubscriptionArn == awsSNSPendingConfirmationMessage {
		log.Printf("[WARN] Invalid SNS Subscription, received a \"%s\" ARN", awsSNSPendingConfirmationMessage)
		return nil
	}

	log.Printf("New subscription ARN: %s", *output.SubscriptionArn)
	d.SetId(*output.SubscriptionArn)

	// Write the ARN to the 'arn' field for export
	d.Set("arn", *output.SubscriptionArn)

	return resourceAwsSnsTopicSubscriptionUpdate(d, meta)
}

func resourceAwsSnsTopicSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error {
	snsconn := meta.(*AWSClient).snsconn

	// If any changes happened, un-subscribe and re-subscribe
	if d.HasChange("protocol") || d.HasChange("endpoint") || d.HasChange("topic_arn") {
		log.Printf("[DEBUG] Updating subscription %s", d.Id())
		// Unsubscribe
		_, err := snsconn.Unsubscribe(&sns.UnsubscribeInput{
			SubscriptionArn: aws.String(d.Id()),
		})

		if err != nil {
			return fmt.Errorf("Error unsubscribing from SNS topic: %s", err)
		}

		// Re-subscribe and set id
		output, err := subscribeToSNSTopic(d, snsconn)
		d.SetId(*output.SubscriptionArn)
		d.Set("arn", *output.SubscriptionArn)
	}

	if d.HasChange("raw_message_delivery") {
		_, n := d.GetChange("raw_message_delivery")

		attrValue := "false"

		if n.(bool) {
			attrValue = "true"
		}

		req := &sns.SetSubscriptionAttributesInput{
			SubscriptionArn: aws.String(d.Id()),
			AttributeName:   aws.String("RawMessageDelivery"),
			AttributeValue:  aws.String(attrValue),
		}
		_, err := snsconn.SetSubscriptionAttributes(req)

		if err != nil {
			return fmt.Errorf("Unable to set raw message delivery attribute on subscription")
		}
	}

	return resourceAwsSnsTopicSubscriptionRead(d, meta)
}

func resourceAwsSnsTopicSubscriptionRead(d *schema.ResourceData, meta interface{}) error {
	snsconn := meta.(*AWSClient).snsconn

	log.Printf("[DEBUG] Loading subscription %s", d.Id())

	attributeOutput, err := snsconn.GetSubscriptionAttributes(&sns.GetSubscriptionAttributesInput{
		SubscriptionArn: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}

	if attributeOutput.Attributes != nil && len(attributeOutput.Attributes) > 0 {
		attrHash := attributeOutput.Attributes
		log.Printf("[DEBUG] raw message delivery: %s", *attrHash["RawMessageDelivery"])
		if *attrHash["RawMessageDelivery"] == "true" {
			d.Set("raw_message_delivery", true)
		} else {
			d.Set("raw_message_delivery", false)
		}
	}

	return nil
}

func resourceAwsSnsTopicSubscriptionDelete(d *schema.ResourceData, meta interface{}) error {
	snsconn := meta.(*AWSClient).snsconn

	log.Printf("[DEBUG] SNS delete topic subscription: %s", d.Id())
	_, err := snsconn.Unsubscribe(&sns.UnsubscribeInput{
		SubscriptionArn: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}
	return nil
}

func subscribeToSNSTopic(d *schema.ResourceData, snsconn *sns.SNS) (output *sns.SubscribeOutput, err error) {
	protocol := d.Get("protocol").(string)
	endpoint := d.Get("endpoint").(string)
	topic_arn := d.Get("topic_arn").(string)
	endpoint_auto_confirms := d.Get("endpoint_auto_confirms").(bool)
	max_fetch_retries := d.Get("max_fetch_retries").(int)
	fetch_retry_delay := time.Duration(d.Get("fetch_retry_delay").(int))

	if strings.Contains(protocol, "http") && !endpoint_auto_confirms {
		return nil, fmt.Errorf("Protocol http/https is only supported for endpoints which auto confirms!")
	}

	log.Printf("[DEBUG] SNS create topic subscription: %s (%s) @ '%s'", endpoint, protocol, topic_arn)

	req := &sns.SubscribeInput{
		Protocol: aws.String(protocol),
		Endpoint: aws.String(endpoint),
		TopicArn: aws.String(topic_arn),
	}

	output, err = snsconn.Subscribe(req)
	if err != nil {
		return nil, fmt.Errorf("Error creating SNS topic: %s", err)
	}

	if strings.Contains(protocol, "http") && (output.SubscriptionArn == nil || *output.SubscriptionArn == awsSNSPendingConfirmationMessage) {

		log.Printf("[DEBUG] SNS create topic subscritpion is pending so fetching the subscription list for topic : %s (%s) @ '%s'", endpoint, protocol, topic_arn)

		for i := 0; i < max_fetch_retries && output.SubscriptionArn != nil && *output.SubscriptionArn == awsSNSPendingConfirmationMessage; i++ {

			subscription, err := findSubscriptionByNonID(d, snsconn)

			if err != nil {
				return nil, fmt.Errorf("Error fetching subscriptions for SNS topic %s: %s", topic_arn, err)
			}

			if subscription != nil {
				output.SubscriptionArn = subscription.SubscriptionArn
				break
			}

			time.Sleep(time.Second * fetch_retry_delay)
		}

		if output.SubscriptionArn == nil || *output.SubscriptionArn == awsSNSPendingConfirmationMessage {
			return nil, fmt.Errorf("Endpoint (%s) did not autoconfirm the subscription for topic %s", endpoint, topic_arn)
		}
	}

	log.Printf("[DEBUG] Created new subscription!")
	return output, nil
}

// finds a subscription using protocol, endpoint and topic_arn (which is a key in sns subscription)
func findSubscriptionByNonID(d *schema.ResourceData, snsconn *sns.SNS) (*sns.Subscription, error) {
	protocol := d.Get("protocol").(string)
	endpoint := d.Get("endpoint").(string)
	topic_arn := d.Get("topic_arn").(string)

	req := &sns.ListSubscriptionsByTopicInput{
		TopicArn: aws.String(topic_arn),
	}

	for {

		res, err := snsconn.ListSubscriptionsByTopic(req)

		if err != nil {
			return nil, fmt.Errorf("Error fetching subscripitions for topic %s : %s", topic_arn, err)
		}

		for _, subscription := range res.Subscriptions {
			if *subscription.Endpoint == endpoint && *subscription.Protocol == protocol && *subscription.TopicArn == topic_arn && *subscription.SubscriptionArn != awsSNSPendingConfirmationMessage {
				return subscription, nil
			}
		}

		// if there are more than 100 subscriptions then go to the next 100 otherwise return nil
		if res.NextToken != nil {
			req.NextToken = res.NextToken
		} else {
			return nil, nil
		}
	}
}
<commit_msg>Found an issue with more testing aws api is responding with various of "pending confirmation" such as "PendingConfirmation", "Pending Confirmation" etc.<commit_after>package aws

import (
	"fmt"
	"log"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/sns"
	"time"
)

const awsSNSPendingConfirmationMessage = "pending confirmation"

func resourceAwsSnsTopicSubscription() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsSnsTopicSubscriptionCreate,
		Read:   resourceAwsSnsTopicSubscriptionRead,
		Update: resourceAwsSnsTopicSubscriptionUpdate,
		Delete: resourceAwsSnsTopicSubscriptionDelete,

		Schema: map[string]*schema.Schema{
			"protocol": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					value := v.(string)
					forbidden := []string{"email", "sms"}
					for _, f := range forbidden {
						if strings.Contains(value, f) {
							errors = append(
								errors,
								fmt.Errorf("Unsupported protocol (%s) for SNS Topic", value),
							)
						}
					}
					return
				},
			},
			"endpoint": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
			"endpoint_auto_confirms": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: false,
				Default:  false,
			},
			"max_fetch_retries": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: false,
				Default:  3,
			},
			"fetch_retry_delay": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				ForceNew: false,
				Default:  1,
			},
			"topic_arn": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
			"delivery_policy": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},
			"raw_message_delivery": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: false,
				Default:  false,
			},
			"arn": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsSnsTopicSubscriptionCreate(d *schema.ResourceData, meta interface{}) error {
	snsconn := meta.(*AWSClient).snsconn

	output, err := subscribeToSNSTopic(d, snsconn)

	if err != nil {
		return err
	}

	if subscriptionHasPendingConfirmation(output.SubscriptionArn) {
		log.Printf("[WARN] Invalid SNS Subscription, received a \"%s\" ARN", awsSNSPendingConfirmationMessage)
		return nil
	}

	log.Printf("New subscription ARN: %s", *output.SubscriptionArn)
	d.SetId(*output.SubscriptionArn)

	// Write the ARN to the 'arn' field for export
	d.Set("arn", *output.SubscriptionArn)

	return resourceAwsSnsTopicSubscriptionUpdate(d, meta)
}

func resourceAwsSnsTopicSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error {
	snsconn := meta.(*AWSClient).snsconn

	// If any changes happened, un-subscribe and re-subscribe
	if d.HasChange("protocol") || d.HasChange("endpoint") || d.HasChange("topic_arn") {
		log.Printf("[DEBUG] Updating subscription %s", d.Id())
		// Unsubscribe
		_, err := snsconn.Unsubscribe(&sns.UnsubscribeInput{
			SubscriptionArn: aws.String(d.Id()),
		})

		if err != nil {
			return fmt.Errorf("Error unsubscribing from SNS topic: %s", err)
		}

		// Re-subscribe and set id
		output, err := subscribeToSNSTopic(d, snsconn)
		d.SetId(*output.SubscriptionArn)
		d.Set("arn", *output.SubscriptionArn)
	}

	if d.HasChange("raw_message_delivery") {
		_, n := d.GetChange("raw_message_delivery")

		attrValue := "false"

		if n.(bool) {
			attrValue = "true"
		}

		req := &sns.SetSubscriptionAttributesInput{
			SubscriptionArn: aws.String(d.Id()),
			AttributeName:   aws.String("RawMessageDelivery"),
			AttributeValue:  aws.String(attrValue),
		}
		_, err := snsconn.SetSubscriptionAttributes(req)

		if err != nil {
			return fmt.Errorf("Unable to set raw message delivery attribute on subscription")
		}
	}

	return resourceAwsSnsTopicSubscriptionRead(d, meta)
}

func resourceAwsSnsTopicSubscriptionRead(d *schema.ResourceData, meta interface{}) error {
	snsconn := meta.(*AWSClient).snsconn

	log.Printf("[DEBUG] Loading subscription %s", d.Id())

	attributeOutput, err := snsconn.GetSubscriptionAttributes(&sns.GetSubscriptionAttributesInput{
		SubscriptionArn: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}

	if attributeOutput.Attributes != nil && len(attributeOutput.Attributes) > 0 {
		attrHash := attributeOutput.Attributes
		log.Printf("[DEBUG] raw message delivery: %s", *attrHash["RawMessageDelivery"])
		if *attrHash["RawMessageDelivery"] == "true" {
			d.Set("raw_message_delivery", true)
		} else {
			d.Set("raw_message_delivery", false)
		}
	}

	return nil
}

func resourceAwsSnsTopicSubscriptionDelete(d *schema.ResourceData, meta interface{}) error {
	snsconn := meta.(*AWSClient).snsconn

	log.Printf("[DEBUG] SNS delete topic subscription: %s", d.Id())
	_, err := snsconn.Unsubscribe(&sns.UnsubscribeInput{
		SubscriptionArn: aws.String(d.Id()),
	})
	if err != nil {
		return err
	}
	return nil
}

func subscribeToSNSTopic(d *schema.ResourceData, snsconn *sns.SNS) (output *sns.SubscribeOutput, err error) {
	protocol := d.Get("protocol").(string)
	endpoint := d.Get("endpoint").(string)
	topic_arn := d.Get("topic_arn").(string)
	endpoint_auto_confirms := d.Get("endpoint_auto_confirms").(bool)
	max_fetch_retries := d.Get("max_fetch_retries").(int)
	fetch_retry_delay := time.Duration(d.Get("fetch_retry_delay").(int))

	if strings.Contains(protocol, "http") && !endpoint_auto_confirms {
		return nil, fmt.Errorf("Protocol http/https is only supported for endpoints which auto confirms!")
	}

	log.Printf("[DEBUG] SNS create topic subscription: %s (%s) @ '%s'", endpoint, protocol, topic_arn)

	req := &sns.SubscribeInput{
		Protocol: aws.String(protocol),
		Endpoint: aws.String(endpoint),
		TopicArn: aws.String(topic_arn),
	}

	output, err = snsconn.Subscribe(req)
	if err != nil {
		return nil, fmt.Errorf("Error creating SNS topic: %s", err)
	}

	log.Printf("[DEBUG] Finished subscribing to topic %s with subscription arn %s", topic_arn, *output.SubscriptionArn)

	if strings.Contains(protocol, "http") && subscriptionHasPendingConfirmation(output.SubscriptionArn) {

		log.Printf("[DEBUG] SNS create topic subscritpion is pending so fetching the subscription list for topic : %s (%s) @ '%s'", endpoint, protocol, topic_arn)

		for i := 0; i < max_fetch_retries && subscriptionHasPendingConfirmation(output.SubscriptionArn); i++ {

			subscription, err := findSubscriptionByNonID(d, snsconn)

			if err != nil {
				return nil, fmt.Errorf("Error fetching subscriptions for SNS topic %s: %s", topic_arn, err)
			}

			if subscription != nil {
				output.SubscriptionArn = subscription.SubscriptionArn
				break
			}

			time.Sleep(time.Second * fetch_retry_delay)
		}

		if subscriptionHasPendingConfirmation(output.SubscriptionArn) {
			return nil, fmt.Errorf("Endpoint (%s) did not autoconfirm the subscription for topic %s", endpoint, topic_arn)
		}
	}

	log.Printf("[DEBUG] Created new subscription! %s", *output.SubscriptionArn)
	return output, nil
}

// finds a subscription using protocol, endpoint and topic_arn (which is a key in sns subscription)
func findSubscriptionByNonID(d *schema.ResourceData, snsconn *sns.SNS) (*sns.Subscription, error) {
	protocol := d.Get("protocol").(string)
	endpoint := d.Get("endpoint").(string)
	topic_arn := d.Get("topic_arn").(string)

	req := &sns.ListSubscriptionsByTopicInput{
		TopicArn: aws.String(topic_arn),
	}

	for {

		res, err := snsconn.ListSubscriptionsByTopic(req)

		if err != nil {
			return nil, fmt.Errorf("Error fetching subscripitions for topic %s : %s", topic_arn, err)
		}

		for _, subscription := range res.Subscriptions {
			log.Printf("[DEBUG] check subscription with EndPoint %s, Protocol %s,  topicARN %s and SubscriptionARN %s", *subscription.Endpoint, *subscription.Protocol, *subscription.TopicArn, *subscription.SubscriptionArn)
			if *subscription.Endpoint == endpoint && *subscription.Protocol == protocol && *subscription.TopicArn == topic_arn && !subscriptionHasPendingConfirmation(subscription.SubscriptionArn) {
				return subscription, nil
			}
		}

		// if there are more than 100 subscriptions then go to the next 100 otherwise return nil
		if res.NextToken != nil {
			req.NextToken = res.NextToken
		} else {
			return nil, nil
		}
	}
}

// returns true if arn is nil or has both pending and confirmation words in the arn
func subscriptionHasPendingConfirmation(arn *string) bool {
	if arn != nil && !strings.Contains(strings.ToLower(*arn), "pending") && !strings.Contains(strings.ToLower(*arn), "confirmation") {
		return false
	}

	return true
}
<|endoftext|>


<commit_before>package typeddata

import (
	"crypto/ecdsa"
	"encoding/json"
	"math/big"
	"testing"

	"github.com/stretchr/testify/suite"

	"github.com/ethereum/go-ethereum/crypto"

	"github.com/ethereum/go-ethereum/signer/core/apitypes"
	"github.com/status-im/status-go/eth-node/types"
)

func TestTypedDataSuite(t *testing.T) {
	suite.Run(t, new(TypedDataSuite))
}

type TypedDataSuite struct {
	suite.Suite

	privateKey  *ecdsa.PrivateKey
	typedDataV3 apitypes.TypedData
	typedDataV4 apitypes.TypedData
}

func (s *TypedDataSuite) SetupTest() {
	pk, err := crypto.ToECDSA(crypto.Keccak256([]byte("cow")))
	s.Require().NoError(err)

	s.privateKey = pk

	s.Require().NoError(json.Unmarshal([]byte(typedDataV3), &s.typedDataV3))
	s.Require().NoError(json.Unmarshal([]byte(typedDataV4), &s.typedDataV4))
}

func (s *TypedDataSuite) TestTypedDataV3() {
	signature, err := SignTypedDataV4(s.typedDataV3, s.privateKey, big.NewInt(1))
	s.Require().NoError(err)
	s.Require().Equal("0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c", types.EncodeHex(signature))
}

func (s *TypedDataSuite) TestTypedDataV4() {

	expected := "0xfabfe1ed996349fc6027709802be19d047da1aa5d6894ff5f6486d92db2e6860"
	actual := s.typedDataV4.TypeHash("Person")
	s.Require().Equal(expected, actual.String())

	fromTypedData := apitypes.TypedData{}
	s.Require().NoError(json.Unmarshal([]byte(fromJSON), &fromTypedData))

	actual, err := s.typedDataV4.HashStruct("Person", fromTypedData.Message)
	s.Require().NoError(err)
	expected = "0x9b4846dd48b866f0ac54d61b9b21a9e746f921cefa4ee94c4c0a1c49c774f67f"
	s.Require().Equal(expected, actual.String())

	encodedData, err := s.typedDataV4.EncodeData(s.typedDataV4.PrimaryType, s.typedDataV4.Message, 1)
	s.Require().NoError(err)

	expected = "0x4bd8a9a2b93427bb184aca81e24beb30ffa3c747e2a33d4225ec08bf12e2e7539b4846dd48b866f0ac54d61b9b21a9e746f921cefa4ee94c4c0a1c49c774f67fefa62530c7ae3a290f8a13a5fc20450bdb3a6af19d9d9d2542b5a94e631a9168b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8"
	s.Require().Equal(expected, encodedData.String())

	actual, err = s.typedDataV4.HashStruct(s.typedDataV4.PrimaryType, s.typedDataV4.Message)
	s.Require().NoError(err)

	expected = "0x99b97a26b830a26d5ca27ced87ba4d73c6276a2b8315656882a771d6f98b01f3"
	s.Require().Equal(expected, actual.String())

	signature, err := SignTypedDataV4(s.typedDataV4, s.privateKey, big.NewInt(1))
	s.Require().NoError(err)
	s.Require().Equal("0xf632e305033e23de75545fcdd0a481d83d9d41954e12c07004327cddf4e3c762757652b04d11dd022e0018e6160723f322d0b4bd9b41c87db93755405f5548391b", types.EncodeHex(signature))
}

const typedDataV3 = `
{
	"types": {
		"EIP712Domain": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "version",
				"type": "string"
			},
			{
				"name": "chainId",
				"type": "uint256"
			},
			{
				"name": "verifyingContract",
				"type": "address"
			}
		],
		"Person": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "wallet",
				"type": "address"
			}
		],
		"Mail": [
			{
				"name": "from",
				"type": "Person"
			},
			{
				"name": "to",
				"type": "Person"
			},
			{
				"name": "contents",
				"type": "string"
			}
		]
	},
	"primaryType": "Mail",
	"domain": {
		"name": "Ether Mail",
		"version": "1",
		"chainId": "1",
		"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
	},
	"message": {
		"from": {
			"name": "Cow",
			"wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
		},
		"to": {
			"name": "Bob",
			"wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
		},
		"contents": "Hello, Bob!"
	}
}
`

const typedDataV4 = `
{
	"types": {
		"EIP712Domain": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "version",
				"type": "string"
			},
			{
				"name": "chainId",
				"type": "uint256"
			},
			{
				"name": "verifyingContract",
				"type": "address"
			}
		],
		"Person": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "wallets",
				"type": "address[]"
			}
		],
		"Mail": [
			{
				"name": "from",
				"type": "Person"
			},
			{
				"name": "to",
				"type": "Person[]"
			},
			{
				"name": "contents",
				"type": "string"
			}
		],
		"Group": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "members",
				"type": "Person[]"
			}
		]
	},
	"domain": {
		"name": "Ether Mail",
		"version": "1",
		"chainId": "1",
		"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
	},
	"primaryType": "Mail",
	"message": {
		"from": {
			"name": "Cow",
			"wallets": [
				"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
				"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
			]
		},
		"to": [
			{
				"name": "Bob",
				"wallets": [
					"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
					"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
					"0xB0B0b0b0b0b0B000000000000000000000000000"
				]
			}
		],
		"contents": "Hello, Bob!"
	}
}
`
const fromJSON = `
{
	"types": {
		"EIP712Domain": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "version",
				"type": "string"
			},
			{
				"name": "chainId",
				"type": "uint256"
			},
			{
				"name": "verifyingContract",
				"type": "address"
			}
		],
		"Person": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "wallets",
				"type": "address[]"
			}
		],
		"Mail": [
			{
				"name": "from",
				"type": "Person"
			},
			{
				"name": "to",
				"type": "Person[]"
			},
			{
				"name": "contents",
				"type": "string"
			}
		],
		"Group": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "members",
				"type": "Person[]"
			}
		]
	},
	"domain": {
		"name": "Ether Mail",
		"version": "1",
		"chainId": "1",
		"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
	},
	"primaryType": "Mail",
	"message": {
			"name": "Cow",
			"wallets": [
				"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
				"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
			]
		}
	}
`
<commit_msg>fix: metamask test<commit_after>package typeddata

import (
	"crypto/ecdsa"
	"encoding/json"
	"math/big"
	"testing"

	"github.com/stretchr/testify/suite"

	"github.com/ethereum/go-ethereum/crypto"

	"github.com/ethereum/go-ethereum/signer/core/apitypes"
	"github.com/status-im/status-go/eth-node/types"
)

func TestTypedDataSuite(t *testing.T) {
	suite.Run(t, new(TypedDataSuite))
}

type TypedDataSuite struct {
	suite.Suite

	privateKey  *ecdsa.PrivateKey
	typedDataV3 apitypes.TypedData
	typedDataV4 apitypes.TypedData
}

func (s *TypedDataSuite) SetupTest() {
	pk, err := crypto.ToECDSA(crypto.Keccak256([]byte("cow")))
	s.Require().NoError(err)

	s.privateKey = pk

	s.Require().NoError(json.Unmarshal([]byte(typedDataV3), &s.typedDataV3))
	s.Require().NoError(json.Unmarshal([]byte(typedDataV4), &s.typedDataV4))
}

func (s *TypedDataSuite) TestTypedDataV3() {
	signature, err := SignTypedDataV4(s.typedDataV3, s.privateKey, big.NewInt(1))
	s.Require().NoError(err)
	s.Require().Equal("0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c", types.EncodeHex(signature))
}

func (s *TypedDataSuite) TestTypedDataV4() {

	expected := "0xfabfe1ed996349fc6027709802be19d047da1aa5d6894ff5f6486d92db2e6860"
	actual := s.typedDataV4.TypeHash("Person")
	s.Require().Equal(expected, actual.String())

	fromTypedData := apitypes.TypedData{}
	s.Require().NoError(json.Unmarshal([]byte(fromJSON), &fromTypedData))

	actual, err := s.typedDataV4.HashStruct("Person", fromTypedData.Message)
	s.Require().NoError(err)
	expected = "0x9b4846dd48b866f0ac54d61b9b21a9e746f921cefa4ee94c4c0a1c49c774f67f"
	s.Require().Equal(expected, actual.String())

	encodedData, err := s.typedDataV4.EncodeData(s.typedDataV4.PrimaryType, s.typedDataV4.Message, 1)
	s.Require().NoError(err)

	expected = "0x4bd8a9a2b93427bb184aca81e24beb30ffa3c747e2a33d4225ec08bf12e2e7539b4846dd48b866f0ac54d61b9b21a9e746f921cefa4ee94c4c0a1c49c774f67fca322beec85be24e374d18d582a6f2997f75c54e7993ab5bc07404ce176ca7cdb5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8"
	s.Require().Equal(expected, encodedData.String())

	actual, err = s.typedDataV4.HashStruct(s.typedDataV4.PrimaryType, s.typedDataV4.Message)
	s.Require().NoError(err)

	expected = "0xeb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8"
	s.Require().Equal(expected, actual.String())

	signature, err := SignTypedDataV4(s.typedDataV4, s.privateKey, big.NewInt(1))
	s.Require().NoError(err)
	s.Require().Equal("0x65cbd956f2fae28a601bebc9b906cea0191744bd4c4247bcd27cd08f8eb6b71c78efdf7a31dc9abee78f492292721f362d296cf86b4538e07b51303b67f749061b", types.EncodeHex(signature))
}

const typedDataV3 = `
{
	"types": {
		"EIP712Domain": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "version",
				"type": "string"
			},
			{
				"name": "chainId",
				"type": "uint256"
			},
			{
				"name": "verifyingContract",
				"type": "address"
			}
		],
		"Person": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "wallet",
				"type": "address"
			}
		],
		"Mail": [
			{
				"name": "from",
				"type": "Person"
			},
			{
				"name": "to",
				"type": "Person"
			},
			{
				"name": "contents",
				"type": "string"
			}
		]
	},
	"primaryType": "Mail",
	"domain": {
		"name": "Ether Mail",
		"version": "1",
		"chainId": "1",
		"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
	},
	"message": {
		"from": {
			"name": "Cow",
			"wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
		},
		"to": {
			"name": "Bob",
			"wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
		},
		"contents": "Hello, Bob!"
	}
}
`

const typedDataV4 = `
{
	"types": {
		"EIP712Domain": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "version",
				"type": "string"
			},
			{
				"name": "chainId",
				"type": "uint256"
			},
			{
				"name": "verifyingContract",
				"type": "address"
			}
		],
		"Person": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "wallets",
				"type": "address[]"
			}
		],
		"Mail": [
			{
				"name": "from",
				"type": "Person"
			},
			{
				"name": "to",
				"type": "Person[]"
			},
			{
				"name": "contents",
				"type": "string"
			}
		],
		"Group": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "members",
				"type": "Person[]"
			}
		]
	},
	"domain": {
		"name": "Ether Mail",
		"version": "1",
		"chainId": "1",
		"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
	},
	"primaryType": "Mail",
	"message": {
		"from": {
			"name": "Cow",
			"wallets": [
				"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
				"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
			]
		},
		"to": [
			{
				"name": "Bob",
				"wallets": [
					"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
					"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57",
					"0xB0B0b0b0b0b0B000000000000000000000000000"
				]
			}
		],
		"contents": "Hello, Bob!"
	}
}
`
const fromJSON = `
{
	"types": {
		"EIP712Domain": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "version",
				"type": "string"
			},
			{
				"name": "chainId",
				"type": "uint256"
			},
			{
				"name": "verifyingContract",
				"type": "address"
			}
		],
		"Person": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "wallets",
				"type": "address[]"
			}
		],
		"Mail": [
			{
				"name": "from",
				"type": "Person"
			},
			{
				"name": "to",
				"type": "Person[]"
			},
			{
				"name": "contents",
				"type": "string"
			}
		],
		"Group": [
			{
				"name": "name",
				"type": "string"
			},
			{
				"name": "members",
				"type": "Person[]"
			}
		]
	},
	"domain": {
		"name": "Ether Mail",
		"version": "1",
		"chainId": "1",
		"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
	},
	"primaryType": "Mail",
	"message": {
			"name": "Cow",
			"wallets": [
				"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
				"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF"
			]
		}
	}
`
<|endoftext|>


<commit_before>package topgun_test

import (
	. "github.com/concourse/concourse/topgun/common"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("A pipeline-provided resource type", func() {
	BeforeEach(func() {
		Deploy("deployments/concourse.yml", "-o", "operations/no-gc.yml")
	})

	It("does not result in redundant containers when running resource actions", func() {
		By("setting a pipeline")
		Fly.Run("set-pipeline", "-n", "-c", "pipelines/custom-types.yml", "-p", "pipe")
		Fly.Run("unpause-pipeline", "-p", "pipe")

		By("triggering the build")
		buildSession := Fly.Start("trigger-job", "-w", "-j", "pipe/get-10m")
		<-buildSession.Exited
		Expect(buildSession.ExitCode()).To(Equal(1))

		By("expecting a container for the resource check, resource type check, and task image check")
		Expect(ContainersBy("type", "check")).To(HaveLen(3))

		By("expecting a container for the resource check, resource type check, build resource image get, build get, build task image check, build task image get, and build task")
		expectedContainersBefore := 7
		Expect(FlyTable("containers")).Should(HaveLen(expectedContainersBefore))

		By("triggering the build again")
		buildSession = Fly.Start("trigger-job", "-w", "-j", "pipe/get-10m")
		<-buildSession.Exited
		Expect(buildSession.ExitCode()).To(Equal(1))

		By("expecting only one additional check container for the task's image check")
		Expect(ContainersBy("type", "check")).To(HaveLen(4))

		By("expecting to only have new containers for build task image check and build task")
		Expect(FlyTable("containers")).Should(HaveLen(expectedContainersBefore + 2))
	})
})

var _ = Describe("Tagged resource types", func() {
	BeforeEach(func() {
		Deploy("deployments/concourse.yml", "-o", "operations/tagged-worker.yml")

		By("setting a pipeline with tagged custom types")
		Fly.Run("set-pipeline", "-n", "-c", "pipelines/tagged-custom-types.yml", "-p", "pipe")
		Fly.Run("unpause-pipeline", "-p", "pipe")
	})

	It("is able to be used with tagged workers", func() {
		By("running a check which uses the tagged custom resource")
		Eventually(Fly.Start("check-resource", "-r", "pipe/10m")).Should(gexec.Exit(0))

		By("triggering a build which uses the tagged custom resource")
		buildSession := Fly.Start("trigger-job", "-w", "-j", "pipe/get-10m")
		<-buildSession.Exited
		Expect(buildSession.ExitCode()).To(Equal(0))
	})
})
<commit_msg>update test due to in-DB check change<commit_after>package topgun_test

import (
	. "github.com/concourse/concourse/topgun/common"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

var _ = Describe("A pipeline-provided resource type", func() {
	BeforeEach(func() {
		Deploy("deployments/concourse.yml", "-o", "operations/no-gc.yml")
	})

	It("does not result in redundant containers when running resource actions", func() {
		By("setting a pipeline")
		Fly.Run("set-pipeline", "-n", "-c", "pipelines/custom-types.yml", "-p", "pipe")
		Fly.Run("unpause-pipeline", "-p", "pipe")

		By("triggering the build")
		buildSession := Fly.Start("trigger-job", "-w", "-j", "pipe/get-10m")
		<-buildSession.Exited
		Expect(buildSession.ExitCode()).To(Equal(1))

		By("expecting a container for the resource check and task image check")
		Expect(ContainersBy("type", "check")).To(HaveLen(2))

		By("expecting a container for the resource check, build get, build task image check, build task image get, and build task")
		expectedContainersBefore := 5
		Expect(FlyTable("containers")).Should(HaveLen(expectedContainersBefore))

		By("triggering the build again")
		buildSession = Fly.Start("trigger-job", "-w", "-j", "pipe/get-10m")
		<-buildSession.Exited
		Expect(buildSession.ExitCode()).To(Equal(1))

		By("expecting only one additional check container for the task's image check")
		Expect(ContainersBy("type", "check")).To(HaveLen(3))

		By("expecting to only have new containers for build task image check and build task")
		Expect(FlyTable("containers")).Should(HaveLen(expectedContainersBefore + 2))
	})
})

var _ = Describe("Tagged resource types", func() {
	BeforeEach(func() {
		Deploy("deployments/concourse.yml", "-o", "operations/tagged-worker.yml")

		By("setting a pipeline with tagged custom types")
		Fly.Run("set-pipeline", "-n", "-c", "pipelines/tagged-custom-types.yml", "-p", "pipe")
		Fly.Run("unpause-pipeline", "-p", "pipe")
	})

	It("is able to be used with tagged workers", func() {
		By("running a check which uses the tagged custom resource")
		Eventually(Fly.Start("check-resource", "-r", "pipe/10m")).Should(gexec.Exit(0))

		By("triggering a build which uses the tagged custom resource")
		buildSession := Fly.Start("trigger-job", "-w", "-j", "pipe/get-10m")
		<-buildSession.Exited
		Expect(buildSession.ExitCode()).To(Equal(0))
	})
})
<|endoftext|>