<commit_before>package fuse

import (
	"bytes"
	"fmt"
	"log"
	"strings"
	"time"
	"unsafe"
)

var sizeOfOutHeader = unsafe.Sizeof(OutHeader{})
var zeroOutBuf [outputHeaderSize]byte

type request struct {
	inputBuf []byte

	// These split up inputBuf.
	inHeader *InHeader      // generic header
	inData   unsafe.Pointer // per op data
	arg      []byte         // flat data.

	filenames []string // filename arguments

	// Unstructured data, a pointer to the relevant XxxxOut struct.
	outData  unsafe.Pointer
	status   Status
	flatData []byte
	fdData   *readResultFd

	// In case of read, keep read result here so we can call
	// Done() on it.
	readResult ReadResult

	// Start timestamp for timing info.
	startTime time.Time

	// All information pertaining to opcode of this request.
	handler *operationHandler

	// Request storage. For large inputs and outputs, use data
	// obtained through bufferpool.
	bufferPoolInputBuf  []byte
	bufferPoolOutputBuf []byte

	// For small pieces of data, we use the following inlines
	// arrays:
	//
	// Output header and structured data.
	outBuf [outputHeaderSize]byte

	// Input, if small enough to fit here.
	smallInputBuf [128]byte

	context Context
}

func (r *request) clear() {
	r.inputBuf = nil
	r.inHeader = nil
	r.inData = nil
	r.arg = nil
	r.filenames = nil
	r.outData = nil
	r.status = OK
	r.flatData = nil
	r.fdData = nil
	r.startTime = time.Time{}
	r.handler = nil
	r.readResult = nil
}

func (r *request) InputDebug() string {
	val := " "
	if r.handler.DecodeIn != nil {
		val = fmt.Sprintf(" data: %v ", Print(r.handler.DecodeIn(r.inData)))
	}

	names := ""
	if r.filenames != nil {
		names = fmt.Sprintf("names: %v", r.filenames)
	}

	if len(r.arg) > 0 {
		names += fmt.Sprintf(" %d bytes", len(r.arg))
	}

	return fmt.Sprintf("Dispatch: %s, NodeId: %v.%v%v",
		operationName(r.inHeader.Opcode), r.inHeader.NodeId, val, names)
}

func (r *request) OutputDebug() string {
	var dataStr string
	if r.handler.DecodeOut != nil && r.outData != nil {
		dataStr = Print(r.handler.DecodeOut(r.outData))
	}

	max := 1024
	if len(dataStr) > max {
		dataStr = dataStr[:max] + fmt.Sprintf(" ...trimmed")
	}

	flatStr := ""
	if r.flatDataSize() > 0 {
		if r.handler.FileNameOut {
			s := strings.TrimRight(string(r.flatData), "\x00")
			flatStr = fmt.Sprintf(" %q", s)
		} else {
			spl := ""
			if r.fdData != nil {
				spl = " (fd data)"
			}
			flatStr = fmt.Sprintf(" %d bytes data%s\n", r.flatDataSize(), spl)
		}
	}

	return fmt.Sprintf("Serialize: %s code: %v value: %v%v",
		operationName(r.inHeader.Opcode), r.status, dataStr, flatStr)
}

// setInput returns true if it takes ownership of the argument, false if not.
func (r *request) setInput(input []byte) bool {
	if len(input) < len(r.smallInputBuf) {
		copy(r.smallInputBuf[:], input)
		r.inputBuf = r.smallInputBuf[:len(input)]
		return false
	}
	r.inputBuf = input
	r.bufferPoolInputBuf = input

	return true
}

func (r *request) parse() {
	inHSize := int(unsafe.Sizeof(InHeader{}))
	if len(r.inputBuf) < inHSize {
		log.Printf("Short read for input header: %v", r.inputBuf)
		return
	}

	r.inHeader = (*InHeader)(unsafe.Pointer(&r.inputBuf[0]))
	r.arg = r.inputBuf[:]

	r.handler = getHandler(r.inHeader.Opcode)
	if r.handler == nil {
		log.Printf("Unknown opcode %d", r.inHeader.Opcode)
		r.status = ENOSYS
		return
	}

	if len(r.arg) < int(r.handler.InputSize) {
		log.Printf("Short read for %v: %v", operationName(r.inHeader.Opcode), r.arg)
		r.status = EIO
		return
	}

	if r.handler.InputSize > 0 {
		r.inData = unsafe.Pointer(&r.arg[0])
		r.arg = r.arg[r.handler.InputSize:]
	} else {
		r.arg = r.arg[inHSize:]
	}

	count := r.handler.FileNames
	if count > 0 {
		if count == 1 {
			r.filenames = []string{string(r.arg[:len(r.arg)-1])}
		} else {
			names := bytes.SplitN(r.arg[:len(r.arg)-1], []byte{0}, count)
			r.filenames = make([]string, len(names))
			for i, n := range names {
				r.filenames[i] = string(n)
			}
			if len(names) != count {
				log.Println("filename argument mismatch", names, count)
				r.status = EIO
			}
		}
	}

	copy(r.outBuf[:r.handler.OutputSize], zeroOutBuf[:r.handler.OutputSize])
	r.outData = unsafe.Pointer(&r.outBuf[sizeOfOutHeader])
}

func (r *request) serializeHeader(dataSize int) (header []byte) {
	dataLength := r.handler.OutputSize
	if r.outData == nil || r.status > OK {
		dataLength = 0
	}

	sizeOfOutHeader := unsafe.Sizeof(OutHeader{})
	header = r.outBuf[:sizeOfOutHeader+dataLength]
	o := (*OutHeader)(unsafe.Pointer(&header[0]))
	o.Unique = r.inHeader.Unique
	o.Status = int32(-r.status)
	o.Length = uint32(
		int(sizeOfOutHeader) + int(dataLength) + dataSize)

	var asSlice []byte
	toSlice(&asSlice, r.outData, dataLength)
	copy(header[sizeOfOutHeader:], asSlice)
	return header
}

func (r *request) flatDataSize() int {
	if r.fdData != nil {
		return r.fdData.Size()
	}
	return len(r.flatData)
}
<commit_msg>fuse: zero out the whole output buffer<commit_after>package fuse

import (
	"bytes"
	"fmt"
	"log"
	"strings"
	"time"
	"unsafe"
)

var sizeOfOutHeader = unsafe.Sizeof(OutHeader{})
var zeroOutBuf [outputHeaderSize]byte

type request struct {
	inputBuf []byte

	// These split up inputBuf.
	inHeader *InHeader      // generic header
	inData   unsafe.Pointer // per op data
	arg      []byte         // flat data.

	filenames []string // filename arguments

	// Unstructured data, a pointer to the relevant XxxxOut struct.
	outData  unsafe.Pointer
	status   Status
	flatData []byte
	fdData   *readResultFd

	// In case of read, keep read result here so we can call
	// Done() on it.
	readResult ReadResult

	// Start timestamp for timing info.
	startTime time.Time

	// All information pertaining to opcode of this request.
	handler *operationHandler

	// Request storage. For large inputs and outputs, use data
	// obtained through bufferpool.
	bufferPoolInputBuf  []byte
	bufferPoolOutputBuf []byte

	// For small pieces of data, we use the following inlines
	// arrays:
	//
	// Output header and structured data.
	outBuf [outputHeaderSize]byte

	// Input, if small enough to fit here.
	smallInputBuf [128]byte

	context Context
}

func (r *request) clear() {
	r.inputBuf = nil
	r.inHeader = nil
	r.inData = nil
	r.arg = nil
	r.filenames = nil
	r.outData = nil
	r.status = OK
	r.flatData = nil
	r.fdData = nil
	r.startTime = time.Time{}
	r.handler = nil
	r.readResult = nil
}

func (r *request) InputDebug() string {
	val := " "
	if r.handler.DecodeIn != nil {
		val = fmt.Sprintf(" data: %v ", Print(r.handler.DecodeIn(r.inData)))
	}

	names := ""
	if r.filenames != nil {
		names = fmt.Sprintf("names: %v", r.filenames)
	}

	if len(r.arg) > 0 {
		names += fmt.Sprintf(" %d bytes", len(r.arg))
	}

	return fmt.Sprintf("Dispatch: %s, NodeId: %v.%v%v",
		operationName(r.inHeader.Opcode), r.inHeader.NodeId, val, names)
}

func (r *request) OutputDebug() string {
	var dataStr string
	if r.handler.DecodeOut != nil && r.outData != nil {
		dataStr = Print(r.handler.DecodeOut(r.outData))
	}

	max := 1024
	if len(dataStr) > max {
		dataStr = dataStr[:max] + fmt.Sprintf(" ...trimmed")
	}

	flatStr := ""
	if r.flatDataSize() > 0 {
		if r.handler.FileNameOut {
			s := strings.TrimRight(string(r.flatData), "\x00")
			flatStr = fmt.Sprintf(" %q", s)
		} else {
			spl := ""
			if r.fdData != nil {
				spl = " (fd data)"
			}
			flatStr = fmt.Sprintf(" %d bytes data%s\n", r.flatDataSize(), spl)
		}
	}

	return fmt.Sprintf("Serialize: %s code: %v value: %v%v",
		operationName(r.inHeader.Opcode), r.status, dataStr, flatStr)
}

// setInput returns true if it takes ownership of the argument, false if not.
func (r *request) setInput(input []byte) bool {
	if len(input) < len(r.smallInputBuf) {
		copy(r.smallInputBuf[:], input)
		r.inputBuf = r.smallInputBuf[:len(input)]
		return false
	}
	r.inputBuf = input
	r.bufferPoolInputBuf = input

	return true
}

func (r *request) parse() {
	inHSize := int(unsafe.Sizeof(InHeader{}))
	if len(r.inputBuf) < inHSize {
		log.Printf("Short read for input header: %v", r.inputBuf)
		return
	}

	r.inHeader = (*InHeader)(unsafe.Pointer(&r.inputBuf[0]))
	r.arg = r.inputBuf[:]

	r.handler = getHandler(r.inHeader.Opcode)
	if r.handler == nil {
		log.Printf("Unknown opcode %d", r.inHeader.Opcode)
		r.status = ENOSYS
		return
	}

	if len(r.arg) < int(r.handler.InputSize) {
		log.Printf("Short read for %v: %v", operationName(r.inHeader.Opcode), r.arg)
		r.status = EIO
		return
	}

	if r.handler.InputSize > 0 {
		r.inData = unsafe.Pointer(&r.arg[0])
		r.arg = r.arg[r.handler.InputSize:]
	} else {
		r.arg = r.arg[inHSize:]
	}

	count := r.handler.FileNames
	if count > 0 {
		if count == 1 {
			r.filenames = []string{string(r.arg[:len(r.arg)-1])}
		} else {
			names := bytes.SplitN(r.arg[:len(r.arg)-1], []byte{0}, count)
			r.filenames = make([]string, len(names))
			for i, n := range names {
				r.filenames[i] = string(n)
			}
			if len(names) != count {
				log.Println("filename argument mismatch", names, count)
				r.status = EIO
			}
		}
	}

	copy(r.outBuf[:r.handler.OutputSize+sizeOfOutHeader],
		zeroOutBuf[:r.handler.OutputSize+sizeOfOutHeader])
	r.outData = unsafe.Pointer(&r.outBuf[sizeOfOutHeader])
}

func (r *request) serializeHeader(dataSize int) (header []byte) {
	dataLength := r.handler.OutputSize
	if r.outData == nil || r.status > OK {
		dataLength = 0
	}

	sizeOfOutHeader := unsafe.Sizeof(OutHeader{})
	header = r.outBuf[:sizeOfOutHeader+dataLength]
	o := (*OutHeader)(unsafe.Pointer(&header[0]))
	o.Unique = r.inHeader.Unique
	o.Status = int32(-r.status)
	o.Length = uint32(
		int(sizeOfOutHeader) + int(dataLength) + dataSize)

	var asSlice []byte
	toSlice(&asSlice, r.outData, dataLength)
	copy(header[sizeOfOutHeader:], asSlice)
	return header
}

func (r *request) flatDataSize() int {
	if r.fdData != nil {
		return r.fdData.Size()
	}
	return len(r.flatData)
}
<|endoftext|>


<commit_before>package openstack_test

import (
	. "launchpad.net/gocheck"
	"launchpad.net/goose/identity"
	"launchpad.net/goose/testservices/openstack"
	"net/http"
	"net/http/httptest"
)

// Register tests to run against a test Openstack instance (service doubles).
func registerServiceDoubleTests() {
	cred := &identity.Credentials{
		User:       "fred",
		Secrets:    "secret",
		Region:     "some region",
		TenantName: "some tenant",
	}
	Suite(&localLiveSuite{
		LiveTests: LiveTests{
			cred: cred,
		},
	})
}

type localLiveSuite struct {
	LiveTests
	// The following attributes are for using the service doubles.
	Server     *httptest.Server
	Mux        *http.ServeMux
	oldHandler http.Handler
}

func (s *localLiveSuite) SetUpSuite(c *C) {
	c.Logf("Using openstack service test doubles")

	// Set up the HTTP server.
	s.Server = httptest.NewServer(nil)
	s.oldHandler = s.Server.Config.Handler
	s.Mux = http.NewServeMux()
	s.Server.Config.Handler = s.Mux

	s.cred.URL = s.Server.URL
	openstack := openstack.New(s.cred)
	openstack.SetupHTTP(s.Mux)

	s.LiveTests.SetUpSuite(c)
}

func (s *localLiveSuite) TearDownSuite(c *C) {
	s.LiveTests.TearDownSuite(c)
	s.Mux = nil
	s.Server.Config.Handler = s.oldHandler
	s.Server.Close()
}

func (s *localLiveSuite) SetUpTest(c *C) {
	s.LiveTests.SetUpTest(c)
}

func (s *localLiveSuite) TearDownTest(c *C) {
	s.LiveTests.TearDownTest(c)
}
<commit_msg>openstack: use short timeouts for openstack-double tests<commit_after>package openstack_test

import (
	. "launchpad.net/gocheck"
	"launchpad.net/goose/identity"
	"launchpad.net/goose/testservices/openstack"
	"net/http"
	"net/http/httptest"
)

// Register tests to run against a test Openstack instance (service doubles).
func registerServiceDoubleTests() {
	cred := &identity.Credentials{
		User:       "fred",
		Secrets:    "secret",
		Region:     "some region",
		TenantName: "some tenant",
	}
	Suite(&localLiveSuite{
		LiveTests: LiveTests{
			cred: cred,
		},
	})
}

type localLiveSuite struct {
	LiveTests
	// The following attributes are for using the service doubles.
	Server     *httptest.Server
	Mux        *http.ServeMux
	oldHandler http.Handler
}

func (s *localLiveSuite) SetUpSuite(c *C) {
	c.Logf("Using openstack service test doubles")

	openstack.ShortTimeouts(true)
	// Set up the HTTP server.
	s.Server = httptest.NewServer(nil)
	s.oldHandler = s.Server.Config.Handler
	s.Mux = http.NewServeMux()
	s.Server.Config.Handler = s.Mux

	s.cred.URL = s.Server.URL
	openstack := openstack.New(s.cred)
	openstack.SetupHTTP(s.Mux)

	s.LiveTests.SetUpSuite(c)
}

func (s *localLiveSuite) TearDownSuite(c *C) {
	s.LiveTests.TearDownSuite(c)
	s.Mux = nil
	s.Server.Config.Handler = s.oldHandler
	s.Server.Close()
	openstack.ShortTimeouts(false)
}

func (s *localLiveSuite) SetUpTest(c *C) {
	s.LiveTests.SetUpTest(c)
}

func (s *localLiveSuite) TearDownTest(c *C) {
	s.LiveTests.TearDownTest(c)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"net/http"
	"os"

	"github.com/gorilla/pat"
	"github.com/gorilla/sessions"
	"github.com/markbates/goth"
	"github.com/markbates/goth/gothic"
	"github.com/markbates/goth/providers/amazon"
	"github.com/markbates/goth/providers/bitbucket"
	"github.com/markbates/goth/providers/box"
	"github.com/markbates/goth/providers/digitalocean"
	"github.com/markbates/goth/providers/dropbox"
	"github.com/markbates/goth/providers/facebook"
	"github.com/markbates/goth/providers/github"
	"github.com/markbates/goth/providers/gitlab"
	"github.com/markbates/goth/providers/gplus"
	"github.com/markbates/goth/providers/heroku"
	"github.com/markbates/goth/providers/instagram"
	"github.com/markbates/goth/providers/lastfm"
	"github.com/markbates/goth/providers/linkedin"
	"github.com/markbates/goth/providers/onedrive"
	"github.com/markbates/goth/providers/paypal"
	"github.com/markbates/goth/providers/salesforce"
	"github.com/markbates/goth/providers/slack"
	"github.com/markbates/goth/providers/soundcloud"
	"github.com/markbates/goth/providers/spotify"
	"github.com/markbates/goth/providers/steam"
	"github.com/markbates/goth/providers/stripe"
	"github.com/markbates/goth/providers/twitch"
	"github.com/markbates/goth/providers/twitter"
	"github.com/markbates/goth/providers/uber"
	"github.com/markbates/goth/providers/wepay"
	"github.com/markbates/goth/providers/yahoo"
	"github.com/markbates/goth/providers/yammer"
	"sort"
)

func init() {
	gothic.Store = sessions.NewFilesystemStore(os.TempDir(), []byte("goth-example"))
}

func main() {
	goth.UseProviders(
		twitter.New(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), "http://localhost:3000/auth/twitter/callback"),
		// If you'd like to use authenticate instead of authorize in Twitter provider, use this instead.
		// twitter.NewAuthenticate(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), "http://localhost:3000/auth/twitter/callback"),

		facebook.New(os.Getenv("FACEBOOK_KEY"), os.Getenv("FACEBOOK_SECRET"), "http://localhost:3000/auth/facebook/callback"),
		gplus.New(os.Getenv("GPLUS_KEY"), os.Getenv("GPLUS_SECRET"), "http://localhost:3000/auth/gplus/callback"),
		github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback"),
		spotify.New(os.Getenv("SPOTIFY_KEY"), os.Getenv("SPOTIFY_SECRET"), "http://localhost:3000/auth/spotify/callback"),
		linkedin.New(os.Getenv("LINKEDIN_KEY"), os.Getenv("LINKEDIN_SECRET"), "http://localhost:3000/auth/linkedin/callback"),
		lastfm.New(os.Getenv("LASTFM_KEY"), os.Getenv("LASTFM_SECRET"), "http://localhost:3000/auth/lastfm/callback"),
		twitch.New(os.Getenv("TWITCH_KEY"), os.Getenv("TWITCH_SECRET"), "http://localhost:3000/auth/twitch/callback"),
		dropbox.New(os.Getenv("DROPBOX_KEY"), os.Getenv("DROPBOX_SECRET"), "http://localhost:3000/auth/dropbox/callback"),
		digitalocean.New(os.Getenv("DIGITALOCEAN_KEY"), os.Getenv("DIGITALOCEAN_SECRET"), "http://localhost:3000/auth/digitalocean/callback", "read"),
		bitbucket.New(os.Getenv("BITBUCKET_KEY"), os.Getenv("BITBUCKET_SECRET"), "http://localhost:3000/auth/bitbucket/callback"),
		instagram.New(os.Getenv("INSTAGRAM_KEY"), os.Getenv("INSTAGRAM_SECRET"), "http://localhost:3000/auth/instagram/callback"),
		box.New(os.Getenv("BOX_KEY"), os.Getenv("BOX_SECRET"), "http://localhost:3000/auth/box/callback"),
		salesforce.New(os.Getenv("SALESFORCE_KEY"), os.Getenv("SALESFORCE_SECRET"), "http://localhost:3000/auth/salesforce/callback"),
		amazon.New(os.Getenv("AMAZON_KEY"), os.Getenv("AMAZON_SECRET"), "http://localhost:3000/auth/amazon/callback"),
		yammer.New(os.Getenv("YAMMER_KEY"), os.Getenv("YAMMER_SECRET"), "http://localhost:3000/auth/yammer/callback"),
		onedrive.New(os.Getenv("ONEDRIVE_KEY"), os.Getenv("ONEDRIVE_SECRET"), "http://localhost:3000/auth/onedrive/callback"),

		//Pointed localhost.com to http://localhost:3000/auth/yahoo/callback through proxy as yahoo
		// does not allow to put custom ports in redirection uri
		yahoo.New(os.Getenv("YAHOO_KEY"), os.Getenv("YAHOO_SECRET"), "http://localhost.com"),
		slack.New(os.Getenv("SLACK_KEY"), os.Getenv("SLACK_SECRET"), "http://localhost:3000/auth/slack/callback"),
		stripe.New(os.Getenv("STRIPE_KEY"), os.Getenv("STRIPE_SECRET"), "http://localhost:3000/auth/stripe/callback"),
		wepay.New(os.Getenv("WEPAY_KEY"), os.Getenv("WEPAY_SECRET"), "http://localhost:3000/auth/wepay/callback", "view_user"),
		//By default paypal production auth urls will be used, please set PAYPAL_ENV=sandbox as environment variable for testing
		//in sandbox environment
		paypal.New(os.Getenv("PAYPAL_KEY"), os.Getenv("PAYPAL_SECRET"), "http://localhost:3000/auth/paypal/callback"),
		steam.New(os.Getenv("STEAM_KEY"), "http://localhost:3000/auth/steam/callback"),
		heroku.New(os.Getenv("HEROKU_KEY"), os.Getenv("HEROKU_SECRET"), "http://localhost:3000/auth/heroku/callback"),
		uber.New(os.Getenv("UBER_KEY"), os.Getenv("UBER_SECRET"), "http://localhost:3000/auth/uber/callback"),
		soundcloud.New(os.Getenv("SOUNDCLOUD_KEY"), os.Getenv("SOUNDCLOUD_SECRET"), "http://localhost:3000/auth/soundcloud/callback"),
		gitlab.New(os.Getenv("GITLAB_KEY"), os.Getenv("GITLAB_SECRET"), "http://localhost:3000/auth/gitlab/callback"),
	)

	m := make(map[string]string)
	m["amazon"] = "Amazon"
	m["bitbucket"] = "Bitbucket"
	m["box"] = "Box"
	m["digitalocean"] = "Digital Ocean"
	m["dropbox"] = "Dropbox"
	m["facebook"] = "Facebook"
	m["github"] = "Github"
	m["gitlab"] = "Gitlab"
	m["soundcloud"] = "SoundCloud"
	m["spotify"] = "Spotify"
	m["steam"] = "Steam"
	m["stripe"] = "Stripe"
	m["twitch"] = "Twitch"
	m["uber"] = "Uber"
	m["wepay"] = "Wepay"
	m["yahoo"] = "Yahoo"
	m["yammer"] = "Yammer"
	m["gplus"] = "Google Plus"
	m["heroku"] = "Heroku"
	m["instagram"] = "Instagram"
	m["lastfm"] = "Last FM"
	m["linkedin"] = "Linkedin"
	m["onedrive"] = "Onedrive"
	m["paypal"] = "Paypal"
	m["twitter"] = "Twitter"
	m["salesforce"] = "Salesforce"
	m["slack"] = "Slack"

	var keys []string
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	providerIndex := &ProviderIndex{Providers: keys, ProvidersMap: m}

	p := pat.New()
	p.Get("/auth/{provider}/callback", func(res http.ResponseWriter, req *http.Request) {

		user, err := gothic.CompleteUserAuth(res, req)
		if err != nil {
			fmt.Fprintln(res, err)
			return
		}
		t, _ := template.New("foo").Parse(userTemplate)
		t.Execute(res, user)
	})

	p.Get("/auth/{provider}", gothic.BeginAuthHandler)
	p.Get("/", func(res http.ResponseWriter, req *http.Request) {
		t, _ := template.New("foo").Parse(indexTemplate)
		t.Execute(res, providerIndex)
	})
	http.ListenAndServe(":3000", p)
}

type ProviderIndex struct {
	Providers    []string
	ProvidersMap map[string]string
}

var indexTemplate = `{{range $key,$value:=.Providers}}

Log in with {{index $.ProvidersMap $value}}

{{end}}`

var userTemplate = `

Name: {{.Name}} [{{.LastName}}, {{.FirstName}}]

Email: {{.Email}}

NickName: {{.NickName}}

Location: {{.Location}}

AvatarURL: {{.AvatarURL}}

Description: {{.Description}}

UserID: {{.UserID}}

AccessToken: {{.AccessToken}}

ExpiresAt: {{.ExpiresAt}}

RefreshToken: {{.RefreshToken}}

`
<commit_msg>added fitbit to examples<commit_after>package main

import (
	"fmt"
	"html/template"
	"net/http"
	"os"

	"sort"

	"github.com/gorilla/pat"
	"github.com/gorilla/sessions"
	"github.com/markbates/goth"
	"github.com/markbates/goth/gothic"
	"github.com/markbates/goth/providers/amazon"
	"github.com/markbates/goth/providers/bitbucket"
	"github.com/markbates/goth/providers/box"
	"github.com/markbates/goth/providers/digitalocean"
	"github.com/markbates/goth/providers/dropbox"
	"github.com/markbates/goth/providers/facebook"
	"github.com/markbates/goth/providers/fitbit"
	"github.com/markbates/goth/providers/github"
	"github.com/markbates/goth/providers/gitlab"
	"github.com/markbates/goth/providers/gplus"
	"github.com/markbates/goth/providers/heroku"
	"github.com/markbates/goth/providers/instagram"
	"github.com/markbates/goth/providers/lastfm"
	"github.com/markbates/goth/providers/linkedin"
	"github.com/markbates/goth/providers/onedrive"
	"github.com/markbates/goth/providers/paypal"
	"github.com/markbates/goth/providers/salesforce"
	"github.com/markbates/goth/providers/slack"
	"github.com/markbates/goth/providers/soundcloud"
	"github.com/markbates/goth/providers/spotify"
	"github.com/markbates/goth/providers/steam"
	"github.com/markbates/goth/providers/stripe"
	"github.com/markbates/goth/providers/twitch"
	"github.com/markbates/goth/providers/twitter"
	"github.com/markbates/goth/providers/uber"
	"github.com/markbates/goth/providers/wepay"
	"github.com/markbates/goth/providers/yahoo"
	"github.com/markbates/goth/providers/yammer"
)

func init() {
	gothic.Store = sessions.NewFilesystemStore(os.TempDir(), []byte("goth-example"))
}

func main() {
	goth.UseProviders(
		twitter.New(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), "http://localhost:3000/auth/twitter/callback"),
		// If you'd like to use authenticate instead of authorize in Twitter provider, use this instead.
		// twitter.NewAuthenticate(os.Getenv("TWITTER_KEY"), os.Getenv("TWITTER_SECRET"), "http://localhost:3000/auth/twitter/callback"),

		facebook.New(os.Getenv("FACEBOOK_KEY"), os.Getenv("FACEBOOK_SECRET"), "http://localhost:3000/auth/facebook/callback"),
		fitbit.New(os.Getenv("FITBIT_KEY"), os.Getenv("FITBIT_SECRET"), "http://localhost:3000/auth/fitbit/callback"),
		gplus.New(os.Getenv("GPLUS_KEY"), os.Getenv("GPLUS_SECRET"), "http://localhost:3000/auth/gplus/callback"),
		github.New(os.Getenv("GITHUB_KEY"), os.Getenv("GITHUB_SECRET"), "http://localhost:3000/auth/github/callback"),
		spotify.New(os.Getenv("SPOTIFY_KEY"), os.Getenv("SPOTIFY_SECRET"), "http://localhost:3000/auth/spotify/callback"),
		linkedin.New(os.Getenv("LINKEDIN_KEY"), os.Getenv("LINKEDIN_SECRET"), "http://localhost:3000/auth/linkedin/callback"),
		lastfm.New(os.Getenv("LASTFM_KEY"), os.Getenv("LASTFM_SECRET"), "http://localhost:3000/auth/lastfm/callback"),
		twitch.New(os.Getenv("TWITCH_KEY"), os.Getenv("TWITCH_SECRET"), "http://localhost:3000/auth/twitch/callback"),
		dropbox.New(os.Getenv("DROPBOX_KEY"), os.Getenv("DROPBOX_SECRET"), "http://localhost:3000/auth/dropbox/callback"),
		digitalocean.New(os.Getenv("DIGITALOCEAN_KEY"), os.Getenv("DIGITALOCEAN_SECRET"), "http://localhost:3000/auth/digitalocean/callback", "read"),
		bitbucket.New(os.Getenv("BITBUCKET_KEY"), os.Getenv("BITBUCKET_SECRET"), "http://localhost:3000/auth/bitbucket/callback"),
		instagram.New(os.Getenv("INSTAGRAM_KEY"), os.Getenv("INSTAGRAM_SECRET"), "http://localhost:3000/auth/instagram/callback"),
		box.New(os.Getenv("BOX_KEY"), os.Getenv("BOX_SECRET"), "http://localhost:3000/auth/box/callback"),
		salesforce.New(os.Getenv("SALESFORCE_KEY"), os.Getenv("SALESFORCE_SECRET"), "http://localhost:3000/auth/salesforce/callback"),
		amazon.New(os.Getenv("AMAZON_KEY"), os.Getenv("AMAZON_SECRET"), "http://localhost:3000/auth/amazon/callback"),
		yammer.New(os.Getenv("YAMMER_KEY"), os.Getenv("YAMMER_SECRET"), "http://localhost:3000/auth/yammer/callback"),
		onedrive.New(os.Getenv("ONEDRIVE_KEY"), os.Getenv("ONEDRIVE_SECRET"), "http://localhost:3000/auth/onedrive/callback"),

		//Pointed localhost.com to http://localhost:3000/auth/yahoo/callback through proxy as yahoo
		// does not allow to put custom ports in redirection uri
		yahoo.New(os.Getenv("YAHOO_KEY"), os.Getenv("YAHOO_SECRET"), "http://localhost.com"),
		slack.New(os.Getenv("SLACK_KEY"), os.Getenv("SLACK_SECRET"), "http://localhost:3000/auth/slack/callback"),
		stripe.New(os.Getenv("STRIPE_KEY"), os.Getenv("STRIPE_SECRET"), "http://localhost:3000/auth/stripe/callback"),
		wepay.New(os.Getenv("WEPAY_KEY"), os.Getenv("WEPAY_SECRET"), "http://localhost:3000/auth/wepay/callback", "view_user"),
		//By default paypal production auth urls will be used, please set PAYPAL_ENV=sandbox as environment variable for testing
		//in sandbox environment
		paypal.New(os.Getenv("PAYPAL_KEY"), os.Getenv("PAYPAL_SECRET"), "http://localhost:3000/auth/paypal/callback"),
		steam.New(os.Getenv("STEAM_KEY"), "http://localhost:3000/auth/steam/callback"),
		heroku.New(os.Getenv("HEROKU_KEY"), os.Getenv("HEROKU_SECRET"), "http://localhost:3000/auth/heroku/callback"),
		uber.New(os.Getenv("UBER_KEY"), os.Getenv("UBER_SECRET"), "http://localhost:3000/auth/uber/callback"),
		soundcloud.New(os.Getenv("SOUNDCLOUD_KEY"), os.Getenv("SOUNDCLOUD_SECRET"), "http://localhost:3000/auth/soundcloud/callback"),
		gitlab.New(os.Getenv("GITLAB_KEY"), os.Getenv("GITLAB_SECRET"), "http://localhost:3000/auth/gitlab/callback"),
	)

	m := make(map[string]string)
	m["amazon"] = "Amazon"
	m["bitbucket"] = "Bitbucket"
	m["box"] = "Box"
	m["digitalocean"] = "Digital Ocean"
	m["dropbox"] = "Dropbox"
	m["facebook"] = "Facebook"
	m["fitbit"] = "Fitbit"
	m["github"] = "Github"
	m["gitlab"] = "Gitlab"
	m["soundcloud"] = "SoundCloud"
	m["spotify"] = "Spotify"
	m["steam"] = "Steam"
	m["stripe"] = "Stripe"
	m["twitch"] = "Twitch"
	m["uber"] = "Uber"
	m["wepay"] = "Wepay"
	m["yahoo"] = "Yahoo"
	m["yammer"] = "Yammer"
	m["gplus"] = "Google Plus"
	m["heroku"] = "Heroku"
	m["instagram"] = "Instagram"
	m["lastfm"] = "Last FM"
	m["linkedin"] = "Linkedin"
	m["onedrive"] = "Onedrive"
	m["paypal"] = "Paypal"
	m["twitter"] = "Twitter"
	m["salesforce"] = "Salesforce"
	m["slack"] = "Slack"

	var keys []string
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	providerIndex := &ProviderIndex{Providers: keys, ProvidersMap: m}

	p := pat.New()
	p.Get("/auth/{provider}/callback", func(res http.ResponseWriter, req *http.Request) {

		user, err := gothic.CompleteUserAuth(res, req)
		if err != nil {
			fmt.Fprintln(res, err)
			return
		}
		t, _ := template.New("foo").Parse(userTemplate)
		t.Execute(res, user)
	})

	p.Get("/auth/{provider}", gothic.BeginAuthHandler)
	p.Get("/", func(res http.ResponseWriter, req *http.Request) {
		t, _ := template.New("foo").Parse(indexTemplate)
		t.Execute(res, providerIndex)
	})
	http.ListenAndServe(":3000", p)
}

type ProviderIndex struct {
	Providers    []string
	ProvidersMap map[string]string
}

var indexTemplate = `{{range $key,$value:=.Providers}}

Log in with {{index $.ProvidersMap $value}}

{{end}}`

var userTemplate = `

Name: {{.Name}} [{{.LastName}}, {{.FirstName}}]

Email: {{.Email}}

NickName: {{.NickName}}

Location: {{.Location}}

AvatarURL: {{.AvatarURL}}

Description: {{.Description}}

UserID: {{.UserID}}

AccessToken: {{.AccessToken}}

ExpiresAt: {{.ExpiresAt}}

RefreshToken: {{.RefreshToken}}

`
<|endoftext|>


<commit_before>/*
Package grpc provides user grpc server
*/
package grpc

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/golang/protobuf/ptypes/empty"
	"github.com/vardius/go-api-boilerplate/cmd/user/application"
	"github.com/vardius/go-api-boilerplate/cmd/user/domain/user"
	"github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/persistence"
	"github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/persistence/mysql"
	"github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/proto"
	"github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/repository"
	"github.com/vardius/go-api-boilerplate/pkg/commandbus"
	"github.com/vardius/go-api-boilerplate/pkg/errors"
	"github.com/vardius/go-api-boilerplate/pkg/eventbus"
	"github.com/vardius/go-api-boilerplate/pkg/eventstore"
	"github.com/vardius/go-api-boilerplate/pkg/jwt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type userServer struct {
	commandBus commandbus.CommandBus
	eventBus   eventbus.EventBus
	eventStore eventstore.EventStore
	db         *sql.DB
	jwt        jwt.Jwt
}

// NewServer returns new user server object
func NewServer(cb commandbus.CommandBus, eb eventbus.EventBus, es eventstore.EventStore, db *sql.DB, j jwt.Jwt) proto.UserServiceServer {
	s := &userServer{cb, eb, es, db, j}

	userRepository := repository.NewUserRepository(es, eb)
	userMYSQLRepository := mysql.NewUserRepository(db)

	s.registerCommandHandlers(userRepository)
	s.registerEventHandlers(userMYSQLRepository)

	return s
}

// DispatchCommand implements proto.UserServiceServer interface
func (s *userServer) DispatchCommand(ctx context.Context, r *proto.DispatchCommandRequest) (*empty.Empty, error) {
	out := make(chan error)
	defer close(out)

	go func() {
		defer func() {
			if rec := recover(); rec != nil {
				out <- errors.Newf(errors.INTERNAL, "DispatchCommand recovered in f %v", rec)
			}
		}()

		c, err := buildDomainCommand(ctx, r.GetName(), r.GetPayload())
		if err != nil {
			out <- err
			return
		}

		s.commandBus.Publish(ctx, fmt.Sprintf("%T", c), c, out)
	}()

	select {
	case <-ctx.Done():
		return new(empty.Empty), ctx.Err()
	case err := <-out:
		return new(empty.Empty), err
	}
}

// GetUser implements proto.UserServiceServer interface
func (s *userServer) GetUser(ctx context.Context, r *proto.GetUserRequest) (*proto.User, error) {
	repository := mysql.NewUserRepository(s.db)

	user, err := repository.Get(ctx, r.GetId())
	if err != nil {
		return nil, status.Error(codes.NotFound, "User not found")
	}

	return user, nil
}

// ListUsers implements proto.UserServiceServer interface
func (s *userServer) ListUsers(ctx context.Context, r *proto.ListUserRequest) (*proto.ListUserResponse, error) {
	if r.GetPage() < 1 || r.GetLimit() < 1 {
		return nil, status.Error(codes.Internal, "Invalid page or limit value. Please provide values greater then 1")
	}

	var users []*proto.User

	repository := mysql.NewUserRepository(s.db)

	totalUsers, err := repository.Count(ctx)
	if err != nil {
		return nil, status.Error(codes.Internal, "Failed to count users")
	}

	offset := (r.GetPage() * r.GetLimit()) - r.GetLimit()

	if totalUsers < 1 || offset > (totalUsers-1) {
		return &proto.ListUserResponse{
			Page:  r.GetPage(),
			Limit: r.GetLimit(),
			Total: totalUsers,
			Users: users,
		}, nil
	}

	users, err = repository.FindAll(ctx, r.GetLimit(), offset)
	if err != nil {
		return nil, status.Error(codes.Internal, "Failed to fetch users")
	}

	response := &proto.ListUserResponse{
		Page:  r.GetPage(),
		Limit: r.GetLimit(),
		Total: totalUsers,
		Users: users,
	}

	return response, nil
}

func (s *userServer) registerCommandHandlers(r user.Repository) {
	s.commandBus.Subscribe(fmt.Sprintf("%T", &user.RegisterWithEmail{}), user.OnRegisterWithEmail(r, s.db))
	s.commandBus.Subscribe(fmt.Sprintf("%T", &user.RegisterWithGoogle{}), user.OnRegisterWithGoogle(r, s.db))
	s.commandBus.Subscribe(fmt.Sprintf("%T", &user.RegisterWithFacebook{}), user.OnRegisterWithFacebook(r, s.db))
	s.commandBus.Subscribe(fmt.Sprintf("%T", &user.ChangeEmailAddress{}), user.OnChangeEmailAddress(r, s.db))
}

func (s *userServer) registerEventHandlers(r persistence.UserRepository) {
	s.eventBus.Subscribe(fmt.Sprintf("%T", &user.WasRegisteredWithEmail{}), application.WhenUserWasRegisteredWithEmail(s.db, r))
	s.eventBus.Subscribe(fmt.Sprintf("%T", &user.WasRegisteredWithGoogle{}), application.WhenUserWasRegisteredWithGoogle(s.db, r))
	s.eventBus.Subscribe(fmt.Sprintf("%T", &user.WasRegisteredWithFacebook{}), application.WhenUserWasRegisteredWithFacebook(s.db, r))
	s.eventBus.Subscribe(fmt.Sprintf("%T", &user.EmailAddressWasChanged{}), application.WhenUserEmailAddressWasChanged(s.db, r))
}
<commit_msg>Do not recover from panic here<commit_after>/*
Package grpc provides user grpc server
*/
package grpc

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/golang/protobuf/ptypes/empty"
	"github.com/vardius/go-api-boilerplate/cmd/user/application"
	"github.com/vardius/go-api-boilerplate/cmd/user/domain/user"
	"github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/persistence"
	"github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/persistence/mysql"
	"github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/proto"
	"github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/repository"
	"github.com/vardius/go-api-boilerplate/pkg/commandbus"
	"github.com/vardius/go-api-boilerplate/pkg/eventbus"
	"github.com/vardius/go-api-boilerplate/pkg/eventstore"
	"github.com/vardius/go-api-boilerplate/pkg/jwt"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type userServer struct {
	commandBus commandbus.CommandBus
	eventBus   eventbus.EventBus
	eventStore eventstore.EventStore
	db         *sql.DB
	jwt        jwt.Jwt
}

// NewServer returns new user server object
func NewServer(cb commandbus.CommandBus, eb eventbus.EventBus, es eventstore.EventStore, db *sql.DB, j jwt.Jwt) proto.UserServiceServer {
	s := &userServer{cb, eb, es, db, j}

	userRepository := repository.NewUserRepository(es, eb)
	userMYSQLRepository := mysql.NewUserRepository(db)

	s.registerCommandHandlers(userRepository)
	s.registerEventHandlers(userMYSQLRepository)

	return s
}

// DispatchCommand implements proto.UserServiceServer interface
func (s *userServer) DispatchCommand(ctx context.Context, r *proto.DispatchCommandRequest) (*empty.Empty, error) {
	c, err := buildDomainCommand(ctx, r.GetName(), r.GetPayload())
	if err != nil {
		return new(empty.Empty), err
	}

	out := make(chan error)
	defer close(out)

	go func() {
		s.commandBus.Publish(ctx, fmt.Sprintf("%T", c), c, out)
	}()

	select {
	case <-ctx.Done():
		return new(empty.Empty), ctx.Err()
	case err := <-out:
		return new(empty.Empty), err
	}
}

// GetUser implements proto.UserServiceServer interface
func (s *userServer) GetUser(ctx context.Context, r *proto.GetUserRequest) (*proto.User, error) {
	repository := mysql.NewUserRepository(s.db)

	user, err := repository.Get(ctx, r.GetId())
	if err != nil {
		return nil, status.Error(codes.NotFound, "User not found")
	}

	return user, nil
}

// ListUsers implements proto.UserServiceServer interface
func (s *userServer) ListUsers(ctx context.Context, r *proto.ListUserRequest) (*proto.ListUserResponse, error) {
	if r.GetPage() < 1 || r.GetLimit() < 1 {
		return nil, status.Error(codes.Internal, "Invalid page or limit value. Please provide values greater then 1")
	}

	var users []*proto.User

	repository := mysql.NewUserRepository(s.db)

	totalUsers, err := repository.Count(ctx)
	if err != nil {
		return nil, status.Error(codes.Internal, "Failed to count users")
	}

	offset := (r.GetPage() * r.GetLimit()) - r.GetLimit()

	if totalUsers < 1 || offset > (totalUsers-1) {
		return &proto.ListUserResponse{
			Page:  r.GetPage(),
			Limit: r.GetLimit(),
			Total: totalUsers,
			Users: users,
		}, nil
	}

	users, err = repository.FindAll(ctx, r.GetLimit(), offset)
	if err != nil {
		return nil, status.Error(codes.Internal, "Failed to fetch users")
	}

	response := &proto.ListUserResponse{
		Page:  r.GetPage(),
		Limit: r.GetLimit(),
		Total: totalUsers,
		Users: users,
	}

	return response, nil
}

func (s *userServer) registerCommandHandlers(r user.Repository) {
	s.commandBus.Subscribe(fmt.Sprintf("%T", &user.RegisterWithEmail{}), user.OnRegisterWithEmail(r, s.db))
	s.commandBus.Subscribe(fmt.Sprintf("%T", &user.RegisterWithGoogle{}), user.OnRegisterWithGoogle(r, s.db))
	s.commandBus.Subscribe(fmt.Sprintf("%T", &user.RegisterWithFacebook{}), user.OnRegisterWithFacebook(r, s.db))
	s.commandBus.Subscribe(fmt.Sprintf("%T", &user.ChangeEmailAddress{}), user.OnChangeEmailAddress(r, s.db))
}

func (s *userServer) registerEventHandlers(r persistence.UserRepository) {
	s.eventBus.Subscribe(fmt.Sprintf("%T", &user.WasRegisteredWithEmail{}), application.WhenUserWasRegisteredWithEmail(s.db, r))
	s.eventBus.Subscribe(fmt.Sprintf("%T", &user.WasRegisteredWithGoogle{}), application.WhenUserWasRegisteredWithGoogle(s.db, r))
	s.eventBus.Subscribe(fmt.Sprintf("%T", &user.WasRegisteredWithFacebook{}), application.WhenUserWasRegisteredWithFacebook(s.db, r))
	s.eventBus.Subscribe(fmt.Sprintf("%T", &user.EmailAddressWasChanged{}), application.WhenUserEmailAddressWasChanged(s.db, r))
}
<|endoftext|>


<commit_before>package uinput

import (
	"fmt"
	"io/ioutil"
	"os"
	"testing"
)

// This test inputs the konami code
func TestInfiniteKonami(t *testing.T) {
	vg, err := CreateGamepad("/dev/uinput", []byte("Hot gophers in your area"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}

	for i := 0; i < 10; i++ {
		for j := 0; j < 3; j++ {
			err = vg.ButtonPress(ButtonDpadUp)
			if err != nil {
				t.Fatalf("Failed to send button press. Last error was: %s\n", err)
			}

			err = vg.ButtonPress(ButtonDpadDown)
			if err != nil {
				t.Fatalf("Failed to send button press. Last error was: %s\n", err)
			}

		}

		for j := 0; j < 3; j++ {
			err = vg.ButtonPress(ButtonDpadLeft)
			if err != nil {
				t.Fatalf("Failed to send button press. Last error was: %s\n", err)
			}

			err = vg.ButtonPress(ButtonDpadRight)
			if err != nil {
				t.Fatalf("Failed to send button press. Last error was: %s\n", err)
			}

		}

		err = vg.ButtonPress(ButtonSouth)
		if err != nil {
			t.Fatalf("Failed to send button press. Last error was: %s\n", err)
		}

		err = vg.ButtonPress(ButtonEast)
		if err != nil {
			t.Fatalf("Failed to send button press. Last error was: %s\n", err)
		}

		err = vg.ButtonPress(ButtonStart)
		if err != nil {
			t.Fatalf("Failed to send button press. Last error was: %s\n", err)
		}
	}
}

// This test moves the axes around a bit
func TestAxisMovement(t *testing.T) {
	vg, err := CreateGamepad("/dev/uinput", []byte("Hot gophers in your area"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}

	err = vg.LeftStickMove(0.2, 1.0)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.LeftStickMoveX(0.2)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.LeftStickMoveY(1)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.RightStickMove(0.2, 1.0)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.RightStickMoveX(0.2)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.RightStickMoveY(1)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}
}

func TestHatMovement(t *testing.T) {
	vg, err := CreateGamepad("/dev/uinput", []byte("Hot gophers in your area"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}

	err = vg.HatPress(HatUp)
	if err != nil {
		t.Fatalf("Falied to move hat up")
	}
	err = vg.HatRelease(HatUp)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatRight)
	if err != nil {
		t.Fatalf("Falied to move hat right")
	}
	err = vg.HatRelease(HatRight)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatDown)
	if err != nil {
		t.Fatalf("Falied to move hat down")
	}
	err = vg.HatRelease(HatDown)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatLeft)
	if err != nil {
		t.Fatalf("Falied to move hat left")
	}
	err = vg.HatRelease(HatLeft)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
}

func TestGamepadCreationFailsOnEmptyPath(t *testing.T) {
	expected := "device path must not be empty"
	_, err := CreateGamepad("", []byte("Gamepad"), 0xDEAD, 0xBEEF)
	if err.Error() != expected {
		t.Fatalf("Expected: %s\nActual: %s", expected, err)
	}
}

func TestGamepadCreationFailsOnNonExistentPathName(t *testing.T) {
	path := "/some/bogus/path"
	_, err := CreateGamepad(path, []byte("Gamepad"), 0xDEAD, 0xBEEF)
	if !os.IsNotExist(err) {
		t.Fatalf("Expected: os.IsNotExist error\nActual: %s", err)
	}
}

func TestGamepadCreationFailsOnWrongPathName(t *testing.T) {
	file, err := ioutil.TempFile(os.TempDir(), "uinput-gamepad-test-")
	if err != nil {
		t.Fatalf("Failed to setup test. Unable to create tempfile: %v", err)
	}
	defer file.Close()

	expected := "failed to register virtual gamepad device: failed to close device: inappropriate ioctl for device"
	_, err = CreateGamepad(file.Name(), []byte("GamepadDevice"), 0xDEAD, 0xBEEF)
	if err == nil || !(expected == err.Error()) {
		t.Fatalf("Expected: %s\nActual: %s", expected, err)
	}
}

func TestGamepadCreationFailsIfNameIsTooLong(t *testing.T) {
	name := "adsfdsferqewoirueworiuejdsfjdfa;ljoewrjeworiewuoruew;rj;kdlfjoeai;jfewoaifjef;das"
	expected := fmt.Sprintf("device name %s is too long (maximum of %d characters allowed)", name, uinputMaxNameSize)
	_, err := CreateGamepad("/dev/uinput", []byte(name), 0xDEAD, 0xBEEF)
	if err.Error() != expected {
		t.Fatalf("Expected: %s\nActual: %s", expected, err)
	}
}

func TestGamepadMoveToFailsOnClosedDevice(t *testing.T) {
	gamepad, err := CreateGamepad("/dev/uinput", []byte("Test Gamepad"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}
	_ = gamepad.Close()
	err = gamepad.LeftStickMoveX(1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
}
<commit_msg>Add Tests<commit_after>package uinput

import (
	"fmt"
	"io/ioutil"
	"os"
	"testing"
)

// This test inputs the konami code
func TestInfiniteKonami(t *testing.T) {
	vg, err := CreateGamepad("/dev/uinput", []byte("Hot gophers in your area"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}

	for i := 0; i < 10; i++ {
		for j := 0; j < 3; j++ {
			err = vg.ButtonPress(ButtonDpadUp)
			if err != nil {
				t.Fatalf("Failed to send button press. Last error was: %s\n", err)
			}

			err = vg.ButtonPress(ButtonDpadDown)
			if err != nil {
				t.Fatalf("Failed to send button press. Last error was: %s\n", err)
			}

		}

		for j := 0; j < 3; j++ {
			err = vg.ButtonPress(ButtonDpadLeft)
			if err != nil {
				t.Fatalf("Failed to send button press. Last error was: %s\n", err)
			}

			err = vg.ButtonPress(ButtonDpadRight)
			if err != nil {
				t.Fatalf("Failed to send button press. Last error was: %s\n", err)
			}

		}

		err = vg.ButtonPress(ButtonSouth)
		if err != nil {
			t.Fatalf("Failed to send button press. Last error was: %s\n", err)
		}

		err = vg.ButtonPress(ButtonEast)
		if err != nil {
			t.Fatalf("Failed to send button press. Last error was: %s\n", err)
		}

		err = vg.ButtonPress(ButtonStart)
		if err != nil {
			t.Fatalf("Failed to send button press. Last error was: %s\n", err)
		}
	}
}

// This test moves the axes around a bit
func TestAxisMovement(t *testing.T) {
	vg, err := CreateGamepad("/dev/uinput", []byte("Hot gophers in your area"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}

	err = vg.LeftStickMove(0.2, 1.0)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.LeftStickMoveX(0.2)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.LeftStickMoveY(1)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.RightStickMove(0.2, 1.0)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.RightStickMoveX(0.2)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}

	err = vg.RightStickMoveY(1)
	if err != nil {
		t.Fatalf("Failed to send axis event. Last error was: %s\n", err)
	}
}

func TestHatMovement(t *testing.T) {
	vg, err := CreateGamepad("/dev/uinput", []byte("Hot gophers in your area"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}

	err = vg.HatPress(HatUp)
	if err != nil {
		t.Fatalf("Falied to move hat up")
	}
	err = vg.HatRelease(HatUp)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatRight)
	if err != nil {
		t.Fatalf("Falied to move hat right")
	}
	err = vg.HatRelease(HatRight)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatDown)
	if err != nil {
		t.Fatalf("Falied to move hat down")
	}
	err = vg.HatRelease(HatDown)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatLeft)
	if err != nil {
		t.Fatalf("Falied to move hat left")
	}
	err = vg.HatRelease(HatLeft)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
}

func TestGamepadCreationFailsOnEmptyPath(t *testing.T) {
	expected := "device path must not be empty"
	_, err := CreateGamepad("", []byte("Gamepad"), 0xDEAD, 0xBEEF)
	if err.Error() != expected {
		t.Fatalf("Expected: %s\nActual: %s", expected, err)
	}
}

func TestGamepadCreationFailsOnNonExistentPathName(t *testing.T) {
	path := "/some/bogus/path"
	_, err := CreateGamepad(path, []byte("Gamepad"), 0xDEAD, 0xBEEF)
	if !os.IsNotExist(err) {
		t.Fatalf("Expected: os.IsNotExist error\nActual: %s", err)
	}
}

func TestGamepadCreationFailsOnWrongPathName(t *testing.T) {
	file, err := ioutil.TempFile(os.TempDir(), "uinput-gamepad-test-")
	if err != nil {
		t.Fatalf("Failed to setup test. Unable to create tempfile: %v", err)
	}
	defer file.Close()

	expected := "failed to register virtual gamepad device: failed to close device: inappropriate ioctl for device"
	_, err = CreateGamepad(file.Name(), []byte("GamepadDevice"), 0xDEAD, 0xBEEF)
	if err == nil || !(expected == err.Error()) {
		t.Fatalf("Expected: %s\nActual: %s", expected, err)
	}
}

func TestGamepadCreationFailsIfNameIsTooLong(t *testing.T) {
	name := "adsfdsferqewoirueworiuejdsfjdfa;ljoewrjeworiewuoruew;rj;kdlfjoeai;jfewoaifjef;das"
	expected := fmt.Sprintf("device name %s is too long (maximum of %d characters allowed)", name, uinputMaxNameSize)
	_, err := CreateGamepad("/dev/uinput", []byte(name), 0xDEAD, 0xBEEF)
	if err.Error() != expected {
		t.Fatalf("Expected: %s\nActual: %s", expected, err)
	}
}

func TestGamepadButtonEventsFailOnClosedDevice(t *testing.T) {
	gamepad, err := CreateGamepad("/dev/uinput", []byte("Test Gamepad"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}
	_ = gamepad.Close()

	err = gamepad.ButtonUp(1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
	err = gamepad.ButtonDown(1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
	err = gamepad.ButtonPress(1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
}

func TestGamepadHatEventsFailOnClosedDevice(t *testing.T) {
	gamepad, err := CreateGamepad("/dev/uinput", []byte("Test Gamepad"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}
	_ = gamepad.Close()

	err = gamepad.HatPress(HatUp)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
	err = gamepad.HatRelease(HatUp)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
}

func TestGamepadMoveToFailsOnClosedDevice(t *testing.T) {
	gamepad, err := CreateGamepad("/dev/uinput", []byte("Test Gamepad"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}
	_ = gamepad.Close()

	err = gamepad.LeftStickMoveX(1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
	err = gamepad.LeftStickMoveY(1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
	err = gamepad.LeftStickMove(1, 1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}

	err = gamepad.RightStickMoveX(1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
	err = gamepad.RightStickMoveY(1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
	err = gamepad.RightStickMove(1, 1)
	if err == nil {
		t.Fatalf("Expected error due to closed device, but no error was returned.")
	}
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 electron

import (
	"qpid.apache.org/amqp"
	"qpid.apache.org/proton"
)

// NOTE: methods in this file are called only in the proton goroutine unless otherwise indicated.

type handler struct {
	delegator    *proton.MessagingAdapter
	connection   *connection
	links        map[proton.Link]Endpoint
	sentMessages map[proton.Delivery]sentMessage
	sessions     map[proton.Session]*session
}

func newHandler(c *connection) *handler {
	h := &handler{
		connection:   c,
		links:        make(map[proton.Link]Endpoint),
		sentMessages: make(map[proton.Delivery]sentMessage),
		sessions:     make(map[proton.Session]*session),
	}
	h.delegator = proton.NewMessagingAdapter(h)
	// Disable auto features of MessagingAdapter, we do these ourselves.
	h.delegator.Prefetch = 0
	h.delegator.AutoAccept = false
	h.delegator.AutoSettle = false
	h.delegator.AutoOpen = false
	return h
}

func (h *handler) linkError(l proton.Link, msg string) {
	proton.CloseError(l, amqp.Errorf(amqp.InternalError, "%s for %s %s", msg, l.Type(), l))
}

func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) {
	switch t {

	case proton.MMessage:
		if r, ok := h.links[e.Link()].(*receiver); ok {
			r.message(e.Delivery())
		} else {
			h.linkError(e.Link(), "no receiver")
		}

	case proton.MSettled:
		if sm, ok := h.sentMessages[e.Delivery()]; ok {
			d := e.Delivery().Remote()
			sm.ack <- Outcome{sentStatus(d.Type()), d.Condition().Error(), sm.value}
			delete(h.sentMessages, e.Delivery())
		}

	case proton.MSendable:
		if s, ok := h.links[e.Link()].(*sender); ok {
			s.sendable()
		} else {
			h.linkError(e.Link(), "no sender")
		}

	case proton.MConnectionOpening:
		h.connection.heartbeat = e.Transport().RemoteIdleTimeout()
		if e.Connection().State().LocalUninit() { // Remotely opened
			h.incoming(newIncomingConnection(h.connection))
		}
		h.connection.wakeSync()

	case proton.MSessionOpening:
		if e.Session().State().LocalUninit() { // Remotely opened
			h.incoming(newIncomingSession(h, e.Session()))
		}
		h.sessions[e.Session()].wakeSync()

	case proton.MSessionClosed:
		h.sessionClosed(e.Session(), proton.EndpointError(e.Session()))

	case proton.MLinkOpening:
		l := e.Link()
		if ss := h.sessions[l.Session()]; ss != nil {
			if l.State().LocalUninit() { // Remotely opened.
				if l.IsReceiver() {
					h.incoming(newIncomingReceiver(ss, l))
				} else {
					h.incoming(newIncomingSender(ss, l))
				}
			}
			if ep, ok := h.links[l]; ok {
				ep.wakeSync()
			} else {
				h.linkError(l, "no link")
			}
		} else {
			h.linkError(l, "no session")
		}

	case proton.MLinkClosing:
		e.Link().Close()

	case proton.MLinkClosed:
		h.linkClosed(e.Link(), proton.EndpointError(e.Link()))

	case proton.MConnectionClosing:
		h.connection.err.Set(e.Connection().RemoteCondition().Error())

	case proton.MConnectionClosed:
		h.shutdown(proton.EndpointError(e.Connection()))

	case proton.MDisconnected:
		err := e.Transport().Condition().Error()
		if err == nil {
			err = amqp.Errorf(amqp.IllegalState, "unexpected disconnect on %s", h.connection)
		}
		h.shutdown(err)
	}
}

func (h *handler) incoming(in Incoming) {
	var err error
	if h.connection.incoming != nil {
		h.connection.incoming <- in
		// Must block until accept/reject, subsequent events may use the incoming endpoint.
		err = in.wait()
	} else {
		err = amqp.Errorf(amqp.NotAllowed, "rejected incoming %s %s",
			in.pEndpoint().Type(), in.pEndpoint().String())
	}
	if err == nil {
		in.pEndpoint().Open()
	} else {
		proton.CloseError(in.pEndpoint(), err)
	}
}

func (h *handler) addLink(pl proton.Link, el Endpoint) {
	h.links[pl] = el
}

func (h *handler) linkClosed(l proton.Link, err error) {
	if link, ok := h.links[l]; ok {
		_ = link.closed(err)
		delete(h.links, l)
	}
}

func (h *handler) sessionClosed(ps proton.Session, err error) {
	if s, ok := h.sessions[ps]; ok {
		delete(h.sessions, ps)
		err = s.closed(err)
		for l, _ := range h.links {
			if l.Session() == ps {
				h.linkClosed(l, err)
			}
		}
	}
}

func (h *handler) shutdown(err error) {
	err = h.connection.closed(err)
	for _, sm := range h.sentMessages {
		// Don't block but ensure outcome is sent eventually.
		if sm.ack != nil {
			o := Outcome{Unacknowledged, err, sm.value}
			select {
			case sm.ack <- o:
			default:
				go func(ack chan<- Outcome) { ack <- o }(sm.ack) // Deliver it eventually
			}
		}
	}
	h.sentMessages = nil
	for _, l := range h.links {
		_ = l.closed(err)
	}
	h.links = nil
	for _, s := range h.sessions {
		_ = s.closed(err)
	}
	h.sessions = nil
}
<commit_msg>PROTON-1332: go: electron client leaking links/sessions<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 electron

import (
	"qpid.apache.org/amqp"
	"qpid.apache.org/proton"
)

// NOTE: methods in this file are called only in the proton goroutine unless otherwise indicated.

type handler struct {
	delegator    *proton.MessagingAdapter
	connection   *connection
	links        map[proton.Link]Endpoint
	sentMessages map[proton.Delivery]sentMessage
	sessions     map[proton.Session]*session
}

func newHandler(c *connection) *handler {
	h := &handler{
		connection:   c,
		links:        make(map[proton.Link]Endpoint),
		sentMessages: make(map[proton.Delivery]sentMessage),
		sessions:     make(map[proton.Session]*session),
	}
	h.delegator = proton.NewMessagingAdapter(h)
	// Disable auto features of MessagingAdapter, we do these ourselves.
	h.delegator.Prefetch = 0
	h.delegator.AutoAccept = false
	h.delegator.AutoSettle = false
	h.delegator.AutoOpen = false
	return h
}

func (h *handler) linkError(l proton.Link, msg string) {
	proton.CloseError(l, amqp.Errorf(amqp.InternalError, "%s for %s %s", msg, l.Type(), l))
}

func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) {
	switch t {

	case proton.MMessage:
		if r, ok := h.links[e.Link()].(*receiver); ok {
			r.message(e.Delivery())
		} else {
			h.linkError(e.Link(), "no receiver")
		}

	case proton.MSettled:
		if sm, ok := h.sentMessages[e.Delivery()]; ok {
			d := e.Delivery().Remote()
			sm.ack <- Outcome{sentStatus(d.Type()), d.Condition().Error(), sm.value}
			delete(h.sentMessages, e.Delivery())
		}

	case proton.MSendable:
		if s, ok := h.links[e.Link()].(*sender); ok {
			s.sendable()
		} else {
			h.linkError(e.Link(), "no sender")
		}

	case proton.MConnectionOpening:
		h.connection.heartbeat = e.Transport().RemoteIdleTimeout()
		if e.Connection().State().LocalUninit() { // Remotely opened
			h.incoming(newIncomingConnection(h.connection))
		}
		h.connection.wakeSync()

	case proton.MSessionOpening:
		if e.Session().State().LocalUninit() { // Remotely opened
			h.incoming(newIncomingSession(h, e.Session()))
		}
		h.sessions[e.Session()].wakeSync()

	case proton.MSessionClosed:
		h.sessionClosed(e.Session(), proton.EndpointError(e.Session()))

	case proton.MLinkOpening:
		l := e.Link()
		if ss := h.sessions[l.Session()]; ss != nil {
			if l.State().LocalUninit() { // Remotely opened.
				if l.IsReceiver() {
					h.incoming(newIncomingReceiver(ss, l))
				} else {
					h.incoming(newIncomingSender(ss, l))
				}
			}
			if ep, ok := h.links[l]; ok {
				ep.wakeSync()
			} else {
				h.linkError(l, "no link")
			}
		} else {
			h.linkError(l, "no session")
		}

	case proton.MLinkClosing:
		e.Link().Close()

	case proton.MLinkClosed:
		h.linkClosed(e.Link(), proton.EndpointError(e.Link()))

	case proton.MConnectionClosing:
		h.connection.err.Set(e.Connection().RemoteCondition().Error())

	case proton.MConnectionClosed:
		h.shutdown(proton.EndpointError(e.Connection()))

	case proton.MDisconnected:
		err := e.Transport().Condition().Error()
		if err == nil {
			err = amqp.Errorf(amqp.IllegalState, "unexpected disconnect on %s", h.connection)
		}
		h.shutdown(err)
	}
}

func (h *handler) incoming(in Incoming) {
	var err error
	if h.connection.incoming != nil {
		h.connection.incoming <- in
		// Must block until accept/reject, subsequent events may use the incoming endpoint.
		err = in.wait()
	} else {
		err = amqp.Errorf(amqp.NotAllowed, "rejected incoming %s %s",
			in.pEndpoint().Type(), in.pEndpoint().String())
	}
	if err == nil {
		in.pEndpoint().Open()
	} else {
		proton.CloseError(in.pEndpoint(), err)
	}
}

func (h *handler) addLink(pl proton.Link, el Endpoint) {
	h.links[pl] = el
}

func (h *handler) linkClosed(l proton.Link, err error) {
	if link, ok := h.links[l]; ok {
		_ = link.closed(err)
		delete(h.links, l)
		l.Free()
	}
}

func (h *handler) sessionClosed(ps proton.Session, err error) {
	if s, ok := h.sessions[ps]; ok {
		delete(h.sessions, ps)
		err = s.closed(err)
		for l, _ := range h.links {
			if l.Session() == ps {
				h.linkClosed(l, err)
			}
		}
		ps.Free()
	}
}

func (h *handler) shutdown(err error) {
	err = h.connection.closed(err)
	for _, sm := range h.sentMessages {
		// Don't block but ensure outcome is sent eventually.
		if sm.ack != nil {
			o := Outcome{Unacknowledged, err, sm.value}
			select {
			case sm.ack <- o:
			default:
				go func(ack chan<- Outcome) { ack <- o }(sm.ack) // Deliver it eventually
			}
		}
	}
	h.sentMessages = nil
	for _, l := range h.links {
		_ = l.closed(err)
	}
	h.links = nil
	for _, s := range h.sessions {
		_ = s.closed(err)
	}
	h.sessions = nil
}
<|endoftext|>


<commit_before>package iter

import (
	"github.com/reiver/go-iter/string"

	"testing"
)

func TestForSingle(t *testing.T) {

	const expectedValue = "Hello world!"
	slice := []string{
		expectedValue,
	}

	iterator := &iterstring.Slice{
		Slice: slice,
	}

	var actualValue string
	numIteration := 0
	err := For{iterator}.Each(func(datum string){
		numIteration++

		actualValue = datum
	})
	if nil != err {
		t.Errorf("Did not expect an error, but actually got one: (%T) %v", err, err)
		return
	}
	if expected, actual := len(slice), numIteration; expected != actual {
		t.Errorf("Expected %d, but actually got %d.", expected, actual)
		return
	}
	if expected, actual := expectedValue, actualValue; expected != actual {
		t.Errorf("Expected %q, but actually got %q.", expected, actual)
		return
	}
}

func TestForMant(t *testing.T) {

	slice := []string{
		"Apple",
		"Banana",
		"Cherry",
		"Date",
	}

	iterator := &iterstring.Slice{
		Slice: slice,
	}

	var actualValues []string
	err := For{iterator}.Each(func(datum string){
		actualValues = append(actualValues, datum)
	})
	if nil != err {
		t.Errorf("Did not expect an error, but actually got one: (%T) %v", err, err)
		return
	}
	if expected, actual := len(slice), len(actualValues); expected != actual {
		t.Errorf("Expected %d, but actually got %d.", expected, actual)
		return
	}
	for valueNumber, expectedValue := range slice {
		actualValue := actualValues[valueNumber]

		if expected, actual := expectedValue, actualValue; expected != actual {
			t.Errorf("For value #%d, expected %q, but actually got %q.", valueNumber, expected, actual)
			continue
		}
	}
}

func TestForFail(t *testing.T) {

	const expectedValue = "Hello world!"
	slice := []string{
		expectedValue,
	}

	iterator := &iterstring.Slice{
		Slice: slice,
	}

	var actualValue int64
	numIteration := 0
	err := For{iterator}.Each(func(datum int64){
		numIteration++

		actualValue = datum
	})
	if nil == err {
		t.Errorf("Expect an error, but did not actually got one: %v", err)
		return
	}
	if expected, actual := 0, numIteration; expected != actual {
		t.Errorf("Expected %d, but actually got %d.", expected, actual)
		return
	}
}
<commit_msg>corrected typo<commit_after>package iter

import (
	"github.com/reiver/go-iter/string"

	"testing"
)

func TestForSingle(t *testing.T) {

	const expectedValue = "Hello world!"
	slice := []string{
		expectedValue,
	}

	iterator := &iterstring.Slice{
		Slice: slice,
	}

	var actualValue string
	numIteration := 0
	err := For{iterator}.Each(func(datum string){
		numIteration++

		actualValue = datum
	})
	if nil != err {
		t.Errorf("Did not expect an error, but actually got one: (%T) %v", err, err)
		return
	}
	if expected, actual := len(slice), numIteration; expected != actual {
		t.Errorf("Expected %d, but actually got %d.", expected, actual)
		return
	}
	if expected, actual := expectedValue, actualValue; expected != actual {
		t.Errorf("Expected %q, but actually got %q.", expected, actual)
		return
	}
}

func TestForMany(t *testing.T) {

	slice := []string{
		"Apple",
		"Banana",
		"Cherry",
		"Date",
	}

	iterator := &iterstring.Slice{
		Slice: slice,
	}

	var actualValues []string
	err := For{iterator}.Each(func(datum string){
		actualValues = append(actualValues, datum)
	})
	if nil != err {
		t.Errorf("Did not expect an error, but actually got one: (%T) %v", err, err)
		return
	}
	if expected, actual := len(slice), len(actualValues); expected != actual {
		t.Errorf("Expected %d, but actually got %d.", expected, actual)
		return
	}
	for valueNumber, expectedValue := range slice {
		actualValue := actualValues[valueNumber]

		if expected, actual := expectedValue, actualValue; expected != actual {
			t.Errorf("For value #%d, expected %q, but actually got %q.", valueNumber, expected, actual)
			continue
		}
	}
}

func TestForFail(t *testing.T) {

	const expectedValue = "Hello world!"
	slice := []string{
		expectedValue,
	}

	iterator := &iterstring.Slice{
		Slice: slice,
	}

	var actualValue int64
	numIteration := 0
	err := For{iterator}.Each(func(datum int64){
		numIteration++

		actualValue = datum
	})
	if nil == err {
		t.Errorf("Expect an error, but did not actually got one: %v", err)
		return
	}
	if expected, actual := 0, numIteration; expected != actual {
		t.Errorf("Expected %d, but actually got %d.", expected, actual)
		return
	}
}
<|endoftext|>


<commit_before>package fastsql

import (
	"database/sql"
	"net/url"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	_ "github.com/go-sql-driver/mysql"
) //import

func TestClose(t *testing.T) {
	var (
		err error
		dbh *DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}

	if err = dbh.Close(); err != nil {
		t.Fatal(err)
	}
}

func TestOpen(t *testing.T) {
	var (
		err        error
		insertRate uint = 100
		dbh        *DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbh.insertRate != insertRate {
		t.Fatal("'insertRate' not being set correctly in Open().")
	}

	if dbh.values != " VALUES" {
		t.Fatal("'values' not being set correctly in Open().")
	}
}

func TestFlush(t *testing.T) {
	var (
		err     error
		query   string
		dbh     *DB
		dbhMock *sql.DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbhMock, err = sqlmock.New(); err != nil {
		t.Fatal(err)
	}
	defer dbhMock.Close()

	dbh.SetDB(dbhMock)

	query = "INSERT INTO table_name(a, b, c) VALUES(?, ?, ?);"

	for i := 0; i < 3; i++ {
		if err = dbh.BatchInsert(
			query,
			[]interface{}{
				1,
				2,
				3,
			}...,
		); err != nil {
			t.Fatal(err)
		}
	}

	sqlmock.ExpectExec("insert into table_name\\(a, b, c\\) VALUES\\(\\?, \\?, \\?\\),\\(\\?, \\?, \\?\\),\\(\\?, \\?, \\?\\)").
		WithArgs(1, 2, 3, 1, 2, 3, 1, 2, 3).
		WillReturnResult(sqlmock.NewResult(0, 3))

	if err = dbh.Flush(); err != nil {
		t.Fatal(err)
	}

	if dbh.values != " VALUES" {
		t.Fatal("dbh.values not properly reset by dbh.Flush().")
	}

	if len(dbh.bindParams) > 0 {
		t.Fatal("dbh.bindParams not properly reset by dbh.Flush().")
	}

	if dbh.insertCtr != 0 {
		t.Fatal("dbh.insertCtr not properly reset by dbh.Flush().")
	}
}

func TestBatchInsert(t *testing.T) {
	var (
		err     error
		query   string
		dbh     *DB
		dbhMock *sql.DB
	) //var

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbhMock, err = sqlmock.New(); err != nil {
		t.Fatal(err)
	}
	defer dbhMock.Close()

	dbh.SetDB(dbhMock)

	query = "INSERT INTO table_name(a, b, c) VALUES(?, ?, ?);"

	for i := 0; i < 3; i++ {
		if err = dbh.BatchInsert(
			query,
			[]interface{}{
				1,
				2,
				3,
			}...,
		); err != nil {
			t.Fatal(err)
		}
	}

	if len(dbh.bindParams) != 9 {
		t.Log(dbh.bindParams)
		t.Fatal("dbh.bindParams not properly set by dbh.BatchInsert().")
	}

	if dbh.insertCtr != 3 {
		t.Log(dbh.insertCtr)
		t.Fatal("dbh.insertCtr not properly being set by dbh.BatchInsert().")
	}

	if dbh.values != " VALUES(?, ?, ?),(?, ?, ?),(?, ?, ?)," {
		t.Log(dbh.values)
		t.Fatal("dbh.values not properly being set by dbh.BatchInsert().")
	}
}

func (this *DB) TestSetDB(t *testing.T) {
	var (
		err     error
		dbhMock *sql.DB
		dbh     *DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbhMock, err = sqlmock.New(); err != nil {
		t.Fatal(err)
	}
	defer dbhMock.Close()

	if err = dbh.SetDB(dbhMock); err != nil {
		t.Fatal(err)
	}
}

func TestSplitQuery(t *testing.T) {
	var (
		err     error
		query   string
		dbh     *DB
		dbhMock *sql.DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbhMock, err = sqlmock.New(); err != nil {
		t.Fatal(err)
	}
	defer dbhMock.Close()

	dbh.SetDB(dbhMock)

	query = "INSERT INTO table_name(a, b, c) VALUES(?, ?, ?);"

	if err = dbh.BatchInsert(
		query,
		[]interface{}{
			1,
			2,
			3,
		}...,
	); err != nil {
		t.Fatal(err)
	}

	if dbh.queryPart1 != "insert into table_name(a, b, c)" {
		t.Log("*" + dbh.queryPart1 + "*")
		t.Fatal("dbh.queryPart1 not formatted correctly.")
	}

	if dbh.queryPart2 != "(?, ?, ?)," {
		t.Log("*" + dbh.queryPart2 + "*")
		t.Fatal("dbh.queryPart2 not formatted correctly.")
	}
}
<commit_msg>Added more test coverage in Flush()<commit_after>package fastsql

import (
	"database/sql"
	"net/url"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	_ "github.com/go-sql-driver/mysql"
) //import

func TestClose(t *testing.T) {
	var (
		err error
		dbh *DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}

	if err = dbh.Close(); err != nil {
		t.Fatal(err)
	}
}

func TestOpen(t *testing.T) {
	var (
		err        error
		insertRate uint = 100
		dbh        *DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbh.insertRate != insertRate {
		t.Fatal("'insertRate' not being set correctly in Open().")
	}

	if dbh.values != " VALUES" {
		t.Fatal("'values' not being set correctly in Open().")
	}
}

func TestFlush(t *testing.T) {
	var (
		err     error
		query   string
		dbh     *DB
		dbhMock *sql.DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbhMock, err = sqlmock.New(); err != nil {
		t.Fatal(err)
	}
	defer dbhMock.Close()

	dbh.SetDB(dbhMock)

	query = "INSERT INTO table_name(a, b, c) VALUES(?, ?, ?);"

	for i := 0; i < 3; i++ {
		if err = dbh.BatchInsert(
			query,
			[]interface{}{
				1,
				2,
				3,
			}...,
		); err != nil {
			t.Fatal(err)
		}
	}

	sqlmock.ExpectExec("insert into table_name\\(a, b, c\\) VALUES\\(\\?, \\?, \\?\\),\\(\\?, \\?, \\?\\),\\(\\?, \\?, \\?\\)").
		WithArgs(1, 2, 3, 1, 2, 3, 1, 2, 3).
		WillReturnResult(sqlmock.NewResult(0, 3))

	if err = dbh.Flush(); err != nil {
		t.Fatal(err)
	}

	if dbh.values != " VALUES" {
		t.Fatal("dbh.values not properly reset by dbh.Flush().")
	}

	if len(dbh.bindParams) > 0 {
		t.Fatal("dbh.bindParams not properly reset by dbh.Flush().")
	}

	if dbh.insertCtr != 0 {
		t.Fatal("dbh.insertCtr not properly reset by dbh.Flush().")
	}

	// Test prepared statement error
	dbh.Close()
	if err = dbh.Flush(); err == nil {
		t.Fatal("Expecting prepared statement to fail and throw an error.")
	}
}

func TestBatchInsert(t *testing.T) {
	var (
		err     error
		query   string
		dbh     *DB
		dbhMock *sql.DB
	) //var

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbhMock, err = sqlmock.New(); err != nil {
		t.Fatal(err)
	}
	defer dbhMock.Close()

	dbh.SetDB(dbhMock)

	query = "INSERT INTO table_name(a, b, c) VALUES(?, ?, ?);"

	for i := 0; i < 3; i++ {
		if err = dbh.BatchInsert(
			query,
			[]interface{}{
				1,
				2,
				3,
			}...,
		); err != nil {
			t.Fatal(err)
		}
	}

	if len(dbh.bindParams) != 9 {
		t.Log(dbh.bindParams)
		t.Fatal("dbh.bindParams not properly set by dbh.BatchInsert().")
	}

	if dbh.insertCtr != 3 {
		t.Log(dbh.insertCtr)
		t.Fatal("dbh.insertCtr not properly being set by dbh.BatchInsert().")
	}

	if dbh.values != " VALUES(?, ?, ?),(?, ?, ?),(?, ?, ?)," {
		t.Log(dbh.values)
		t.Fatal("dbh.values not properly being set by dbh.BatchInsert().")
	}
}

func (this *DB) TestSetDB(t *testing.T) {
	var (
		err     error
		dbhMock *sql.DB
		dbh     *DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbhMock, err = sqlmock.New(); err != nil {
		t.Fatal(err)
	}
	defer dbhMock.Close()

	if err = dbh.SetDB(dbhMock); err != nil {
		t.Fatal(err)
	}
}

func TestSplitQuery(t *testing.T) {
	var (
		err     error
		query   string
		dbh     *DB
		dbhMock *sql.DB
	)

	t.Parallel()

	if dbh, err = Open("mysql", "user:pass@tcp(localhost:3306)/db_name?"+url.QueryEscape("charset=utf8mb4,utf8&loc=America/New_York"), 100); err != nil {
		t.Fatal(err)
	}
	defer dbh.Close()

	if dbhMock, err = sqlmock.New(); err != nil {
		t.Fatal(err)
	}
	defer dbhMock.Close()

	dbh.SetDB(dbhMock)

	query = "INSERT INTO table_name(a, b, c) VALUES(?, ?, ?);"

	if err = dbh.BatchInsert(
		query,
		[]interface{}{
			1,
			2,
			3,
		}...,
	); err != nil {
		t.Fatal(err)
	}

	if dbh.queryPart1 != "insert into table_name(a, b, c)" {
		t.Log("*" + dbh.queryPart1 + "*")
		t.Fatal("dbh.queryPart1 not formatted correctly.")
	}

	if dbh.queryPart2 != "(?, ?, ?)," {
		t.Log("*" + dbh.queryPart2 + "*")
		t.Fatal("dbh.queryPart2 not formatted correctly.")
	}
}
<|endoftext|>


<commit_before>package chapter6

import (
	"math/rand"
	"sort"
	"testing"
	"time"
)

func TestOfflineMinimum(t *testing.T) {
	rand.Seed(time.Now().UTC().UnixNano())

	size_A, size_E := 100, 10

	for tc := 0; tc < 100; tc++ {
		A := rand.Perm(size_A)

		E := make([]int, size_E)
		for i := range E {
			E[i] = rand.Intn(size_A) + 1
		}

		sort.Ints(E)

		expected := make([]int, size_E)

		curr := make([]int, 0, len(A))
		for i := 0; i < size_E; i++ {
			// read new elements
			if i == 0 {
				curr = append(curr, A[:E[i]]...)
			} else {
				curr = append(curr, A[E[i-1]:E[i]]...)
			}
			sort.Ints(curr)
			expected[i] = curr[0] // curr[0] is min element
			curr = curr[1:]       // remove min element
		}

		actual := OfflineMinimum(A, E)

		for i, v := range expected {
			if v != actual[i] {
				t.Errorf("OfflineMinimum(%v, %v): at %d: expected %d, actual %d", A, E, i+1, v, actual[i])
			}
		}
	}
}
<commit_msg>Skip OfflineMinimum tests<commit_after>package chapter6

import (
	"math/rand"
	"sort"
	"testing"
	"time"
)

func TestOfflineMinimum(t *testing.T) {
	t.Skip("Skipping TestOfflineMinimum.")

	rand.Seed(time.Now().UTC().UnixNano())

	size_A, size_E := 100, 10

	for tc := 0; tc < 100; tc++ {
		A := rand.Perm(size_A)

		E := make([]int, size_E)
		for i := range E {
			E[i] = rand.Intn(size_A) + 1
		}

		sort.Ints(E)

		expected := make([]int, size_E)

		curr := make([]int, 0, len(A))
		for i := 0; i < size_E; i++ {
			// read new elements
			if i == 0 {
				curr = append(curr, A[:E[i]]...)
			} else {
				curr = append(curr, A[E[i-1]:E[i]]...)
			}
			sort.Ints(curr)
			expected[i] = curr[0] // curr[0] is min element
			curr = curr[1:]       // remove min element
		}

		actual := OfflineMinimum(A, E)

		for i, v := range expected {
			if v != actual[i] {
				t.Errorf("OfflineMinimum(%v, %v): at %d: expected %d, actual %d", A, E, i+1, v, actual[i])
			}
		}
	}
}
<|endoftext|>


<commit_before>// Errors and error handling

package fs

import (
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strings"

	"github.com/pkg/errors"
)

// Retrier is an optional interface for error as to whether the
// operation should be retried at a high level.
//
// This should be returned from Update or Put methods as required
type Retrier interface {
	error
	Retry() bool
}

// retryError is a type of error
type retryError string

// Error interface
func (r retryError) Error() string {
	return string(r)
}

// Retry interface
func (r retryError) Retry() bool {
	return true
}

// Check interface
var _ Retrier = retryError("")

// RetryErrorf makes an error which indicates it would like to be retried
func RetryErrorf(format string, a ...interface{}) error {
	return retryError(fmt.Sprintf(format, a...))
}

// wrappedRetryError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedRetryError struct {
	error
}

// Retry interface
func (err wrappedRetryError) Retry() bool {
	return true
}

// Check interface
var _ Retrier = wrappedRetryError{(error)(nil)}

// RetryError makes an error which indicates it would like to be retried
func RetryError(err error) error {
	if err == nil {
		err = errors.New("needs retry")
	}
	return wrappedRetryError{err}
}

// IsRetryError returns true if err conforms to the Retry interface
// and calling the Retry method returns true.
func IsRetryError(err error) bool {
	if err == nil {
		return false
	}
	err = errors.Cause(err)
	if r, ok := err.(Retrier); ok {
		return r.Retry()
	}
	return false
}

// Fataler is an optional interface for error as to whether the
// operation should cause the entire operation to finish immediately.
//
// This should be returned from Update or Put methods as required
type Fataler interface {
	error
	Fatal() bool
}

// wrappedFatalError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedFatalError struct {
	error
}

// Fatal interface
func (err wrappedFatalError) Fatal() bool {
	return true
}

// Check interface
var _ Fataler = wrappedFatalError{(error)(nil)}

// FatalError makes an error which indicates it is a fatal error and
// the sync should stop.
func FatalError(err error) error {
	if err == nil {
		err = errors.New("fatal error")
	}
	return wrappedFatalError{err}
}

// IsFatalError returns true if err conforms to the Fatal interface
// and calling the Fatal method returns true.
func IsFatalError(err error) bool {
	if err == nil {
		return false
	}
	err = errors.Cause(err)
	if r, ok := err.(Fataler); ok {
		return r.Fatal()
	}
	return false
}

// NoRetrier is an optional interface for error as to whether the
// operation should not be retried at a high level.
//
// If only NoRetry errors are returned in a sync then the sync won't
// be retried.
//
// This should be returned from Update or Put methods as required
type NoRetrier interface {
	error
	NoRetry() bool
}

// wrappedNoRetryError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedNoRetryError struct {
	error
}

// NoRetry interface
func (err wrappedNoRetryError) NoRetry() bool {
	return true
}

// Check interface
var _ NoRetrier = wrappedNoRetryError{(error)(nil)}

// NoRetryError makes an error which indicates the sync shouldn't be
// retried.
func NoRetryError(err error) error {
	return wrappedNoRetryError{err}
}

// IsNoRetryError returns true if err conforms to the NoRetry
// interface and calling the NoRetry method returns true.
func IsNoRetryError(err error) bool {
	if err == nil {
		return false
	}
	err = errors.Cause(err)
	if r, ok := err.(NoRetrier); ok {
		return r.NoRetry()
	}
	return false
}

// Cause is a souped up errors.Cause which can unwrap some standard
// library errors too.  It returns true if any of the intermediate
// errors had a Timeout() or Temporary() method which returned true.
func Cause(cause error) (retriable bool, err error) {
	err = cause
	for prev := err; err != nil; prev = err {
		// Check for net error Timeout()
		if x, ok := err.(interface {
			Timeout() bool
		}); ok && x.Timeout() {
			retriable = true
		}

		// Check for net error Temporary()
		if x, ok := err.(interface {
			Temporary() bool
		}); ok && x.Temporary() {
			retriable = true
		}

		// Unwrap 1 level if possible
		err = errors.Cause(err)
		if err == prev {
			// Unpack any struct or *struct with a field
			// of name Err which satisfies the error
			// interface.  This includes *url.Error,
			// *net.OpError, *os.SyscallError and many
			// others in the stdlib
			errType := reflect.TypeOf(err)
			errValue := reflect.ValueOf(err)
			if errType.Kind() == reflect.Ptr {
				errType = errType.Elem()
				errValue = errValue.Elem()
			}
			if errType.Kind() == reflect.Struct {
				if errField := errValue.FieldByName("Err"); errField.IsValid() {
					errFieldValue := errField.Interface()
					if newErr, ok := errFieldValue.(error); ok {
						err = newErr
					}
				}
			}
		}
		if err == prev {
			break
		}
	}
	return retriable, err
}

// retriableErrorStrings is a list of phrases which when we find it
// in an an error, we know it is a networking error which should be
// retried.
//
// This is incredibly ugly - if only errors.Cause worked for all
// errors and all errors were exported from the stdlib.
var retriableErrorStrings = []string{
	"use of closed network connection", // not exported :-(
}

// Errors which indicate networking errors which should be retried
//
// These are added to in retriable_errors*.go
var retriableErrors = []error{
	io.EOF,
	io.ErrUnexpectedEOF,
}

// ShouldRetry looks at an error and tries to work out if retrying the
// operation that caused it would be a good idea. It returns true if
// the error implements Timeout() or Temporary() or if the error
// indicates a premature closing of the connection.
func ShouldRetry(err error) bool {
	if err == nil {
		return false
	}

	// Find root cause if available
	retriable, err := Cause(err)
	if retriable {
		return true
	}

	// Check if it is a retriable error
	for _, retriableErr := range retriableErrors {
		if err == retriableErr {
			return true
		}
	}

	// Check error strings (yuch!) too
	errString := err.Error()
	for _, phrase := range retriableErrorStrings {
		if strings.Contains(errString, phrase) {
			return true
		}
	}

	return false
}

// ShouldRetryHTTP returns a boolean as to whether this resp deserves.
// It checks to see if the HTTP response code is in the slice
// retryErrorCodes.
func ShouldRetryHTTP(resp *http.Response, retryErrorCodes []int) bool {
	if resp == nil {
		return false
	}
	for _, e := range retryErrorCodes {
		if resp.StatusCode == e {
			return true
		}
	}
	return false
}
<commit_msg>fs: Add "unexpected EOF reading trailer" as a retriable error - fixes #1730<commit_after>// Errors and error handling

package fs

import (
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strings"

	"github.com/pkg/errors"
)

// Retrier is an optional interface for error as to whether the
// operation should be retried at a high level.
//
// This should be returned from Update or Put methods as required
type Retrier interface {
	error
	Retry() bool
}

// retryError is a type of error
type retryError string

// Error interface
func (r retryError) Error() string {
	return string(r)
}

// Retry interface
func (r retryError) Retry() bool {
	return true
}

// Check interface
var _ Retrier = retryError("")

// RetryErrorf makes an error which indicates it would like to be retried
func RetryErrorf(format string, a ...interface{}) error {
	return retryError(fmt.Sprintf(format, a...))
}

// wrappedRetryError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedRetryError struct {
	error
}

// Retry interface
func (err wrappedRetryError) Retry() bool {
	return true
}

// Check interface
var _ Retrier = wrappedRetryError{(error)(nil)}

// RetryError makes an error which indicates it would like to be retried
func RetryError(err error) error {
	if err == nil {
		err = errors.New("needs retry")
	}
	return wrappedRetryError{err}
}

// IsRetryError returns true if err conforms to the Retry interface
// and calling the Retry method returns true.
func IsRetryError(err error) bool {
	if err == nil {
		return false
	}
	err = errors.Cause(err)
	if r, ok := err.(Retrier); ok {
		return r.Retry()
	}
	return false
}

// Fataler is an optional interface for error as to whether the
// operation should cause the entire operation to finish immediately.
//
// This should be returned from Update or Put methods as required
type Fataler interface {
	error
	Fatal() bool
}

// wrappedFatalError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedFatalError struct {
	error
}

// Fatal interface
func (err wrappedFatalError) Fatal() bool {
	return true
}

// Check interface
var _ Fataler = wrappedFatalError{(error)(nil)}

// FatalError makes an error which indicates it is a fatal error and
// the sync should stop.
func FatalError(err error) error {
	if err == nil {
		err = errors.New("fatal error")
	}
	return wrappedFatalError{err}
}

// IsFatalError returns true if err conforms to the Fatal interface
// and calling the Fatal method returns true.
func IsFatalError(err error) bool {
	if err == nil {
		return false
	}
	err = errors.Cause(err)
	if r, ok := err.(Fataler); ok {
		return r.Fatal()
	}
	return false
}

// NoRetrier is an optional interface for error as to whether the
// operation should not be retried at a high level.
//
// If only NoRetry errors are returned in a sync then the sync won't
// be retried.
//
// This should be returned from Update or Put methods as required
type NoRetrier interface {
	error
	NoRetry() bool
}

// wrappedNoRetryError is an error wrapped so it will satisfy the
// Retrier interface and return true
type wrappedNoRetryError struct {
	error
}

// NoRetry interface
func (err wrappedNoRetryError) NoRetry() bool {
	return true
}

// Check interface
var _ NoRetrier = wrappedNoRetryError{(error)(nil)}

// NoRetryError makes an error which indicates the sync shouldn't be
// retried.
func NoRetryError(err error) error {
	return wrappedNoRetryError{err}
}

// IsNoRetryError returns true if err conforms to the NoRetry
// interface and calling the NoRetry method returns true.
func IsNoRetryError(err error) bool {
	if err == nil {
		return false
	}
	err = errors.Cause(err)
	if r, ok := err.(NoRetrier); ok {
		return r.NoRetry()
	}
	return false
}

// Cause is a souped up errors.Cause which can unwrap some standard
// library errors too.  It returns true if any of the intermediate
// errors had a Timeout() or Temporary() method which returned true.
func Cause(cause error) (retriable bool, err error) {
	err = cause
	for prev := err; err != nil; prev = err {
		// Check for net error Timeout()
		if x, ok := err.(interface {
			Timeout() bool
		}); ok && x.Timeout() {
			retriable = true
		}

		// Check for net error Temporary()
		if x, ok := err.(interface {
			Temporary() bool
		}); ok && x.Temporary() {
			retriable = true
		}

		// Unwrap 1 level if possible
		err = errors.Cause(err)
		if err == prev {
			// Unpack any struct or *struct with a field
			// of name Err which satisfies the error
			// interface.  This includes *url.Error,
			// *net.OpError, *os.SyscallError and many
			// others in the stdlib
			errType := reflect.TypeOf(err)
			errValue := reflect.ValueOf(err)
			if errType.Kind() == reflect.Ptr {
				errType = errType.Elem()
				errValue = errValue.Elem()
			}
			if errType.Kind() == reflect.Struct {
				if errField := errValue.FieldByName("Err"); errField.IsValid() {
					errFieldValue := errField.Interface()
					if newErr, ok := errFieldValue.(error); ok {
						err = newErr
					}
				}
			}
		}
		if err == prev {
			break
		}
	}
	return retriable, err
}

// retriableErrorStrings is a list of phrases which when we find it
// in an an error, we know it is a networking error which should be
// retried.
//
// This is incredibly ugly - if only errors.Cause worked for all
// errors and all errors were exported from the stdlib.
var retriableErrorStrings = []string{
	"use of closed network connection", // not exported :-(
	"unexpected EOF reading trailer",
}

// Errors which indicate networking errors which should be retried
//
// These are added to in retriable_errors*.go
var retriableErrors = []error{
	io.EOF,
	io.ErrUnexpectedEOF,
}

// ShouldRetry looks at an error and tries to work out if retrying the
// operation that caused it would be a good idea. It returns true if
// the error implements Timeout() or Temporary() or if the error
// indicates a premature closing of the connection.
func ShouldRetry(err error) bool {
	if err == nil {
		return false
	}

	// Find root cause if available
	retriable, err := Cause(err)
	if retriable {
		return true
	}

	// Check if it is a retriable error
	for _, retriableErr := range retriableErrors {
		if err == retriableErr {
			return true
		}
	}

	// Check error strings (yuch!) too
	errString := err.Error()
	for _, phrase := range retriableErrorStrings {
		if strings.Contains(errString, phrase) {
			return true
		}
	}

	return false
}

// ShouldRetryHTTP returns a boolean as to whether this resp deserves.
// It checks to see if the HTTP response code is in the slice
// retryErrorCodes.
func ShouldRetryHTTP(resp *http.Response, retryErrorCodes []int) bool {
	if resp == nil {
		return false
	}
	for _, e := range retryErrorCodes {
		if resp.StatusCode == e {
			return true
		}
	}
	return false
}
<|endoftext|>