<commit_before>/*

Package s3 implement the AWS S3 backend for storing blobs.

The bucket must already exists.

*/
package s3

import (
	"bufio"
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	ks3 "github.com/kr/s3"
	"github.com/kr/s3/s3util"
	"sync"
)

func do(verb, url string, body io.Reader, c *s3util.Config) (int, error) {
	if c == nil {
		c = s3util.DefaultConfig
	}
	// TODO(kr): maybe parallel range fetching
	r, err := http.NewRequest(verb, url, body)
	//r.ContentLength =
	r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	c.Sign(r, *c.Keys)
	client := c.Client
	if client == nil {
		client = http.DefaultClient
	}
	resp, err := client.Do(r)
	if err != nil {
		return resp.StatusCode, err
	}
	if resp.StatusCode != 200 && resp.StatusCode != 204 && resp.StatusCode != 404 && resp.StatusCode != 403 {
		var buf bytes.Buffer
		io.Copy(&buf, resp.Body)
		resp.Body.Close()
		return resp.StatusCode, fmt.Errorf("Bad response code for query %v/%v, %v: %+v",
			verb, url, resp.StatusCode, buf.String())
	}
	return resp.StatusCode, nil
}

type S3Backend struct {
	Bucket    string
	Location  string
	BucketURL string
	keys      *ks3.Keys
	sync.Mutex
}

func New(bucket, location string) *S3Backend {
	log.Printf("S3Backend: starting")
	log.Printf("s3Backend: bucket:%v/location:%v", bucket, location)
	keys := ks3.Keys{
		AccessKey: os.Getenv("S3_ACCESS_KEY"),
		SecretKey: os.Getenv("S3_SECRET_KEY"),
	}

	if keys.AccessKey == "" || keys.SecretKey == "" {
		panic("S3_ACCESS_KEY or S3_SECRET_KEY not set")
	}

	s3util.DefaultConfig.AccessKey = keys.AccessKey
	s3util.DefaultConfig.SecretKey = keys.SecretKey
	backend := &S3Backend{Bucket: bucket, Location: location, keys: &keys}
	if err := backend.load(); err != nil {
		panic(fmt.Errorf("Error loading %T: %v", backend, err))
	}
	log.Printf("S3Backend: backend id => %v", backend.String())
	return backend
}

func (backend *S3Backend) String() string {
	return fmt.Sprintf("s3-%v", backend.Bucket)
}

func (backend *S3Backend) bucket(key string) string {
	//"https://%v.s3.amazonaws.com/%v"
	return fmt.Sprintf("https://%v.%v/%v", backend.Bucket, backend.BucketURL, key)
}

func (backend *S3Backend) Close() {
	return
}

func (backend *S3Backend) Done() error {
	return nil
}

type CreateBucketConfiguration struct {
	XMLName            xml.Name `xml:"CreateBucketConfiguration"`
	Xmlns              string   `xml:"xmlns,attr"`
	LocationConstraint string   `xml:"LocationConstraint"`
}

type LocationConstraint struct {
	XMLName  xml.Name `xml:"LocationConstraint"`
	Location string   `xml:",chardata"`
}

const s3Xmlns = "http://s3.amazonaws.com/doc/2006-03-01/"

func newCreateBucketConfiguration(location string) io.Reader {
	if location == "" {
		return nil
	}
	conf := &CreateBucketConfiguration{Xmlns: s3Xmlns, LocationConstraint: location}
	out, err := xml.Marshal(conf)
	if err != nil {
		panic(err)
	}
	return strings.NewReader(string(out))
}

func (backend *S3Backend) bucketLocation(bucket string) (string, error) {
	c := s3util.DefaultConfig
	r, _ := http.NewRequest("GET", fmt.Sprintf("https://%v.s3.amazonaws.com?location", backend.Bucket), nil)
	r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	c.Sign(r, *c.Keys)
	client := c.Client
	if client == nil {
		client = http.DefaultClient
	}
	resp, err := client.Do(r)
	if err != nil {
		return "", err
	}
	var locationConstraint LocationConstraint
	if err := xml.NewDecoder(resp.Body).Decode(&locationConstraint); err != nil {
		return "", err
	}
	if locationConstraint.Location == "" {
		return "s3.amazonaws.com", nil
	}
	return fmt.Sprintf("s3-%v.amazonaws.com", locationConstraint.Location), nil
}

// load check if the bucket already exists, if not, will try to create it.
// It also fetch the bucket location.
func (backend *S3Backend) load() error {
	log.Println("S3Backend: checking if backend exists")
	exists, err := do("HEAD", "https://"+backend.Bucket+".s3.amazonaws.com", nil, nil)
	if err != nil {
		return err
	}
	if exists == 404 {
		log.Printf("S3Backend: creating bucket %v", backend.Bucket)
		created, err := do("PUT", "https://"+backend.Bucket+".s3.amazonaws.com", newCreateBucketConfiguration(backend.Location), nil)
		if created != 200 || err != nil {
			log.Println("S3Backend: error creating bucket: %v", err)
			return err
		}
	}
	burl, err := backend.bucketLocation(backend.Bucket)
	if err != nil {
		return fmt.Errorf("can't find bucket location: %v", err)
	}
	backend.BucketURL = burl
	return nil
}

func (backend *S3Backend) upload(hash string, data []byte) error {
	backend.Lock()
	defer backend.Unlock()
	r := bytes.NewBuffer(data)
	w, err := s3util.Create(fmt.Sprintf("%v%v", backend.bucket(""), hash), nil, nil)
	if err != nil {
		return err
	}
	_, err = io.Copy(w, r)
	if err != nil {
		return err
	}
	if err := w.Close(); err != nil {
		return err
	}
	return nil
}

func (backend *S3Backend) Put(hash string, data []byte) error {
	var err error
	for tries, retry := 0, false; tries < 2 && retry; tries++ {
		err = backend.upload(hash, data)
		if err != nil {
			retry = true
		}
	}
	return err
}

func (backend *S3Backend) Get(hash string) ([]byte, error) {
	r, err := s3util.Open(backend.bucket(hash), nil)
	if err != nil {
		return nil, err
	}
	defer r.Close()
	var buf bytes.Buffer
	w := bufio.NewWriter(&buf)
	io.Copy(w, r)
	return buf.Bytes(), nil
}

func (backend *S3Backend) Exists(hash string) bool {
	r, err := do("HEAD", backend.bucket(hash), nil, nil)
	if r == 200 {
		return true
	} else if r == 404 {
		return false
	} else {
		log.Printf("S3Backend: error performing HEAD request for blob %v, err:%v", hash, err)
	}
	return false
}

func (backend *S3Backend) Delete(hash string) error {
	_, err := do("DELETE", backend.bucket(hash), nil, nil)
	return err
}

func (backend *S3Backend) Enumerate(blobs chan<- string) error {
	defer close(blobs)
	f, err := s3util.NewFile(backend.bucket(""), nil)
	if err != nil {
		return err
	}
	var infos []os.FileInfo
	for {
		infos, err = f.Readdir(0)
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}
		for _, info := range infos {
			c := info.Sys().(*s3util.Stat)
			blobs <- c.Key
		}
	}
	return nil
}

// Delete all keys in a bucket (assumes the directory is flat/no sub-directories).
func (backend *S3Backend) Drop() error {
	log.Printf("S3Backend: dropping bucket...")
	blobs := make(chan string)
	go backend.Enumerate(blobs)
	for blob := range blobs {
		if err := backend.Delete(blob); err != nil {
			return err
		}
	}
	_, err := do("DELETE", backend.bucket(""), nil, nil)
	return err
}
<commit_msg>Bugfix S3 backend retry<commit_after>/*

Package s3 implement the AWS S3 backend for storing blobs.

The bucket must already exists.

*/
package s3

import (
	"bufio"
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	ks3 "github.com/kr/s3"
	"github.com/kr/s3/s3util"
	"sync"
)

func do(verb, url string, body io.Reader, c *s3util.Config) (int, error) {
	if c == nil {
		c = s3util.DefaultConfig
	}
	// TODO(kr): maybe parallel range fetching
	r, err := http.NewRequest(verb, url, body)
	//r.ContentLength =
	r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	c.Sign(r, *c.Keys)
	client := c.Client
	if client == nil {
		client = http.DefaultClient
	}
	resp, err := client.Do(r)
	if err != nil {
		return resp.StatusCode, err
	}
	if resp.StatusCode != 200 && resp.StatusCode != 204 && resp.StatusCode != 404 && resp.StatusCode != 403 {
		var buf bytes.Buffer
		io.Copy(&buf, resp.Body)
		resp.Body.Close()
		return resp.StatusCode, fmt.Errorf("Bad response code for query %v/%v, %v: %+v",
			verb, url, resp.StatusCode, buf.String())
	}
	return resp.StatusCode, nil
}

type S3Backend struct {
	Bucket    string
	Location  string
	BucketURL string
	keys      *ks3.Keys
	sync.Mutex
}

func New(bucket, location string) *S3Backend {
	log.Printf("S3Backend: starting")
	log.Printf("s3Backend: bucket:%v/location:%v", bucket, location)
	keys := ks3.Keys{
		AccessKey: os.Getenv("S3_ACCESS_KEY"),
		SecretKey: os.Getenv("S3_SECRET_KEY"),
	}

	if keys.AccessKey == "" || keys.SecretKey == "" {
		panic("S3_ACCESS_KEY or S3_SECRET_KEY not set")
	}

	s3util.DefaultConfig.AccessKey = keys.AccessKey
	s3util.DefaultConfig.SecretKey = keys.SecretKey
	backend := &S3Backend{Bucket: bucket, Location: location, keys: &keys}
	if err := backend.load(); err != nil {
		panic(fmt.Errorf("Error loading %T: %v", backend, err))
	}
	log.Printf("S3Backend: backend id => %v", backend.String())
	return backend
}

func (backend *S3Backend) String() string {
	return fmt.Sprintf("s3-%v", backend.Bucket)
}

func (backend *S3Backend) bucket(key string) string {
	//"https://%v.s3.amazonaws.com/%v"
	return fmt.Sprintf("https://%v.%v/%v", backend.Bucket, backend.BucketURL, key)
}

func (backend *S3Backend) Close() {
	return
}

func (backend *S3Backend) Done() error {
	return nil
}

type CreateBucketConfiguration struct {
	XMLName            xml.Name `xml:"CreateBucketConfiguration"`
	Xmlns              string   `xml:"xmlns,attr"`
	LocationConstraint string   `xml:"LocationConstraint"`
}

type LocationConstraint struct {
	XMLName  xml.Name `xml:"LocationConstraint"`
	Location string   `xml:",chardata"`
}

const s3Xmlns = "http://s3.amazonaws.com/doc/2006-03-01/"

func newCreateBucketConfiguration(location string) io.Reader {
	if location == "" {
		return nil
	}
	conf := &CreateBucketConfiguration{Xmlns: s3Xmlns, LocationConstraint: location}
	out, err := xml.Marshal(conf)
	if err != nil {
		panic(err)
	}
	return strings.NewReader(string(out))
}

func (backend *S3Backend) bucketLocation(bucket string) (string, error) {
	c := s3util.DefaultConfig
	r, _ := http.NewRequest("GET", fmt.Sprintf("https://%v.s3.amazonaws.com?location", backend.Bucket), nil)
	r.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
	c.Sign(r, *c.Keys)
	client := c.Client
	if client == nil {
		client = http.DefaultClient
	}
	resp, err := client.Do(r)
	if err != nil {
		return "", err
	}
	var locationConstraint LocationConstraint
	if err := xml.NewDecoder(resp.Body).Decode(&locationConstraint); err != nil {
		return "", err
	}
	if locationConstraint.Location == "" {
		return "s3.amazonaws.com", nil
	}
	return fmt.Sprintf("s3-%v.amazonaws.com", locationConstraint.Location), nil
}

// load check if the bucket already exists, if not, will try to create it.
// It also fetch the bucket location.
func (backend *S3Backend) load() error {
	log.Println("S3Backend: checking if backend exists")
	exists, err := do("HEAD", "https://"+backend.Bucket+".s3.amazonaws.com", nil, nil)
	if err != nil {
		return err
	}
	if exists == 404 {
		log.Printf("S3Backend: creating bucket %v", backend.Bucket)
		created, err := do("PUT", "https://"+backend.Bucket+".s3.amazonaws.com", newCreateBucketConfiguration(backend.Location), nil)
		if created != 200 || err != nil {
			log.Println("S3Backend: error creating bucket: %v", err)
			return err
		}
	}
	burl, err := backend.bucketLocation(backend.Bucket)
	if err != nil {
		return fmt.Errorf("can't find bucket location: %v", err)
	}
	backend.BucketURL = burl
	return nil
}

func (backend *S3Backend) upload(hash string, data []byte) error {
	backend.Lock()
	defer backend.Unlock()
	r := bytes.NewBuffer(data)
	w, err := s3util.Create(fmt.Sprintf("%v%v", backend.bucket(""), hash), nil, nil)
	if err != nil {
		return err
	}
	_, err = io.Copy(w, r)
	if err != nil {
		return err
	}
	if err := w.Close(); err != nil {
		return err
	}
	return nil
}

func (backend *S3Backend) Put(hash string, data []byte) error {
	var err error
	for tries, retry := 0, true; tries < 2 && retry; tries++ {
		retry = false
		err = backend.upload(hash, data)
		if err != nil {
			retry = true
		}
	}
	return err
}

func (backend *S3Backend) Get(hash string) ([]byte, error) {
	r, err := s3util.Open(backend.bucket(hash), nil)
	if err != nil {
		return nil, err
	}
	defer r.Close()
	var buf bytes.Buffer
	w := bufio.NewWriter(&buf)
	io.Copy(w, r)
	return buf.Bytes(), nil
}

func (backend *S3Backend) Exists(hash string) bool {
	r, err := do("HEAD", backend.bucket(hash), nil, nil)
	if r == 200 {
		return true
	} else if r == 404 {
		return false
	} else {
		log.Printf("S3Backend: error performing HEAD request for blob %v, err:%v", hash, err)
	}
	return false
}

func (backend *S3Backend) Delete(hash string) error {
	_, err := do("DELETE", backend.bucket(hash), nil, nil)
	return err
}

func (backend *S3Backend) Enumerate(blobs chan<- string) error {
	defer close(blobs)
	f, err := s3util.NewFile(backend.bucket(""), nil)
	if err != nil {
		return err
	}
	var infos []os.FileInfo
	for {
		infos, err = f.Readdir(0)
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}
		for _, info := range infos {
			c := info.Sys().(*s3util.Stat)
			blobs <- c.Key
		}
	}
	return nil
}

// Delete all keys in a bucket (assumes the directory is flat/no sub-directories).
func (backend *S3Backend) Drop() error {
	log.Printf("S3Backend: dropping bucket...")
	blobs := make(chan string)
	go backend.Enumerate(blobs)
	for blob := range blobs {
		if err := backend.Delete(blob); err != nil {
			return err
		}
	}
	_, err := do("DELETE", backend.bucket(""), nil, nil)
	return err
}
<|endoftext|>


<commit_before>package river

import (
	"fmt"
	"net/http"
	"net/url"
	"os"
	"time"

	. "gopkg.in/check.v1"
)

func (s *riverTestSuite) setupExtra(c *C) (r *River) {
	var err error

	schema := `
        CREATE TABLE IF NOT EXISTS %s (
            id INT,
            title VARCHAR(256),
            pid INT,
            PRIMARY KEY(id)) ENGINE=INNODB;
    `

	s.testExecute(c, "DROP TABLE IF EXISTS test_river_extra")
	s.testExecute(c, fmt.Sprintf(schema, "test_river_extra"))

	schema = `
        CREATE TABLE IF NOT EXISTS %s (
            id INT,
            PRIMARY KEY(id)) ENGINE=INNODB;
    `

	s.testExecute(c, "DROP TABLE IF EXISTS test_river_parent")
	s.testExecute(c, fmt.Sprintf(schema, "test_river_parent"))

	cfg := new(Config)
	cfg.MyAddr = *my_addr
	cfg.MyUser = "root"
	cfg.MyPassword = ""
	cfg.ESAddr = *es_addr

	cfg.ServerID = 1001
	cfg.Flavor = "mysql"

	cfg.DataDir = "/tmp/test_river_extra"
	cfg.DumpExec = "mysqldump"

	cfg.StatAddr = "127.0.0.1:12800"
	cfg.BulkSize = 1
	cfg.FlushBulkTime = TomlDuration{3 * time.Millisecond}

	os.RemoveAll(cfg.DataDir)

	cfg.Sources = []SourceConfig{SourceConfig{Schema: "test", Tables: []string{"test_river_extra", "test_river_parent"}}}

	cfg.Rules = []*Rule{
		&Rule{Schema: "test",
			Table: "test_river_parent",
			Index: "river",
			Type:  "river_extra_parent"},
		&Rule{Schema: "test",
			Table:  "test_river_extra",
			Index:  "river",
			Type:   "river_extra",
			Parent: "pid"}}

	r, err = NewRiver(cfg)
	c.Assert(err, IsNil)

	mapping := map[string]interface{}{
		"river_extra": map[string]interface{}{
			"_parent": map[string]string{"type": "river_extra_parent"},
		},
	}

	r.es.CreateMapping("river", "river_extra", mapping)

	return r
}

func (s *riverTestSuite) testPrepareExtraData(c *C) {
	s.testExecute(c, "INSERT INTO test_river_parent (id) VALUES (?)", 1)
	s.testExecute(c, "INSERT INTO test_river_extra (id, title, pid) VALUES (?, ?, ?)", 1, "first", 1)
	s.testExecute(c, "INSERT INTO test_river_extra (id, title, pid) VALUES (?, ?, ?)", 2, "second", 1)
	s.testExecute(c, "INSERT INTO test_river_extra (id, title, pid) VALUES (?, ?, ?)", 3, "third", 1)
	s.testExecute(c, "INSERT INTO test_river_extra (id, title, pid) VALUES (?, ?, ?)", 4, "fourth", 1)
}

func (s *riverTestSuite) testElasticExtraExists(c *C, id string, parent string, exist bool) {
	index := "river"
	docType := "river_extra"

	reqUrl := fmt.Sprintf("http://%s/%s/%s/%s?parent=%s", s.r.es.Addr,
		url.QueryEscape(index),
		url.QueryEscape(docType),
		url.QueryEscape(id),
		url.QueryEscape(parent))

	r, err := s.r.es.Do("HEAD", reqUrl, nil)
	c.Assert(err, IsNil)

	if exist {
		c.Assert(r.Code, Equals, http.StatusOK)
	} else {
		c.Assert(r.Code, Equals, http.StatusNotFound)
	}
}

func (s *riverTestSuite) TestRiverWithParent(c *C) {
	river := s.setupExtra(c)

	defer river.Close()

	s.testPrepareExtraData(c)

	river.Start()

	testWaitSyncDone(c, river)

	s.testElasticExtraExists(c, "1", "1", true)

	s.testExecute(c, "DELETE FROM test_river_extra WHERE id = ?", 1)
	testWaitSyncDone(c, river)

	s.testElasticExtraExists(c, "1", "1", false)
}
<commit_msg>Update river_extra_test.go<commit_after>package river

import (
	"fmt"
	"net/http"
	"net/url"
	"os"
	"time"

	. "gopkg.in/check.v1"
)

func (s *riverTestSuite) setupExtra(c *C) (r *River) {
	var err error

	schema := `
        CREATE TABLE IF NOT EXISTS %s (
            id INT,
            title VARCHAR(256),
            pid INT,
            PRIMARY KEY(id)) ENGINE=INNODB;
    `

	s.testExecute(c, "DROP TABLE IF EXISTS test_river_extra")
	s.testExecute(c, fmt.Sprintf(schema, "test_river_extra"))

	schema = `
        CREATE TABLE IF NOT EXISTS %s (
            id INT,
            PRIMARY KEY(id)) ENGINE=INNODB;
    `

	s.testExecute(c, "DROP TABLE IF EXISTS test_river_parent")
	s.testExecute(c, fmt.Sprintf(schema, "test_river_parent"))

	cfg := new(Config)
	cfg.MyAddr = *my_addr
	cfg.MyUser = "root"
	cfg.MyPassword = ""
	cfg.ESAddr = *es_addr

	cfg.ServerID = 1001
	cfg.Flavor = "mysql"

	cfg.DataDir = "/tmp/test_river_extra"
	cfg.DumpExec = "mysqldump"

	cfg.StatAddr = "127.0.0.1:12800"
	cfg.BulkSize = 1
	cfg.FlushBulkTime = TomlDuration{3 * time.Millisecond}

	os.RemoveAll(cfg.DataDir)

	cfg.Sources = []SourceConfig{SourceConfig{Schema: "test", Tables: []string{"test_river_extra", "test_river_parent"}}}

	cfg.Rules = []*Rule{
		&Rule{Schema: "test",
			Table: "test_river_parent",
			Index: "river",
			Type:  "river_extra_parent"},
		&Rule{Schema: "test",
			Table:  "test_river_extra",
			Index:  "river",
			Type:   "river_extra",
			Parent: "pid"}}

	r, err = NewRiver(cfg)
	c.Assert(err, IsNil)

	mapping := map[string]interface{}{
		"river_extra": map[string]interface{}{
			"_parent": map[string]string{"type": "river_extra_parent"},
		},
	}

	r.es.CreateMapping("river", "river_extra", mapping)

	return r
}

func (s *riverTestSuite) testPrepareExtraData(c *C) {
	s.testExecute(c, "INSERT INTO test_river_parent (id) VALUES (?)", 1)
	s.testExecute(c, "INSERT INTO test_river_extra (id, title, pid) VALUES (?, ?, ?)", 1, "first", 1)
	s.testExecute(c, "INSERT INTO test_river_extra (id, title, pid) VALUES (?, ?, ?)", 2, "second", 1)
	s.testExecute(c, "INSERT INTO test_river_extra (id, title, pid) VALUES (?, ?, ?)", 3, "third", 1)
	s.testExecute(c, "INSERT INTO test_river_extra (id, title, pid) VALUES (?, ?, ?)", 4, "fourth", 1)
}

func (s *riverTestSuite) testElasticExtraExists(c *C, id string, parent string, exist bool) {
	index := "river"
	docType := "river_extra"

	reqUrl := fmt.Sprintf("http://%s/%s/%s/%s?parent=%s", s.r.es.Addr,
		url.QueryEscape(index),
		url.QueryEscape(docType),
		url.QueryEscape(id),
		url.QueryEscape(parent))

	r, err := s.r.es.Do("HEAD", reqUrl, nil)

	if exist {
		c.Assert(r.Code, Equals, http.StatusOK)
	} else {
		c.Assert(err, NotNil)
	}
}

func (s *riverTestSuite) TestRiverWithParent(c *C) {
	river := s.setupExtra(c)

	defer river.Close()

	s.testPrepareExtraData(c)

	river.Start()

	testWaitSyncDone(c, river)

	s.testElasticExtraExists(c, "1", "1", true)

	s.testExecute(c, "DELETE FROM test_river_extra WHERE id = ?", 1)
	testWaitSyncDone(c, river)

	s.testElasticExtraExists(c, "1", "1", false)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/kevinburke/rct-rides/tracks"
)

func hasBit(n int, pos uint) bool {
	val := n & (1 << pos)
	return (val > 0)
}

var reverseMap = map[tracks.DirectionDelta]string{
	tracks.DIR_STRAIGHT:       "DIR_STRAIGHT",
	tracks.DIR_45_DEG_RIGHT:   "DIR_45_DEG_RIGHT",
	tracks.DIR_90_DEG_RIGHT:   "DIR_90_DEG_RIGHT",
	tracks.DIR_180_DEG:        "DIR_180_DEG",
	tracks.DIR_90_DEG_LEFT:    "DIR_90_DEG_LEFT",
	tracks.DIR_45_DEG_LEFT:    "DIR_45_DEG_LEFT",
	tracks.DIR_DIAGONAL:       "DIR_DIAGONAL",
	tracks.DIR_DIAGONAL_LEFT:  "DIR_DIAGONAL_LEFT",
	tracks.DIR_DIAGONAL_RIGHT: "DIR_DIAGONAL_RIGHT",
}

func getDiagonalFromRCTStruct(b []byte) tracks.DirectionDelta {
	startingDirectionInt := int(b[0])
	startingDirection := tracks.RCTDirectionKeys[startingDirectionInt]
	endingDirectionInt := int(b[1])
	endingDirection := tracks.RCTDirectionKeys[endingDirectionInt]

	if startingDirection == tracks.DIR_DIAGONAL {
		if endingDirection == tracks.DIR_DIAGONAL {
			return tracks.DIR_DIAGONAL
		} else if endingDirection == tracks.DIR_90_DEG_RIGHT {
			return tracks.DIR_DIAGONAL_RIGHT
		} else {
			return tracks.DIR_DIAGONAL_LEFT
		}
	} else if endingDirection == tracks.DIR_DIAGONAL {
		return tracks.DIR_DIAGONAL_RIGHT
	} else {
		return endingDirection
	}
}

// XXX, this doesn't correctly handle s-bends, which only move sideways by 1
// piece, I think.
func getSidewaysDelta(sidewaysDeltaByte int) int {
	if hasBit(sidewaysDeltaByte, 7) {
		return 1 + (256-sidewaysDeltaByte)>>5
	}
	if hasBit(sidewaysDeltaByte, 6) {
		return 1 + sidewaysDeltaByte>>5
	}
	return 0
}

// Print out the Go code to make up a track segment
func printValues(elementName string, b []byte) {

	dir := getDiagonalFromRCTStruct(b)
	sidewaysDelta := getSidewaysDelta(int(b[8]))

	fmt.Printf("%s: &Segment{\n", elementName)
	fmt.Printf("\tDirectionDelta: %s,\n", reverseMap[dir])
	fmt.Printf("\tSidewaysDelta: %d,\n", sidewaysDelta)
	//bitVal := int(b[i*8+2])
	//fmt.Printf("\tInputDegree: %s,\n", configTable1Map[2][bitVal])
	//bitVal = int(b[i*8+1])
	//fmt.Printf("\tOutputDegree: %s,\n", configTable1Map[1][bitVal])
	//bitVal = int(b[i*8+4])
	//fmt.Printf("\tStartingBank: %s,\n", configTable1Map[4][bitVal])
	//bitVal = int(b[i*8+3])
	//fmt.Printf("\tEndingBank: %s,\n", configTable1Map[3][bitVal])
	fmt.Printf("},\n")
}

const RCT_DIRECTION_ADDR = 0x005972bb
const RCT_DIRECTION_WIDTH = 10

var configTable1Map = map[int]map[int]string{
	0: map[int]string{
		0:   "TRACK_FLAT",
		2:   "TRACK_STATION_END",
		7:   "TRACK_VERTICAL_LOOP",
		13:  "TRACK_S_BEND",
		17:  "TRACK_TWIST",
		18:  "TRACK_HALF_LOOP",
		19:  "TRACK_CORKSCREW",
		20:  "TRACK_TOWER_BASE",
		21:  "TRACK_HELIX_SMALL",
		22:  "TRACK_HELIX_LARGE",
		23:  "TRACK_HELIX_LARGE_UNBANKED",
		24:  "TRACK_BRAKES",
		26:  "TRACK_ON_RIDE_PHOTO",
		27:  "TRACK_WATER_SPLASH",
		29:  "TRACK_BARREL_ROLL",
		30:  "TRACK_POWERED_LIFT",
		31:  "TRACK_HALF_LOOP_2", // ?
		33:  "TRACK_LOG_FLUME_REVERSER",
		36:  "TRACK_WHOA_BELLY",
		43:  "TRACK_LIFT_HILL",
		46:  "TRACK_SPINNING_TUNNEL",
		47:  "TRACK_ROTATION_CONTROL_TOGGLE",
		52:  "TRACK_RAPIDS",
		152: "TRACK_WATERFALL",
		//152: "TRACK_WHIRLPOOL",
		172: "TRACK_BRAKE_FOR_DROP",
	},
	1: map[int]string{
		0:  "TRACK_NONE",
		2:  "TRACK_UP_25",
		4:  "TRACK_UP_60",
		6:  "TRACK_DOWN_25",
		8:  "TRACK_DOWN_60",
		10: "TRACK_UP_90",
		18: "TRACK_DOWN_90",
	},
	2: map[int]string{
		0:  "TRACK_NONE",
		2:  "TRACK_UP_25",
		4:  "TRACK_UP_60",
		6:  "TRACK_DOWN_25",
		8:  "TRACK_DOWN_60",
		10: "TRACK_UP_90",
		18: "TRACK_DOWN_90",
	},
	3: map[int]string{
		0:  "TRACK_BANK_NONE",
		2:  "TRACK_BANK_LEFT",
		4:  "TRACK_BANK_RIGHT",
		15: "TRACK_BANK_UPSIDE_DOWN",
	},
	4: map[int]string{
		0:  "TRACK_BANK_NONE",
		2:  "TRACK_BANK_LEFT",
		4:  "TRACK_BANK_RIGHT",
		15: "TRACK_BANK_UPSIDE_DOWN",
	},
	5: map[int]string{
		0:   "TRACK_NONE",
		64:  "TRACK_HALF_LOOP_UP",
		192: "TRACK_HALF_LOOP_DOWN",
		208: "TRACK_UNKNOWN_VERTICAL_LOOP",
		224: "TRACK_CORKSCREW_DOWN",
	},
}

func main() {
	f, err := os.Open(os.Getenv("HOME") + "/code/OpenRCT2/openrct2.exe")
	if err != nil {
		panic(err)
	}

	defer f.Close()

	b := make([]byte, 256*RCT_DIRECTION_WIDTH)
	f.ReadAt(b, int64(RCT_DIRECTION_ADDR))

	for i := 0; i < len(tracks.ElementNames); i++ {
		//fmt.Println(i)
		//fmt.Printf("%55s ", tracks.ElementNames[i])
		//fmt.Printf("%4d ", b[i*WIDTH])
		//fmt.Printf("\n")
		idx := i * RCT_DIRECTION_WIDTH
		bitSubset := b[idx : idx+RCT_DIRECTION_WIDTH]
		printValues(tracks.ElementNames[i], bitSubset)
	}

	//fmt.Printf("%#v\n", tracks.TS_MAP)
	//fmt.Printf("%T\n", tracks.TS_MAP)
}
<commit_msg>add elevation delta<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/kevinburke/rct-rides/tracks"
)

func hasBit(n int, pos uint) bool {
	val := n & (1 << pos)
	return (val > 0)
}

var reverseMap = map[tracks.DirectionDelta]string{
	tracks.DIR_STRAIGHT:       "DIR_STRAIGHT",
	tracks.DIR_45_DEG_RIGHT:   "DIR_45_DEG_RIGHT",
	tracks.DIR_90_DEG_RIGHT:   "DIR_90_DEG_RIGHT",
	tracks.DIR_180_DEG:        "DIR_180_DEG",
	tracks.DIR_90_DEG_LEFT:    "DIR_90_DEG_LEFT",
	tracks.DIR_45_DEG_LEFT:    "DIR_45_DEG_LEFT",
	tracks.DIR_DIAGONAL:       "DIR_DIAGONAL",
	tracks.DIR_DIAGONAL_LEFT:  "DIR_DIAGONAL_LEFT",
	tracks.DIR_DIAGONAL_RIGHT: "DIR_DIAGONAL_RIGHT",
}

func getDiagonalFromRCTStruct(b []byte) tracks.DirectionDelta {
	startingDirectionInt := int(b[0])
	startingDirection := tracks.RCTDirectionKeys[startingDirectionInt]
	endingDirectionInt := int(b[1])
	endingDirection := tracks.RCTDirectionKeys[endingDirectionInt]

	if startingDirection == tracks.DIR_DIAGONAL {
		if endingDirection == tracks.DIR_DIAGONAL {
			return tracks.DIR_DIAGONAL
		} else if endingDirection == tracks.DIR_90_DEG_RIGHT {
			return tracks.DIR_DIAGONAL_RIGHT
		} else {
			return tracks.DIR_DIAGONAL_LEFT
		}
	} else if endingDirection == tracks.DIR_DIAGONAL {
		return tracks.DIR_DIAGONAL_RIGHT
	} else {
		return endingDirection
	}
}

// XXX, this doesn't correctly handle s-bends, which only move sideways by 1
// piece, I think.
func getSidewaysDelta(sidewaysDeltaByte int) int {
	if hasBit(sidewaysDeltaByte, 7) {
		return 1 + (256-sidewaysDeltaByte)>>5
	}
	if hasBit(sidewaysDeltaByte, 6) {
		return 1 + sidewaysDeltaByte>>5
	}
	return 0
}

func getElevationDelta(positiveHeightBit int, negativeHeightBit int) int {
	if positiveHeightBit > 0 {
		return positiveHeightBit >> 3
	}
	if negativeHeightBit > 0 {
		return negativeHeightBit >> 3
	}
	return 0
}

// Print out the Go code to make up a track segment
func printValues(elementName string, b []byte) {

	dir := getDiagonalFromRCTStruct(b)
	sidewaysDelta := getSidewaysDelta(int(b[8]))
	negativeHeightBit := int(b[2])
	positiveHeightBit := int(b[4])
	elevationDelta := getElevationDelta(positiveHeightBit, negativeHeightBit)

	fmt.Printf("%s: &Segment{\n", elementName)
	fmt.Printf("\tDirectionDelta: %s,\n", reverseMap[dir])
	fmt.Printf("\tSidewaysDelta: %d,\n", sidewaysDelta)
	fmt.Printf("\tElevationDelta: %d,\n", elevationDelta)
	//bitVal := int(b[i*8+2])
	//fmt.Printf("\tInputDegree: %s,\n", configTable1Map[2][bitVal])
	//bitVal = int(b[i*8+1])
	//fmt.Printf("\tOutputDegree: %s,\n", configTable1Map[1][bitVal])
	//bitVal = int(b[i*8+4])
	//fmt.Printf("\tStartingBank: %s,\n", configTable1Map[4][bitVal])
	//bitVal = int(b[i*8+3])
	//fmt.Printf("\tEndingBank: %s,\n", configTable1Map[3][bitVal])
	fmt.Printf("},\n")
}

const RCT_DIRECTION_ADDR = 0x005972bb
const RCT_DIRECTION_WIDTH = 10

var configTable1Map = map[int]map[int]string{
	0: map[int]string{
		0:   "TRACK_FLAT",
		2:   "TRACK_STATION_END",
		7:   "TRACK_VERTICAL_LOOP",
		13:  "TRACK_S_BEND",
		17:  "TRACK_TWIST",
		18:  "TRACK_HALF_LOOP",
		19:  "TRACK_CORKSCREW",
		20:  "TRACK_TOWER_BASE",
		21:  "TRACK_HELIX_SMALL",
		22:  "TRACK_HELIX_LARGE",
		23:  "TRACK_HELIX_LARGE_UNBANKED",
		24:  "TRACK_BRAKES",
		26:  "TRACK_ON_RIDE_PHOTO",
		27:  "TRACK_WATER_SPLASH",
		29:  "TRACK_BARREL_ROLL",
		30:  "TRACK_POWERED_LIFT",
		31:  "TRACK_HALF_LOOP_2", // ?
		33:  "TRACK_LOG_FLUME_REVERSER",
		36:  "TRACK_WHOA_BELLY",
		43:  "TRACK_LIFT_HILL",
		46:  "TRACK_SPINNING_TUNNEL",
		47:  "TRACK_ROTATION_CONTROL_TOGGLE",
		52:  "TRACK_RAPIDS",
		152: "TRACK_WATERFALL",
		//152: "TRACK_WHIRLPOOL",
		172: "TRACK_BRAKE_FOR_DROP",
	},
	1: map[int]string{
		0:  "TRACK_NONE",
		2:  "TRACK_UP_25",
		4:  "TRACK_UP_60",
		6:  "TRACK_DOWN_25",
		8:  "TRACK_DOWN_60",
		10: "TRACK_UP_90",
		18: "TRACK_DOWN_90",
	},
	2: map[int]string{
		0:  "TRACK_NONE",
		2:  "TRACK_UP_25",
		4:  "TRACK_UP_60",
		6:  "TRACK_DOWN_25",
		8:  "TRACK_DOWN_60",
		10: "TRACK_UP_90",
		18: "TRACK_DOWN_90",
	},
	3: map[int]string{
		0:  "TRACK_BANK_NONE",
		2:  "TRACK_BANK_LEFT",
		4:  "TRACK_BANK_RIGHT",
		15: "TRACK_BANK_UPSIDE_DOWN",
	},
	4: map[int]string{
		0:  "TRACK_BANK_NONE",
		2:  "TRACK_BANK_LEFT",
		4:  "TRACK_BANK_RIGHT",
		15: "TRACK_BANK_UPSIDE_DOWN",
	},
	5: map[int]string{
		0:   "TRACK_NONE",
		64:  "TRACK_HALF_LOOP_UP",
		192: "TRACK_HALF_LOOP_DOWN",
		208: "TRACK_UNKNOWN_VERTICAL_LOOP",
		224: "TRACK_CORKSCREW_DOWN",
	},
}

func main() {
	f, err := os.Open(os.Getenv("HOME") + "/code/OpenRCT2/openrct2.exe")
	if err != nil {
		panic(err)
	}

	defer f.Close()

	b := make([]byte, 256*RCT_DIRECTION_WIDTH)
	f.ReadAt(b, int64(RCT_DIRECTION_ADDR))

	for i := 0; i < len(tracks.ElementNames); i++ {
		//fmt.Println(i)
		//fmt.Printf("%55s ", tracks.ElementNames[i])
		//fmt.Printf("%4d ", b[i*WIDTH])
		//fmt.Printf("\n")
		idx := i * RCT_DIRECTION_WIDTH
		bitSubset := b[idx : idx+RCT_DIRECTION_WIDTH]
		printValues(tracks.ElementNames[i], bitSubset)
	}

	//fmt.Printf("%#v\n", tracks.TS_MAP)
	//fmt.Printf("%T\n", tracks.TS_MAP)
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 trivago GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package filter

import (
	"testing"

	"github.com/trivago/gollum/core"
	"github.com/trivago/tgo/ttesting"
)

func TestFilterAnyAllNone(t *testing.T) {
	expect := ttesting.NewExpect(t)
	conf := core.NewPluginConfig("", "filter.Any")

	conf.Override("Any", []interface{}{"filter.None"})
	plugin, err := core.NewPluginWithConfig(conf)
	expect.NoError(err)

	filter, casted := plugin.(*Any)
	expect.True(casted)

	msg := core.NewMessage(nil, []byte{}, nil, core.InvalidStreamID)

	result, err := filter.filters[0].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)
	expect.NoError(err)

	result, err = filter.ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)
	expect.NoError(err)
}

func TestFilterAnyJsonRegExp(t *testing.T) {
	expect := ttesting.NewExpect(t)
	conf := core.NewPluginConfig("", "filter.Any")

	conf.Override("Any", []interface{}{
		"filter.JSON",
		map[interface{}]interface{}{
			"filter.RegExp": map[string]string{
				"Expression": "^ERROR",
			},
		},
	})
	plugin, err := core.NewPluginWithConfig(conf)
	expect.NoError(err)

	filter, casted := plugin.(*Any)
	expect.True(casted)

	// test case 1
	msg := core.NewMessage(nil, []byte("ERROR"), nil, core.InvalidStreamID)

	result, _ := filter.filters[0].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)

	result, _ = filter.filters[1].ApplyFilter(msg)
	expect.Equal(core.FilterResultMessageAccept, result)

	result, err = filter.ApplyFilter(msg)
	expect.Equal(core.FilterResultMessageAccept, result)
	expect.NoError(err)

	// test case 2
	msg = core.NewMessage(nil, []byte("{}"), nil, core.InvalidStreamID)

	result, _ = filter.filters[0].ApplyFilter(msg)
	expect.Equal(core.FilterResultMessageAccept, result)

	result, _ = filter.filters[1].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)

	result, _ = filter.ApplyFilter(msg)
	expect.Equal(core.FilterResultMessageAccept, result)

	// test case 3
	msg = core.NewMessage(nil, []byte("FAIL"), nil, core.InvalidStreamID)

	result, _ = filter.filters[0].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)

	result, _ = filter.filters[1].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)

	result, _ = filter.ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)
}
<commit_msg>fixed any filter unit tests<commit_after>// Copyright 2015-2017 trivago GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package filter

import (
	"testing"

	"github.com/trivago/gollum/core"
	"github.com/trivago/tgo/ttesting"
)

func TestFilterAnyAllNone(t *testing.T) {
	expect := ttesting.NewExpect(t)
	conf := core.NewPluginConfig("", "filter.Any")

	conf.Override("AnyFilters", []interface{}{"filter.None"})
	plugin, err := core.NewPluginWithConfig(conf)
	expect.NoError(err)

	filter, casted := plugin.(*Any)
	expect.True(casted)

	msg := core.NewMessage(nil, []byte{}, nil, core.InvalidStreamID)

	result, err := filter.filters[0].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)
	expect.NoError(err)

	result, err = filter.ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)
	expect.NoError(err)
}

func TestFilterAnyJsonRegExp(t *testing.T) {
	expect := ttesting.NewExpect(t)
	conf := core.NewPluginConfig("", "filter.Any")

	conf.Override("AnyFilters", []interface{}{
		"filter.JSON",
		map[interface{}]interface{}{
			"filter.RegExp": map[string]string{
				"Expression": "^ERROR",
			},
		},
	})
	plugin, err := core.NewPluginWithConfig(conf)
	expect.NoError(err)

	filter, casted := plugin.(*Any)
	expect.True(casted)

	// test case 1
	msg := core.NewMessage(nil, []byte("ERROR"), nil, core.InvalidStreamID)

	result, _ := filter.filters[0].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)

	result, _ = filter.filters[1].ApplyFilter(msg)
	expect.Equal(core.FilterResultMessageAccept, result)

	result, err = filter.ApplyFilter(msg)
	expect.Equal(core.FilterResultMessageAccept, result)
	expect.NoError(err)

	// test case 2
	msg = core.NewMessage(nil, []byte("{}"), nil, core.InvalidStreamID)

	result, _ = filter.filters[0].ApplyFilter(msg)
	expect.Equal(core.FilterResultMessageAccept, result)

	result, _ = filter.filters[1].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)

	result, _ = filter.ApplyFilter(msg)
	expect.Equal(core.FilterResultMessageAccept, result)

	// test case 3
	msg = core.NewMessage(nil, []byte("FAIL"), nil, core.InvalidStreamID)

	result, _ = filter.filters[0].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)

	result, _ = filter.filters[1].ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)

	result, _ = filter.ApplyFilter(msg)
	expect.Neq(core.FilterResultMessageAccept, result)
}
<|endoftext|>


<commit_before>package handler

import (
	"fmt"
	"fullerite/metric"
	"net"
	"sort"
	"time"

	l "github.com/Sirupsen/logrus"
)

func init() {
	RegisterHandler("Graphite", newGraphite)
}

// Graphite type
type Graphite struct {
	BaseHandler
	server string
	port   string
}

// newGraphite returns a new Graphite handler.
func newGraphite(
	channel chan metric.Metric,
	initialInterval int,
	initialBufferSize int,
	initialTimeout time.Duration,
	log *l.Entry) Handler {

	inst := new(Graphite)
	inst.name = "Graphite"

	inst.interval = initialInterval
	inst.maxBufferSize = initialBufferSize
	inst.timeout = initialTimeout
	inst.log = log
	inst.channel = channel

	return inst
}

// Server returns the Graphite server's name or IP
func (g Graphite) Server() string {
	return g.server
}

// Port returns the Graphite server's port number
func (g Graphite) Port() string {
	return g.port
}

// Configure accepts the different configuration options for the Graphite handler
func (g *Graphite) Configure(configMap map[string]interface{}) {
	if server, exists := configMap["server"]; exists {
		g.server = server.(string)
	} else {
		g.log.Error("There was no server specified for the Graphite Handler, there won't be any emissions")
	}

	if port, exists := configMap["port"]; exists {
		g.port = fmt.Sprint(port)
	} else {
		g.log.Error("There was no port specified for the Graphite Handler, there won't be any emissions")
	}
	g.configureCommonParams(configMap)
}

// Run runs the handler main loop
func (g *Graphite) Run() {
	g.run(g.emitMetrics)
}

func (g Graphite) convertToGraphite(incomingMetric metric.Metric) (datapoint string) {
	//orders dimensions so datapoint keeps consistent name
	var keys []string
	dimensions := incomingMetric.GetDimensions(g.DefaultDimensions())
	for k := range dimensions {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	datapoint = g.Prefix() + incomingMetric.Name
	for _, key := range keys {
		datapoint = fmt.Sprintf("%s.%s.%s", datapoint, key, dimensions[key])
	}
	datapoint = fmt.Sprintf("%s %f %s\n", datapoint, incomingMetric.Value, incomingMetric.MetricTime)
	return datapoint
}

func (g *Graphite) emitMetrics(metrics []metric.Metric) bool {
	g.log.Info("Starting to emit ", len(metrics), " metrics")

	if len(metrics) == 0 {
		g.log.Warn("Skipping send because of an empty payload")
		return false
	}

	addr := fmt.Sprintf("%s:%s", g.server, g.port)
	conn, err := net.DialTimeout("tcp", addr, g.timeout)
	if err != nil {
		g.log.Error("Failed to connect ", addr)
		return false
	}

	for _, m := range metrics {
		fmt.Fprintf(conn, g.convertToGraphite(m))
	}
	return true
}
<commit_msg>use Unix timestamp<commit_after>package handler

import (
	"fmt"
	"fullerite/metric"
	"net"
	"sort"
	"time"

	l "github.com/Sirupsen/logrus"
)

func init() {
	RegisterHandler("Graphite", newGraphite)
}

// Graphite type
type Graphite struct {
	BaseHandler
	server string
	port   string
}

// newGraphite returns a new Graphite handler.
func newGraphite(
	channel chan metric.Metric,
	initialInterval int,
	initialBufferSize int,
	initialTimeout time.Duration,
	log *l.Entry) Handler {

	inst := new(Graphite)
	inst.name = "Graphite"

	inst.interval = initialInterval
	inst.maxBufferSize = initialBufferSize
	inst.timeout = initialTimeout
	inst.log = log
	inst.channel = channel

	return inst
}

// Server returns the Graphite server's name or IP
func (g Graphite) Server() string {
	return g.server
}

// Port returns the Graphite server's port number
func (g Graphite) Port() string {
	return g.port
}

// Configure accepts the different configuration options for the Graphite handler
func (g *Graphite) Configure(configMap map[string]interface{}) {
	if server, exists := configMap["server"]; exists {
		g.server = server.(string)
	} else {
		g.log.Error("There was no server specified for the Graphite Handler, there won't be any emissions")
	}

	if port, exists := configMap["port"]; exists {
		g.port = fmt.Sprint(port)
	} else {
		g.log.Error("There was no port specified for the Graphite Handler, there won't be any emissions")
	}
	g.configureCommonParams(configMap)
}

// Run runs the handler main loop
func (g *Graphite) Run() {
	g.run(g.emitMetrics)
}

func (g Graphite) convertToGraphite(incomingMetric metric.Metric) (datapoint string) {
	//orders dimensions so datapoint keeps consistent name
	var keys []string
	dimensions := incomingMetric.GetDimensions(g.DefaultDimensions())
	for k := range dimensions {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	datapoint = g.Prefix() + incomingMetric.Name
	for _, key := range keys {
		datapoint = fmt.Sprintf("%s.%s.%s", datapoint, key, dimensions[key])
	}
	datapoint = fmt.Sprintf("%s %f %d\n", datapoint, incomingMetric.Value, incomingMetric.MetricTime.Unix())
	return datapoint
}

func (g *Graphite) emitMetrics(metrics []metric.Metric) bool {
	g.log.Info("Starting to emit ", len(metrics), " metrics")

	if len(metrics) == 0 {
		g.log.Warn("Skipping send because of an empty payload")
		return false
	}

	addr := fmt.Sprintf("%s:%s", g.server, g.port)
	conn, err := net.DialTimeout("tcp", addr, g.timeout)
	if err != nil {
		g.log.Error("Failed to connect ", addr)
		return false
	}

	for _, m := range metrics {
		fmt.Fprintf(conn, g.convertToGraphite(m))
	}
	return true
}
<|endoftext|>


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

package net

import (
	"context"
	"errors"
	"io"
	"os"
)

func query(ctx context.Context, filename, query string, bufSize int) (res []string, err error) {
	file, err := os.OpenFile(filename, os.O_RDWR, 0)
	if err != nil {
		return
	}
	defer file.Close()

	_, err = file.Seek(0, io.SeekStart)
	if err != nil {
		return
	}
	_, err = file.WriteString(query)
	if err != nil {
		return
	}
	_, err = file.Seek(0, io.SeekStart)
	if err != nil {
		return
	}
	buf := make([]byte, bufSize)
	for {
		n, _ := file.Read(buf)
		if n <= 0 {
			break
		}
		res = append(res, string(buf[:n]))
	}
	return
}

func queryCS(ctx context.Context, net, host, service string) (res []string, err error) {
	switch net {
	case "tcp4", "tcp6":
		net = "tcp"
	case "udp4", "udp6":
		net = "udp"
	}
	if host == "" {
		host = "*"
	}
	return query(ctx, netdir+"/cs", net+"!"+host+"!"+service, 128)
}

func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest string, err error) {
	ips := "*"
	if len(ip) != 0 && !ip.IsUnspecified() {
		ips = ip.String()
	}
	lines, err := queryCS(ctx, net, ips, itoa(port))
	if err != nil {
		return
	}
	f := getFields(lines[0])
	if len(f) < 2 {
		return "", "", errors.New("bad response from ndb/cs")
	}
	clone, dest = f[0], f[1]
	return
}

func queryDNS(ctx context.Context, addr string, typ string) (res []string, err error) {
	return query(ctx, netdir+"/dns", addr+" "+typ, 1024)
}

// toLower returns a lower-case version of in. Restricting us to
// ASCII is sufficient to handle the IP protocol names and allow
// us to not depend on the strings and unicode packages.
func toLower(in string) string {
	for _, c := range in {
		if 'A' <= c && c <= 'Z' {
			// Has upper case; need to fix.
			out := []byte(in)
			for i := 0; i < len(in); i++ {
				c := in[i]
				if 'A' <= c && c <= 'Z' {
					c += 'a' - 'A'
				}
				out[i] = c
			}
			return string(out)
		}
	}
	return in
}

// lookupProtocol looks up IP protocol name and returns
// the corresponding protocol number.
func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
	lines, err := query(ctx, netdir+"/cs", "!protocol="+toLower(name), 128)
	if err != nil {
		return 0, err
	}
	if len(lines) == 0 {
		return 0, UnknownNetworkError(name)
	}
	f := getFields(lines[0])
	if len(f) < 2 {
		return 0, UnknownNetworkError(name)
	}
	s := f[1]
	if n, _, ok := dtoi(s[byteIndex(s, '=')+1:]); ok {
		return n, nil
	}
	return 0, UnknownNetworkError(name)
}

func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
	// Use netdir/cs instead of netdir/dns because cs knows about
	// host names in local network (e.g. from /lib/ndb/local)
	lines, err := queryCS(ctx, "net", host, "1")
	if err != nil {
		return
	}
loop:
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 2 {
			continue
		}
		addr := f[1]
		if i := byteIndex(addr, '!'); i >= 0 {
			addr = addr[:i] // remove port
		}
		if ParseIP(addr) == nil {
			continue
		}
		// only return unique addresses
		for _, a := range addrs {
			if a == addr {
				continue loop
			}
		}
		addrs = append(addrs, addr)
	}
	return
}

func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
	lits, err := lookupHost(ctx, host)
	if err != nil {
		return
	}
	for _, lit := range lits {
		host, zone := splitHostZone(lit)
		if ip := ParseIP(host); ip != nil {
			addr := IPAddr{IP: ip, Zone: zone}
			addrs = append(addrs, addr)
		}
	}
	return
}

func lookupPort(ctx context.Context, network, service string) (port int, err error) {
	switch network {
	case "tcp4", "tcp6":
		network = "tcp"
	case "udp4", "udp6":
		network = "udp"
	}
	lines, err := queryCS(ctx, network, "127.0.0.1", service)
	if err != nil {
		return
	}
	unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service}
	if len(lines) == 0 {
		return 0, unknownPortError
	}
	f := getFields(lines[0])
	if len(f) < 2 {
		return 0, unknownPortError
	}
	s := f[1]
	if i := byteIndex(s, '!'); i >= 0 {
		s = s[i+1:] // remove address
	}
	if n, _, ok := dtoi(s); ok {
		return n, nil
	}
	return 0, unknownPortError
}

func lookupCNAME(ctx context.Context, name string) (cname string, err error) {
	lines, err := queryDNS(ctx, name, "cname")
	if err != nil {
		return
	}
	if len(lines) > 0 {
		if f := getFields(lines[0]); len(f) >= 3 {
			return f[2] + ".", nil
		}
	}
	return "", errors.New("bad response from ndb/dns")
}

func lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
	var target string
	if service == "" && proto == "" {
		target = name
	} else {
		target = "_" + service + "._" + proto + "." + name
	}
	lines, err := queryDNS(ctx, target, "srv")
	if err != nil {
		return
	}
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 6 {
			continue
		}
		port, _, portOk := dtoi(f[4])
		priority, _, priorityOk := dtoi(f[3])
		weight, _, weightOk := dtoi(f[2])
		if !(portOk && priorityOk && weightOk) {
			continue
		}
		addrs = append(addrs, &SRV{absDomainName([]byte(f[5])), uint16(port), uint16(priority), uint16(weight)})
		cname = absDomainName([]byte(f[0]))
	}
	byPriorityWeight(addrs).sort()
	return
}

func lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
	lines, err := queryDNS(ctx, name, "mx")
	if err != nil {
		return
	}
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 4 {
			continue
		}
		if pref, _, ok := dtoi(f[2]); ok {
			mx = append(mx, &MX{absDomainName([]byte(f[3])), uint16(pref)})
		}
	}
	byPref(mx).sort()
	return
}

func lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
	lines, err := queryDNS(ctx, name, "ns")
	if err != nil {
		return
	}
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 3 {
			continue
		}
		ns = append(ns, &NS{absDomainName([]byte(f[2]))})
	}
	return
}

func lookupTXT(ctx context.Context, name string) (txt []string, err error) {
	lines, err := queryDNS(ctx, name, "txt")
	if err != nil {
		return
	}
	for _, line := range lines {
		if i := byteIndex(line, '\t'); i >= 0 {
			txt = append(txt, absDomainName([]byte(line[i+1:])))
		}
	}
	return
}

func lookupAddr(ctx context.Context, addr string) (name []string, err error) {
	arpa, err := reverseaddr(addr)
	if err != nil {
		return
	}
	lines, err := queryDNS(ctx, arpa, "ptr")
	if err != nil {
		return
	}
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 3 {
			continue
		}
		name = append(name, absDomainName([]byte(f[2])))
	}
	return
}
<commit_msg>net: make lookupPort case-insensitive on Plan 9<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"context"
	"errors"
	"io"
	"os"
)

func query(ctx context.Context, filename, query string, bufSize int) (res []string, err error) {
	file, err := os.OpenFile(filename, os.O_RDWR, 0)
	if err != nil {
		return
	}
	defer file.Close()

	_, err = file.Seek(0, io.SeekStart)
	if err != nil {
		return
	}
	_, err = file.WriteString(query)
	if err != nil {
		return
	}
	_, err = file.Seek(0, io.SeekStart)
	if err != nil {
		return
	}
	buf := make([]byte, bufSize)
	for {
		n, _ := file.Read(buf)
		if n <= 0 {
			break
		}
		res = append(res, string(buf[:n]))
	}
	return
}

func queryCS(ctx context.Context, net, host, service string) (res []string, err error) {
	switch net {
	case "tcp4", "tcp6":
		net = "tcp"
	case "udp4", "udp6":
		net = "udp"
	}
	if host == "" {
		host = "*"
	}
	return query(ctx, netdir+"/cs", net+"!"+host+"!"+service, 128)
}

func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest string, err error) {
	ips := "*"
	if len(ip) != 0 && !ip.IsUnspecified() {
		ips = ip.String()
	}
	lines, err := queryCS(ctx, net, ips, itoa(port))
	if err != nil {
		return
	}
	f := getFields(lines[0])
	if len(f) < 2 {
		return "", "", errors.New("bad response from ndb/cs")
	}
	clone, dest = f[0], f[1]
	return
}

func queryDNS(ctx context.Context, addr string, typ string) (res []string, err error) {
	return query(ctx, netdir+"/dns", addr+" "+typ, 1024)
}

// toLower returns a lower-case version of in. Restricting us to
// ASCII is sufficient to handle the IP protocol names and allow
// us to not depend on the strings and unicode packages.
func toLower(in string) string {
	for _, c := range in {
		if 'A' <= c && c <= 'Z' {
			// Has upper case; need to fix.
			out := []byte(in)
			for i := 0; i < len(in); i++ {
				c := in[i]
				if 'A' <= c && c <= 'Z' {
					c += 'a' - 'A'
				}
				out[i] = c
			}
			return string(out)
		}
	}
	return in
}

// lookupProtocol looks up IP protocol name and returns
// the corresponding protocol number.
func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
	lines, err := query(ctx, netdir+"/cs", "!protocol="+toLower(name), 128)
	if err != nil {
		return 0, err
	}
	if len(lines) == 0 {
		return 0, UnknownNetworkError(name)
	}
	f := getFields(lines[0])
	if len(f) < 2 {
		return 0, UnknownNetworkError(name)
	}
	s := f[1]
	if n, _, ok := dtoi(s[byteIndex(s, '=')+1:]); ok {
		return n, nil
	}
	return 0, UnknownNetworkError(name)
}

func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
	// Use netdir/cs instead of netdir/dns because cs knows about
	// host names in local network (e.g. from /lib/ndb/local)
	lines, err := queryCS(ctx, "net", host, "1")
	if err != nil {
		return
	}
loop:
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 2 {
			continue
		}
		addr := f[1]
		if i := byteIndex(addr, '!'); i >= 0 {
			addr = addr[:i] // remove port
		}
		if ParseIP(addr) == nil {
			continue
		}
		// only return unique addresses
		for _, a := range addrs {
			if a == addr {
				continue loop
			}
		}
		addrs = append(addrs, addr)
	}
	return
}

func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
	lits, err := lookupHost(ctx, host)
	if err != nil {
		return
	}
	for _, lit := range lits {
		host, zone := splitHostZone(lit)
		if ip := ParseIP(host); ip != nil {
			addr := IPAddr{IP: ip, Zone: zone}
			addrs = append(addrs, addr)
		}
	}
	return
}

func lookupPort(ctx context.Context, network, service string) (port int, err error) {
	switch network {
	case "tcp4", "tcp6":
		network = "tcp"
	case "udp4", "udp6":
		network = "udp"
	}
	lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service))
	if err != nil {
		return
	}
	unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service}
	if len(lines) == 0 {
		return 0, unknownPortError
	}
	f := getFields(lines[0])
	if len(f) < 2 {
		return 0, unknownPortError
	}
	s := f[1]
	if i := byteIndex(s, '!'); i >= 0 {
		s = s[i+1:] // remove address
	}
	if n, _, ok := dtoi(s); ok {
		return n, nil
	}
	return 0, unknownPortError
}

func lookupCNAME(ctx context.Context, name string) (cname string, err error) {
	lines, err := queryDNS(ctx, name, "cname")
	if err != nil {
		return
	}
	if len(lines) > 0 {
		if f := getFields(lines[0]); len(f) >= 3 {
			return f[2] + ".", nil
		}
	}
	return "", errors.New("bad response from ndb/dns")
}

func lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
	var target string
	if service == "" && proto == "" {
		target = name
	} else {
		target = "_" + service + "._" + proto + "." + name
	}
	lines, err := queryDNS(ctx, target, "srv")
	if err != nil {
		return
	}
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 6 {
			continue
		}
		port, _, portOk := dtoi(f[4])
		priority, _, priorityOk := dtoi(f[3])
		weight, _, weightOk := dtoi(f[2])
		if !(portOk && priorityOk && weightOk) {
			continue
		}
		addrs = append(addrs, &SRV{absDomainName([]byte(f[5])), uint16(port), uint16(priority), uint16(weight)})
		cname = absDomainName([]byte(f[0]))
	}
	byPriorityWeight(addrs).sort()
	return
}

func lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
	lines, err := queryDNS(ctx, name, "mx")
	if err != nil {
		return
	}
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 4 {
			continue
		}
		if pref, _, ok := dtoi(f[2]); ok {
			mx = append(mx, &MX{absDomainName([]byte(f[3])), uint16(pref)})
		}
	}
	byPref(mx).sort()
	return
}

func lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
	lines, err := queryDNS(ctx, name, "ns")
	if err != nil {
		return
	}
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 3 {
			continue
		}
		ns = append(ns, &NS{absDomainName([]byte(f[2]))})
	}
	return
}

func lookupTXT(ctx context.Context, name string) (txt []string, err error) {
	lines, err := queryDNS(ctx, name, "txt")
	if err != nil {
		return
	}
	for _, line := range lines {
		if i := byteIndex(line, '\t'); i >= 0 {
			txt = append(txt, absDomainName([]byte(line[i+1:])))
		}
	}
	return
}

func lookupAddr(ctx context.Context, addr string) (name []string, err error) {
	arpa, err := reverseaddr(addr)
	if err != nil {
		return
	}
	lines, err := queryDNS(ctx, arpa, "ptr")
	if err != nil {
		return
	}
	for _, line := range lines {
		f := getFields(line)
		if len(f) < 3 {
			continue
		}
		name = append(name, absDomainName([]byte(f[2])))
	}
	return
}
<|endoftext|>


<commit_before>package tree
/*
#include <libxml/tree.h>
*/
import "C"
import "unsafe"

type Element struct {
	*XmlNode
}

func (node *Element) ElementType() int {
	elem := (*C.xmlElement)(unsafe.Pointer(node.ptr()))
	return int(elem.etype)
}

func (node *Element) new(ptr *C.xmlNode) *Element {
	if ptr == nil {
		return nil
	}
	return NewNode(unsafe.Pointer(ptr), node.Doc()).(*Element)
}

func (node *Element) NextElement() *Element {
	return node.new(C.xmlNextElementSibling(node.NodePtr))
}

func (node *Element) PrevElement() *Element {
	return node.new(C.xmlPreviousElementSibling(node.NodePtr))
}

func (node *Element) FirstElement() *Element {
	return node.new(C.xmlFirstElementChild(node.NodePtr))
}

func (node *Element) LastElement() *Element {
	return node.new(C.xmlLastElementChild(node.NodePtr))
}

func (node *Element) Clear() {
	// Remember, as we delete them, the last one moves to the front
	child := node.First()
	for child != nil {
		child.Remove()
		child = node.First()
	}
}

func (node *Element) Content() string {
	child := node.First()
	output := ""
	for child != nil {
		output = output + child.DumpHTML()
		child = child.Next()
	}
	return output
}

func (node *Element) SetContent(content string) {
	node.Clear()
	node.AppendContent(content)
}

func (node *Element) AppendContent(content string) {
	newDoc := XmlParseFragment(content)

	defer newDoc.Free()
	child := newDoc.RootElement().First()
	for child != nil {
		//need to save the next sibling before appending it,
		//because once it loses its link to the next sibling in its original tree once appended to the new doc
		nextChild := child.Next()
		node.AppendChildNode(child)
		child = nextChild
	}
}

func (node *Element) PrependContent(content string) {
	newDoc := XmlParseFragment(content)

	defer newDoc.Free()
	child := newDoc.RootElement().Last()
	for child != nil {
		prevChild := child.Prev()
		node.PrependChildNode(child)
		child = prevChild
	}
}

func (node *Element) AddContentAfter(content string) {
    newDoc := XmlParseFragment(content)
    defer newDoc.Free()
	child := newDoc.Parent().Last()
	for child != nil {
		node.AddNodeAfter(child)
		child = child.Prev()
	}
}
func (node *Element) AddContentBefore(content string) {
    newDoc := XmlParseFragment(content)
    defer newDoc.Free()

	child := newDoc.Parent().First()
	for child != nil {
		node.AddNodeBefore(child)
		child = child.Next()
	}
}
<commit_msg>revert HC's change; it would otherwise leak memory<commit_after>package tree
/*
#include <libxml/tree.h>
*/
import "C"
import "unsafe"

type Element struct {
	*XmlNode
}

func (node *Element) ElementType() int {
	elem := (*C.xmlElement)(unsafe.Pointer(node.ptr()))
	return int(elem.etype)
}

func (node *Element) new(ptr *C.xmlNode) *Element {
	if ptr == nil {
		return nil
	}
	return NewNode(unsafe.Pointer(ptr), node.Doc()).(*Element)
}

func (node *Element) NextElement() *Element {
	return node.new(C.xmlNextElementSibling(node.NodePtr))
}

func (node *Element) PrevElement() *Element {
	return node.new(C.xmlPreviousElementSibling(node.NodePtr))
}

func (node *Element) FirstElement() *Element {
	return node.new(C.xmlFirstElementChild(node.NodePtr))
}

func (node *Element) LastElement() *Element {
	return node.new(C.xmlLastElementChild(node.NodePtr))
}

func (node *Element) Clear() {
	// Remember, as we delete them, the last one moves to the front
	child := node.First()
	for child != nil {
		child.Remove()
    child.Free()
		child = node.First()
	}
}

func (node *Element) Content() string {
	child := node.First()
	output := ""
	for child != nil {
		output = output + child.DumpHTML()
		child = child.Next()
	}
	return output
}

func (node *Element) SetContent(content string) {
	node.Clear()
	node.AppendContent(content)
}

func (node *Element) AppendContent(content string) {
	newDoc := XmlParseFragment(content)

	defer newDoc.Free()
	child := newDoc.RootElement().First()
	for child != nil {
		//need to save the next sibling before appending it,
		//because once it loses its link to the next sibling in its original tree once appended to the new doc
		nextChild := child.Next()
		node.AppendChildNode(child)
		child = nextChild
	}
}

func (node *Element) PrependContent(content string) {
	newDoc := XmlParseFragment(content)

	defer newDoc.Free()
	child := newDoc.RootElement().Last()
	for child != nil {
		prevChild := child.Prev()
		node.PrependChildNode(child)
		child = prevChild
	}
}

func (node *Element) AddContentAfter(content string) {
    newDoc := XmlParseFragment(content)
    defer newDoc.Free()
	child := newDoc.Parent().Last()
	for child != nil {
    prevChild := child.Prev()
		node.AddNodeAfter(child)
		child = prevChild
	}
}
func (node *Element) AddContentBefore(content string) {
    newDoc := XmlParseFragment(content)
    defer newDoc.Free()

	child := newDoc.Parent().First()
	for child != nil {
    nextChild := child.Next()
		node.AddNodeBefore(child)
		child = nextChild
	}
}
<|endoftext|>


<commit_before>package gateway

import (
	"strconv"
	"testing"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/consensus"
)

// TestPeerSharing tests that peers are correctly shared.
func TestPeerSharing(t *testing.T) {
	g := newTestingGateway("TestPeerSharing", t)
	defer g.Close()

	// add a peer
	peer := modules.NetAddress("foo:9001")
	g.AddPeer(peer)
	// gateway only has one peer, so randomPeer should return peer
	if p, err := g.randomPeer(); err != nil || p != peer {
		t.Fatal("gateway has bad peer list:", g.Info().Peers)
	}

	// ask gateway for peers
	var peers []modules.NetAddress
	err := g.RPC(g.myAddr, "SharePeers", readerRPC(&peers, 1024))
	if err != nil {
		t.Fatal(err)
	}
	// response should be exactly []Address{peer}
	if len(peers) != 1 || peers[0] != peer {
		t.Fatal("gateway gave bad peer list:", peers)
	}

	// add a couple more peers
	g.AddPeer("bar:9002")
	g.AddPeer("baz:9003")
	g.AddPeer("quux:9004")
	err = g.RPC(g.myAddr, "SharePeers", readerRPC(&peers, 1024))
	if err != nil {
		t.Fatal(err)
	}
	// peers should now contain 4 distinct addresses
	for i := 0; i < len(peers); i++ {
		for j := i + 1; j < len(peers); j++ {
			if peers[i] == peers[j] {
				t.Fatal("gateway gave duplicate addresses:", peers)
			}
		}
	}

	// remove all the peers
	g.RemovePeer("foo:9001")
	g.RemovePeer("bar:9002")
	g.RemovePeer("baz:9003")
	g.RemovePeer("quux:9004")
	if len(g.peers) != 0 {
		t.Fatal("gateway has peers remaining after removal:", g.Info().Peers)
	}

	// no peers should be returned
	err = g.RPC(g.myAddr, "SharePeers", readerRPC(&peers, 1024))
	if err != nil {
		t.Fatal(err)
	}
	if len(peers) != 0 {
		t.Fatal("gateway gave non-existent addresses:", peers)
	}
}

// TestBadPeer tests that "bad" peers are correctly identified and removed.
func TestBadPeer(t *testing.T) {
	g := newTestingGateway("TestBadPeer1", t)
	defer g.Close()

	// create bad peer
	badpeer := newTestingGateway("TestBadPeer2", t)
	// overwrite badpeer's Ping RPC with an incorrect one
	badpeer.RegisterRPC("Ping", writerRPC("lol"))

	g.AddPeer(badpeer.Address())

	// try to ping the peer 'maxStrikes'+1 times
	for i := 0; i < maxStrikes+1; i++ {
		g.Ping(badpeer.Address())
	}

	// since we are poorly-connected, badpeer should still be in our peer list
	if len(g.peers) != 1 {
		t.Fatal("gateway removed peer when poorly-connected:", g.Info().Peers)
	}

	// add minPeers more peers
	for i := 0; i < minPeers; i++ {
		g.AddPeer(modules.NetAddress("foo" + strconv.Itoa(i)))
	}

	// once we exceed minPeers, badpeer should be kicked out
	if len(g.peers) != minPeers {
		t.Fatal("gateway did not remove bad peer after becoming well-connected:", g.Info().Peers)
	} else if _, ok := g.peers[badpeer.Address()]; ok {
		t.Fatal("gateway removed wrong peer:", g.Info().Peers)
	}
}

// TestBootstrap tests the bootstrapping process, including synchronization.
func TestBootstrap(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	// create bootstrap peer
	bootstrap := newTestingGateway("TestBootstrap1", t)
	ct := consensus.NewConsensusTester(t, bootstrap.state)
	// give it some blocks
	for i := 0; i < MaxCatchUpBlocks*2+1; i++ {
		ct.MineAndApplyValidBlock()
	}
	// give it a peer
	bootstrap.AddPeer(newTestingGateway("TestBootstrap2", t).Address())

	// bootstrap a new peer
	g := newTestingGateway("TestBootstrap3", t)
	err := g.Bootstrap(bootstrap.Address())
	if err != nil {
		t.Fatal(err)
	}

	// heights should match
	if g.state.Height() != bootstrap.state.Height() {
		// g may have tried to synchronize to the other peer, so try manually
		// synchronizing to the bootstrap
		g.Synchronize(bootstrap.Address())
		if g.state.Height() != bootstrap.state.Height() {
			t.Fatalf("gateway height %v does not match bootstrap height %v", g.state.Height(), bootstrap.state.Height())
		}
	}
	// peer lists should be the same size, though they won't match; bootstrap
	// will have g and g will have bootstrap.
	if len(g.Info().Peers) != len(bootstrap.Info().Peers) {
		t.Fatalf("gateway peer list %v does not match bootstrap peer list %v", g.Info().Peers, bootstrap.Info().Peers)
	}

	// add another two peers to bootstrap: a real peer and a "dummy", which won't respond.
	bootstrap.AddPeer(newTestingGateway("TestBootstrap4", t).Address())
	bootstrap.AddPeer("dummy")

	// have g request peers from bootstrap. g should add the real peer, but not the dummy.
	g.threadedPeerDiscovery()
	if len(g.Info().Peers) != len(bootstrap.Info().Peers)-1 {
		t.Fatal("gateway added wrong peers:", g.Info().Peers)
	}
}
<commit_msg>remove defunct peer add test<commit_after>package gateway

import (
	"strconv"
	"testing"

	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/modules/consensus"
)

// TestPeerSharing tests that peers are correctly shared.
func TestPeerSharing(t *testing.T) {
	g := newTestingGateway("TestPeerSharing", t)
	defer g.Close()

	// add a peer
	peer := modules.NetAddress("foo:9001")
	g.AddPeer(peer)
	// gateway only has one peer, so randomPeer should return peer
	if p, err := g.randomPeer(); err != nil || p != peer {
		t.Fatal("gateway has bad peer list:", g.Info().Peers)
	}

	// ask gateway for peers
	var peers []modules.NetAddress
	err := g.RPC(g.myAddr, "SharePeers", readerRPC(&peers, 1024))
	if err != nil {
		t.Fatal(err)
	}
	// response should be exactly []Address{peer}
	if len(peers) != 1 || peers[0] != peer {
		t.Fatal("gateway gave bad peer list:", peers)
	}

	// add a couple more peers
	g.AddPeer("bar:9002")
	g.AddPeer("baz:9003")
	g.AddPeer("quux:9004")
	err = g.RPC(g.myAddr, "SharePeers", readerRPC(&peers, 1024))
	if err != nil {
		t.Fatal(err)
	}
	// peers should now contain 4 distinct addresses
	for i := 0; i < len(peers); i++ {
		for j := i + 1; j < len(peers); j++ {
			if peers[i] == peers[j] {
				t.Fatal("gateway gave duplicate addresses:", peers)
			}
		}
	}

	// remove all the peers
	g.RemovePeer("foo:9001")
	g.RemovePeer("bar:9002")
	g.RemovePeer("baz:9003")
	g.RemovePeer("quux:9004")
	if len(g.peers) != 0 {
		t.Fatal("gateway has peers remaining after removal:", g.Info().Peers)
	}

	// no peers should be returned
	err = g.RPC(g.myAddr, "SharePeers", readerRPC(&peers, 1024))
	if err != nil {
		t.Fatal(err)
	}
	if len(peers) != 0 {
		t.Fatal("gateway gave non-existent addresses:", peers)
	}
}

// TestBadPeer tests that "bad" peers are correctly identified and removed.
func TestBadPeer(t *testing.T) {
	g := newTestingGateway("TestBadPeer1", t)
	defer g.Close()

	// create bad peer
	badpeer := newTestingGateway("TestBadPeer2", t)
	// overwrite badpeer's Ping RPC with an incorrect one
	badpeer.RegisterRPC("Ping", writerRPC("lol"))

	g.AddPeer(badpeer.Address())

	// try to ping the peer 'maxStrikes'+1 times
	for i := 0; i < maxStrikes+1; i++ {
		g.Ping(badpeer.Address())
	}

	// since we are poorly-connected, badpeer should still be in our peer list
	if len(g.peers) != 1 {
		t.Fatal("gateway removed peer when poorly-connected:", g.Info().Peers)
	}

	// add minPeers more peers
	for i := 0; i < minPeers; i++ {
		g.AddPeer(modules.NetAddress("foo" + strconv.Itoa(i)))
	}

	// once we exceed minPeers, badpeer should be kicked out
	if len(g.peers) != minPeers {
		t.Fatal("gateway did not remove bad peer after becoming well-connected:", g.Info().Peers)
	} else if _, ok := g.peers[badpeer.Address()]; ok {
		t.Fatal("gateway removed wrong peer:", g.Info().Peers)
	}
}

// TestBootstrap tests the bootstrapping process, including synchronization.
func TestBootstrap(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	// create bootstrap peer
	bootstrap := newTestingGateway("TestBootstrap1", t)
	ct := consensus.NewConsensusTester(t, bootstrap.state)
	// give it some blocks
	for i := 0; i < MaxCatchUpBlocks*2+1; i++ {
		ct.MineAndApplyValidBlock()
	}
	// give it a peer
	bootstrap.AddPeer(newTestingGateway("TestBootstrap2", t).Address())

	// bootstrap a new peer
	g := newTestingGateway("TestBootstrap3", t)
	err := g.Bootstrap(bootstrap.Address())
	if err != nil {
		t.Fatal(err)
	}

	// heights should match
	if g.state.Height() != bootstrap.state.Height() {
		// g may have tried to synchronize to the other peer, so try manually
		// synchronizing to the bootstrap
		g.Synchronize(bootstrap.Address())
		if g.state.Height() != bootstrap.state.Height() {
			t.Fatalf("gateway height %v does not match bootstrap height %v", g.state.Height(), bootstrap.state.Height())
		}
	}
	// peer lists should be the same size, though they won't match; bootstrap
	// will have g and g will have bootstrap.
	if len(g.Info().Peers) != len(bootstrap.Info().Peers) {
		t.Fatalf("gateway peer list %v does not match bootstrap peer list %v", g.Info().Peers, bootstrap.Info().Peers)
	}
}
<|endoftext|>


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

// This file contains printing suppport for ASTs.

package ast

import (
	"fmt"
	"go/token"
	"io"
	"os"
	"reflect"
)

// A FieldFilter may be provided to Fprint to control the output.
type FieldFilter func(name string, value reflect.Value) bool

// NotNilFilter returns true for field values that are not nil;
// it returns false otherwise.
func NotNilFilter(_ string, value reflect.Value) bool {
	v, ok := value.(interface {
		IsNil() bool
	})
	return !ok || !v.IsNil()
}

// Fprint prints the (sub-)tree starting at AST node x to w.
// If fset != nil, position information is interpreted relative
// to that file set. Otherwise positions are printed as integer
// values (file set specific offsets).
//
// A non-nil FieldFilter f may be provided to control the output:
// struct fields for which f(fieldname, fieldvalue) is true are
// are printed; all others are filtered from the output.
//
func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n int, err os.Error) {
	// setup printer
	p := printer{
		output: w,
		fset:   fset,
		filter: f,
		ptrmap: make(map[interface{}]int),
		last:   '\n', // force printing of line number on first line
	}

	// install error handler
	defer func() {
		n = p.written
		if e := recover(); e != nil {
			err = e.(localError).err // re-panics if it's not a localError
		}
	}()

	// print x
	if x == nil {
		p.printf("nil\n")
		return
	}
	p.print(reflect.NewValue(x))
	p.printf("\n")

	return
}

// Print prints x to standard output, skipping nil fields.
// Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
	return Fprint(os.Stdout, fset, x, NotNilFilter)
}

type printer struct {
	output  io.Writer
	fset    *token.FileSet
	filter  FieldFilter
	ptrmap  map[interface{}]int // *reflect.PtrValue -> line number
	written int                 // number of bytes written to output
	indent  int                 // current indentation level
	last    byte                // the last byte processed by Write
	line    int                 // current line number
}

var indent = []byte(".  ")

func (p *printer) Write(data []byte) (n int, err os.Error) {
	var m int
	for i, b := range data {
		// invariant: data[0:n] has been written
		if b == '\n' {
			m, err = p.output.Write(data[n : i+1])
			n += m
			if err != nil {
				return
			}
			p.line++
		} else if p.last == '\n' {
			_, err = fmt.Fprintf(p.output, "%6d  ", p.line)
			if err != nil {
				return
			}
			for j := p.indent; j > 0; j-- {
				_, err = p.output.Write(indent)
				if err != nil {
					return
				}
			}
		}
		p.last = b
	}
	m, err = p.output.Write(data[n:])
	n += m
	return
}

// localError wraps locally caught os.Errors so we can distinguish
// them from genuine panics which we don't want to return as errors.
type localError struct {
	err os.Error
}

// printf is a convenience wrapper that takes care of print errors.
func (p *printer) printf(format string, args ...interface{}) {
	n, err := fmt.Fprintf(p, format, args...)
	p.written += n
	if err != nil {
		panic(localError{err})
	}
}

// Implementation note: Print is written for AST nodes but could be
// used to print arbitrary data structures; such a version should
// probably be in a different package.

func (p *printer) print(x reflect.Value) {
	if !NotNilFilter("", x) {
		p.printf("nil")
		return
	}

	switch v := x.(type) {
	case *reflect.InterfaceValue:
		p.print(v.Elem())

	case *reflect.MapValue:
		p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
		p.indent++
		for _, key := range v.Keys() {
			p.print(key)
			p.printf(": ")
			p.print(v.Elem(key))
		}
		p.indent--
		p.printf("}")

	case *reflect.PtrValue:
		p.printf("*")
		// type-checked ASTs may contain cycles - use ptrmap
		// to keep track of objects that have been printed
		// already and print the respective line number instead
		ptr := v.Interface()
		if line, exists := p.ptrmap[ptr]; exists {
			p.printf("(obj @ %d)", line)
		} else {
			p.ptrmap[ptr] = p.line
			p.print(v.Elem())
		}

	case *reflect.SliceValue:
		if s, ok := v.Interface().([]byte); ok {
			p.printf("%#q", s)
			return
		}
		p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
		p.indent++
		for i, n := 0, v.Len(); i < n; i++ {
			p.printf("%d: ", i)
			p.print(v.Elem(i))
			p.printf("\n")
		}
		p.indent--
		p.printf("}")

	case *reflect.StructValue:
		p.printf("%s {\n", x.Type().String())
		p.indent++
		t := v.Type().(*reflect.StructType)
		for i, n := 0, t.NumField(); i < n; i++ {
			name := t.Field(i).Name
			value := v.Field(i)
			if p.filter == nil || p.filter(name, value) {
				p.printf("%s: ", name)
				p.print(value)
				p.printf("\n")
			}
		}
		p.indent--
		p.printf("}")

	default:
		value := x.Interface()
		// position values can be printed nicely if we have a file set
		if pos, ok := value.(token.Pos); ok && p.fset != nil {
			value = p.fset.Position(pos)
		}
		p.printf("%v", value)
	}
}
<commit_msg>go/ast: fix printing of maps<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains printing suppport for ASTs.

package ast

import (
	"fmt"
	"go/token"
	"io"
	"os"
	"reflect"
)

// A FieldFilter may be provided to Fprint to control the output.
type FieldFilter func(name string, value reflect.Value) bool

// NotNilFilter returns true for field values that are not nil;
// it returns false otherwise.
func NotNilFilter(_ string, value reflect.Value) bool {
	v, ok := value.(interface {
		IsNil() bool
	})
	return !ok || !v.IsNil()
}

// Fprint prints the (sub-)tree starting at AST node x to w.
// If fset != nil, position information is interpreted relative
// to that file set. Otherwise positions are printed as integer
// values (file set specific offsets).
//
// A non-nil FieldFilter f may be provided to control the output:
// struct fields for which f(fieldname, fieldvalue) is true are
// are printed; all others are filtered from the output.
//
func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n int, err os.Error) {
	// setup printer
	p := printer{
		output: w,
		fset:   fset,
		filter: f,
		ptrmap: make(map[interface{}]int),
		last:   '\n', // force printing of line number on first line
	}

	// install error handler
	defer func() {
		n = p.written
		if e := recover(); e != nil {
			err = e.(localError).err // re-panics if it's not a localError
		}
	}()

	// print x
	if x == nil {
		p.printf("nil\n")
		return
	}
	p.print(reflect.NewValue(x))
	p.printf("\n")

	return
}

// Print prints x to standard output, skipping nil fields.
// Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
	return Fprint(os.Stdout, fset, x, NotNilFilter)
}

type printer struct {
	output  io.Writer
	fset    *token.FileSet
	filter  FieldFilter
	ptrmap  map[interface{}]int // *reflect.PtrValue -> line number
	written int                 // number of bytes written to output
	indent  int                 // current indentation level
	last    byte                // the last byte processed by Write
	line    int                 // current line number
}

var indent = []byte(".  ")

func (p *printer) Write(data []byte) (n int, err os.Error) {
	var m int
	for i, b := range data {
		// invariant: data[0:n] has been written
		if b == '\n' {
			m, err = p.output.Write(data[n : i+1])
			n += m
			if err != nil {
				return
			}
			p.line++
		} else if p.last == '\n' {
			_, err = fmt.Fprintf(p.output, "%6d  ", p.line)
			if err != nil {
				return
			}
			for j := p.indent; j > 0; j-- {
				_, err = p.output.Write(indent)
				if err != nil {
					return
				}
			}
		}
		p.last = b
	}
	m, err = p.output.Write(data[n:])
	n += m
	return
}

// localError wraps locally caught os.Errors so we can distinguish
// them from genuine panics which we don't want to return as errors.
type localError struct {
	err os.Error
}

// printf is a convenience wrapper that takes care of print errors.
func (p *printer) printf(format string, args ...interface{}) {
	n, err := fmt.Fprintf(p, format, args...)
	p.written += n
	if err != nil {
		panic(localError{err})
	}
}

// Implementation note: Print is written for AST nodes but could be
// used to print arbitrary data structures; such a version should
// probably be in a different package.

func (p *printer) print(x reflect.Value) {
	if !NotNilFilter("", x) {
		p.printf("nil")
		return
	}

	switch v := x.(type) {
	case *reflect.InterfaceValue:
		p.print(v.Elem())

	case *reflect.MapValue:
		p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
		p.indent++
		for _, key := range v.Keys() {
			p.print(key)
			p.printf(": ")
			p.print(v.Elem(key))
			p.printf("\n")
		}
		p.indent--
		p.printf("}")

	case *reflect.PtrValue:
		p.printf("*")
		// type-checked ASTs may contain cycles - use ptrmap
		// to keep track of objects that have been printed
		// already and print the respective line number instead
		ptr := v.Interface()
		if line, exists := p.ptrmap[ptr]; exists {
			p.printf("(obj @ %d)", line)
		} else {
			p.ptrmap[ptr] = p.line
			p.print(v.Elem())
		}

	case *reflect.SliceValue:
		if s, ok := v.Interface().([]byte); ok {
			p.printf("%#q", s)
			return
		}
		p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
		p.indent++
		for i, n := 0, v.Len(); i < n; i++ {
			p.printf("%d: ", i)
			p.print(v.Elem(i))
			p.printf("\n")
		}
		p.indent--
		p.printf("}")

	case *reflect.StructValue:
		p.printf("%s {\n", x.Type().String())
		p.indent++
		t := v.Type().(*reflect.StructType)
		for i, n := 0, t.NumField(); i < n; i++ {
			name := t.Field(i).Name
			value := v.Field(i)
			if p.filter == nil || p.filter(name, value) {
				p.printf("%s: ", name)
				p.print(value)
				p.printf("\n")
			}
		}
		p.indent--
		p.printf("}")

	default:
		value := x.Interface()
		// position values can be printed nicely if we have a file set
		if pos, ok := value.(token.Pos); ok && p.fset != nil {
			value = p.fset.Position(pos)
		}
		p.printf("%v", value)
	}
}
<|endoftext|>


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

// This file implements scopes and the objects they contain.

package ast

import (
	"bytes"
	"fmt"
	"go/token"
)

// A Scope maintains the set of named language entities declared
// in the scope and a link to the immediately surrounding (outer)
// scope.
//
type Scope struct {
	Outer   *Scope
	Objects map[string]*Object
}

// NewScope creates a new scope nested in the outer scope.
func NewScope(outer *Scope) *Scope {
	const n = 4 // initial scope capacity
	return &Scope{outer, make(map[string]*Object, n)}
}

// Lookup returns the object with the given name if it is
// found in scope s, otherwise it returns nil. Outer scopes
// are ignored.
//
func (s *Scope) Lookup(name string) *Object {
	return s.Objects[name]
}

// Insert attempts to insert a named object obj into the scope s.
// If the scope already contains an object alt with the same name,
// Insert leaves the scope unchanged and returns alt. Otherwise
// it inserts obj and returns nil."
//
func (s *Scope) Insert(obj *Object) (alt *Object) {
	if alt = s.Objects[obj.Name]; alt == nil {
		s.Objects[obj.Name] = obj
	}
	return
}

// Debugging support
func (s *Scope) String() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "scope %p {", s)
	if s != nil && len(s.Objects) > 0 {
		fmt.Fprintln(&buf)
		for _, obj := range s.Objects {
			fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name)
		}
	}
	fmt.Fprintf(&buf, "}\n")
	return buf.String()
}

// ----------------------------------------------------------------------------
// Objects

// An Object describes a named language entity such as a package,
// constant, type, variable, function (incl. methods), or label.
//
// The Data fields contains object-specific data:
//
//	Kind    Data type         Data value
//	Pkg	*types.Package    package scope
//	Con     int               iota for the respective declaration
//	Con     != nil            constant value
//	Typ     *Scope            (used as method scope during type checking - transient)
//
type Object struct {
	Kind ObjKind
	Name string      // declared name
	Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
	Data interface{} // object-specific data; or nil
	Type interface{} // place holder for type information; may be nil
}

// NewObj creates a new object of a given kind and name.
func NewObj(kind ObjKind, name string) *Object {
	return &Object{Kind: kind, Name: name}
}

// Pos computes the source position of the declaration of an object name.
// The result may be an invalid position if it cannot be computed
// (obj.Decl may be nil or not correct).
func (obj *Object) Pos() token.Pos {
	name := obj.Name
	switch d := obj.Decl.(type) {
	case *Field:
		for _, n := range d.Names {
			if n.Name == name {
				return n.Pos()
			}
		}
	case *ImportSpec:
		if d.Name != nil && d.Name.Name == name {
			return d.Name.Pos()
		}
		return d.Path.Pos()
	case *ValueSpec:
		for _, n := range d.Names {
			if n.Name == name {
				return n.Pos()
			}
		}
	case *TypeSpec:
		if d.Name.Name == name {
			return d.Name.Pos()
		}
	case *FuncDecl:
		if d.Name.Name == name {
			return d.Name.Pos()
		}
	case *LabeledStmt:
		if d.Label.Name == name {
			return d.Label.Pos()
		}
	case *AssignStmt:
		for _, x := range d.Lhs {
			if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
				return ident.Pos()
			}
		}
	case *Scope:
		// predeclared object - nothing to do for now
	}
	return token.NoPos
}

// ObjKind describes what an object represents.
type ObjKind int

// The list of possible Object kinds.
const (
	Bad ObjKind = iota // for error handling
	Pkg                // package
	Con                // constant
	Typ                // type
	Var                // variable
	Fun                // function or method
	Lbl                // label
)

var objKindStrings = [...]string{
	Bad: "bad",
	Pkg: "package",
	Con: "const",
	Typ: "type",
	Var: "var",
	Fun: "func",
	Lbl: "label",
}

func (kind ObjKind) String() string { return objKindStrings[kind] }
<commit_msg>go/ast: fix typo in comment<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements scopes and the objects they contain.

package ast

import (
	"bytes"
	"fmt"
	"go/token"
)

// A Scope maintains the set of named language entities declared
// in the scope and a link to the immediately surrounding (outer)
// scope.
//
type Scope struct {
	Outer   *Scope
	Objects map[string]*Object
}

// NewScope creates a new scope nested in the outer scope.
func NewScope(outer *Scope) *Scope {
	const n = 4 // initial scope capacity
	return &Scope{outer, make(map[string]*Object, n)}
}

// Lookup returns the object with the given name if it is
// found in scope s, otherwise it returns nil. Outer scopes
// are ignored.
//
func (s *Scope) Lookup(name string) *Object {
	return s.Objects[name]
}

// Insert attempts to insert a named object obj into the scope s.
// If the scope already contains an object alt with the same name,
// Insert leaves the scope unchanged and returns alt. Otherwise
// it inserts obj and returns nil."
//
func (s *Scope) Insert(obj *Object) (alt *Object) {
	if alt = s.Objects[obj.Name]; alt == nil {
		s.Objects[obj.Name] = obj
	}
	return
}

// Debugging support
func (s *Scope) String() string {
	var buf bytes.Buffer
	fmt.Fprintf(&buf, "scope %p {", s)
	if s != nil && len(s.Objects) > 0 {
		fmt.Fprintln(&buf)
		for _, obj := range s.Objects {
			fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name)
		}
	}
	fmt.Fprintf(&buf, "}\n")
	return buf.String()
}

// ----------------------------------------------------------------------------
// Objects

// An Object describes a named language entity such as a package,
// constant, type, variable, function (incl. methods), or label.
//
// The Data fields contains object-specific data:
//
//	Kind    Data type         Data value
//	Pkg	*types.Package    package scope
//	Con     int               iota for the respective declaration
//	Con     != nil            constant value
//	Typ     *Scope            (used as method scope during type checking - transient)
//
type Object struct {
	Kind ObjKind
	Name string      // declared name
	Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
	Data interface{} // object-specific data; or nil
	Type interface{} // placeholder for type information; may be nil
}

// NewObj creates a new object of a given kind and name.
func NewObj(kind ObjKind, name string) *Object {
	return &Object{Kind: kind, Name: name}
}

// Pos computes the source position of the declaration of an object name.
// The result may be an invalid position if it cannot be computed
// (obj.Decl may be nil or not correct).
func (obj *Object) Pos() token.Pos {
	name := obj.Name
	switch d := obj.Decl.(type) {
	case *Field:
		for _, n := range d.Names {
			if n.Name == name {
				return n.Pos()
			}
		}
	case *ImportSpec:
		if d.Name != nil && d.Name.Name == name {
			return d.Name.Pos()
		}
		return d.Path.Pos()
	case *ValueSpec:
		for _, n := range d.Names {
			if n.Name == name {
				return n.Pos()
			}
		}
	case *TypeSpec:
		if d.Name.Name == name {
			return d.Name.Pos()
		}
	case *FuncDecl:
		if d.Name.Name == name {
			return d.Name.Pos()
		}
	case *LabeledStmt:
		if d.Label.Name == name {
			return d.Label.Pos()
		}
	case *AssignStmt:
		for _, x := range d.Lhs {
			if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
				return ident.Pos()
			}
		}
	case *Scope:
		// predeclared object - nothing to do for now
	}
	return token.NoPos
}

// ObjKind describes what an object represents.
type ObjKind int

// The list of possible Object kinds.
const (
	Bad ObjKind = iota // for error handling
	Pkg                // package
	Con                // constant
	Typ                // type
	Var                // variable
	Fun                // function or method
	Lbl                // label
)

var objKindStrings = [...]string{
	Bad: "bad",
	Pkg: "package",
	Con: "const",
	Typ: "type",
	Var: "var",
	Fun: "func",
	Lbl: "label",
}

func (kind ObjKind) String() string { return objKindStrings[kind] }
<|endoftext|>


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

package os_test

import (
	. "os"
	"testing"
	"syscall"
)

func TestMkdirAll(t *testing.T) {
	// Create new dir, in _obj so it will get
	// cleaned up by make if not by us.
	path := "_obj/_TestMkdirAll_/dir/./dir2"
	err := MkdirAll(path, 0777)
	if err != nil {
		t.Fatalf("MkdirAll %q: %s", path, err)
	}

	// Already exists, should succeed.
	err = MkdirAll(path, 0777)
	if err != nil {
		t.Fatalf("MkdirAll %q (second time): %s", path, err)
	}

	// Make file.
	fpath := path + "/file"
	_, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
	if err != nil {
		t.Fatalf("create %q: %s", fpath, err)
	}

	// Can't make directory named after file.
	err = MkdirAll(fpath, 0777)
	if err == nil {
		t.Fatalf("MkdirAll %q: no error", fpath)
	}
	perr, ok := err.(*PathError)
	if !ok {
		t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err)
	}
	if perr.Path != fpath {
		t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, perr.Path, fpath)
	}

	// Can't make subdirectory of file.
	ffpath := fpath + "/subdir"
	err = MkdirAll(ffpath, 0777)
	if err == nil {
		t.Fatalf("MkdirAll %q: no error", ffpath)
	}
	perr, ok = err.(*PathError)
	if !ok {
		t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err)
	}
	if perr.Path != fpath {
		t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, perr.Path, fpath)
	}

	RemoveAll("_obj/_TestMkdirAll_")
}

func TestRemoveAll(t *testing.T) {
	// Work directory.
	path := "_obj/_TestRemoveAll_"
	fpath := path + "/file"
	dpath := path + "/dir"

	// Make directory with 1 file and remove.
	if err := MkdirAll(path, 0777); err != nil {
		t.Fatalf("MkdirAll %q: %s", path, err)
	}
	fd, err := Open(fpath, O_WRONLY|O_CREAT, 0666)
	if err != nil {
		t.Fatalf("create %q: %s", fpath, err)
	}
	fd.Close()
	if err = RemoveAll(path); err != nil {
		t.Fatalf("RemoveAll %q (first): %s", path, err)
	}
	if _, err := Lstat(path); err == nil {
		t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
	}

	// Make directory with file and subdirectory and remove.
	if err = MkdirAll(dpath, 0777); err != nil {
		t.Fatalf("MkdirAll %q: %s", dpath, err)
	}
	fd, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
	if err != nil {
		t.Fatalf("create %q: %s", fpath, err)
	}
	fd.Close()
	fd, err = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
	if err != nil {
		t.Fatalf("create %q: %s", fpath, err)
	}
	fd.Close()
	if err = RemoveAll(path); err != nil {
		t.Fatalf("RemoveAll %q (second): %s", path, err)
	}
	if _, err := Lstat(path); err == nil {
		t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
	}

	// Determine if we should run the following test.
	testit := true
	if syscall.OS == "windows" {
		// Chmod is not supported under windows.
		testit = false
	} else {
		// Test fails as root.
		testit = Getuid() != 0
	}
	if testit {
		// Make directory with file and subdirectory and trigger error.
		if err = MkdirAll(dpath, 0777); err != nil {
			t.Fatalf("MkdirAll %q: %s", dpath, err)
		}

		for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
			fd, err = Open(s, O_WRONLY|O_CREAT, 0666)
			if err != nil {
				t.Fatalf("create %q: %s", s, err)
			}
			fd.Close()
		}
		if err = Chmod(dpath, 0); err != nil {
			t.Fatalf("Chmod %q 0: %s", dpath, err)
		}
		if err = RemoveAll(path); err == nil {
			_, err := Lstat(path)
			if err == nil {
				t.Errorf("Can lstat %q after supposed RemoveAll", path)
			}
			t.Fatalf("RemoveAll %q succeeded with chmod 0 subdirectory: err %s", path, err)
		}
		perr, ok := err.(*PathError)
		if !ok {
			t.Fatalf("RemoveAll %q returned %T not *PathError", path, err)
		}
		if perr.Path != dpath {
			t.Fatalf("RemoveAll %q failed at %q not %q", path, perr.Path, dpath)
		}
		if err = Chmod(dpath, 0777); err != nil {
			t.Fatalf("Chmod %q 0777: %s", dpath, err)
		}
		for _, s := range []string{fpath, path + "/zzz"} {
			if _, err := Lstat(s); err == nil {
				t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
			}
		}
	}
	if err = RemoveAll(path); err != nil {
		t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
	}
	if _, err := Lstat(path); err == nil {
		t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
	}
}
<commit_msg>os: fix test of RemoveAll<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package os_test

import (
	. "os"
	"testing"
	"syscall"
)

func TestMkdirAll(t *testing.T) {
	// Create new dir, in _obj so it will get
	// cleaned up by make if not by us.
	path := "_obj/_TestMkdirAll_/dir/./dir2"
	err := MkdirAll(path, 0777)
	if err != nil {
		t.Fatalf("MkdirAll %q: %s", path, err)
	}

	// Already exists, should succeed.
	err = MkdirAll(path, 0777)
	if err != nil {
		t.Fatalf("MkdirAll %q (second time): %s", path, err)
	}

	// Make file.
	fpath := path + "/file"
	_, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
	if err != nil {
		t.Fatalf("create %q: %s", fpath, err)
	}

	// Can't make directory named after file.
	err = MkdirAll(fpath, 0777)
	if err == nil {
		t.Fatalf("MkdirAll %q: no error", fpath)
	}
	perr, ok := err.(*PathError)
	if !ok {
		t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err)
	}
	if perr.Path != fpath {
		t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, perr.Path, fpath)
	}

	// Can't make subdirectory of file.
	ffpath := fpath + "/subdir"
	err = MkdirAll(ffpath, 0777)
	if err == nil {
		t.Fatalf("MkdirAll %q: no error", ffpath)
	}
	perr, ok = err.(*PathError)
	if !ok {
		t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err)
	}
	if perr.Path != fpath {
		t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, perr.Path, fpath)
	}

	RemoveAll("_obj/_TestMkdirAll_")
}

func TestRemoveAll(t *testing.T) {
	// Work directory.
	path := "_obj/_TestRemoveAll_"
	fpath := path + "/file"
	dpath := path + "/dir"

	// Make directory with 1 file and remove.
	if err := MkdirAll(path, 0777); err != nil {
		t.Fatalf("MkdirAll %q: %s", path, err)
	}
	fd, err := Open(fpath, O_WRONLY|O_CREAT, 0666)
	if err != nil {
		t.Fatalf("create %q: %s", fpath, err)
	}
	fd.Close()
	if err = RemoveAll(path); err != nil {
		t.Fatalf("RemoveAll %q (first): %s", path, err)
	}
	if _, err := Lstat(path); err == nil {
		t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
	}

	// Make directory with file and subdirectory and remove.
	if err = MkdirAll(dpath, 0777); err != nil {
		t.Fatalf("MkdirAll %q: %s", dpath, err)
	}
	fd, err = Open(fpath, O_WRONLY|O_CREAT, 0666)
	if err != nil {
		t.Fatalf("create %q: %s", fpath, err)
	}
	fd.Close()
	fd, err = Open(dpath+"/file", O_WRONLY|O_CREAT, 0666)
	if err != nil {
		t.Fatalf("create %q: %s", fpath, err)
	}
	fd.Close()
	if err = RemoveAll(path); err != nil {
		t.Fatalf("RemoveAll %q (second): %s", path, err)
	}
	if _, err := Lstat(path); err == nil {
		t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
	}

	// Determine if we should run the following test.
	testit := true
	if syscall.OS == "windows" {
		// Chmod is not supported under windows.
		testit = false
	} else {
		// Test fails as root.
		testit = Getuid() != 0
	}
	if testit {
		// Make directory with file and subdirectory and trigger error.
		if err = MkdirAll(dpath, 0777); err != nil {
			t.Fatalf("MkdirAll %q: %s", dpath, err)
		}

		for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
			fd, err = Open(s, O_WRONLY|O_CREAT, 0666)
			if err != nil {
				t.Fatalf("create %q: %s", s, err)
			}
			fd.Close()
		}
		if err = Chmod(dpath, 0); err != nil {
			t.Fatalf("Chmod %q 0: %s", dpath, err)
		}

		// No error checking here: either RemoveAll
		// will or won't be able to remove dpath;
		// either way we want to see if it removes fpath
		// and path/zzz.  Reasons why RemoveAll might
		// succeed in removing dpath as well include:
		//	* running as root
		//	* running on a file system without permissions (FAT)
		RemoveAll(path)
		Chmod(dpath, 0777)

		for _, s := range []string{fpath, path + "/zzz"} {
			if _, err := Lstat(s); err == nil {
				t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
			}
		}
	}
	if err = RemoveAll(path); err != nil {
		t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
	}
	if _, err := Lstat(path); err == nil {
		t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
	}
}
<|endoftext|>