<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type PackageIndex struct {
	URI string
}

type Requirement struct {
	Name string
}

var allPkgRegexp = regexp.MustCompile(`<a href='([A-Za-z0-9\._\-]+)'>([A-Za-z0-9\._\-]+)</a><br/>`)
var pkgFilesRegexp = regexp.MustCompile(`<a href="([/A-Za-z0-9\._\-]+)#md5=[0-9a-z]+"[^>]*>([A-Za-z0-9\._\-]+)</a><br/>`)
var tarRegexp = regexp.MustCompile(`[/A-Za-z0-9\._\-]+\.(?:tar\.(?:gz|bz2)|tgz)`)
var zipRegexp = regexp.MustCompile(`[/A-Za-z0-9\._\-]+\.zip`)
var eggRegexp = regexp.MustCompile(`[/A-Za-z0-9\._\-]+\.egg`)
var requirementRegexp = regexp.MustCompile(`(?P<package>[A-Za-z0-9\._\-]+)(?:\[([A-Za-z0-9\._\-]+)\])?\s*(?:(?P<constraint>==|>=|>|<|<=)\s*(?P<version>[A-Za-z0-9\._\-]+)(?:\s*,\s*[<>=!]+\s*[a-z0-9\.]+)?)?`)
var reqHeaderRegexp = regexp.MustCompile(`\[[A-Za-z0-9\._\-]+\]`)

func (p *PackageIndex) AllPackages() ([]string, error) {
	pkgs := make([]string, 0)

	resp, err := http.Get(fmt.Sprintf("%s/simple", p.URI))
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	matches := allPkgRegexp.FindAllStringSubmatch(string(body), -1)
	for _, match := range matches {
		if len(match) != 3 {
			return nil, fmt.Errorf("Unexpected number of submatches: %d, %v", len(match), match)
		} else if match[1] != match[2] {
			return nil, fmt.Errorf("Names do not match %s != %s", match[1], match[2])
		} else {
			pkgs = append(pkgs, match[1])
		}
	}

	return pkgs, nil
}

func (p *PackageIndex) PackageRequirements(pkg string) ([]*Requirement, error) {
	files, err := p.pkgFiles(pkg)
	if err != nil {
		return nil, err
	} else if len(files) == 0 {
		// os.Stderr.WriteString(fmt.Sprintf("[no-files] no files found for pkg %s\n", pkg))
		return nil, nil
	}

	if path := lastTar(files); path != "" {
		return p.fetchRequiresTar(path)
	} else if path := lastEgg(files); path != "" {
		return p.fetchRequiresZip(path, true)
	} else if path := lastZip(files); path != "" {
		return p.fetchRequiresZip(path, false)
	} else {
		os.Stderr.WriteString(fmt.Sprintf("[tar/zip] no tar or zip found in %+v for pkg %s\n", files, pkg))
		return nil, nil
	}
}

func (p *PackageIndex) pkgFiles(pkg string) ([]string, error) {
	files := make([]string, 0)

	uriPath := fmt.Sprintf("/simple/%s", pkg)
	uri := fmt.Sprintf("%s%s", p.URI, uriPath)
	resp, err := http.Get(uri)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	matches := pkgFilesRegexp.FindAllStringSubmatch(string(body), -1)
	for _, match := range matches {
		if len(match) != 3 {
			return nil, fmt.Errorf("Unexpected number of submatches: %d, %v", len(match), match)
		} else {
			files = append(files, filepath.Clean(filepath.Join(uriPath, match[1])))
		}
	}

	return files, nil
}

func (p *PackageIndex) fetchRequiresZip(path string, isEgg bool) ([]*Requirement, error) {
	f, err := ioutil.TempFile("", "pypigraph_zip")
	if err != nil {
		return nil, err
	}
	defer os.Remove(f.Name())
	if err := f.Close(); err != nil {
		return nil, err
	}

	uri := fmt.Sprintf("%s%s", p.URI, path)
	wget := exec.Command("wget", uri, "-O", f.Name())
	var eggInfoFilePattern string
	if isEgg {
		eggInfoFilePattern = "EGG-INFO/requires.txt"
	} else {
		eggInfoFilePattern = "**/*.egg-info/requires.txt"
	}
	unzip := exec.Command("unzip", "-cq", f.Name(), eggInfoFilePattern)

	err = wget.Run()
	if err != nil {
		return nil, fmt.Errorf("Error running wget: %s", err)
	}

	unzipOutput, err := unzip.Output()
	if err != nil {
		if strings.Contains(err.Error(), "exit status 11") {
			// os.Stderr.WriteString(fmt.Sprintf("[requires.txt] no requires.txt found in %s\n", uri))
			return nil, nil
		} else {
			return nil, fmt.Errorf("Error running unzip on file %s: %s", f.Name(), err)
		}
	}

	rawReqs := strings.TrimSpace(string(unzipOutput))
	return parseRequirements(rawReqs)
}

func (p *PackageIndex) fetchRequiresTar(path string) ([]*Requirement, error) {
	uri := fmt.Sprintf("%s%s", p.URI, path)
	curl := exec.Command("curl", uri)
	tar := exec.Command("tar", "-xvO", "--include", "**/*.egg-info/requires.txt")

	curlOut, err := curl.StdoutPipe()
	if err != nil {
		return nil, err
	}
	tarIn, err := tar.StdinPipe()
	if err != nil {
		return nil, err
	}
	tarOut, err := tar.StdoutPipe()
	if err != nil {
		return nil, err
	}

	go func() {
		io.Copy(tarIn, curlOut)
		tarIn.Close()
	}()

	curl.Start()
	tar.Start()

	tarOutput, err := ioutil.ReadAll(tarOut)
	if err != nil {
		return nil, err
	}

	curl.Wait()
	tar.Wait()

	rawReqs := strings.TrimSpace(string(tarOutput))
	if rawReqs == "" {
		// os.Stderr.WriteString(fmt.Sprintf("[requires.txt] no requires.txt found in %s\n", uri))
		return nil, nil
	}

	return parseRequirements(rawReqs)
}

func lastTar(files []string) string {
	for f := len(files) - 1; f >= 0; f-- {
		if tarRegexp.MatchString(files[f]) {
			return files[f]
		}
	}
	return ""
}

func lastEgg(files []string) string {
	for f := len(files) - 1; f >= 0; f-- {
		if eggRegexp.MatchString(files[f]) {
			return files[f]
		}
	}
	return ""
}

func lastZip(files []string) string {
	for f := len(files) - 1; f >= 0; f-- {
		if zipRegexp.MatchString(files[f]) {
			return files[f]
		}
	}
	return ""
}

func parseRequirements(rawReqs string) ([]*Requirement, error) {
	rawReqs = strings.TrimSpace(rawReqs)

	reqStrs := strings.Split(rawReqs, "\n")
	reqs := make([]*Requirement, 0)
	for _, reqStr := range reqStrs {
		if reqStr == "" {
			continue
		}

		if req, err := parseRequirement(reqStr); err == nil {
			reqs = append(reqs, req)
		} else if reqHeaderRegexp.MatchString(reqStr) {
			// do nothing
		} else {
			os.Stderr.WriteString(fmt.Sprintf("[req] Could not parse requirement: %s\n", err))
		}
	}
	return reqs, nil
}

func parseRequirement(reqStr string) (*Requirement, error) {
	reqStr = strings.TrimSpace(reqStr)
	match := requirementRegexp.FindStringSubmatch(reqStr)
	if len(match) != 5 {
		return nil, fmt.Errorf("Expected match of length 5, but got %+v from '%s'", match, reqStr)
	} else if match[0] != reqStr {
		return nil, fmt.Errorf("Unable to parse requirement from string: '%s'", reqStr)
	}

	return &Requirement{Name: match[1]}, nil
}

func main() {
	p := &PackageIndex{URI: "https://pypi.python.org"}
	pkgs, err := p.AllPackages()
	if err != nil {
		os.Stderr.WriteString(fmt.Sprintf("[FATAL] %s\n", err))
		os.Exit(1)
	}

	for _, pkg := range pkgs {
		reqs, err := p.PackageRequirements(pkg)
		if err != nil {
			os.Stderr.WriteString(fmt.Sprintf("[ERROR] unable to parse pkg %s due to error: %s\n", pkg, err))
		} else {
			for _, req := range reqs {
				fmt.Printf("%s:%s\n", pkg, req.Name)
			}
		}
	}
}
<commit_msg>emit normalized package names<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type PackageIndex struct {
	URI string
}

type Requirement struct {
	Name string
}

var allPkgRegexp = regexp.MustCompile(`<a href='([A-Za-z0-9\._\-]+)'>([A-Za-z0-9\._\-]+)</a><br/>`)
var pkgFilesRegexp = regexp.MustCompile(`<a href="([/A-Za-z0-9\._\-]+)#md5=[0-9a-z]+"[^>]*>([A-Za-z0-9\._\-]+)</a><br/>`)
var tarRegexp = regexp.MustCompile(`[/A-Za-z0-9\._\-]+\.(?:tar\.(?:gz|bz2)|tgz)`)
var zipRegexp = regexp.MustCompile(`[/A-Za-z0-9\._\-]+\.zip`)
var eggRegexp = regexp.MustCompile(`[/A-Za-z0-9\._\-]+\.egg`)
var requirementRegexp = regexp.MustCompile(`(?P<package>[A-Za-z0-9\._\-]+)(?:\[([A-Za-z0-9\._\-]+)\])?\s*(?:(?P<constraint>==|>=|>|<|<=)\s*(?P<version>[A-Za-z0-9\._\-]+)(?:\s*,\s*[<>=!]+\s*[a-z0-9\.]+)?)?`)
var reqHeaderRegexp = regexp.MustCompile(`\[[A-Za-z0-9\._\-]+\]`)

func (p *PackageIndex) AllPackages() ([]string, error) {
	pkgs := make([]string, 0)

	resp, err := http.Get(fmt.Sprintf("%s/simple", p.URI))
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	matches := allPkgRegexp.FindAllStringSubmatch(string(body), -1)
	for _, match := range matches {
		if len(match) != 3 {
			return nil, fmt.Errorf("Unexpected number of submatches: %d, %v", len(match), match)
		} else if match[1] != match[2] {
			return nil, fmt.Errorf("Names do not match %s != %s", match[1], match[2])
		} else {
			pkgs = append(pkgs, match[1])
		}
	}

	return pkgs, nil
}

func (p *PackageIndex) PackageRequirements(pkg string) ([]*Requirement, error) {
	files, err := p.pkgFiles(pkg)
	if err != nil {
		return nil, err
	} else if len(files) == 0 {
		// os.Stderr.WriteString(fmt.Sprintf("[no-files] no files found for pkg %s\n", pkg))
		return nil, nil
	}

	if path := lastTar(files); path != "" {
		return p.fetchRequiresTar(path)
	} else if path := lastEgg(files); path != "" {
		return p.fetchRequiresZip(path, true)
	} else if path := lastZip(files); path != "" {
		return p.fetchRequiresZip(path, false)
	} else {
		os.Stderr.WriteString(fmt.Sprintf("[tar/zip] no tar or zip found in %+v for pkg %s\n", files, pkg))
		return nil, nil
	}
}

func (p *PackageIndex) pkgFiles(pkg string) ([]string, error) {
	files := make([]string, 0)

	uriPath := fmt.Sprintf("/simple/%s", pkg)
	uri := fmt.Sprintf("%s%s", p.URI, uriPath)
	resp, err := http.Get(uri)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	matches := pkgFilesRegexp.FindAllStringSubmatch(string(body), -1)
	for _, match := range matches {
		if len(match) != 3 {
			return nil, fmt.Errorf("Unexpected number of submatches: %d, %v", len(match), match)
		} else {
			files = append(files, filepath.Clean(filepath.Join(uriPath, match[1])))
		}
	}

	return files, nil
}

func (p *PackageIndex) fetchRequiresZip(path string, isEgg bool) ([]*Requirement, error) {
	f, err := ioutil.TempFile("", "pypigraph_zip")
	if err != nil {
		return nil, err
	}
	defer os.Remove(f.Name())
	if err := f.Close(); err != nil {
		return nil, err
	}

	uri := fmt.Sprintf("%s%s", p.URI, path)
	wget := exec.Command("wget", uri, "-O", f.Name())
	var eggInfoFilePattern string
	if isEgg {
		eggInfoFilePattern = "EGG-INFO/requires.txt"
	} else {
		eggInfoFilePattern = "**/*.egg-info/requires.txt"
	}
	unzip := exec.Command("unzip", "-cq", f.Name(), eggInfoFilePattern)

	err = wget.Run()
	if err != nil {
		return nil, fmt.Errorf("Error running wget: %s", err)
	}

	unzipOutput, err := unzip.Output()
	if err != nil {
		if strings.Contains(err.Error(), "exit status 11") {
			// os.Stderr.WriteString(fmt.Sprintf("[requires.txt] no requires.txt found in %s\n", uri))
			return nil, nil
		} else {
			return nil, fmt.Errorf("Error running unzip on file %s: %s", f.Name(), err)
		}
	}

	rawReqs := strings.TrimSpace(string(unzipOutput))
	return parseRequirements(rawReqs)
}

func (p *PackageIndex) fetchRequiresTar(path string) ([]*Requirement, error) {
	uri := fmt.Sprintf("%s%s", p.URI, path)
	curl := exec.Command("curl", uri)
	tar := exec.Command("tar", "-xvO", "--include", "**/*.egg-info/requires.txt")

	curlOut, err := curl.StdoutPipe()
	if err != nil {
		return nil, err
	}
	tarIn, err := tar.StdinPipe()
	if err != nil {
		return nil, err
	}
	tarOut, err := tar.StdoutPipe()
	if err != nil {
		return nil, err
	}

	go func() {
		io.Copy(tarIn, curlOut)
		tarIn.Close()
	}()

	curl.Start()
	tar.Start()

	tarOutput, err := ioutil.ReadAll(tarOut)
	if err != nil {
		return nil, err
	}

	curl.Wait()
	tar.Wait()

	rawReqs := strings.TrimSpace(string(tarOutput))
	if rawReqs == "" {
		// os.Stderr.WriteString(fmt.Sprintf("[requires.txt] no requires.txt found in %s\n", uri))
		return nil, nil
	}

	return parseRequirements(rawReqs)
}

func lastTar(files []string) string {
	for f := len(files) - 1; f >= 0; f-- {
		if tarRegexp.MatchString(files[f]) {
			return files[f]
		}
	}
	return ""
}

func lastEgg(files []string) string {
	for f := len(files) - 1; f >= 0; f-- {
		if eggRegexp.MatchString(files[f]) {
			return files[f]
		}
	}
	return ""
}

func lastZip(files []string) string {
	for f := len(files) - 1; f >= 0; f-- {
		if zipRegexp.MatchString(files[f]) {
			return files[f]
		}
	}
	return ""
}

func parseRequirements(rawReqs string) ([]*Requirement, error) {
	rawReqs = strings.TrimSpace(rawReqs)

	reqStrs := strings.Split(rawReqs, "\n")
	reqs := make([]*Requirement, 0)
	for _, reqStr := range reqStrs {
		if reqStr == "" {
			continue
		}

		if req, err := parseRequirement(reqStr); err == nil {
			reqs = append(reqs, req)
		} else if reqHeaderRegexp.MatchString(reqStr) {
			// do nothing
		} else {
			os.Stderr.WriteString(fmt.Sprintf("[req] Could not parse requirement: %s\n", err))
		}
	}
	return reqs, nil
}

func parseRequirement(reqStr string) (*Requirement, error) {
	reqStr = strings.TrimSpace(reqStr)
	match := requirementRegexp.FindStringSubmatch(reqStr)
	if len(match) != 5 {
		return nil, fmt.Errorf("Expected match of length 5, but got %+v from '%s'", match, reqStr)
	} else if match[0] != reqStr {
		return nil, fmt.Errorf("Unable to parse requirement from string: '%s'", reqStr)
	}
	return &Requirement{Name: match[1]}, nil
}

func normalizedPkgName(pkg string) string {
	return strings.ToLower(pkg)
}

func main() {
	p := &PackageIndex{URI: "https://pypi.python.org"}
	pkgs, err := p.AllPackages()
	if err != nil {
		os.Stderr.WriteString(fmt.Sprintf("[FATAL] %s\n", err))
		os.Exit(1)
	}

	for _, pkg := range pkgs {
		reqs, err := p.PackageRequirements(pkg)
		if err != nil {
			os.Stderr.WriteString(fmt.Sprintf("[ERROR] unable to parse pkg %s due to error: %s\n", pkg, err))
		} else {
			for _, req := range reqs {
				fmt.Printf("%s:%s\n", normalizedPkgName(pkg), normalizedPkgName(req.Name))
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/anacrolix/tagflag"
	"github.com/anacrolix/torrent/bencode"
	"github.com/anacrolix/torrent/metainfo"
)

var (
	builtinAnnounceList = [][]string{
		{"udp://tracker.openbittorrent.com:80"},
		{"udp://tracker.publicbt.com:80"},
		{"udp://tracker.istole.it:6969"},
	}
)

func main() {
	log.SetFlags(log.Flags() | log.Lshortfile)
	var args struct {
		AnnounceList []string `name:"a" help:"extra announce-list tier entry"`
		tagflag.StartPos
		Root string
	}
	tagflag.Parse(&args, tagflag.Description("Creates a torrent metainfo for the file system rooted at ROOT, and outputs it to stdout."))
	mi := metainfo.MetaInfo{
		AnnounceList: builtinAnnounceList,
	}
	for _, a := range args.AnnounceList {
		mi.AnnounceList = append(mi.AnnounceList, []string{a})
	}
	mi.SetDefaults()
	info := metainfo.Info{
		PieceLength: 256 * 1024,
	}
	err := info.BuildFromFilePath(args.Root)
	if err != nil {
		log.Fatal(err)
	}
	mi.InfoBytes, err = bencode.Marshal(info)
	if err != nil {
		log.Fatal(err)
	}
	err = mi.Write(os.Stdout)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Adds more flags to torrent-create<commit_after>package main

import (
	"log"
	"os"

	"github.com/anacrolix/tagflag"
	"github.com/anacrolix/torrent/bencode"
	"github.com/anacrolix/torrent/metainfo"
)

var (
	builtinAnnounceList = [][]string{
		{"udp://tracker.openbittorrent.com:80"},
		{"udp://tracker.publicbt.com:80"},
		{"udp://tracker.istole.it:6969"},
	}
)

func main() {
	log.SetFlags(log.Flags() | log.Lshortfile)
	var args struct {
		AnnounceList      []string `name:"a" help:"extra announce-list tier entry"`
		EmptyAnnounceList bool     `name:"n" help:"exclude default announce-list entries"`
		Comment           string   `name:"t" help:"comment"`
		CreatedBy         string   `name:"c" help:"created by"`
		tagflag.StartPos
		Root string
	}
	tagflag.Parse(&args, tagflag.Description("Creates a torrent metainfo for the file system rooted at ROOT, and outputs it to stdout."))
	mi := metainfo.MetaInfo{
		AnnounceList: builtinAnnounceList,
	}
	if args.EmptyAnnounceList {
		mi.AnnounceList = make([][]string, 0)
	}
	for _, a := range args.AnnounceList {
		mi.AnnounceList = append(mi.AnnounceList, []string{a})
	}
	mi.SetDefaults()
	if len(args.Comment) > 0 {
		mi.Comment = args.Comment
	}
	if len(args.CreatedBy) > 0 {
		mi.CreatedBy = args.CreatedBy
	}
	info := metainfo.Info{
		PieceLength: 256 * 1024,
	}
	err := info.BuildFromFilePath(args.Root)
	if err != nil {
		log.Fatal(err)
	}
	mi.InfoBytes, err = bencode.Marshal(info)
	if err != nil {
		log.Fatal(err)
	}
	err = mi.Write(os.Stdout)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package xml

import "testing"
import "fmt"

func TestAddChild(t *testing.T) {

	docAssertion := func(doc *XmlDocument) (string, string, string) {
		expectedDocAfterAdd :=
			`<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar/>
</foo>
`
		doc.Root().AddChild("<bar></bar>")

		return doc.String(), expectedDocAfterAdd, "output of the xml doc after AddChild does not match"
	}

	nodeAssertion := func(doc *XmlDocument) (string, string, string) {
		expectedNodeAfterAdd :=
			`<foo>
  <bar/>
</foo>`

		return doc.Root().String(), expectedNodeAfterAdd, "the output of the xml root after AddChild does not match"
	}

	RunTest(t, "node", "add_child", nil, docAssertion, nodeAssertion)

}

func TestAddAncestorAsChild(t *testing.T) {
	docAssertion := func(doc *XmlDocument) (string, string, string) {
		expectedDocAfterAdd :=
			`<?xml version="1.0" encoding="utf-8"?>
<foo/>
`

		foo := doc.Root()
		bar := foo.FirstChild()
		holiday := bar.FirstChild()
		fun := holiday.FirstChild()
		fun.AddChild(bar)

		return doc.String(), expectedDocAfterAdd, "output of the xml doc after AddChild does not match"
	}

	nodeAssertion := func(doc *XmlDocument) (string, string, string) {
		expectedNodeAfterAdd :=
			`<foo/>`

		return doc.Root().String(), expectedNodeAfterAdd, "the output of the xml root after AddChild does not match"
	}

	RunTest(t, "node", "add_ancestor", nil, docAssertion, nodeAssertion)

}

func addChildBenchLogic(b *testing.B, doc *XmlDocument) {
	root := doc.Root()

	for i := 0; i < b.N; i++ {
		root.AddChild("<bar></bar>")
	}
}

func BenchmarkAddChild(b *testing.B) {
	RunBenchmark(b, "document", "big_un", addChildBenchLogic) // Run against big doc
}

func BenchmarkAddChildBigDoc(b *testing.B) {
	RunBenchmark(b, "node", "add_child", addChildBenchLogic)
}

func TestAddPreviousSibling(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		err := doc.Root().AddPreviousSibling("<bar></bar><cat></cat>")

		if err != nil {
			t.Errorf("Error adding previous sibling:\n%v\n", err.Error())
		}
	}

	RunTest(t, "node", "add_previous_sibling", testLogic)
}

func TestAddPreviousSibling2(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		err := doc.Root().FirstChild().AddPreviousSibling("COOL")

		if err != nil {
			t.Errorf("Error adding previous sibling:\n%v\n", err.Error())
		}
	}

	RunTest(t, "node", "add_previous_sibling2", testLogic)
}

func TestAddNextSibling(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		doc.Root().AddNextSibling("<bar></bar><baz></baz>")
	}

	RunTest(t, "node", "add_next_sibling", testLogic)
}

func TestSetContent(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetContent("<fun></fun>")
	}

	RunTest(t, "node", "set_content", testLogic)
}

func BenchmarkSetContent(b *testing.B) {

	benchmarkLogic := func(b *testing.B, doc *XmlDocument) {
		root := doc.Root()
		for i := 0; i < b.N; i++ {
			root.SetContent("<fun></fun>")
		}
	}

	RunBenchmark(b, "node", "set_content", benchmarkLogic)
}

func TestSetChildren(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetChildren("<fun></fun>")
	}

	RunTest(t, "node", "set_children", testLogic)
}

func BenchmarkSetChildren(b *testing.B) {
	benchmarkLogic := func(b *testing.B, doc *XmlDocument) {
		root := doc.Root()
		for i := 0; i < b.N; i++ {
			root.SetChildren("<fun></fun>")
		}
	}

	RunBenchmark(b, "node", "set_children", benchmarkLogic)
}

func TestReplace(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.Replace("<fun></fun><cool/>")
	}

	rootAssertion := func(doc *XmlDocument) (string, string, string) {
		root := doc.Root()
		return root.String(), "<fun/>", "the output of the xml root does not match"
	}

	RunTest(t, "node", "replace", testLogic, rootAssertion)
}

func BenchmarkReplace(b *testing.B) {

	benchmarkLogic := func(b *testing.B, doc *XmlDocument) {
		root := doc.Root()
		for i := 0; i < b.N; i++ {
			root.Replace("<fun></fun>")
			root = doc.Root() //once the node has been replaced, we need to get a new node
		}
	}

	RunBenchmark(b, "node", "replace", benchmarkLogic)
}

func TestAttributes(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {

		root := doc.Root()
		attributes := root.Attributes()

		if len(attributes) != 2 || attributes["myname"].String() != "ff" {
			fmt.Printf("%v, %q\n", attributes, attributes["myname"].String())
			t.Error("root's attributes do not match")
		}

		child := root.FirstChild()
		childAttributes := child.Attributes()

		if len(childAttributes) != 1 || childAttributes["class"].String() != "shine" {
			t.Error("child's attributes do not match")
		}
	}

	RunTest(t, "node", "attributes", testLogic)

}

func BenchmarkAttributes(b *testing.B) {
	benchmarkLogic := func(b *testing.B, doc *XmlDocument) {

		root := doc.Root()

		for i := 0; i < b.N; i++ {
			root.SetAttr("garfield", "spaghetti")
		}
	}

	RunBenchmark(b, "node", "attributes", benchmarkLogic)
}

func TestInner(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetInnerHtml("<bar></bar><baz></baz>")
	}

	RunTest(t, "node", "inner", testLogic)
}
func TestInnerWithAttributes(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetInnerHtml("<bar give='me' something='good' to='eat'></bar>")
	}

	RunTest(t, "node", "inner_with_attributes", testLogic)
}

func TestSetNamespace(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetNamespace("foo", "bar")
	}

	RunTest(t, "node", "set_namespace", testLogic)
}

func TestSetDefaultNamespace(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetNamespace("", "bar")
	}

	RunTest(t, "node", "set_default_namespace", testLogic)
}

func TestDeclareNamespace(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.DeclareNamespace("foo", "bar")
		child := root.FirstChild()
		child.SetNamespace("foo", "bar")
	}

	RunTest(t, "node", "declare_namespace", testLogic)
}

func TestNamespaceAttribute(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.DeclareNamespace("foo", "bar")
		root.SetNsAttr("bar", "hello", "world")
	}

	RunTest(t, "node", "set_ns_attr", testLogic)
}
<commit_msg>Tests for SerializeWithFormat, ToUnformattedXml<commit_after>package xml

import "testing"
import "fmt"

func TestAddChild(t *testing.T) {

	docAssertion := func(doc *XmlDocument) (string, string, string) {
		expectedDocAfterAdd :=
			`<?xml version="1.0" encoding="utf-8"?>
<foo>
  <bar/>
</foo>
`
		doc.Root().AddChild("<bar></bar>")

		return doc.String(), expectedDocAfterAdd, "output of the xml doc after AddChild does not match"
	}

	nodeAssertion := func(doc *XmlDocument) (string, string, string) {
		expectedNodeAfterAdd :=
			`<foo>
  <bar/>
</foo>`

		return doc.Root().String(), expectedNodeAfterAdd, "the output of the xml root after AddChild does not match"
	}

	RunTest(t, "node", "add_child", nil, docAssertion, nodeAssertion)

}

func TestAddAncestorAsChild(t *testing.T) {
	docAssertion := func(doc *XmlDocument) (string, string, string) {
		expectedDocAfterAdd :=
			`<?xml version="1.0" encoding="utf-8"?>
<foo/>
`

		foo := doc.Root()
		bar := foo.FirstChild()
		holiday := bar.FirstChild()
		fun := holiday.FirstChild()
		fun.AddChild(bar)

		return doc.String(), expectedDocAfterAdd, "output of the xml doc after AddChild does not match"
	}

	nodeAssertion := func(doc *XmlDocument) (string, string, string) {
		expectedNodeAfterAdd :=
			`<foo/>`

		return doc.Root().String(), expectedNodeAfterAdd, "the output of the xml root after AddChild does not match"
	}

	RunTest(t, "node", "add_ancestor", nil, docAssertion, nodeAssertion)

}

func addChildBenchLogic(b *testing.B, doc *XmlDocument) {
	root := doc.Root()

	for i := 0; i < b.N; i++ {
		root.AddChild("<bar></bar>")
	}
}

func BenchmarkAddChild(b *testing.B) {
	RunBenchmark(b, "document", "big_un", addChildBenchLogic) // Run against big doc
}

func BenchmarkAddChildBigDoc(b *testing.B) {
	RunBenchmark(b, "node", "add_child", addChildBenchLogic)
}

func TestAddPreviousSibling(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		err := doc.Root().AddPreviousSibling("<bar></bar><cat></cat>")

		if err != nil {
			t.Errorf("Error adding previous sibling:\n%v\n", err.Error())
		}
	}

	RunTest(t, "node", "add_previous_sibling", testLogic)
}

func TestAddPreviousSibling2(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		err := doc.Root().FirstChild().AddPreviousSibling("COOL")

		if err != nil {
			t.Errorf("Error adding previous sibling:\n%v\n", err.Error())
		}
	}

	RunTest(t, "node", "add_previous_sibling2", testLogic)
}

func TestAddNextSibling(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		doc.Root().AddNextSibling("<bar></bar><baz></baz>")
	}

	RunTest(t, "node", "add_next_sibling", testLogic)
}

func TestSetContent(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetContent("<fun></fun>")
	}

	RunTest(t, "node", "set_content", testLogic)
}

func BenchmarkSetContent(b *testing.B) {

	benchmarkLogic := func(b *testing.B, doc *XmlDocument) {
		root := doc.Root()
		for i := 0; i < b.N; i++ {
			root.SetContent("<fun></fun>")
		}
	}

	RunBenchmark(b, "node", "set_content", benchmarkLogic)
}

func TestSetChildren(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetChildren("<fun></fun>")
	}

	RunTest(t, "node", "set_children", testLogic)
}

func BenchmarkSetChildren(b *testing.B) {
	benchmarkLogic := func(b *testing.B, doc *XmlDocument) {
		root := doc.Root()
		for i := 0; i < b.N; i++ {
			root.SetChildren("<fun></fun>")
		}
	}

	RunBenchmark(b, "node", "set_children", benchmarkLogic)
}

func TestReplace(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.Replace("<fun></fun><cool/>")
	}

	rootAssertion := func(doc *XmlDocument) (string, string, string) {
		root := doc.Root()
		return root.String(), "<fun/>", "the output of the xml root does not match"
	}

	RunTest(t, "node", "replace", testLogic, rootAssertion)
}

func BenchmarkReplace(b *testing.B) {

	benchmarkLogic := func(b *testing.B, doc *XmlDocument) {
		root := doc.Root()
		for i := 0; i < b.N; i++ {
			root.Replace("<fun></fun>")
			root = doc.Root() //once the node has been replaced, we need to get a new node
		}
	}

	RunBenchmark(b, "node", "replace", benchmarkLogic)
}

func TestAttributes(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {

		root := doc.Root()
		attributes := root.Attributes()

		if len(attributes) != 2 || attributes["myname"].String() != "ff" {
			fmt.Printf("%v, %q\n", attributes, attributes["myname"].String())
			t.Error("root's attributes do not match")
		}

		child := root.FirstChild()
		childAttributes := child.Attributes()

		if len(childAttributes) != 1 || childAttributes["class"].String() != "shine" {
			t.Error("child's attributes do not match")
		}
	}

	RunTest(t, "node", "attributes", testLogic)

}

func BenchmarkAttributes(b *testing.B) {
	benchmarkLogic := func(b *testing.B, doc *XmlDocument) {

		root := doc.Root()

		for i := 0; i < b.N; i++ {
			root.SetAttr("garfield", "spaghetti")
		}
	}

	RunBenchmark(b, "node", "attributes", benchmarkLogic)
}

func TestInner(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetInnerHtml("<bar></bar><baz></baz>")
	}

	RunTest(t, "node", "inner", testLogic)
}
func TestInnerWithAttributes(t *testing.T) {

	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetInnerHtml("<bar give='me' something='good' to='eat'></bar>")
	}

	RunTest(t, "node", "inner_with_attributes", testLogic)
}

func TestSetNamespace(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetNamespace("foo", "bar")
	}

	RunTest(t, "node", "set_namespace", testLogic)
}

func TestSetDefaultNamespace(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.SetNamespace("", "bar")
	}

	RunTest(t, "node", "set_default_namespace", testLogic)
}

func TestDeclareNamespace(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.DeclareNamespace("foo", "bar")
		child := root.FirstChild()
		child.SetNamespace("foo", "bar")
	}

	RunTest(t, "node", "declare_namespace", testLogic)
}

func TestNamespaceAttribute(t *testing.T) {
	testLogic := func(t *testing.T, doc *XmlDocument) {
		root := doc.Root()
		root.DeclareNamespace("foo", "bar")
		root.SetNsAttr("bar", "hello", "world")
	}

	RunTest(t, "node", "set_ns_attr", testLogic)
}

func TestUnformattedXml(t *testing.T) {
	xml := "<?xml version=\"1.0\"?>\n<foo>\n\t<bar>Test</bar>\n</foo>"
	expected := "<foo><bar>Test</bar></foo>"
	doc, _ := Parse([]byte(xml), DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes)
	root := doc.Root()
	out := root.ToUnformattedXml()
	if out != expected {
		t.Errorf("TestUnformattedXml Expected: %v\nActual: %v", expected, out)
	}

}

func TestSerializewithFomat(t *testing.T) {
	xml := "<?xml version=\"1.0\"?>\n<foo>\n\t<bar>Test</bar>\n</foo>"
	expected := "<foo><bar>Test</bar></foo>"
	doc, _ := Parse([]byte(xml), DefaultEncodingBytes, nil, DefaultParseOption, DefaultEncodingBytes)
	root := doc.Root()
	b, size = root.SerializeWithFormat(XML_SAVE_AS_XML|XML_SAVE_NO_DECL, nil, nil)
	if b == nil {
		t.Errorf("SerializeWithFormat Expected: %v\nActual: (nil)", expected)
		return
	}
	out := string(b[:size])
	if out != expected {
		t.Errorf("SerializeWithFormat Expected: %v\nActual: %v", expected, out)
	}

}
<|endoftext|>


<commit_before>package metadata

import (
	"strings"

	"github.com/bosun-monitor/bosun/_third_party/github.com/bosun-monitor/scollector/util"
)

func init() {
	metafuncs = append(metafuncs, collectMetadataOmreport)
}

func collectMetadataOmreport() {
	util.ReadCommand(func(line string) error {
		fields := strings.Split(line, ";")
		if len(fields) != 2 {
			return nil
		}
		switch fields[0] {
		case "Chassis Service Tag":
			AddMeta("", nil, "svctag", fields[1], true)
		case "Chassis Model":
			AddMeta("", nil, "model", fields[1], true)
		}
		return nil
	}, "omreport", "chassis", "info", "-fmt", "ssv")
}
<commit_msg>party sync<commit_after><|endoftext|>


<commit_before>/*
 *
 * Copyright IBM Corp. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 * /
 *
 */

package gossip

import (
	"fmt"
	"io/ioutil"
	"os"
	"syscall"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/hyperledger/fabric/integration/nwo"
	"github.com/hyperledger/fabric/integration/nwo/commands"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

var _ = Describe("Gossip Test", func() {
	var (
		testDir   string
		client    *docker.Client
		network   *nwo.Network
		chaincode nwo.Chaincode
	)

	BeforeEach(func() {
		var err error
		testDir, err = ioutil.TempDir("", "e2e")
		Expect(err).NotTo(HaveOccurred())

		client, err = docker.NewClientFromEnv()
		Expect(err).NotTo(HaveOccurred())

		chaincode = nwo.Chaincode{
			Name:    "mycc",
			Version: "0.0",
			Path:    "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
			Ctor:    `{"Args":["init","a","100","b","200"]}`,
			Policy:  `OR ('Org1MSP.member','Org2MSP.member')`,
		}
	})

	AfterEach(func() {
		if network != nil {
			network.Cleanup()
		}
		os.RemoveAll(testDir)
	})

	Describe("Gossip state transfer test", func() {
		var (
			ordererProcess ifrit.Process
			peerProcesses  = map[string]ifrit.Process{}
			peerRunners    = map[string]*ginkgomon.Runner{}
		)

		BeforeEach(func() {
			network = nwo.New(nwo.FullSolo(), testDir, client, StartPort(), components)

			network.GenerateConfigTree()
			//  modify peer config
			//  Org1: leader election
			//  Org2: no leader election
			//      peer0: follower
			//      peer1: leader
			for _, peer := range network.Peers {
				if peer.Organization == "Org1" {
					core := network.ReadPeerConfig(peer)
					if peer.Name == "peer1" {
						core.Peer.Gossip.Bootstrap = "127.0.0.1:21004"
						network.WritePeerConfig(peer, core)
					}

				}
				if peer.Organization == "Org2" {
					core := network.ReadPeerConfig(peer)
					core.Peer.Gossip.UseLeaderElection = false
					if peer.Name == "peer1" {
						core.Peer.Gossip.OrgLeader = true
					} else {
						core.Peer.Gossip.OrgLeader = false
					}

					network.WritePeerConfig(peer, core)
				}
			}
			network.Bootstrap()
		})

		AfterEach(func() {
			if ordererProcess != nil {
				ordererProcess.Signal(syscall.SIGTERM)
				Eventually(ordererProcess.Wait(), network.EventuallyTimeout).Should(Receive())
			}

			for _, process := range peerProcesses {
				process.Signal(syscall.SIGTERM)
				Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
			}
		})

		It("syncs blocks from the peer if no orderer is available, using solo network with 2 orgs, 2 peers each", func() {
			orderer := network.Orderer("orderer")
			ordererRunner := network.OrdererRunner(orderer)
			ordererProcess = ifrit.Invoke(ordererRunner)
			Eventually(ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed())

			peer0Org1, peer1Org1 := network.Peer("Org1", "peer0"), network.Peer("Org1", "peer1")
			peer0Org2, peer1Org2 := network.Peer("Org2", "peer0"), network.Peer("Org2", "peer1")

			By("bring up all four peers")
			peersToBringUp := []*nwo.Peer{peer0Org1, peer1Org1, peer0Org2, peer1Org2}
			startPeers(network, peersToBringUp, peerProcesses, peerRunners, false)

			channelName := "testchannel"
			network.CreateChannel(channelName, orderer, peer0Org1)
			By("join all peers to channel")
			network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1, peer0Org2, peer1Org2)

			network.UpdateChannelAnchors(orderer, channelName)

			// base peer will be used for chaincode interactions
			basePeerForTransactions := peer0Org1
			nwo.DeployChaincodeLegacy(network, channelName, orderer, chaincode, basePeerForTransactions)

			By("STATE TRANSFER TEST 1: newly joined peers should receive blocks from the peers that are already up")

			// Note, a better test would be to bring orderer down before joining the two peers.
			// However, network.JoinChannel() requires orderer to be up so that genesis block can be fetched from orderer before joining peers.
			// Therefore, for now we've joined all four peers and stop the two peers that should be synced up.
			peersToStop := []*nwo.Peer{peer1Org1, peer1Org2}
			stopPeers(network, peersToStop, peerProcesses)

			By("confirm peer0Org1 elected to be a leader")
			expectedMsg := "Elected as a leader, starting delivery service for channel testchannel"
			Eventually(peerRunners[peer0Org1.ID()].Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsg))

			peersToSyncUp := []*nwo.Peer{peer1Org1, peer1Org2}
			sendTransactionsAndSyncUpPeers(network, orderer, basePeerForTransactions, peersToSyncUp, channelName, &ordererProcess, ordererRunner, peerProcesses, peerRunners)

			By("STATE TRANSFER TEST 2: restarted peers should receive blocks from the peers that are already up")
			basePeerForTransactions = peer1Org1
			nwo.InstallChaincodeLegacy(network, chaincode, basePeerForTransactions)

			By("stop peer0Org1 (currently elected leader in Org1) and peer1Org2 (static leader in Org2)")
			peersToStop = []*nwo.Peer{peer0Org1, peer1Org2}
			stopPeers(network, peersToStop, peerProcesses)

			By("confirm peer1Org1 elected to be a leader")
			Eventually(peerRunners[peer1Org1.ID()].Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsg))

			peersToSyncUp = []*nwo.Peer{peer0Org1, peer1Org2}
			// Note that with the static leader in Org2 down, the static follower peer0Org2 will also get blocks via state transfer
			// This effectively tests leader election as well, since the newly elected leader in Org1 (peer1Org1) will be the only peer
			// that receives blocks from orderer and will therefore serve as the provider of blocks to all other peers.
			sendTransactionsAndSyncUpPeers(network, orderer, basePeerForTransactions, peersToSyncUp, channelName, &ordererProcess, ordererRunner, peerProcesses, peerRunners)

		})

	})
})

func runTransactions(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, chaincodeName string, channelID string) {
	for i := 0; i < 5; i++ {
		sess, err := n.PeerUserSession(peer, "User1", commands.ChaincodeInvoke{
			ChannelID: channelID,
			Orderer:   n.OrdererAddress(orderer, nwo.ListenPort),
			Name:      chaincodeName,
			Ctor:      `{"Args":["invoke","a","b","10"]}`,
			PeerAddresses: []string{
				n.PeerAddress(peer, nwo.ListenPort),
			},
			WaitForEvent: true,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
		Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200"))
	}
}

func startPeers(network *nwo.Network, peersToStart []*nwo.Peer, peerProc map[string]ifrit.Process, peerRun map[string]*ginkgomon.Runner, forceStateTransfer bool) {

	env := []string{fmt.Sprint("FABRIC_LOGGING_SPEC=info:gossip.state=debug")}

	// Setting CORE_PEER_GOSSIP_STATE_CHECKINTERVAL to 200ms (from default of 10s) will ensure that state transfer happens quickly,
	// before blocks are gossipped through normal mechanisms
	if forceStateTransfer {
		env = append(env, fmt.Sprint("CORE_PEER_GOSSIP_STATE_CHECKINTERVAL=200ms"))
	}

	for _, peer := range peersToStart {
		runner := network.PeerRunner(peer, env...)
		process := ifrit.Invoke(runner)
		Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())

		peerProc[peer.ID()] = process
		peerRun[peer.ID()] = runner
	}
}

func stopPeers(network *nwo.Network, peersToStop []*nwo.Peer, peerProcesses map[string]ifrit.Process) {
	for _, peer := range peersToStop {
		id := peer.ID()
		proc := peerProcesses[id]
		proc.Signal(syscall.SIGTERM)
		Eventually(proc.Wait(), network.EventuallyTimeout).Should(Receive())
		delete(peerProcesses, id)
	}
}

func assertPeersLedgerHeight(n *nwo.Network, orderer *nwo.Orderer, peersToSyncUp []*nwo.Peer, expectedVal int, channelID string) {
	for _, peer := range peersToSyncUp {
		Eventually(func() int {
			return nwo.GetLedgerHeight(n, peer, channelID)
		}, n.EventuallyTimeout).Should(Equal(expectedVal))
	}
}

// send transactions, stop orderering server, then start peers to ensure they received blcoks via state transfer
func sendTransactionsAndSyncUpPeers(network *nwo.Network, orderer *nwo.Orderer, basePeer *nwo.Peer, peersToSyncUp []*nwo.Peer, channelName string,
	ordererProcess *ifrit.Process, ordererRunner *ginkgomon.Runner,
	peerProcesses map[string]ifrit.Process, peerRunners map[string]*ginkgomon.Runner) {

	By("create transactions")
	runTransactions(network, orderer, basePeer, "mycc", channelName)
	basePeerLedgerHeight := nwo.GetLedgerHeight(network, basePeer, channelName)

	By("stop orderer")
	(*ordererProcess).Signal(syscall.SIGTERM)
	Eventually((*ordererProcess).Wait(), network.EventuallyTimeout).Should(Receive())
	*ordererProcess = nil

	By("start the peers contained in the peersToSyncUp list")
	startPeers(network, peersToSyncUp, peerProcesses, peerRunners, true)

	By("ensure the peers are synced up")
	assertPeersLedgerHeight(network, orderer, peersToSyncUp, basePeerLedgerHeight, channelName)

	By("restart orderer")
	orderer = network.Orderer("orderer")
	ordererRunner = network.OrdererRunner(orderer)
	*ordererProcess = ifrit.Invoke(ordererRunner)
	Eventually((*ordererProcess).Ready(), network.EventuallyTimeout).Should(BeClosed())
}
<commit_msg>Minor refactor of gossip integration test<commit_after>/*
 * Copyright IBM Corp. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

package gossip

import (
	"fmt"
	"io/ioutil"
	"os"
	"syscall"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/hyperledger/fabric/integration/nwo"
	"github.com/hyperledger/fabric/integration/nwo/commands"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
)

var _ = Describe("Gossip State Transfer", func() {
	var (
		testDir   string
		network   *nwo.Network
		nwprocs   *networkProcesses
		chaincode nwo.Chaincode
	)

	BeforeEach(func() {
		var err error
		testDir, err = ioutil.TempDir("", "gossip-statexfer")
		Expect(err).NotTo(HaveOccurred())

		dockerClient, err := docker.NewClientFromEnv()
		Expect(err).NotTo(HaveOccurred())

		network = nwo.New(nwo.FullSolo(), testDir, dockerClient, StartPort(), components)
		network.GenerateConfigTree()

		//  modify peer config
		//  Org1: leader election
		//  Org2: no leader election
		//      peer0: follower
		//      peer1: leader
		for _, peer := range network.Peers {
			if peer.Organization == "Org1" {
				if peer.Name == "peer1" {
					core := network.ReadPeerConfig(peer)
					core.Peer.Gossip.Bootstrap = fmt.Sprintf("127.0.0.1:%d", network.ReservePort())
					network.WritePeerConfig(peer, core)
				}
			}
			if peer.Organization == "Org2" {
				core := network.ReadPeerConfig(peer)
				core.Peer.Gossip.UseLeaderElection = false
				core.Peer.Gossip.OrgLeader = peer.Name == "peer1"
				network.WritePeerConfig(peer, core)
			}
		}

		network.Bootstrap()
		nwprocs = &networkProcesses{
			network:       network,
			peerRunners:   map[string]*ginkgomon.Runner{},
			peerProcesses: map[string]ifrit.Process{},
		}

		chaincode = nwo.Chaincode{
			Name:    "mycc",
			Version: "0.0",
			Path:    "github.com/hyperledger/fabric/integration/chaincode/simple/cmd",
			Ctor:    `{"Args":["init","a","100","b","200"]}`,
			Policy:  `OR ('Org1MSP.member','Org2MSP.member')`,
		}
	})

	AfterEach(func() {
		if nwprocs != nil {
			nwprocs.terminateAll()
		}
		if network != nil {
			network.Cleanup()
		}
		os.RemoveAll(testDir)
	})

	It("syncs blocks from the peer when no orderer is available", func() {
		orderer := network.Orderer("orderer")
		nwprocs.ordererRunner = network.OrdererRunner(orderer)
		nwprocs.ordererProcess = ifrit.Invoke(nwprocs.ordererRunner)
		Eventually(nwprocs.ordererProcess.Ready(), network.EventuallyTimeout).Should(BeClosed())

		peer0Org1, peer1Org1 := network.Peer("Org1", "peer0"), network.Peer("Org1", "peer1")
		peer0Org2, peer1Org2 := network.Peer("Org2", "peer0"), network.Peer("Org2", "peer1")

		By("bringing up all four peers")
		startPeers(nwprocs, false, peer0Org1, peer1Org1, peer0Org2, peer1Org2)

		channelName := "testchannel"
		network.CreateChannel(channelName, orderer, peer0Org1)
		By("joining all peers to channel")
		network.JoinChannel(channelName, orderer, peer0Org1, peer1Org1, peer0Org2, peer1Org2)

		network.UpdateChannelAnchors(orderer, channelName)

		// base peer will be used for chaincode interactions
		basePeerForTransactions := peer0Org1
		nwo.DeployChaincodeLegacy(network, channelName, orderer, chaincode, basePeerForTransactions)

		By("STATE TRANSFER TEST 1: newly joined peers should receive blocks from the peers that are already up")

		// Note, a better test would be to bring orderer down before joining the two peers.
		// However, network.JoinChannel() requires orderer to be up so that genesis block can be fetched from orderer before joining peers.
		// Therefore, for now we've joined all four peers and stop the two peers that should be synced up.
		stopPeers(nwprocs, peer1Org1, peer1Org2)

		By("confirming peer0Org1 was elected to be a leader")
		expectedMsg := "Elected as a leader, starting delivery service for channel testchannel"
		Eventually(nwprocs.peerRunners[peer0Org1.ID()].Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsg))

		sendTransactionsAndSyncUpPeers(nwprocs, orderer, basePeerForTransactions, channelName, peer1Org1, peer1Org2)

		By("STATE TRANSFER TEST 2: restarted peers should receive blocks from the peers that are already up")
		basePeerForTransactions = peer1Org1
		nwo.InstallChaincodeLegacy(network, chaincode, basePeerForTransactions)

		By("stopping peer0Org1 (currently elected leader in Org1) and peer1Org2 (static leader in Org2)")
		stopPeers(nwprocs, peer0Org1, peer1Org2)

		By("confirming peer1Org1 was elected to be a leader")
		Eventually(nwprocs.peerRunners[peer1Org1.ID()].Err(), network.EventuallyTimeout).Should(gbytes.Say(expectedMsg))

		// Note that with the static leader in Org2 down, the static follower peer0Org2 will also get blocks via state transfer
		// This effectively tests leader election as well, since the newly elected leader in Org1 (peer1Org1) will be the only peer
		// that receives blocks from orderer and will therefore serve as the provider of blocks to all other peers.
		sendTransactionsAndSyncUpPeers(nwprocs, orderer, basePeerForTransactions, channelName, peer0Org1, peer1Org2)
	})
})

func runTransactions(n *nwo.Network, orderer *nwo.Orderer, peer *nwo.Peer, chaincodeName string, channelID string) {
	for i := 0; i < 5; i++ {
		sess, err := n.PeerUserSession(peer, "User1", commands.ChaincodeInvoke{
			ChannelID: channelID,
			Orderer:   n.OrdererAddress(orderer, nwo.ListenPort),
			Name:      chaincodeName,
			Ctor:      `{"Args":["invoke","a","b","10"]}`,
			PeerAddresses: []string{
				n.PeerAddress(peer, nwo.ListenPort),
			},
			WaitForEvent: true,
		})
		Expect(err).NotTo(HaveOccurred())
		Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
		Expect(sess.Err).To(gbytes.Say("Chaincode invoke successful. result: status:200"))
	}
}

// networkProcesses holds references to the network, its runners, and processes.
type networkProcesses struct {
	network *nwo.Network

	ordererRunner  *ginkgomon.Runner
	ordererProcess ifrit.Process

	peerRunners   map[string]*ginkgomon.Runner
	peerProcesses map[string]ifrit.Process
}

func (n *networkProcesses) terminateAll() {
	if n.ordererProcess != nil {
		n.ordererProcess.Signal(syscall.SIGTERM)
		Eventually(n.ordererProcess.Wait(), n.network.EventuallyTimeout).Should(Receive())
	}
	for _, process := range n.peerProcesses {
		process.Signal(syscall.SIGTERM)
		Eventually(process.Wait(), n.network.EventuallyTimeout).Should(Receive())
	}
}

func startPeers(n *networkProcesses, forceStateTransfer bool, peersToStart ...*nwo.Peer) {
	env := []string{"FABRIC_LOGGING_SPEC=info:gossip.state=debug"}

	// Setting CORE_PEER_GOSSIP_STATE_CHECKINTERVAL to 200ms (from default of 10s) will ensure that state transfer happens quickly,
	// before blocks are gossipped through normal mechanisms
	if forceStateTransfer {
		env = append(env, "CORE_PEER_GOSSIP_STATE_CHECKINTERVAL=200ms")
	}

	for _, peer := range peersToStart {
		runner := n.network.PeerRunner(peer, env...)
		process := ifrit.Invoke(runner)
		Eventually(process.Ready(), n.network.EventuallyTimeout).Should(BeClosed())

		n.peerProcesses[peer.ID()] = process
		n.peerRunners[peer.ID()] = runner
	}
}

func stopPeers(n *networkProcesses, peersToStop ...*nwo.Peer) {
	for _, peer := range peersToStop {
		id := peer.ID()
		proc := n.peerProcesses[id]
		proc.Signal(syscall.SIGTERM)
		Eventually(proc.Wait(), n.network.EventuallyTimeout).Should(Receive())
		delete(n.peerProcesses, id)
	}
}

func assertPeersLedgerHeight(n *nwo.Network, peersToSyncUp []*nwo.Peer, expectedVal int, channelID string) {
	for _, peer := range peersToSyncUp {
		Eventually(func() int {
			return nwo.GetLedgerHeight(n, peer, channelID)
		}, n.EventuallyTimeout).Should(Equal(expectedVal))
	}
}

// send transactions, stop orderering server, then start peers to ensure they received blcoks via state transfer
func sendTransactionsAndSyncUpPeers(n *networkProcesses, orderer *nwo.Orderer, basePeer *nwo.Peer, channelName string, peersToSyncUp ...*nwo.Peer) {
	By("creating transactions")
	runTransactions(n.network, orderer, basePeer, "mycc", channelName)
	basePeerLedgerHeight := nwo.GetLedgerHeight(n.network, basePeer, channelName)

	By("stopping orderer")
	n.ordererProcess.Signal(syscall.SIGTERM)
	Eventually(n.ordererProcess.Wait(), n.network.EventuallyTimeout).Should(Receive())
	n.ordererProcess = nil

	By("starting the peers contained in the peersToSyncUp list")
	startPeers(n, true, peersToSyncUp...)

	By("ensuring the peers are synced up")
	assertPeersLedgerHeight(n.network, peersToSyncUp, basePeerLedgerHeight, channelName)

	By("restarting orderer")
	n.ordererRunner = n.network.OrdererRunner(orderer)
	n.ordererProcess = ifrit.Invoke(n.ordererRunner)
	Eventually(n.ordererProcess.Ready(), n.network.EventuallyTimeout).Should(BeClosed())
}
<|endoftext|>


<commit_before>package nakadi

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/pkg/errors"
)

type AuthorizationAttribute struct {
	DataType string `json:"data_type"`
	Value    string `json:"value"`
}

type SubscriptionAuthorization struct {
	Admins  []AuthorizationAttribute `json:"admins"`
	Readers []AuthorizationAttribute `json:"readers"`
}

// Subscription represents a subscription as used by the Nakadi high level API.
type Subscription struct {
	ID                string                    `json:"id,omitempty"`
	OwningApplication string                    `json:"owning_application"`
	EventTypes        []string                  `json:"event_types"`
	ConsumerGroup     string                    `json:"consumer_group,omitempty"`
	ReadFrom          string                    `json:"read_from,omitempty"`
	CreatedAt         time.Time                 `json:"created_at,omitempty"`
	Authorization     SubscriptionAuthorization `json:"authorization"`
}

// SubscriptionOptions is a set of optional parameters used to configure the SubscriptionAPI.
type SubscriptionOptions struct {
	// Whether or not methods of the SubscriptionAPI retry when a request fails. If
	// set to true InitialRetryInterval, MaxRetryInterval, and MaxElapsedTime have
	// no effect (default: false).
	Retry bool
	// The initial (minimal) retry interval used for the exponential backoff algorithm
	// when retry is enables.
	InitialRetryInterval time.Duration
	// MaxRetryInterval the maximum retry interval. Once the exponential backoff reaches
	// this value the retry intervals remain constant.
	MaxRetryInterval time.Duration
	// MaxElapsedTime is the maximum time spent on retries when when performing a request.
	// Once this value was reached the exponential backoff is halted and the request will
	// fail with an error.
	MaxElapsedTime time.Duration
}

func (o *SubscriptionOptions) withDefaults() *SubscriptionOptions {
	var copyOptions SubscriptionOptions
	if o != nil {
		copyOptions = *o
	}
	if copyOptions.InitialRetryInterval == 0 {
		copyOptions.InitialRetryInterval = defaultInitialRetryInterval
	}
	if copyOptions.MaxRetryInterval == 0 {
		copyOptions.MaxRetryInterval = defaultMaxRetryInterval
	}
	if copyOptions.MaxElapsedTime == 0 {
		copyOptions.MaxElapsedTime = defaultMaxElapsedTime
	}
	return &copyOptions
}

// NewSubscriptionAPI crates a new instance of the SubscriptionAPI. As for all sub APIs of the `go-nakadi` package
// NewSubscriptionAPI receives a configured Nakadi client. The last parameter is a struct containing only optional \
// parameters. The options may be nil.
func NewSubscriptionAPI(client *Client, options *SubscriptionOptions) *SubscriptionAPI {
	options = options.withDefaults()

	return &SubscriptionAPI{
		client: client,
		backOffConf: backOffConfiguration{
			Retry:                options.Retry,
			InitialRetryInterval: options.InitialRetryInterval,
			MaxRetryInterval:     options.MaxRetryInterval,
			MaxElapsedTime:       options.MaxElapsedTime}}
}

// SubscriptionAPI is a sub API that is used to manage subscriptions.
type SubscriptionAPI struct {
	client      *Client
	backOffConf backOffConfiguration
}

// List returns all available subscriptions.
func (s *SubscriptionAPI) List() ([]*Subscription, error) {
	subscriptions := struct {
		Items []*Subscription `json:"items"`
	}{}
	err := s.client.httpGET(s.backOffConf.create(), s.subBaseURL(), &subscriptions, "unable to request subscriptions")
	if err != nil {
		return nil, err
	}
	return subscriptions.Items, nil
}

// Get obtains a single subscription identified by its ID.
func (s *SubscriptionAPI) Get(id string) (*Subscription, error) {
	subscription := &Subscription{}
	err := s.client.httpGET(s.backOffConf.create(), s.subURL(id), subscription, "unable to request subscription")
	if err != nil {
		return nil, err
	}
	return subscription, err
}

// Create initializes a new subscription. If the subscription already exists the pre existing subscription
// is returned.
func (s *SubscriptionAPI) Create(subscription *Subscription) (*Subscription, error) {
	const errMsg = "unable to create subscription"

	response, err := s.client.httpPOST(s.backOffConf.create(), s.subBaseURL(), subscription, errMsg)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusCreated {
		buffer, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return nil, errors.Wrapf(err, "%s: unable to read response body", errMsg)
		}
		return nil, decodeResponseToError(buffer, errMsg)
	}

	subscription = &Subscription{}
	err = json.NewDecoder(response.Body).Decode(subscription)
	if err != nil {
		return nil, errors.Wrapf(err, "%s: unable to decode response body", errMsg)
	}

	return subscription, nil
}

// Delete removes an existing subscription.
func (s *SubscriptionAPI) Delete(id string) error {
	return s.client.httpDELETE(s.backOffConf.create(), s.subURL(id), "unable to delete subscription")
}

// SubscriptionStats represents detailed statistics for the subscription
type SubscriptionStats struct {
	EventType  string            `json:"event_type"`
	Partitions []*PartitionStats `json:"partitions"`
}

// PartitionStats represents statistic information for the particular partition
type PartitionStats struct {
	Partition        string `json:"partition"`
	State            string `json:"state"`
	UnconsumedEvents int    `json:"unconsumed_events"`
	StreamID         string `json:"stream_id"`
}

type statsResponse struct {
	Items []*SubscriptionStats `json:"items"`
}

// GetStats returns statistic information for subscription
func (s *SubscriptionAPI) GetStats(id string) ([]*SubscriptionStats, error) {
	stats := &statsResponse{}
	if err := s.client.httpGET(s.backOffConf.create(), s.subURL(id)+"/stats", stats, "unable to get stats for subscription"); err != nil {
		return nil, err
	}
	return stats.Items, nil
}

func (s *SubscriptionAPI) subURL(id string) string {
	return fmt.Sprintf("%s/subscriptions/%s", s.client.nakadiURL, id)
}

func (s *SubscriptionAPI) subBaseURL() string {
	return fmt.Sprintf("%s/subscriptions", s.client.nakadiURL)
}
<commit_msg>fixing go lint issues<commit_after>package nakadi

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/pkg/errors"
)

// AuthorizationAttribute represents a record for SubscriptionAuthorization which is used by the Nakadi high level API.
type AuthorizationAttribute struct {
	DataType string `json:"data_type"`
	Value    string `json:"value"`
}

// SubscriptionAuthorization represents a subscription auth as used by the Nakadi high level API.
type SubscriptionAuthorization struct {
	Admins  []AuthorizationAttribute `json:"admins"`
	Readers []AuthorizationAttribute `json:"readers"`
}

// Subscription represents a subscription as used by the Nakadi high level API.
type Subscription struct {
	ID                string                    `json:"id,omitempty"`
	OwningApplication string                    `json:"owning_application"`
	EventTypes        []string                  `json:"event_types"`
	ConsumerGroup     string                    `json:"consumer_group,omitempty"`
	ReadFrom          string                    `json:"read_from,omitempty"`
	CreatedAt         time.Time                 `json:"created_at,omitempty"`
	Authorization     SubscriptionAuthorization `json:"authorization"`
}

// SubscriptionOptions is a set of optional parameters used to configure the SubscriptionAPI.
type SubscriptionOptions struct {
	// Whether or not methods of the SubscriptionAPI retry when a request fails. If
	// set to true InitialRetryInterval, MaxRetryInterval, and MaxElapsedTime have
	// no effect (default: false).
	Retry bool
	// The initial (minimal) retry interval used for the exponential backoff algorithm
	// when retry is enables.
	InitialRetryInterval time.Duration
	// MaxRetryInterval the maximum retry interval. Once the exponential backoff reaches
	// this value the retry intervals remain constant.
	MaxRetryInterval time.Duration
	// MaxElapsedTime is the maximum time spent on retries when when performing a request.
	// Once this value was reached the exponential backoff is halted and the request will
	// fail with an error.
	MaxElapsedTime time.Duration
}

func (o *SubscriptionOptions) withDefaults() *SubscriptionOptions {
	var copyOptions SubscriptionOptions
	if o != nil {
		copyOptions = *o
	}
	if copyOptions.InitialRetryInterval == 0 {
		copyOptions.InitialRetryInterval = defaultInitialRetryInterval
	}
	if copyOptions.MaxRetryInterval == 0 {
		copyOptions.MaxRetryInterval = defaultMaxRetryInterval
	}
	if copyOptions.MaxElapsedTime == 0 {
		copyOptions.MaxElapsedTime = defaultMaxElapsedTime
	}
	return &copyOptions
}

// NewSubscriptionAPI crates a new instance of the SubscriptionAPI. As for all sub APIs of the `go-nakadi` package
// NewSubscriptionAPI receives a configured Nakadi client. The last parameter is a struct containing only optional \
// parameters. The options may be nil.
func NewSubscriptionAPI(client *Client, options *SubscriptionOptions) *SubscriptionAPI {
	options = options.withDefaults()

	return &SubscriptionAPI{
		client: client,
		backOffConf: backOffConfiguration{
			Retry:                options.Retry,
			InitialRetryInterval: options.InitialRetryInterval,
			MaxRetryInterval:     options.MaxRetryInterval,
			MaxElapsedTime:       options.MaxElapsedTime}}
}

// SubscriptionAPI is a sub API that is used to manage subscriptions.
type SubscriptionAPI struct {
	client      *Client
	backOffConf backOffConfiguration
}

// List returns all available subscriptions.
func (s *SubscriptionAPI) List() ([]*Subscription, error) {
	subscriptions := struct {
		Items []*Subscription `json:"items"`
	}{}
	err := s.client.httpGET(s.backOffConf.create(), s.subBaseURL(), &subscriptions, "unable to request subscriptions")
	if err != nil {
		return nil, err
	}
	return subscriptions.Items, nil
}

// Get obtains a single subscription identified by its ID.
func (s *SubscriptionAPI) Get(id string) (*Subscription, error) {
	subscription := &Subscription{}
	err := s.client.httpGET(s.backOffConf.create(), s.subURL(id), subscription, "unable to request subscription")
	if err != nil {
		return nil, err
	}
	return subscription, err
}

// Create initializes a new subscription. If the subscription already exists the pre existing subscription
// is returned.
func (s *SubscriptionAPI) Create(subscription *Subscription) (*Subscription, error) {
	const errMsg = "unable to create subscription"

	response, err := s.client.httpPOST(s.backOffConf.create(), s.subBaseURL(), subscription, errMsg)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusCreated {
		buffer, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return nil, errors.Wrapf(err, "%s: unable to read response body", errMsg)
		}
		return nil, decodeResponseToError(buffer, errMsg)
	}

	subscription = &Subscription{}
	err = json.NewDecoder(response.Body).Decode(subscription)
	if err != nil {
		return nil, errors.Wrapf(err, "%s: unable to decode response body", errMsg)
	}

	return subscription, nil
}

// Delete removes an existing subscription.
func (s *SubscriptionAPI) Delete(id string) error {
	return s.client.httpDELETE(s.backOffConf.create(), s.subURL(id), "unable to delete subscription")
}

// SubscriptionStats represents detailed statistics for the subscription
type SubscriptionStats struct {
	EventType  string            `json:"event_type"`
	Partitions []*PartitionStats `json:"partitions"`
}

// PartitionStats represents statistic information for the particular partition
type PartitionStats struct {
	Partition        string `json:"partition"`
	State            string `json:"state"`
	UnconsumedEvents int    `json:"unconsumed_events"`
	StreamID         string `json:"stream_id"`
}

type statsResponse struct {
	Items []*SubscriptionStats `json:"items"`
}

// GetStats returns statistic information for subscription
func (s *SubscriptionAPI) GetStats(id string) ([]*SubscriptionStats, error) {
	stats := &statsResponse{}
	if err := s.client.httpGET(s.backOffConf.create(), s.subURL(id)+"/stats", stats, "unable to get stats for subscription"); err != nil {
		return nil, err
	}
	return stats.Items, nil
}

func (s *SubscriptionAPI) subURL(id string) string {
	return fmt.Sprintf("%s/subscriptions/%s", s.client.nakadiURL, id)
}

func (s *SubscriptionAPI) subBaseURL() string {
	return fmt.Sprintf("%s/subscriptions", s.client.nakadiURL)
}
<|endoftext|>


<commit_before>package downloader

import (
	"sync"
	"time"

	"github.com/cenkalti/rain/internal/downloader/piecedownloader"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/peer"
	"github.com/cenkalti/rain/internal/peermanager"
	"github.com/cenkalti/rain/internal/piece"
	"github.com/cenkalti/rain/internal/torrentdata"
)

const parallelPieceDownloads = 4

type Downloader struct {
	peerManager *peermanager.PeerManager
	data        *torrentdata.Data
	pieces      []Piece
	downloads   map[*piecedownloader.PieceDownloader]struct{}
	log         logger.Logger
	m           sync.Mutex
}

type Piece struct {
	*piece.Piece
	index          int
	havingPeers    map[*peer.Peer]struct{}
	requestedPeers map[*peer.Peer]*piecedownloader.PieceDownloader
}

func New(pm *peermanager.PeerManager, d *torrentdata.Data, l logger.Logger) *Downloader {
	pieces := make([]Piece, len(d.Pieces))
	for i := range d.Pieces {
		pieces[i] = Piece{
			Piece:          &d.Pieces[i],
			index:          i,
			havingPeers:    make(map[*peer.Peer]struct{}),
			requestedPeers: make(map[*peer.Peer]*piecedownloader.PieceDownloader),
		}
	}
	return &Downloader{
		peerManager: pm,
		data:        d,
		pieces:      pieces,
		downloads:   make(map[*piecedownloader.PieceDownloader]struct{}),
		log:         l,
	}
}

func (d *Downloader) Run(stopC chan struct{}) {
	for {
		// TODO extract cases to methods
		select {
		case <-time.After(time.Second):
			for len(d.downloads) < parallelPieceDownloads {
				pi, pe, ok := d.nextDownload()
				if !ok {
					break
				}
				pd := piecedownloader.New(pi, pe)
				d.log.Debugln("downloading piece", pi.Index, "from", pe.String())
				d.m.Lock()
				d.downloads[pd] = struct{}{}
				d.pieces[pi.Index].requestedPeers[pe] = pd
				d.m.Unlock()
				go d.downloadPiece(pd, stopC)
			}
		case pm := <-d.peerManager.PeerMessages():
			switch msg := pm.Message.(type) {
			case peer.Have:
				d.pieces[msg.Index].havingPeers[pm.Peer] = struct{}{}
			case peer.Choke:
				// for _, p := range pieces {
				// 	delete(p.havingPeers, pm.Peer)
				// }
			case peer.Piece:
				// TODO handle piece message
				pd := d.pieces[msg.Piece.Index].requestedPeers[pm.Peer]
				pd.PieceC <- msg

				// 				p.torrent.m.Lock()
				// 				p.torrent.bitfield.Set(piece.Index)
				// 				percentDone := p.torrent.bitfield.Count() * 100 / p.torrent.bitfield.Len()
				// 				p.torrent.m.Unlock()
				// 				p.cond.Broadcast()
				// 				p.torrent.log.Infof("Completed: %d%%", percentDone)
			}
		case <-stopC:
			return
		}
	}
}

func (d *Downloader) nextDownload() (pi *piece.Piece, pe *peer.Peer, ok bool) {
	// TODO selecting pieces in sequential order, change to rarest first
	for _, p := range d.pieces {
		if p.OK {
			continue
		}
		if len(p.havingPeers) == 0 {
			continue
		}
		// TODO selecting first peer having the piece, change to more smart decision
		for pe = range p.havingPeers {
			continue
		}
		if pe == nil {
			continue
		}
		pi = p.Piece
		ok = true
		break
	}
	return
}

func (d *Downloader) downloadPiece(pd *piecedownloader.PieceDownloader, stopC chan struct{}) {
	err := pd.Run(stopC)
	if err != nil {
		d.log.Error(err)
		return
	}
	d.data.Bitfield().Set(pd.Piece.Index)
	d.m.Lock()
	delete(d.downloads, pd)
	delete(d.pieces[pd.Piece.Index].requestedPeers, pd.Peer)
	d.m.Unlock()
}
<commit_msg>startDownload<commit_after>package downloader

import (
	"sync"
	"time"

	"github.com/cenkalti/rain/internal/downloader/piecedownloader"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/internal/peer"
	"github.com/cenkalti/rain/internal/peermanager"
	"github.com/cenkalti/rain/internal/piece"
	"github.com/cenkalti/rain/internal/torrentdata"
)

const parallelPieceDownloads = 4

type Downloader struct {
	peerManager *peermanager.PeerManager
	data        *torrentdata.Data
	pieces      []Piece
	downloads   map[*piecedownloader.PieceDownloader]struct{}
	log         logger.Logger
	m           sync.Mutex
}

type Piece struct {
	*piece.Piece
	index          int
	havingPeers    map[*peer.Peer]struct{}
	requestedPeers map[*peer.Peer]*piecedownloader.PieceDownloader
}

func New(pm *peermanager.PeerManager, d *torrentdata.Data, l logger.Logger) *Downloader {
	pieces := make([]Piece, len(d.Pieces))
	for i := range d.Pieces {
		pieces[i] = Piece{
			Piece:          &d.Pieces[i],
			index:          i,
			havingPeers:    make(map[*peer.Peer]struct{}),
			requestedPeers: make(map[*peer.Peer]*piecedownloader.PieceDownloader),
		}
	}
	return &Downloader{
		peerManager: pm,
		data:        d,
		pieces:      pieces,
		downloads:   make(map[*piecedownloader.PieceDownloader]struct{}),
		log:         l,
	}
}

func (d *Downloader) Run(stopC chan struct{}) {
	for {
		// TODO extract cases to methods
		select {
		case <-time.After(time.Second):
			// TODO check status of existing downloads
			d.m.Lock()
			for len(d.downloads) < parallelPieceDownloads {
				pi, pe, ok := d.nextDownload()
				if !ok {
					break
				}
				d.startDownload(pi, pe, stopC)
			}
			d.m.Unlock()
		case pm := <-d.peerManager.PeerMessages():
			switch msg := pm.Message.(type) {
			case peer.Have:
				d.pieces[msg.Index].havingPeers[pm.Peer] = struct{}{}
			case peer.Choke:
				// for _, p := range pieces {
				// 	delete(p.havingPeers, pm.Peer)
				// }
			case peer.Piece:
				pd := d.pieces[msg.Piece.Index].requestedPeers[pm.Peer]
				pd.PieceC <- msg
			}
		case <-stopC:
			return
		}
	}
}

func (d *Downloader) nextDownload() (pi *piece.Piece, pe *peer.Peer, ok bool) {
	// TODO selecting pieces in sequential order, change to rarest first
	for _, p := range d.pieces {
		if p.OK {
			continue
		}
		if len(p.havingPeers) == 0 {
			continue
		}
		// TODO selecting first peer having the piece, change to more smart decision
		for pe2 := range p.havingPeers {
			if _, ok2 := p.requestedPeers[pe2]; ok2 {
				continue
			}
			pe = pe2
			break
		}
		if pe == nil {
			continue
		}
		pi = p.Piece
		ok = true
		break
	}
	return
}

func (d *Downloader) startDownload(pi *piece.Piece, pe *peer.Peer, stopC chan struct{}) {
	d.log.Debugln("downloading piece", pi.Index, "from", pe.String())
	pd := piecedownloader.New(pi, pe)
	d.downloads[pd] = struct{}{}
	d.pieces[pi.Index].requestedPeers[pe] = pd
	go d.downloadPiece(pd, stopC)
}

func (d *Downloader) downloadPiece(pd *piecedownloader.PieceDownloader, stopC chan struct{}) {
	err := pd.Run(stopC)
	if err != nil {
		d.log.Error(err)
		return
	}
	d.data.Bitfield().Set(pd.Piece.Index)
	d.m.Lock()
	delete(d.downloads, pd)
	delete(d.pieces[pd.Piece.Index].requestedPeers, pd.Peer)
	d.m.Unlock()
}
<|endoftext|>


<commit_before>package address

type (
	Addressable interface {
		Addresses() Addresses
	}
	Addresses []string
)
<commit_msg>chore(net/addresses): remove unused<commit_after><|endoftext|>


<commit_before>// Copyright 2015, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// +build cgo,!no_cgo_bz2

package bench

/*
#cgo LDFLAGS: -lbz2
#include "bzlib.h"

void bzStreamInit(void* zs) {
	((bz_stream*)zs)->bzalloc = NULL;
	((bz_stream*)zs)->bzfree = NULL;
	((bz_stream*)zs)->opaque = NULL;
	((bz_stream*)zs)->next_in = NULL;
	((bz_stream*)zs)->avail_in = 0;
	((bz_stream*)zs)->next_out = NULL;
	((bz_stream*)zs)->avail_out = 0;
}

int bzCompressInit(void* zs, int lvl) {
	bzStreamInit(zs);
	BZ2_bzCompressInit((bz_stream*)zs, lvl, 0, 0);
}
int bzCompress(void* zs, int mode) { return BZ2_bzCompress((bz_stream*)zs, mode); }
int bzCompressEnd(void* zs)        { return BZ2_bzCompressEnd((bz_stream*)zs); }

int bzDecompressInit(void* zs) {
	bzStreamInit(zs);
	BZ2_bzDecompressInit((bz_stream*)zs, 0, 0);
}
int bzDecompress(void* zs)    { return BZ2_bzDecompress((bz_stream*)zs); }
int bzDecompressEnd(void* zs) { return BZ2_bzDecompressEnd((bz_stream*)zs); }

void bzSetInput(void* zs, void* ptr, unsigned int len) {
	((bz_stream*)zs)->next_in = ptr;
	((bz_stream*)zs)->avail_in = len;
}
int bzAvailInput(void* zs) { return ((bz_stream*)zs)->avail_in; }

void bzSetOutput(void* zs, void* ptr, unsigned int len) {
	((bz_stream*)zs)->next_out = ptr;
	((bz_stream*)zs)->avail_out = len;
}
int bzAvailOutput(void* zs) { return ((bz_stream*)zs)->avail_out; }
*/
import "C"

import (
	"fmt"
	"io"
	"unsafe"
)

type bz2Err struct{ code int }

func newBZ2Err(code int) error {
	if code == C.BZ_OK {
		return nil
	}
	return &bz2Err{code}
}
func (ze *bz2Err) Error() string { return fmt.Sprintf("bzip2 error %d", ze.code) }

type bz2Stream [unsafe.Sizeof(C.bz_stream{})]byte

func (z *bz2Stream) C() unsafe.Pointer { return unsafe.Pointer(z) }

func (z *bz2Stream) setInput(buf []byte) {
	if len(buf) == 0 {
		C.bzSetInput(z.C(), nil, 0)
	} else {
		C.bzSetInput(z.C(), unsafe.Pointer(&buf[0]), C.uint(len(buf)))
	}
}
func (z *bz2Stream) availInput() int { return int(C.bzAvailInput(z.C())) }

func (z *bz2Stream) setOutput(buf []byte) {
	if len(buf) == 0 {
		C.bzSetOutput(z.C(), nil, 0)
	} else {
		C.bzSetOutput(z.C(), unsafe.Pointer(&buf[0]), C.uint(len(buf)))
	}
}
func (z *bz2Stream) availOutput() int { return int(C.bzAvailOutput(z.C())) }

type bz2Writer struct {
	wr   io.Writer
	strm *bz2Stream
	buf  [4096]byte
	mode int
	err  error
}

func newBZ2Writer(w io.Writer, lvl int) io.WriteCloser {
	zw := &bz2Writer{wr: w, strm: new(bz2Stream), mode: C.BZ_RUN}
	if ret := int(C.bzCompressInit(zw.strm.C(), C.int(lvl))); ret != C.BZ_OK {
		panic(newBZ2Err(ret))
	}
	return zw
}

func (zw *bz2Writer) Write(buf []byte) (int, error) {
	zw.strm.setInput(buf)
	for zw.err == nil {
		zw.strm.setOutput(zw.buf[:])
		if zw.strm.availOutput() > 0 {
			ret := int(C.bzCompress(zw.strm.C(), C.int(zw.mode)))
			switch ret {
			case C.BZ_RUN_OK, C.BZ_FLUSH_OK, C.BZ_FINISH_OK, C.BZ_STREAM_END:
				// Do nothing.
			default:
				zw.err = newBZ2Err(ret)
			}
		}
		cnt := len(zw.buf) - zw.strm.availOutput()
		if _, err := zw.wr.Write(zw.buf[:cnt]); err != nil {
			zw.err = err
		}
		if zw.strm.availOutput() != 0 {
			break
		}
	}
	return len(buf) - zw.strm.availInput(), zw.err
}

func (zw *bz2Writer) Close() error {
	if zw.strm == nil {
		return zw.err
	}
	zw.mode = C.BZ_FINISH
	if _, err := zw.Write(nil); zw.err == nil {
		zw.err = err
	}
	if err := newBZ2Err(int(C.bzCompressEnd(zw.strm.C()))); zw.err == nil {
		zw.err = err
	}
	zw.strm = nil
	if zw.err == nil {
		zw.err = io.ErrClosedPipe
		return nil
	}
	return zw.err
}

type bz2Reader struct {
	rd   io.Reader
	strm *bz2Stream
	buf  [4096]byte
	err  error
}

func newBZ2Reader(r io.Reader) io.ReadCloser {
	zr := &bz2Reader{rd: r, strm: new(bz2Stream)}
	if ret := int(C.bzDecompressInit(zr.strm.C())); ret != C.BZ_OK {
		panic(newBZ2Err(ret))
	}
	return zr
}

func (zr *bz2Reader) Read(buf []byte) (int, error) {
	zr.strm.setOutput(buf)
	for zr.strm.availOutput() > 0 && zr.err == nil {
		if zr.strm.availInput() == 0 {
			cnt, err := zr.rd.Read(zr.buf[:])
			if cnt > 0 && err == io.EOF {
				err = nil
			}
			if err != nil {
				if err == io.EOF {
					err = io.ErrUnexpectedEOF
				}
				zr.err = err
			}
			zr.strm.setInput(zr.buf[:cnt])
		}
		if zr.strm.availInput() > 0 {
			var err error
			ret := int(C.bzDecompress(zr.strm.C()))
			switch ret {
			case C.BZ_RUN_OK:
				// Do nothing.
			case C.BZ_STREAM_END:
				err = io.EOF
			default:
				err = newBZ2Err(ret)
			}
			if err != nil {
				zr.err = err
			}
		}
	}
	return len(buf) - zr.strm.availOutput(), zr.err
}

func (zr *bz2Reader) Close() error {
	if zr.strm == nil {
		return zr.err
	}
	if err := newBZ2Err(int(C.bzDecompressEnd(zr.strm.C()))); zr.err == nil {
		zr.err = err
	}
	zr.strm = nil
	if zr.err == io.EOF {
		return nil
	}
	return zr.err
}

func init() {
	RegisterEncoder(FormatBZ2, "cgo", newBZ2Writer)
	RegisterDecoder(FormatBZ2, "cgo", newBZ2Reader)
}
<commit_msg>internal/tool/bench: fix cgo warning<commit_after>// Copyright 2015, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// +build cgo,!no_cgo_bz2

package bench

/*
#cgo LDFLAGS: -lbz2
#include "bzlib.h"

void bzStreamInit(void* zs) {
	((bz_stream*)zs)->bzalloc = NULL;
	((bz_stream*)zs)->bzfree = NULL;
	((bz_stream*)zs)->opaque = NULL;
	((bz_stream*)zs)->next_in = NULL;
	((bz_stream*)zs)->avail_in = 0;
	((bz_stream*)zs)->next_out = NULL;
	((bz_stream*)zs)->avail_out = 0;
}

int bzCompressInit(void* zs, int lvl) {
	bzStreamInit(zs);
	return BZ2_bzCompressInit((bz_stream*)zs, lvl, 0, 0);
}
int bzCompress(void* zs, int mode) { return BZ2_bzCompress((bz_stream*)zs, mode); }
int bzCompressEnd(void* zs)        { return BZ2_bzCompressEnd((bz_stream*)zs); }

int bzDecompressInit(void* zs) {
	bzStreamInit(zs);
	return BZ2_bzDecompressInit((bz_stream*)zs, 0, 0);
}
int bzDecompress(void* zs)    { return BZ2_bzDecompress((bz_stream*)zs); }
int bzDecompressEnd(void* zs) { return BZ2_bzDecompressEnd((bz_stream*)zs); }

void bzSetInput(void* zs, void* ptr, unsigned int len) {
	((bz_stream*)zs)->next_in = ptr;
	((bz_stream*)zs)->avail_in = len;
}
int bzAvailInput(void* zs) { return ((bz_stream*)zs)->avail_in; }

void bzSetOutput(void* zs, void* ptr, unsigned int len) {
	((bz_stream*)zs)->next_out = ptr;
	((bz_stream*)zs)->avail_out = len;
}
int bzAvailOutput(void* zs) { return ((bz_stream*)zs)->avail_out; }
*/
import "C"

import (
	"fmt"
	"io"
	"unsafe"
)

type bz2Err struct{ code int }

func newBZ2Err(code int) error {
	if code == C.BZ_OK {
		return nil
	}
	return &bz2Err{code}
}
func (ze *bz2Err) Error() string { return fmt.Sprintf("bzip2 error %d", ze.code) }

type bz2Stream [unsafe.Sizeof(C.bz_stream{})]byte

func (z *bz2Stream) C() unsafe.Pointer { return unsafe.Pointer(z) }

func (z *bz2Stream) setInput(buf []byte) {
	if len(buf) == 0 {
		C.bzSetInput(z.C(), nil, 0)
	} else {
		C.bzSetInput(z.C(), unsafe.Pointer(&buf[0]), C.uint(len(buf)))
	}
}
func (z *bz2Stream) availInput() int { return int(C.bzAvailInput(z.C())) }

func (z *bz2Stream) setOutput(buf []byte) {
	if len(buf) == 0 {
		C.bzSetOutput(z.C(), nil, 0)
	} else {
		C.bzSetOutput(z.C(), unsafe.Pointer(&buf[0]), C.uint(len(buf)))
	}
}
func (z *bz2Stream) availOutput() int { return int(C.bzAvailOutput(z.C())) }

type bz2Writer struct {
	wr   io.Writer
	strm *bz2Stream
	buf  [4096]byte
	mode int
	err  error
}

func newBZ2Writer(w io.Writer, lvl int) io.WriteCloser {
	zw := &bz2Writer{wr: w, strm: new(bz2Stream), mode: C.BZ_RUN}
	if ret := int(C.bzCompressInit(zw.strm.C(), C.int(lvl))); ret != C.BZ_OK {
		panic(newBZ2Err(ret))
	}
	return zw
}

func (zw *bz2Writer) Write(buf []byte) (int, error) {
	zw.strm.setInput(buf)
	for zw.err == nil {
		zw.strm.setOutput(zw.buf[:])
		if zw.strm.availOutput() > 0 {
			ret := int(C.bzCompress(zw.strm.C(), C.int(zw.mode)))
			switch ret {
			case C.BZ_RUN_OK, C.BZ_FLUSH_OK, C.BZ_FINISH_OK, C.BZ_STREAM_END:
				// Do nothing.
			default:
				zw.err = newBZ2Err(ret)
			}
		}
		cnt := len(zw.buf) - zw.strm.availOutput()
		if _, err := zw.wr.Write(zw.buf[:cnt]); err != nil {
			zw.err = err
		}
		if zw.strm.availOutput() != 0 {
			break
		}
	}
	return len(buf) - zw.strm.availInput(), zw.err
}

func (zw *bz2Writer) Close() error {
	if zw.strm == nil {
		return zw.err
	}
	zw.mode = C.BZ_FINISH
	if _, err := zw.Write(nil); zw.err == nil {
		zw.err = err
	}
	if err := newBZ2Err(int(C.bzCompressEnd(zw.strm.C()))); zw.err == nil {
		zw.err = err
	}
	zw.strm = nil
	if zw.err == nil {
		zw.err = io.ErrClosedPipe
		return nil
	}
	return zw.err
}

type bz2Reader struct {
	rd   io.Reader
	strm *bz2Stream
	buf  [4096]byte
	err  error
}

func newBZ2Reader(r io.Reader) io.ReadCloser {
	zr := &bz2Reader{rd: r, strm: new(bz2Stream)}
	if ret := int(C.bzDecompressInit(zr.strm.C())); ret != C.BZ_OK {
		panic(newBZ2Err(ret))
	}
	return zr
}

func (zr *bz2Reader) Read(buf []byte) (int, error) {
	zr.strm.setOutput(buf)
	for zr.strm.availOutput() > 0 && zr.err == nil {
		if zr.strm.availInput() == 0 {
			cnt, err := zr.rd.Read(zr.buf[:])
			if cnt > 0 && err == io.EOF {
				err = nil
			}
			if err != nil {
				if err == io.EOF {
					err = io.ErrUnexpectedEOF
				}
				zr.err = err
			}
			zr.strm.setInput(zr.buf[:cnt])
		}
		if zr.strm.availInput() > 0 {
			var err error
			ret := int(C.bzDecompress(zr.strm.C()))
			switch ret {
			case C.BZ_RUN_OK:
				// Do nothing.
			case C.BZ_STREAM_END:
				err = io.EOF
			default:
				err = newBZ2Err(ret)
			}
			if err != nil {
				zr.err = err
			}
		}
	}
	return len(buf) - zr.strm.availOutput(), zr.err
}

func (zr *bz2Reader) Close() error {
	if zr.strm == nil {
		return zr.err
	}
	if err := newBZ2Err(int(C.bzDecompressEnd(zr.strm.C()))); zr.err == nil {
		zr.err = err
	}
	zr.strm = nil
	if zr.err == io.EOF {
		return nil
	}
	return zr.err
}

func init() {
	RegisterEncoder(FormatBZ2, "cgo", newBZ2Writer)
	RegisterDecoder(FormatBZ2, "cgo", newBZ2Reader)
}
<|endoftext|>


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

// +build !386

// strace is a simple multi-process tracer.
// It starts the comand and lets the strace.Run() do all the work.
//
// Synopsis:
//     strace <command> [args...]
//
// Description:
//	trace a single process given a command name.
package main

import (
	// Don't use spf13 flags. It will not allow commands like
	// strace ls -l
	// it tries to use the -l for strace instead of leaving it alone.
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"

	"github.com/u-root/u-root/pkg/strace"
)

var (
	cmdUsage = "Usage: strace <command> [args...]"
	debug    = flag.Bool("d", false, "enable debug printing")
)

func usage() {
	log.Fatalf(cmdUsage)
}

func main() {

	flag.Parse()

	if *debug {
		strace.Debug = log.Printf
	}
	a := flag.Args()
	if len(a) < 1 {
		usage()
	}

	c := exec.Command(a[0], a[1:]...)
	c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr

	t, err := strace.New()
	if err != nil {
		log.Fatal(err)
	}

	go t.RunTracerFromCmd(c)
	for r := range t.Records {
		if r.Err != nil {
			fmt.Printf("Record shows error %v\n", r.Err)
			continue
		}
		fmt.Printf("%s\n", r.Out)
	}
}
<commit_msg>cmds/core/strace: disable strace for mipsle<commit_after>// Copyright 2012-2018 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !386,!mipsle

// strace is a simple multi-process tracer.
// It starts the comand and lets the strace.Run() do all the work.
//
// Synopsis:
//     strace <command> [args...]
//
// Description:
//	trace a single process given a command name.
package main

import (
	// Don't use spf13 flags. It will not allow commands like
	// strace ls -l
	// it tries to use the -l for strace instead of leaving it alone.
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"

	"github.com/u-root/u-root/pkg/strace"
)

var (
	cmdUsage = "Usage: strace <command> [args...]"
	debug    = flag.Bool("d", false, "enable debug printing")
)

func usage() {
	log.Fatalf(cmdUsage)
}

func main() {

	flag.Parse()

	if *debug {
		strace.Debug = log.Printf
	}
	a := flag.Args()
	if len(a) < 1 {
		usage()
	}

	c := exec.Command(a[0], a[1:]...)
	c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr

	t, err := strace.New()
	if err != nil {
		log.Fatal(err)
	}

	go t.RunTracerFromCmd(c)
	for r := range t.Records {
		if r.Err != nil {
			fmt.Printf("Record shows error %v\n", r.Err)
			continue
		}
		fmt.Printf("%s\n", r.Out)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package stateconfigwatcher_test

import (
	"time"

	"github.com/juju/names"
	"github.com/juju/testing"
	"github.com/juju/utils/voyeur"
	gc "gopkg.in/check.v1"

	coreagent "github.com/juju/juju/agent"
	"github.com/juju/juju/apiserver/params"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/worker"
	"github.com/juju/juju/worker/dependency"
	dt "github.com/juju/juju/worker/dependency/testing"
	"github.com/juju/juju/worker/stateconfigwatcher"
	jc "github.com/juju/testing/checkers"
)

type ManifoldSuite struct {
	testing.IsolationSuite
	agent              *mockAgent
	goodGetResource    dependency.GetResourceFunc
	agentConfigChanged *voyeur.Value
	manifold           dependency.Manifold
	worker             worker.Worker
}

var _ = gc.Suite(&ManifoldSuite{})

func (s *ManifoldSuite) SetUpTest(c *gc.C) {
	s.IsolationSuite.SetUpTest(c)

	s.agent = new(mockAgent)
	s.agent.conf.stateServingInfoSet = true
	s.agent.conf.tag = names.NewMachineTag("99")

	s.goodGetResource = dt.StubGetResource(dt.StubResources{
		"agent": dt.StubResource{Output: s.agent},
	})

	s.agentConfigChanged = voyeur.NewValue(0)
	s.manifold = stateconfigwatcher.Manifold(stateconfigwatcher.ManifoldConfig{
		AgentName:          "agent",
		AgentConfigChanged: s.agentConfigChanged,
	})
}

func (s *ManifoldSuite) TestInputs(c *gc.C) {
	c.Assert(s.manifold.Inputs, jc.SameContents, []string{"agent"})
}

func (s *ManifoldSuite) TestNoAgent(c *gc.C) {
	getResource := dt.StubGetResource(dt.StubResources{
		"agent": dt.StubResource{Error: dependency.ErrMissing},
	})
	_, err := s.manifold.Start(getResource)
	c.Assert(err, gc.Equals, dependency.ErrMissing)
}

func (s *ManifoldSuite) TestNilAgentConfigChanged(c *gc.C) {
	manifold := stateconfigwatcher.Manifold(stateconfigwatcher.ManifoldConfig{
		AgentName: "agent",
	})
	_, err := manifold.Start(s.goodGetResource)
	c.Assert(err, gc.ErrorMatches, "nil AgentConfigChanged .+")
}

func (s *ManifoldSuite) TestNotMachineAgent(c *gc.C) {
	s.agent.conf.tag = names.NewUnitTag("foo/0")
	_, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, gc.ErrorMatches, "manifold can only be used with a machine agent")
}

func (s *ManifoldSuite) TestStart(c *gc.C) {
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	checkStop(c, w)
}

func (s *ManifoldSuite) TestOutputBadWorker(c *gc.C) {
	var out bool
	err := s.manifold.Output(dummyWorker{}, &out)
	c.Check(err, gc.ErrorMatches, `in should be a \*stateconfigwatcher.stateConfigWatcher; .+`)
}

func (s *ManifoldSuite) TestOutputWrongType(c *gc.C) {
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	defer checkStop(c, w)

	var out int
	err = s.manifold.Output(w, &out)
	c.Check(err, gc.ErrorMatches, `out should be \*bool; got .+`)
}

func (s *ManifoldSuite) TestOutputSuccessNotStateServer(c *gc.C) {
	s.agent.conf.stateServingInfoSet = false
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	defer checkStop(c, w)

	var out bool
	err = s.manifold.Output(w, &out)
	c.Check(err, jc.ErrorIsNil)
	c.Check(out, jc.IsFalse)
}

func (s *ManifoldSuite) TestOutputSuccessStateServer(c *gc.C) {
	s.agent.conf.stateServingInfoSet = true
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	defer checkStop(c, w)

	var out bool
	err = s.manifold.Output(w, &out)
	c.Check(err, jc.ErrorIsNil)
	c.Check(out, jc.IsTrue)
}

func (s *ManifoldSuite) TestBounceOnChange(c *gc.C) {
	s.agent.conf.stateServingInfoSet = false
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	checkNotExiting(c, w)

	checkOutput := func(expected bool) {
		var out bool
		err = s.manifold.Output(w, &out)
		c.Assert(err, jc.ErrorIsNil)
		c.Check(out, gc.Equals, expected)
	}

	// Not a state server yet, initial output should be False.
	checkOutput(false)

	// Changing the config without changing the state server status -
	// worker should keep running and output should remain false.
	s.agentConfigChanged.Set(0)
	checkNotExiting(c, w)
	checkOutput(false)

	// Now change the config to include state serving info, worker
	// should bounce.
	s.agent.conf.stateServingInfoSet = true
	s.agentConfigChanged.Set(0)
	checkExitsWithError(c, w, dependency.ErrBounce)

	// Restart the worker, the output should now be true.
	w, err = s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	checkNotExiting(c, w)
	checkOutput(true)

	// Changing the config again without changing the state serving
	// info shouldn't cause the agent to exit.
	s.agentConfigChanged.Set(0)
	checkNotExiting(c, w)
	checkOutput(true)

	// Now remove the state serving info, the agent should bounce.
	s.agent.conf.stateServingInfoSet = false
	s.agentConfigChanged.Set(0)
	checkExitsWithError(c, w, dependency.ErrBounce)
}

func (s *ManifoldSuite) TestClosedVoyeur(c *gc.C) {
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	checkNotExiting(c, w)

	s.agentConfigChanged.Close()

	c.Check(waitForExit(c, w), gc.ErrorMatches, "config changed value closed")
}

func checkStop(c *gc.C, w worker.Worker) {
	err := worker.Stop(w)
	c.Check(err, jc.ErrorIsNil)
}

func checkNotExiting(c *gc.C, w worker.Worker) {
	exited := make(chan bool)
	go func() {
		w.Wait()
		close(exited)
	}()

	select {
	case <-exited:
		c.Fatal("worker exited unexpectedly")
	case <-time.After(coretesting.ShortWait):
		// Worker didn't exit (good)
	}
}

func checkExitsWithError(c *gc.C, w worker.Worker, expectedErr error) {
	c.Check(waitForExit(c, w), gc.Equals, expectedErr)
}

func waitForExit(c *gc.C, w worker.Worker) error {
	errCh := make(chan error)
	go func() {
		errCh <- w.Wait()
	}()
	select {
	case err := <-errCh:
		return err
	case <-time.After(coretesting.LongWait):
		c.Fatal("timed out waiting for worker to exit")
	}
	panic("can't get here")
}

type mockAgent struct {
	coreagent.Agent
	conf mockConfig
}

func (ma *mockAgent) CurrentConfig() coreagent.Config {
	return &ma.conf
}

type mockConfig struct {
	coreagent.ConfigSetter
	tag                 names.Tag
	stateServingInfoSet bool
}

func (mc *mockConfig) Tag() names.Tag {
	return mc.tag
}

func (mc *mockConfig) StateServingInfo() (params.StateServingInfo, bool) {
	return params.StateServingInfo{}, mc.stateServingInfoSet
}

type dummyWorker struct {
	worker.Worker
}
<commit_msg>worker/stateconfigwatcher: Fix a trival race in the tests<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package stateconfigwatcher_test

import (
	"sync"
	"time"

	"github.com/juju/names"
	"github.com/juju/testing"
	"github.com/juju/utils/voyeur"
	gc "gopkg.in/check.v1"

	coreagent "github.com/juju/juju/agent"
	"github.com/juju/juju/apiserver/params"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/juju/worker"
	"github.com/juju/juju/worker/dependency"
	dt "github.com/juju/juju/worker/dependency/testing"
	"github.com/juju/juju/worker/stateconfigwatcher"
	jc "github.com/juju/testing/checkers"
)

type ManifoldSuite struct {
	testing.IsolationSuite
	agent              *mockAgent
	goodGetResource    dependency.GetResourceFunc
	agentConfigChanged *voyeur.Value
	manifold           dependency.Manifold
	worker             worker.Worker
}

var _ = gc.Suite(&ManifoldSuite{})

func (s *ManifoldSuite) SetUpTest(c *gc.C) {
	s.IsolationSuite.SetUpTest(c)

	s.agent = new(mockAgent)
	s.agent.conf.setStateServingInfo(true)
	s.agent.conf.tag = names.NewMachineTag("99")

	s.goodGetResource = dt.StubGetResource(dt.StubResources{
		"agent": dt.StubResource{Output: s.agent},
	})

	s.agentConfigChanged = voyeur.NewValue(0)
	s.manifold = stateconfigwatcher.Manifold(stateconfigwatcher.ManifoldConfig{
		AgentName:          "agent",
		AgentConfigChanged: s.agentConfigChanged,
	})
}

func (s *ManifoldSuite) TestInputs(c *gc.C) {
	c.Assert(s.manifold.Inputs, jc.SameContents, []string{"agent"})
}

func (s *ManifoldSuite) TestNoAgent(c *gc.C) {
	getResource := dt.StubGetResource(dt.StubResources{
		"agent": dt.StubResource{Error: dependency.ErrMissing},
	})
	_, err := s.manifold.Start(getResource)
	c.Assert(err, gc.Equals, dependency.ErrMissing)
}

func (s *ManifoldSuite) TestNilAgentConfigChanged(c *gc.C) {
	manifold := stateconfigwatcher.Manifold(stateconfigwatcher.ManifoldConfig{
		AgentName: "agent",
	})
	_, err := manifold.Start(s.goodGetResource)
	c.Assert(err, gc.ErrorMatches, "nil AgentConfigChanged .+")
}

func (s *ManifoldSuite) TestNotMachineAgent(c *gc.C) {
	s.agent.conf.tag = names.NewUnitTag("foo/0")
	_, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, gc.ErrorMatches, "manifold can only be used with a machine agent")
}

func (s *ManifoldSuite) TestStart(c *gc.C) {
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	checkStop(c, w)
}

func (s *ManifoldSuite) TestOutputBadWorker(c *gc.C) {
	var out bool
	err := s.manifold.Output(dummyWorker{}, &out)
	c.Check(err, gc.ErrorMatches, `in should be a \*stateconfigwatcher.stateConfigWatcher; .+`)
}

func (s *ManifoldSuite) TestOutputWrongType(c *gc.C) {
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	defer checkStop(c, w)

	var out int
	err = s.manifold.Output(w, &out)
	c.Check(err, gc.ErrorMatches, `out should be \*bool; got .+`)
}

func (s *ManifoldSuite) TestOutputSuccessNotStateServer(c *gc.C) {
	s.agent.conf.setStateServingInfo(false)
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	defer checkStop(c, w)

	var out bool
	err = s.manifold.Output(w, &out)
	c.Check(err, jc.ErrorIsNil)
	c.Check(out, jc.IsFalse)
}

func (s *ManifoldSuite) TestOutputSuccessStateServer(c *gc.C) {
	s.agent.conf.setStateServingInfo(true)
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	defer checkStop(c, w)

	var out bool
	err = s.manifold.Output(w, &out)
	c.Check(err, jc.ErrorIsNil)
	c.Check(out, jc.IsTrue)
}

func (s *ManifoldSuite) TestBounceOnChange(c *gc.C) {
	s.agent.conf.setStateServingInfo(false)
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	checkNotExiting(c, w)

	checkOutput := func(expected bool) {
		var out bool
		err = s.manifold.Output(w, &out)
		c.Assert(err, jc.ErrorIsNil)
		c.Check(out, gc.Equals, expected)
	}

	// Not a state server yet, initial output should be False.
	checkOutput(false)

	// Changing the config without changing the state server status -
	// worker should keep running and output should remain false.
	s.agentConfigChanged.Set(0)
	checkNotExiting(c, w)
	checkOutput(false)

	// Now change the config to include state serving info, worker
	// should bounce.
	s.agent.conf.setStateServingInfo(true)
	s.agentConfigChanged.Set(0)
	checkExitsWithError(c, w, dependency.ErrBounce)

	// Restart the worker, the output should now be true.
	w, err = s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	checkNotExiting(c, w)
	checkOutput(true)

	// Changing the config again without changing the state serving
	// info shouldn't cause the agent to exit.
	s.agentConfigChanged.Set(0)
	checkNotExiting(c, w)
	checkOutput(true)

	// Now remove the state serving info, the agent should bounce.
	s.agent.conf.setStateServingInfo(false)
	s.agentConfigChanged.Set(0)
	checkExitsWithError(c, w, dependency.ErrBounce)
}

func (s *ManifoldSuite) TestClosedVoyeur(c *gc.C) {
	w, err := s.manifold.Start(s.goodGetResource)
	c.Assert(err, jc.ErrorIsNil)
	checkNotExiting(c, w)

	s.agentConfigChanged.Close()

	c.Check(waitForExit(c, w), gc.ErrorMatches, "config changed value closed")
}

func checkStop(c *gc.C, w worker.Worker) {
	err := worker.Stop(w)
	c.Check(err, jc.ErrorIsNil)
}

func checkNotExiting(c *gc.C, w worker.Worker) {
	exited := make(chan bool)
	go func() {
		w.Wait()
		close(exited)
	}()

	select {
	case <-exited:
		c.Fatal("worker exited unexpectedly")
	case <-time.After(coretesting.ShortWait):
		// Worker didn't exit (good)
	}
}

func checkExitsWithError(c *gc.C, w worker.Worker, expectedErr error) {
	c.Check(waitForExit(c, w), gc.Equals, expectedErr)
}

func waitForExit(c *gc.C, w worker.Worker) error {
	errCh := make(chan error)
	go func() {
		errCh <- w.Wait()
	}()
	select {
	case err := <-errCh:
		return err
	case <-time.After(coretesting.LongWait):
		c.Fatal("timed out waiting for worker to exit")
	}
	panic("can't get here")
}

type mockAgent struct {
	coreagent.Agent
	conf mockConfig
}

func (ma *mockAgent) CurrentConfig() coreagent.Config {
	return &ma.conf
}

type mockConfig struct {
	coreagent.ConfigSetter
	tag         names.Tag
	mu          sync.Mutex
	ssInfoIsSet bool
}

func (mc *mockConfig) Tag() names.Tag {
	return mc.tag
}

func (mc *mockConfig) setStateServingInfo(isSet bool) {
	mc.mu.Lock()
	defer mc.mu.Unlock()
	mc.ssInfoIsSet = isSet
}

func (mc *mockConfig) StateServingInfo() (params.StateServingInfo, bool) {
	mc.mu.Lock()
	defer mc.mu.Unlock()
	return params.StateServingInfo{}, mc.ssInfoIsSet
}

type dummyWorker struct {
	worker.Worker
}
<|endoftext|>