<commit_before>package main

import (
	"errors"
	"fmt"
	"net/http"

	"github.com/Xe/middleware"
	"github.com/codegangsta/negroni"
	"github.com/drone/routes"
	"github.com/goincremental/negroni-sessions"
	"stevenbooru.cf/csrf"
	"stevenbooru.cf/eye"
	. "stevenbooru.cf/globals"
	"stevenbooru.cf/middleware/users"
	"stevenbooru.cf/models"
)

func main() {
	mux := routes.New()

	mux.Get("/", func(rw http.ResponseWriter, r *http.Request) {
		eye.DoTemplate("index", rw, r, nil)
	})

	mux.Get("/login", func(rw http.ResponseWriter, r *http.Request) {
		tok := csrf.SetToken(r)
		eye.DoTemplate("users/login", rw, r, tok)
	})

	mux.Post("/login", func(rw http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()

		if err != nil {
			panic(err)
		}

		sess := sessions.GetSession(r)

		tok := r.PostForm.Get("token")
		if !csrf.CheckToken(tok, r) {
			eye.HandleError(rw, r, errors.New("Invalid CSRF token"))
			return
		}

		user, err := models.Login(r.PostForm)
		if err != nil {
			if err == models.ErrBadPassword {
				err = errors.New("invalid password")
			}

			eye.HandleError(rw, r, err)
			return
		}

		sess.Set("uid", user.UUID)

		http.Redirect(rw, r, "/", http.StatusMovedPermanently)
	})

	mux.Get("/logout", func(rw http.ResponseWriter, r *http.Request) {
		sess := sessions.GetSession(r)
		sess.Delete("uid")

		http.Redirect(rw, r, "/", http.StatusMovedPermanently)
	})

	mux.Get("/register", func(rw http.ResponseWriter, r *http.Request) {
		tok := csrf.SetToken(r)
		eye.DoTemplate("users/register", rw, r, tok)
	})

	mux.Post("/register", func(rw http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()

		if err != nil {
			panic(err)
		}

		sess := sessions.GetSession(r)

		tok := r.PostForm.Get("token")
		if !csrf.CheckToken(tok, r) {
			eye.HandleError(rw, r, errors.New("Invalid CSRF token"))
			return
		}

		u, err := models.NewUser(r.PostForm)
		if err != nil {
			eye.HandleError(rw, r, err)
		}

		sess.Set("uid", u.UUID)

		http.Redirect(rw, r, "/", http.StatusMovedPermanently)
	})

	n := negroni.Classic()

	n.Use(sessions.Sessions("stevenbooru", CookieStore))
	n.Use(&users.Middleware{})
	middleware.Inject(n)
	n.UseHandler(mux)

	n.Run(fmt.Sprintf("%s:%s", Config.HTTP.Bindhost, Config.HTTP.Port))
}
<commit_msg>Add testing code for error generation here<commit_after>package main

import (
	"errors"
	"fmt"
	"net/http"

	"github.com/Xe/middleware"
	"github.com/codegangsta/negroni"
	"github.com/drone/routes"
	"github.com/goincremental/negroni-sessions"
	"stevenbooru.cf/csrf"
	"stevenbooru.cf/eye"
	. "stevenbooru.cf/globals"
	"stevenbooru.cf/middleware/users"
	"stevenbooru.cf/models"
)

func main() {
	mux := routes.New()

	mux.Get("/", func(rw http.ResponseWriter, r *http.Request) {
		eye.DoTemplate("index", rw, r, nil)
	})

	mux.Get("/login", func(rw http.ResponseWriter, r *http.Request) {
		tok := csrf.SetToken(r)
		eye.DoTemplate("users/login", rw, r, tok)
	})

	mux.Post("/login", func(rw http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()

		if err != nil {
			panic(err)
		}

		sess := sessions.GetSession(r)

		tok := r.PostForm.Get("token")
		if !csrf.CheckToken(tok, r) {
			eye.HandleError(rw, r, errors.New("Invalid CSRF token"))
			return
		}

		user, err := models.Login(r.PostForm)
		if err != nil {
			if err == models.ErrBadPassword {
				err = errors.New("invalid password")
			}

			eye.HandleError(rw, r, err)
			return
		}

		sess.Set("uid", user.UUID)

		http.Redirect(rw, r, "/", http.StatusMovedPermanently)
	})

	mux.Get("/logout", func(rw http.ResponseWriter, r *http.Request) {
		sess := sessions.GetSession(r)
		sess.Delete("uid")

		http.Redirect(rw, r, "/", http.StatusMovedPermanently)
	})

	mux.Get("/register", func(rw http.ResponseWriter, r *http.Request) {
		tok := csrf.SetToken(r)
		eye.DoTemplate("users/register", rw, r, tok)
	})

	mux.Post("/register", func(rw http.ResponseWriter, r *http.Request) {
		err := r.ParseForm()

		if err != nil {
			panic(err)
		}

		sess := sessions.GetSession(r)

		tok := r.PostForm.Get("token")
		if !csrf.CheckToken(tok, r) {
			eye.HandleError(rw, r, errors.New("Invalid CSRF token"))
			return
		}

		u, err := models.NewUser(r.PostForm)
		if err != nil {
			eye.HandleError(rw, r, err)
		}

		sess.Set("uid", u.UUID)

		http.Redirect(rw, r, "/", http.StatusMovedPermanently)
	})

	// Test code goes here
	if Config.Site.Testing {
		mux.Get("/____error____", func(rw http.ResponseWriter, r *http.Request) {
			eye.HandleError(rw, r, errors.New("test error"))
		})
	}

	n := negroni.Classic()

	n.Use(sessions.Sessions("stevenbooru", CookieStore))
	n.Use(&users.Middleware{})
	middleware.Inject(n)
	n.UseHandler(mux)

	n.Run(fmt.Sprintf("%s:%s", Config.HTTP.Bindhost, Config.HTTP.Port))
}
<|endoftext|>


<commit_before>package warserver

import (
    "container/list"
    "encoding/json"
    "errors"
    "fmt"
    "os"
    "strings"
    "warserver/logger"
    "github.com/DomoCo/connection"
    "code.google.com/p/go-sqlite/go1/sqlite3"
)

const (
    NUM_PLAYERS = 2
)

type newGame struct {
    NumPlayers int
    cconn *clientConnection
}

type localHandler func(message string, cconn *clientConnection)

type game_hub struct {
    gameRequests chan *newGame
    uncommittedGames map[int]*game
    committedGames *list.List
    connRegister chan connection.Connection
    localHandlers map[string]localHandler
}

func (gh *game_hub) handleWebsocket(message []byte, cconn *clientConnection) {
    cmds := strings.SplitN(string(message), ":", 2)
    if len(cmds) == 2 {
        if fun, ok := gh.localHandlers[cmds[0]]; ok {
            fun(cmds[1], cconn)
        } else {
            logger.Warnf("Unrecognized command: %s", cmds[0])
            cconn.toClient <- []byte("unrecognized:")
        }
    } else {
        logger.Errorf("Malformed command: %s", cmds)
    }
}

func (gh *game_hub) handleClientInfo(message string, cconn *clientConnection) {
    ci := clientInfo{}
    // I hate repeating this unmarshalling code, does Go allow something more general?
    err := json.Unmarshal([]byte(message), &ci)
    if err != nil {
        logger.Warnf("Error unmarshalling json: %s", err)
        return
    }
    userid, err := getClientIdFromToken(ci.Token)
    if err != nil {
        logger.Errorf("Error querying database: %s", err)
        cconn.toClient <- []byte("clientinfo:failure")
        return
    }
    ci.id = userid
    cconn.info = ci
    cconn.toClient <- []byte("clientinfo:success")
}

func getClientIdFromToken(token string) (int, error) {
    dbPath := os.Getenv("DOMOROOT") + "/domoweb/db.sqlite3"
    db, err := sqlite3.Open(dbPath)
    if err != nil {
        logger.Fatalf("%s", err)
    }
    defer db.Close()

    sql := fmt.Sprintf("select id, userid from interface_logindata where token='%s';", token)
    for rows, err := db.Query(sql); err == nil; rows.Next() {
        var rowId int
        var userId int
        err := rows.Scan(&rowId, &userId)
        if err != nil {
            return 0, err
        }
        deleteRow := fmt.Sprintf("delete from interface_logindata where id='%s';", rowId)
        err = db.Exec(deleteRow)
        if err != nil {
            return 0, err
        }

        return userId, nil
    }

    return 0, errors.New("SQL query totally failed")
}

func (gh *game_hub) handleNewGame(message string, cconn *clientConnection) {
    ng := newGame{}
    err := json.Unmarshal([]byte(message), &ng)
    if err != nil {
        logger.Warnf("Error unmarshalling json: %s", err)
        return
    }
    ng.cconn = cconn
    logger.Infof("Got new game %s", ng)
    gh.gameRequests <- &ng
}

func (gh *game_hub) handleDisconnection(message string, cconn *clientConnection) {
    // Find the connection and kill it, cleaning up its game if necessary
    logger.Info("Client Disconnected. Cleaning up...")
    for np, game := range gh.uncommittedGames {
        for i := 0; i < game.currentPlayers; i++ {
            if game.proxy.proxyConns[i].info.id == cconn.info.id {
                game.proxy.removeClientConnection(i)
                game.currentPlayers -= 1
                if game.currentPlayers == 0 {
                    logger.Infof("%d player uncommitted game empty. Dropping", np)
                    delete(gh.uncommittedGames, np)
                }
                break
            }
        }
    }
}

func (gh *game_hub) handleConnections() {
    for conn := range gh.connRegister {
        cconn := clientConnection{conn: conn, currentHandler: gh,
                                  handlers: make(chan websocketHandler, 5),
                                  toClient: make(chan []byte)}
        go cconn.wsReadPump()
        go cconn.wsWritePump()
    }
}

func (gh *game_hub) makeGame(numPlayers int) *game {
    proxy := *newProxy(numPlayers)
    game := game{numPlayers: numPlayers, currentPlayers: 0,
                 proxy: &proxy}
    gh.uncommittedGames[numPlayers] = &game

    return &game
}

func (gh *game_hub) commitGame(game *game) {
    delete(gh.uncommittedGames, game.numPlayers)
    // make connection to server

    conn, err := connectToServer()
    if err != nil {
        logger.Errorf("Could not connect to server, this game is going to hang...")
        return
    }
    game.proxy.server = &serverConnection{conn: conn}
    game.channelInHandler(game.proxy)
    go game.proxy.serverReadPump()
    game.proxy.sendInitialGameInfo()
    logger.Info("Committed a game, proxying its messages")

    gh.committedGames.PushBack(game)
}

func (gh *game_hub) processNewGameRequests() {
    for ng := range gh.gameRequests {
        // look for an existing game to satisfy the new request
        gm := gh.findGame(ng)
        // create a game if one can't be found
        if gm == nil {
            logger.Info("Couldn't find an available game. Creating a new one")
            gm = gh.makeGame(ng.NumPlayers)
        } else {
            logger.Info("Found existing game. Slotting in")
        }
        gm.proxy.slotClientConnection(gm.currentPlayers, ng.cconn)
        gm.currentPlayers += 1
        if gm.currentPlayers == gm.numPlayers {
            gh.commitGame(gm)
        }
    }
}

func (gh *game_hub) findGame(ng *newGame) *game {
    game := gh.uncommittedGames[ng.NumPlayers]
    return game
}

var gamehub = game_hub {
    gameRequests: make(chan *newGame),
    uncommittedGames: make(map [int]*game),
    committedGames: list.New(),
    connRegister: make(chan connection.Connection),
    localHandlers: make(map [string]localHandler),
}

func setupGamehub() {
    gamehub.localHandlers["clientInfo"] = gamehub.handleClientInfo
    hookupLobbyHandlers()

    go gamehub.processNewGameRequests()
}

func hookupLobbyHandlers() {
    gamehub.localHandlers["newGame"] = gamehub.handleNewGame
    gamehub.localHandlers["killClient"] = gamehub.handleDisconnection
}
<commit_msg>Hopefully prevent database locks when pulling rows<commit_after>package warserver

import (
    "container/list"
    "encoding/json"
    "errors"
    "fmt"
    "os"
    "strings"
    "warserver/logger"
    "github.com/DomoCo/connection"
    "code.google.com/p/go-sqlite/go1/sqlite3"
)

const (
    NUM_PLAYERS = 2
)

type newGame struct {
    NumPlayers int
    cconn *clientConnection
}

type localHandler func(message string, cconn *clientConnection)

type game_hub struct {
    gameRequests chan *newGame
    uncommittedGames map[int]*game
    committedGames *list.List
    connRegister chan connection.Connection
    localHandlers map[string]localHandler
}

func (gh *game_hub) handleWebsocket(message []byte, cconn *clientConnection) {
    cmds := strings.SplitN(string(message), ":", 2)
    if len(cmds) == 2 {
        if fun, ok := gh.localHandlers[cmds[0]]; ok {
            fun(cmds[1], cconn)
        } else {
            logger.Warnf("Unrecognized command: %s", cmds[0])
            cconn.toClient <- []byte("unrecognized:")
        }
    } else {
        logger.Errorf("Malformed command: %s", cmds)
    }
}

func (gh *game_hub) handleClientInfo(message string, cconn *clientConnection) {
    ci := clientInfo{}
    // I hate repeating this unmarshalling code, does Go allow something more general?
    err := json.Unmarshal([]byte(message), &ci)
    if err != nil {
        logger.Warnf("Error unmarshalling json: %s", err)
        return
    }
    userid, err := getClientIdFromToken(ci.Token)
    if err != nil {
        logger.Errorf("Error querying database: %s", err)
        cconn.toClient <- []byte("clientinfo:failure")
        return
    }
    ci.id = userid
    cconn.info = ci
    cconn.toClient <- []byte("clientinfo:success")
}

func getClientIdFromToken(token string) (int, error) {
    dbPath := os.Getenv("DOMOROOT") + "/domoweb/db.sqlite3"
    db, err := sqlite3.Open(dbPath)
    if err != nil {
        logger.Fatalf("%s", err)
    }
    defer db.Close()

    sql := fmt.Sprintf("select id, userid from interface_logindata where token='%s';", token)
    for rows, err := db.Query(sql); err == nil; rows.Next() {
        defer rows.Close()
        var rowId int
        var userId int
        err := rows.Scan(&rowId, &userId)
        if err != nil {
            return 0, err
        }
        deleteRow := fmt.Sprintf("delete from interface_logindata where id='%s';", rowId)
        err = db.Exec(deleteRow)
        if err != nil {
            return 0, err
        }

        return userId, nil
    }

    return 0, errors.New("SQL query totally failed")
}

func (gh *game_hub) handleNewGame(message string, cconn *clientConnection) {
    ng := newGame{}
    err := json.Unmarshal([]byte(message), &ng)
    if err != nil {
        logger.Warnf("Error unmarshalling json: %s", err)
        return
    }
    ng.cconn = cconn
    logger.Infof("Got new game %s", ng)
    gh.gameRequests <- &ng
}

func (gh *game_hub) handleDisconnection(message string, cconn *clientConnection) {
    // Find the connection and kill it, cleaning up its game if necessary
    logger.Info("Client Disconnected. Cleaning up...")
    for np, game := range gh.uncommittedGames {
        for i := 0; i < game.currentPlayers; i++ {
            if game.proxy.proxyConns[i].info.id == cconn.info.id {
                game.proxy.removeClientConnection(i)
                game.currentPlayers -= 1
                if game.currentPlayers == 0 {
                    logger.Infof("%d player uncommitted game empty. Dropping", np)
                    delete(gh.uncommittedGames, np)
                }
                break
            }
        }
    }
}

func (gh *game_hub) handleConnections() {
    for conn := range gh.connRegister {
        cconn := clientConnection{conn: conn, currentHandler: gh,
                                  handlers: make(chan websocketHandler, 5),
                                  toClient: make(chan []byte)}
        go cconn.wsReadPump()
        go cconn.wsWritePump()
    }
}

func (gh *game_hub) makeGame(numPlayers int) *game {
    proxy := *newProxy(numPlayers)
    game := game{numPlayers: numPlayers, currentPlayers: 0,
                 proxy: &proxy}
    gh.uncommittedGames[numPlayers] = &game

    return &game
}

func (gh *game_hub) commitGame(game *game) {
    delete(gh.uncommittedGames, game.numPlayers)
    // make connection to server

    conn, err := connectToServer()
    if err != nil {
        logger.Errorf("Could not connect to server, this game is going to hang...")
        return
    }
    game.proxy.server = &serverConnection{conn: conn}
    game.channelInHandler(game.proxy)
    go game.proxy.serverReadPump()
    game.proxy.sendInitialGameInfo()
    logger.Info("Committed a game, proxying its messages")

    gh.committedGames.PushBack(game)
}

func (gh *game_hub) processNewGameRequests() {
    for ng := range gh.gameRequests {
        // look for an existing game to satisfy the new request
        gm := gh.findGame(ng)
        // create a game if one can't be found
        if gm == nil {
            logger.Info("Couldn't find an available game. Creating a new one")
            gm = gh.makeGame(ng.NumPlayers)
        } else {
            logger.Info("Found existing game. Slotting in")
        }
        gm.proxy.slotClientConnection(gm.currentPlayers, ng.cconn)
        gm.currentPlayers += 1
        if gm.currentPlayers == gm.numPlayers {
            gh.commitGame(gm)
        }
    }
}

func (gh *game_hub) findGame(ng *newGame) *game {
    game := gh.uncommittedGames[ng.NumPlayers]
    return game
}

var gamehub = game_hub {
    gameRequests: make(chan *newGame),
    uncommittedGames: make(map [int]*game),
    committedGames: list.New(),
    connRegister: make(chan connection.Connection),
    localHandlers: make(map [string]localHandler),
}

func setupGamehub() {
    gamehub.localHandlers["clientInfo"] = gamehub.handleClientInfo
    hookupLobbyHandlers()

    go gamehub.processNewGameRequests()
}

func hookupLobbyHandlers() {
    gamehub.localHandlers["newGame"] = gamehub.handleNewGame
    gamehub.localHandlers["killClient"] = gamehub.handleDisconnection
}
<|endoftext|>


<commit_before>package config

import (
	"os"
	"xd/lib/configparser"
)

type RPCConfig struct {
	Enabled bool
	Bind    string
	// TODO: authentication
}

const DefaultRPCAddr = "127.0.0.1:1488"

func (cfg *RPCConfig) Load(s *configparser.Section) error {
	if s != nil {
		cfg.Bind = s.Get("bind", DefaultRPCAddr)
		cfg.Enabled = s.Get("enabled", "1") == "1"
	}
	if cfg.Bind == "" {
		cfg.Bind = DefaultRPCAddr
	}
	return nil
}

func (cfg *RPCConfig) Save(s *configparser.Section) error {
	enabled := "1"
	if !cfg.Enabled {
		enabled = "0"
	}
	opts := map[string]string{
		"enabled": enabled,
	}
	if cfg.Bind != "" {
		opts["bind"] = cfg.Bind
	}

	for k := range opts {
		s.Add(k, opts[k])
	}

	return nil
}

const EnvRPCAddr = "XD_RPC_ADDRESS"

func (cfg *RPCConfig) LoadEnv() {
	addr := os.Getenv(EnvRPCAddr)
	if addr != "" {
		cfg.Bind = addr
	}
}
<commit_msg>enable rpc by default<commit_after>package config

import (
	"os"
	"xd/lib/configparser"
)

type RPCConfig struct {
	Enabled bool
	Bind    string
	// TODO: authentication
}

const DefaultRPCAddr = "127.0.0.1:1488"

func (cfg *RPCConfig) Load(s *configparser.Section) error {
	if s != nil {
		cfg.Bind = s.Get("bind", DefaultRPCAddr)
		cfg.Enabled = s.Get("enabled", "1") == "1"
	}
	if cfg.Bind == "" {
		cfg.Bind = DefaultRPCAddr
		cfg.Enabled = true
	}
	return nil
}

func (cfg *RPCConfig) Save(s *configparser.Section) error {
	enabled := "1"
	if !cfg.Enabled {
		enabled = "0"
	}
	opts := map[string]string{
		"enabled": enabled,
	}
	if cfg.Bind != "" {
		opts["bind"] = cfg.Bind
	}

	for k := range opts {
		s.Add(k, opts[k])
	}

	return nil
}

const EnvRPCAddr = "XD_RPC_ADDRESS"

func (cfg *RPCConfig) LoadEnv() {
	addr := os.Getenv(EnvRPCAddr)
	if addr != "" {
		cfg.Bind = addr
	}
}
<|endoftext|>


<commit_before>package storage

import (
	"fmt"
	"path"
	"strconv"
	"sync"
	"time"

	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/storage/backend"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/storage/super_block"
	"github.com/chrislusf/seaweedfs/weed/storage/types"

	"github.com/chrislusf/seaweedfs/weed/glog"
)

type Volume struct {
	Id                 needle.VolumeId
	dir                string
	Collection         string
	DataBackend        backend.BackendStorageFile
	nm                 NeedleMapper
	needleMapKind      NeedleMapType
	noWriteOrDelete    bool // if readonly, either noWriteOrDelete or noWriteCanDelete
	noWriteCanDelete   bool // if readonly, either noWriteOrDelete or noWriteCanDelete
	MemoryMapMaxSizeMb uint32

	super_block.SuperBlock

	dataFileAccessLock    sync.RWMutex
	lastModifiedTsSeconds uint64 //unix time in seconds
	lastAppendAtNs        uint64 //unix time in nanoseconds

	lastCompactIndexOffset uint64
	lastCompactRevision    uint16

	isCompacting bool

	volumeTierInfo *volume_server_pb.VolumeTierInfo
}

func NewVolume(dirname string, collection string, id needle.VolumeId, needleMapKind NeedleMapType, replicaPlacement *super_block.ReplicaPlacement, ttl *needle.TTL, preallocate int64, memoryMapMaxSizeMb uint32) (v *Volume, e error) {
	// if replicaPlacement is nil, the superblock will be loaded from disk
	v = &Volume{dir: dirname, Collection: collection, Id: id, MemoryMapMaxSizeMb: memoryMapMaxSizeMb}
	v.SuperBlock = super_block.SuperBlock{ReplicaPlacement: replicaPlacement, Ttl: ttl}
	v.needleMapKind = needleMapKind
	e = v.load(true, true, needleMapKind, preallocate)
	return
}
func (v *Volume) String() string {
	return fmt.Sprintf("Id:%v, dir:%s, Collection:%s, dataFile:%v, nm:%v, noWrite:%v canDelete:%v", v.Id, v.dir, v.Collection, v.DataBackend, v.nm, v.noWriteOrDelete || v.noWriteCanDelete, v.noWriteCanDelete)
}

func VolumeFileName(dir string, collection string, id int) (fileName string) {
	idString := strconv.Itoa(id)
	if collection == "" {
		fileName = path.Join(dir, idString)
	} else {
		fileName = path.Join(dir, collection+"_"+idString)
	}
	return
}
func (v *Volume) FileName() (fileName string) {
	return VolumeFileName(v.dir, v.Collection, int(v.Id))
}

func (v *Volume) Version() needle.Version {
	return v.SuperBlock.Version
}

func (v *Volume) FileStat() (datSize uint64, idxSize uint64, modTime time.Time) {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()

	if v.DataBackend == nil {
		return
	}

	datFileSize, modTime, e := v.DataBackend.GetStat()
	if e == nil {
		return uint64(datFileSize), v.nm.IndexFileSize(), modTime
	}
	glog.V(0).Infof("Failed to read file size %s %v", v.DataBackend.Name(), e)
	return // -1 causes integer overflow and the volume to become unwritable.
}

func (v *Volume) ContentSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.ContentSize()
}

func (v *Volume) DeletedSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.DeletedSize()
}

func (v *Volume) FileCount() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return uint64(v.nm.FileCount())
}

func (v *Volume) DeletedCount() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return uint64(v.nm.DeletedCount())
}

func (v *Volume) MaxFileKey() types.NeedleId {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.MaxFileKey()
}

func (v *Volume) IndexFileSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.IndexFileSize()
}

// Close cleanly shuts down this volume
func (v *Volume) Close() {
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if v.nm != nil {
		v.nm.Close()
		v.nm = nil
	}
	if v.DataBackend != nil {
		_ = v.DataBackend.Close()
		v.DataBackend = nil
		stats.VolumeServerVolumeCounter.WithLabelValues(v.Collection, "volume").Dec()
	}
}

func (v *Volume) NeedToReplicate() bool {
	return v.ReplicaPlacement.GetCopyCount() > 1
}

// volume is expired if modified time + volume ttl < now
// except when volume is empty
// or when the volume does not have a ttl
// or when volumeSizeLimit is 0 when server just starts
func (v *Volume) expired(volumeSizeLimit uint64) bool {
	if volumeSizeLimit == 0 {
		//skip if we don't know size limit
		return false
	}
	if v.ContentSize() == 0 {
		return false
	}
	if v.Ttl == nil || v.Ttl.Minutes() == 0 {
		return false
	}
	glog.V(1).Infof("now:%v lastModified:%v", time.Now().Unix(), v.lastModifiedTsSeconds)
	livedMinutes := (time.Now().Unix() - int64(v.lastModifiedTsSeconds)) / 60
	glog.V(1).Infof("ttl:%v lived:%v", v.Ttl, livedMinutes)
	if int64(v.Ttl.Minutes()) < livedMinutes {
		return true
	}
	return false
}

// wait either maxDelayMinutes or 10% of ttl minutes
func (v *Volume) expiredLongEnough(maxDelayMinutes uint32) bool {
	if v.Ttl == nil || v.Ttl.Minutes() == 0 {
		return false
	}
	removalDelay := v.Ttl.Minutes() / 10
	if removalDelay > maxDelayMinutes {
		removalDelay = maxDelayMinutes
	}

	if uint64(v.Ttl.Minutes()+removalDelay)*60+v.lastModifiedTsSeconds < uint64(time.Now().Unix()) {
		return true
	}
	return false
}

func (v *Volume) ToVolumeInformationMessage() *master_pb.VolumeInformationMessage {
	size, _, modTime := v.FileStat()

	volumInfo := &master_pb.VolumeInformationMessage{
		Id:               uint32(v.Id),
		Size:             size,
		Collection:       v.Collection,
		FileCount:        uint64(v.FileCount()),
		DeleteCount:      uint64(v.DeletedCount()),
		DeletedByteCount: v.DeletedSize(),
		ReadOnly:         v.noWriteOrDelete,
		ReplicaPlacement: uint32(v.ReplicaPlacement.Byte()),
		Version:          uint32(v.Version()),
		Ttl:              v.Ttl.ToUint32(),
		CompactRevision:  uint32(v.SuperBlock.CompactionRevision),
		ModifiedAtSecond: modTime.Unix(),
	}

	volumInfo.RemoteStorageName, volumInfo.RemoteStorageKey = v.RemoteStorageNameKey()

	return volumInfo
}

func (v *Volume) RemoteStorageNameKey() (storageName, storageKey string) {
	if len(v.volumeTierInfo.GetFiles()) == 0 {
		return
	}
	return v.volumeTierInfo.GetFiles()[0].BackendName(), v.volumeTierInfo.GetFiles()[0].GetKey()
}
<commit_msg>remove the redundant type conversion<commit_after>package storage

import (
	"fmt"
	"path"
	"strconv"
	"sync"
	"time"

	"github.com/chrislusf/seaweedfs/weed/pb/master_pb"
	"github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/storage/backend"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
	"github.com/chrislusf/seaweedfs/weed/storage/super_block"
	"github.com/chrislusf/seaweedfs/weed/storage/types"

	"github.com/chrislusf/seaweedfs/weed/glog"
)

type Volume struct {
	Id                 needle.VolumeId
	dir                string
	Collection         string
	DataBackend        backend.BackendStorageFile
	nm                 NeedleMapper
	needleMapKind      NeedleMapType
	noWriteOrDelete    bool // if readonly, either noWriteOrDelete or noWriteCanDelete
	noWriteCanDelete   bool // if readonly, either noWriteOrDelete or noWriteCanDelete
	MemoryMapMaxSizeMb uint32

	super_block.SuperBlock

	dataFileAccessLock    sync.RWMutex
	lastModifiedTsSeconds uint64 //unix time in seconds
	lastAppendAtNs        uint64 //unix time in nanoseconds

	lastCompactIndexOffset uint64
	lastCompactRevision    uint16

	isCompacting bool

	volumeTierInfo *volume_server_pb.VolumeTierInfo
}

func NewVolume(dirname string, collection string, id needle.VolumeId, needleMapKind NeedleMapType, replicaPlacement *super_block.ReplicaPlacement, ttl *needle.TTL, preallocate int64, memoryMapMaxSizeMb uint32) (v *Volume, e error) {
	// if replicaPlacement is nil, the superblock will be loaded from disk
	v = &Volume{dir: dirname, Collection: collection, Id: id, MemoryMapMaxSizeMb: memoryMapMaxSizeMb}
	v.SuperBlock = super_block.SuperBlock{ReplicaPlacement: replicaPlacement, Ttl: ttl}
	v.needleMapKind = needleMapKind
	e = v.load(true, true, needleMapKind, preallocate)
	return
}
func (v *Volume) String() string {
	return fmt.Sprintf("Id:%v, dir:%s, Collection:%s, dataFile:%v, nm:%v, noWrite:%v canDelete:%v", v.Id, v.dir, v.Collection, v.DataBackend, v.nm, v.noWriteOrDelete || v.noWriteCanDelete, v.noWriteCanDelete)
}

func VolumeFileName(dir string, collection string, id int) (fileName string) {
	idString := strconv.Itoa(id)
	if collection == "" {
		fileName = path.Join(dir, idString)
	} else {
		fileName = path.Join(dir, collection+"_"+idString)
	}
	return
}
func (v *Volume) FileName() (fileName string) {
	return VolumeFileName(v.dir, v.Collection, int(v.Id))
}

func (v *Volume) Version() needle.Version {
	return v.SuperBlock.Version
}

func (v *Volume) FileStat() (datSize uint64, idxSize uint64, modTime time.Time) {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()

	if v.DataBackend == nil {
		return
	}

	datFileSize, modTime, e := v.DataBackend.GetStat()
	if e == nil {
		return uint64(datFileSize), v.nm.IndexFileSize(), modTime
	}
	glog.V(0).Infof("Failed to read file size %s %v", v.DataBackend.Name(), e)
	return // -1 causes integer overflow and the volume to become unwritable.
}

func (v *Volume) ContentSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.ContentSize()
}

func (v *Volume) DeletedSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.DeletedSize()
}

func (v *Volume) FileCount() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return uint64(v.nm.FileCount())
}

func (v *Volume) DeletedCount() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return uint64(v.nm.DeletedCount())
}

func (v *Volume) MaxFileKey() types.NeedleId {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.MaxFileKey()
}

func (v *Volume) IndexFileSize() uint64 {
	v.dataFileAccessLock.RLock()
	defer v.dataFileAccessLock.RUnlock()
	if v.nm == nil {
		return 0
	}
	return v.nm.IndexFileSize()
}

// Close cleanly shuts down this volume
func (v *Volume) Close() {
	v.dataFileAccessLock.Lock()
	defer v.dataFileAccessLock.Unlock()
	if v.nm != nil {
		v.nm.Close()
		v.nm = nil
	}
	if v.DataBackend != nil {
		_ = v.DataBackend.Close()
		v.DataBackend = nil
		stats.VolumeServerVolumeCounter.WithLabelValues(v.Collection, "volume").Dec()
	}
}

func (v *Volume) NeedToReplicate() bool {
	return v.ReplicaPlacement.GetCopyCount() > 1
}

// volume is expired if modified time + volume ttl < now
// except when volume is empty
// or when the volume does not have a ttl
// or when volumeSizeLimit is 0 when server just starts
func (v *Volume) expired(volumeSizeLimit uint64) bool {
	if volumeSizeLimit == 0 {
		//skip if we don't know size limit
		return false
	}
	if v.ContentSize() == 0 {
		return false
	}
	if v.Ttl == nil || v.Ttl.Minutes() == 0 {
		return false
	}
	glog.V(1).Infof("now:%v lastModified:%v", time.Now().Unix(), v.lastModifiedTsSeconds)
	livedMinutes := (time.Now().Unix() - int64(v.lastModifiedTsSeconds)) / 60
	glog.V(1).Infof("ttl:%v lived:%v", v.Ttl, livedMinutes)
	if int64(v.Ttl.Minutes()) < livedMinutes {
		return true
	}
	return false
}

// wait either maxDelayMinutes or 10% of ttl minutes
func (v *Volume) expiredLongEnough(maxDelayMinutes uint32) bool {
	if v.Ttl == nil || v.Ttl.Minutes() == 0 {
		return false
	}
	removalDelay := v.Ttl.Minutes() / 10
	if removalDelay > maxDelayMinutes {
		removalDelay = maxDelayMinutes
	}

	if uint64(v.Ttl.Minutes()+removalDelay)*60+v.lastModifiedTsSeconds < uint64(time.Now().Unix()) {
		return true
	}
	return false
}

func (v *Volume) ToVolumeInformationMessage() *master_pb.VolumeInformationMessage {
	size, _, modTime := v.FileStat()

	volumInfo := &master_pb.VolumeInformationMessage{
		Id:               uint32(v.Id),
		Size:             size,
		Collection:       v.Collection,
		FileCount:        v.FileCount(),
		DeleteCount:      v.DeletedCount(),
		DeletedByteCount: v.DeletedSize(),
		ReadOnly:         v.noWriteOrDelete,
		ReplicaPlacement: uint32(v.ReplicaPlacement.Byte()),
		Version:          uint32(v.Version()),
		Ttl:              v.Ttl.ToUint32(),
		CompactRevision:  uint32(v.SuperBlock.CompactionRevision),
		ModifiedAtSecond: modTime.Unix(),
	}

	volumInfo.RemoteStorageName, volumInfo.RemoteStorageKey = v.RemoteStorageNameKey()

	return volumInfo
}

func (v *Volume) RemoteStorageNameKey() (storageName, storageKey string) {
	if len(v.volumeTierInfo.GetFiles()) == 0 {
		return
	}
	return v.volumeTierInfo.GetFiles()[0].BackendName(), v.volumeTierInfo.GetFiles()[0].GetKey()
}
<|endoftext|>


<commit_before>package util

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

var (
	client    *http.Client
	Transport *http.Transport
)

func init() {
	Transport = &http.Transport{
		MaxIdleConnsPerHost: 1024,
	}
	client = &http.Client{
		Transport: Transport,
	}
}

func PostBytes(url string, body []byte) ([]byte, error) {
	r, err := client.Post(url, "", bytes.NewReader(body))
	if err != nil {
		return nil, fmt.Errorf("Post to %s: %v", url, err)
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", url, r.Status)
	}
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, fmt.Errorf("Read response body: %v", err)
	}
	return b, nil
}

func Post(url string, values url.Values) ([]byte, error) {
	r, err := client.PostForm(url, values)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()
	b, err := ioutil.ReadAll(r.Body)
	if r.StatusCode >= 400 {
		if err != nil {
			return nil, fmt.Errorf("%s: %d - %s", url, r.StatusCode, string(b))
		} else {
			return nil, fmt.Errorf("%s: %s", url, r.Status)
		}
	}
	if err != nil {
		return nil, err
	}
	return b, nil
}

//	github.com/chrislusf/seaweedfs/unmaintained/repeated_vacuum/repeated_vacuum.go
//	may need increasing http.Client.Timeout
func Get(url string) ([]byte, error) {
	r, err := client.Get(url)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()
	b, err := ioutil.ReadAll(r.Body)
	if r.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", url, r.Status)
	}
	if err != nil {
		return nil, err
	}
	return b, nil
}

func Head(url string) (http.Header, error) {
	r, err := client.Head(url)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", url, r.Status)
	}
	return r.Header, nil
}

func Delete(url string, jwt string) error {
	req, err := http.NewRequest("DELETE", url, nil)
	if jwt != "" {
		req.Header.Set("Authorization", "BEARER "+string(jwt))
	}
	if err != nil {
		return err
	}
	resp, e := client.Do(req)
	if e != nil {
		return e
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	switch resp.StatusCode {
	case http.StatusNotFound, http.StatusAccepted, http.StatusOK:
		return nil
	}
	m := make(map[string]interface{})
	if e := json.Unmarshal(body, m); e == nil {
		if s, ok := m["error"].(string); ok {
			return errors.New(s)
		}
	}
	return errors.New(string(body))
}

func GetBufferStream(url string, values url.Values, allocatedBytes []byte, eachBuffer func([]byte)) error {
	r, err := client.PostForm(url, values)
	if err != nil {
		return err
	}
	defer r.Body.Close()
	if r.StatusCode != 200 {
		return fmt.Errorf("%s: %s", url, r.Status)
	}
	for {
		n, err := r.Body.Read(allocatedBytes)
		if n > 0 {
			eachBuffer(allocatedBytes[:n])
		}
		if err != nil {
			if err == io.EOF {
				return nil
			}
			return err
		}
	}
}

func GetUrlStream(url string, values url.Values, readFn func(io.Reader) error) error {
	r, err := client.PostForm(url, values)
	if err != nil {
		return err
	}
	defer r.Body.Close()
	if r.StatusCode != 200 {
		return fmt.Errorf("%s: %s", url, r.Status)
	}
	return readFn(r.Body)
}

func DownloadFile(fileUrl string) (filename string, header http.Header, rc io.ReadCloser, e error) {
	response, err := client.Get(fileUrl)
	if err != nil {
		return "", nil, nil, err
	}
	header = response.Header
	contentDisposition := response.Header["Content-Disposition"]
	if len(contentDisposition) > 0 {
		idx := strings.Index(contentDisposition[0], "filename=")
		if idx != -1 {
			filename = contentDisposition[0][idx+len("filename="):]
			filename = strings.Trim(filename, "\"")
		}
	}
	rc = response.Body
	return
}

func Do(req *http.Request) (resp *http.Response, err error) {
	return client.Do(req)
}

func NormalizeUrl(url string) string {
	if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
		return url
	}
	return "http://" + url
}

func ReadUrl(fileUrl string, offset int64, size int, buf []byte, isReadRange bool) (int64, error) {

	req, err := http.NewRequest("GET", fileUrl, nil)
	if err != nil {
		return 0, err
	}
	if isReadRange {
		req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+int64(size)))
	} else {
		req.Header.Set("Accept-Encoding", "gzip")
	}

	r, err := client.Do(req)
	if err != nil {
		return 0, err
	}

	defer r.Body.Close()
	if r.StatusCode >= 400 {
		return 0, fmt.Errorf("%s: %s", fileUrl, r.Status)
	}

	var reader io.ReadCloser
	switch r.Header.Get("Content-Encoding") {
	case "gzip":
		reader, err = gzip.NewReader(r.Body)
		defer reader.Close()
	default:
		reader = r.Body
	}

	var (
		i, m int
		n    int64
	)

	// refers to https://github.com/golang/go/blob/master/src/bytes/buffer.go#L199
	// commit id c170b14c2c1cfb2fd853a37add92a82fd6eb4318
	for {
		m, err = reader.Read(buf[i:])
		i += m
		n += int64(m)
		if err == io.EOF {
			return n, nil
		}
		if err != nil {
			return n, err
		}
	}

}

func ReadUrlAsStream(fileUrl string, offset int64, size int, fn func(data []byte)) (int64, error) {

	req, err := http.NewRequest("GET", fileUrl, nil)
	if err != nil {
		return 0, err
	}
	req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+int64(size)))

	r, err := client.Do(req)
	if err != nil {
		return 0, err
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		return 0, fmt.Errorf("%s: %s", fileUrl, r.Status)
	}

	var (
		m int
		n int64
	)
	buf := make([]byte, 64*1024)

	for {
		m, err = r.Body.Read(buf)
		fn(buf[:m])
		n += int64(m)
		if err == io.EOF {
			return n, nil
		}
		if err != nil {
			return n, err
		}
	}

}
<commit_msg>feat: drains http body if buffer is too small<commit_after>package util

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

var (
	client    *http.Client
	Transport *http.Transport
)

func init() {
	Transport = &http.Transport{
		MaxIdleConnsPerHost: 1024,
	}
	client = &http.Client{
		Transport: Transport,
	}
}

func PostBytes(url string, body []byte) ([]byte, error) {
	r, err := client.Post(url, "", bytes.NewReader(body))
	if err != nil {
		return nil, fmt.Errorf("Post to %s: %v", url, err)
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", url, r.Status)
	}
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, fmt.Errorf("Read response body: %v", err)
	}
	return b, nil
}

func Post(url string, values url.Values) ([]byte, error) {
	r, err := client.PostForm(url, values)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()
	b, err := ioutil.ReadAll(r.Body)
	if r.StatusCode >= 400 {
		if err != nil {
			return nil, fmt.Errorf("%s: %d - %s", url, r.StatusCode, string(b))
		} else {
			return nil, fmt.Errorf("%s: %s", url, r.Status)
		}
	}
	if err != nil {
		return nil, err
	}
	return b, nil
}

//	github.com/chrislusf/seaweedfs/unmaintained/repeated_vacuum/repeated_vacuum.go
//	may need increasing http.Client.Timeout
func Get(url string) ([]byte, error) {
	r, err := client.Get(url)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()
	b, err := ioutil.ReadAll(r.Body)
	if r.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", url, r.Status)
	}
	if err != nil {
		return nil, err
	}
	return b, nil
}

func Head(url string) (http.Header, error) {
	r, err := client.Head(url)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", url, r.Status)
	}
	return r.Header, nil
}

func Delete(url string, jwt string) error {
	req, err := http.NewRequest("DELETE", url, nil)
	if jwt != "" {
		req.Header.Set("Authorization", "BEARER "+string(jwt))
	}
	if err != nil {
		return err
	}
	resp, e := client.Do(req)
	if e != nil {
		return e
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	switch resp.StatusCode {
	case http.StatusNotFound, http.StatusAccepted, http.StatusOK:
		return nil
	}
	m := make(map[string]interface{})
	if e := json.Unmarshal(body, m); e == nil {
		if s, ok := m["error"].(string); ok {
			return errors.New(s)
		}
	}
	return errors.New(string(body))
}

func GetBufferStream(url string, values url.Values, allocatedBytes []byte, eachBuffer func([]byte)) error {
	r, err := client.PostForm(url, values)
	if err != nil {
		return err
	}
	defer r.Body.Close()
	if r.StatusCode != 200 {
		return fmt.Errorf("%s: %s", url, r.Status)
	}
	for {
		n, err := r.Body.Read(allocatedBytes)
		if n > 0 {
			eachBuffer(allocatedBytes[:n])
		}
		if err != nil {
			if err == io.EOF {
				return nil
			}
			return err
		}
	}
}

func GetUrlStream(url string, values url.Values, readFn func(io.Reader) error) error {
	r, err := client.PostForm(url, values)
	if err != nil {
		return err
	}
	defer r.Body.Close()
	if r.StatusCode != 200 {
		return fmt.Errorf("%s: %s", url, r.Status)
	}
	return readFn(r.Body)
}

func DownloadFile(fileUrl string) (filename string, header http.Header, rc io.ReadCloser, e error) {
	response, err := client.Get(fileUrl)
	if err != nil {
		return "", nil, nil, err
	}
	header = response.Header
	contentDisposition := response.Header["Content-Disposition"]
	if len(contentDisposition) > 0 {
		idx := strings.Index(contentDisposition[0], "filename=")
		if idx != -1 {
			filename = contentDisposition[0][idx+len("filename="):]
			filename = strings.Trim(filename, "\"")
		}
	}
	rc = response.Body
	return
}

func Do(req *http.Request) (resp *http.Response, err error) {
	return client.Do(req)
}

func NormalizeUrl(url string) string {
	if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
		return url
	}
	return "http://" + url
}

func ReadUrl(fileUrl string, offset int64, size int, buf []byte, isReadRange bool) (int64, error) {

	req, err := http.NewRequest("GET", fileUrl, nil)
	if err != nil {
		return 0, err
	}
	if isReadRange {
		req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+int64(size)))
	} else {
		req.Header.Set("Accept-Encoding", "gzip")
	}

	r, err := client.Do(req)
	if err != nil {
		return 0, err
	}

	defer r.Body.Close()
	if r.StatusCode >= 400 {
		return 0, fmt.Errorf("%s: %s", fileUrl, r.Status)
	}

	var reader io.ReadCloser
	switch r.Header.Get("Content-Encoding") {
	case "gzip":
		reader, err = gzip.NewReader(r.Body)
		defer reader.Close()
	default:
		reader = r.Body
	}

	var (
		i, m int
		n    int64
	)

	// refers to https://github.com/golang/go/blob/master/src/bytes/buffer.go#L199
	// commit id c170b14c2c1cfb2fd853a37add92a82fd6eb4318
	for {
		m, err = reader.Read(buf[i:])
		i += m
		n += int64(m)
		if err == io.EOF {
			return n, nil
		}
		if err != nil {
			return n, err
		}
		if n == int64(len(buf)) {
			break
		}
	}
	// drains the response body to avoid memory leak
	data, err := ioutil.ReadAll(reader)
	if len(data) != 0 {
		err = fmt.Errorf("buffer size is too small. remains %d", len(data))
	}
	return n, err
}

func ReadUrlAsStream(fileUrl string, offset int64, size int, fn func(data []byte)) (int64, error) {

	req, err := http.NewRequest("GET", fileUrl, nil)
	if err != nil {
		return 0, err
	}
	req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+int64(size)))

	r, err := client.Do(req)
	if err != nil {
		return 0, err
	}
	defer r.Body.Close()
	if r.StatusCode >= 400 {
		return 0, fmt.Errorf("%s: %s", fileUrl, r.Status)
	}

	var (
		m int
		n int64
	)
	buf := make([]byte, 64*1024)

	for {
		m, err = r.Body.Read(buf)
		fn(buf[:m])
		n += int64(m)
		if err == io.EOF {
			return n, nil
		}
		if err != nil {
			return n, err
		}
	}

}
<|endoftext|>


<commit_before>package crawlbot

import (
	"fmt"
	"log"
	"runtime"
	"testing"
)

var pagecount int

func TestCrawler(t *testing.T) {
	runtime.GOMAXPROCS(3)

	crawler := Crawler{
		URLs:       []string{"http://example.com", "http://cnn.com", "http://en.wikipedia.org"},
		NumWorkers: 12,
		Handler:    PrintTitle,
		CheckURL:   AllowEverything,
	}
	crawler.Start()
	crawler.Wait()
}

// Print the title of the page
func PrintTitle(resp *Response) {
	if resp.Err != nil {
		log.Println(resp.Err)
	}

	if resp.Doc != nil {
		title, err := resp.Doc.Search("//title")
		if err != nil {
			log.Println(err)
		}
		fmt.Printf("Title of %s is %s\n", resp.URL, title[0].Content())
	} else {
		fmt.Println("HTML was not parsed for " + resp.URL)
	}
}

// Crawl everything!
func AllowEverything(crawler *Crawler, url string) bool {
	return true
}
<commit_msg>Removing tests - not ready yet<commit_after><|endoftext|>


<commit_before>package avcompat

import "errors"

// ISC Errors
var (
	ErrIndexRange        = errors.New("Transition index exceeds encoding range")
	ErrSerialLength      = errors.New("Serial transition length cannot exceed 252 bytes")
	ErrSerialInvalidByte = errors.New("Serial transition cannot contain \\xFF byte")
	ErrDecodeLength      = errors.New("Cannot decode due to short buffer")
	ErrDecodeIllegal     = errors.New("Cannot decode due to invalid bitstream")
)

type ISCDigitalTransition struct {
	Index uint
	Value bool
}

type ISCAnalogTransition struct {
	Index uint
	Value uint16
}

type ISCSerialTransition struct {
	Index uint
	Value []byte
}

type ISCClearOperation struct{}
type ISCRefreshOperation struct{}

func (t *ISCDigitalTransition) MarshalBinary() ([]byte, error) {
	var buf [2]byte
	if t.Index > 4095 {
		return nil, ErrIndexRange
	}
	buf[0] = byte(0x80) | byte(0x1f&(t.Index>>7))
	if !t.Value {
		buf[0] |= 0x20 // contains the complement of the value
	}
	buf[1] = byte(0x7f & t.Index)
	return buf[:], nil
}

func (t *ISCDigitalTransition) UnmarshalBinary(buf []byte) error {
	if len(buf) < 2 {
		return ErrDecodeLength
	}
	if (buf[0]&byte(0xC0) != byte(0x80)) || (buf[1]&byte(0x80) != byte(0x00)) {
		return ErrDecodeIllegal
	}

	t.Index = uint(buf[1]) | uint(0x1f&(buf[0])<<7)
	t.Value = (buf[0]&byte(0x20) == byte(0x00))
	return nil
}

func (t *ISCAnalogTransition) MarshalBinary() ([]byte, error) {
	var buf [4]byte
	if t.Index > 1023 {
		return nil, ErrIndexRange
	}
	buf[0] = byte(0xc0) | byte((t.Value>>14)<<4) | byte(t.Index>>7)
	buf[1] = byte(0x7f & t.Index)
	buf[2] = byte(0x7f & (t.Value >> 7))
	buf[3] = byte(0x7f & t.Value)
	return buf[0:4], nil
}

func (t *ISCAnalogTransition) UnmarshalBinary(buf []byte) error {
	if len(buf) < 4 {
		return ErrDecodeLength
	}
	if (buf[0]&byte(0xC8) != byte(0xC0)) ||
		(buf[1]&byte(0x80) != byte(0x00)) ||
		(buf[2]&byte(0x80) != byte(0x00)) ||
		(buf[3]&byte(0x80) != byte(0x00)) {
		return ErrDecodeIllegal
	}

	t.Index = uint(buf[1]) | uint(0x07&(buf[0])<<7)
	t.Value = uint16(0x30&buf[0]<<14) | uint16(buf[2]<<7) | uint16(buf[3])
	return nil
}

func (t *ISCSerialTransition) MarshalBinary() ([]byte, error) {
	if t.Index > 1023 {
		return nil, ErrIndexRange
	}
	if len(t.Value) > 252 {
		return nil, ErrSerialLength
	}
	for j := range t.Value {
		if t.Value[j] == byte(0xFF) {
			return nil, ErrSerialInvalidByte
		}
	}
	buf := make([]byte, len(t.Value)+3, len(t.Value)+3)
	buf[0] = byte(0xc8) | byte(t.Index>>7)
	buf[1] = byte(0x7f & t.Index)
	copy(buf[2:], t.Value)
	buf[len(buf)-1] = 0xff
	return buf, nil
}

func (t *ISCSerialTransition) UnmarshalBinary(buf []byte) error {
	if len(buf) < 3 {
		return ErrDecodeLength
	}
	if buf[len(buf)-1] != 0xff {
		// this has three sane causes:
		// 1: the buffer we have is incomplete, and more data will come (error = ErrDecodeLength)
		// 2: the buffer we have contains more than one packet (error = nil)
		// 3: the buffer contains invalid data (error = ErrDecodeIllegal)
		//
		// we will assume that UnmarshalBinary will always be called with a perfectly
		// framed packet, which renders 1 & 2 impossible.
		return ErrDecodeIllegal
	}

	if (buf[0]&byte(0xF8) != byte(0xC8)) || (buf[1]&byte(0x80) != byte(0x00)) {
		return ErrDecodeIllegal
	}

	t.Index = uint(buf[1]) | uint(0x07&(buf[0])<<7)
	t.Value = make([]byte, len(buf)-3)
	copy(t.Value, buf[2:])
	return nil
}

func (o *ISCClearOperation) MarshalBinary() ([]byte, error) {
	return []byte{0xFC}, nil
}

func (o *ISCClearOperation) UnmarshalBinary(buf []byte) error {
	if len(buf) < 1 {
		return ErrDecodeLength
	}
	if buf[0] != 0xFC {
		return ErrDecodeIllegal
	}
	return nil
}

func (o *ISCRefreshOperation) MarshalBinary() ([]byte, error) {
	return []byte{0xFD}, nil
}

func (o *ISCRefreshOperation) UnmarshalBinary(buf []byte) error {
	if len(buf) < 1 {
		return ErrDecodeLength
	}
	if buf[0] != 0xFD {
		return ErrDecodeIllegal
	}
	return nil
}
<commit_msg>go vet caught some parenthetical errors<commit_after>package avcompat

import "errors"

// ISC Errors
var (
	ErrIndexRange        = errors.New("Transition index exceeds encoding range")
	ErrSerialLength      = errors.New("Serial transition length cannot exceed 252 bytes")
	ErrSerialInvalidByte = errors.New("Serial transition cannot contain \\xFF byte")
	ErrDecodeLength      = errors.New("Cannot decode due to short buffer")
	ErrDecodeIllegal     = errors.New("Cannot decode due to invalid bitstream")
)

type ISCDigitalTransition struct {
	Index uint
	Value bool
}

type ISCAnalogTransition struct {
	Index uint
	Value uint16
}

type ISCSerialTransition struct {
	Index uint
	Value []byte
}

type ISCClearOperation struct{}
type ISCRefreshOperation struct{}

func (t *ISCDigitalTransition) MarshalBinary() ([]byte, error) {
	var buf [2]byte
	if t.Index > 4095 {
		return nil, ErrIndexRange
	}
	buf[0] = byte(0x80) | byte(0x1f&(t.Index>>7))
	if !t.Value {
		buf[0] |= 0x20 // contains the complement of the value
	}
	buf[1] = byte(0x7f & t.Index)
	return buf[:], nil
}

func (t *ISCDigitalTransition) UnmarshalBinary(buf []byte) error {
	if len(buf) < 2 {
		return ErrDecodeLength
	}
	if (buf[0]&byte(0xC0) != byte(0x80)) || (buf[1]&byte(0x80) != byte(0x00)) {
		return ErrDecodeIllegal
	}

	t.Index = uint(buf[1]) | uint(0x1f&buf[0])<<7
	t.Value = (buf[0]&byte(0x20) == byte(0x00))
	return nil
}

func (t *ISCAnalogTransition) MarshalBinary() ([]byte, error) {
	var buf [4]byte
	if t.Index > 1023 {
		return nil, ErrIndexRange
	}
	buf[0] = byte(0xc0) | byte((t.Value>>14)<<4) | byte(t.Index>>7)
	buf[1] = byte(0x7f & t.Index)
	buf[2] = byte(0x7f & (t.Value >> 7))
	buf[3] = byte(0x7f & t.Value)
	return buf[0:4], nil
}

func (t *ISCAnalogTransition) UnmarshalBinary(buf []byte) error {
	if len(buf) < 4 {
		return ErrDecodeLength
	}
	if (buf[0]&byte(0xC8) != byte(0xC0)) ||
		(buf[1]&byte(0x80) != byte(0x00)) ||
		(buf[2]&byte(0x80) != byte(0x00)) ||
		(buf[3]&byte(0x80) != byte(0x00)) {
		return ErrDecodeIllegal
	}

	t.Index = uint(buf[1]) | uint(0x07&buf[0])<<7
	t.Value = uint16(0x30&buf[0])<<14 | uint16(buf[2])<<7 | uint16(buf[3])
	return nil
}

func (t *ISCSerialTransition) MarshalBinary() ([]byte, error) {
	if t.Index > 1023 {
		return nil, ErrIndexRange
	}
	if len(t.Value) > 252 {
		return nil, ErrSerialLength
	}
	for j := range t.Value {
		if t.Value[j] == byte(0xFF) {
			return nil, ErrSerialInvalidByte
		}
	}
	buf := make([]byte, len(t.Value)+3, len(t.Value)+3)
	buf[0] = byte(0xc8) | byte(t.Index>>7)
	buf[1] = byte(0x7f & t.Index)
	copy(buf[2:], t.Value)
	buf[len(buf)-1] = 0xff
	return buf, nil
}

func (t *ISCSerialTransition) UnmarshalBinary(buf []byte) error {
	if len(buf) < 3 {
		return ErrDecodeLength
	}
	if buf[len(buf)-1] != 0xff {
		// this has three sane causes:
		// 1: the buffer we have is incomplete, and more data will come (error = ErrDecodeLength)
		// 2: the buffer we have contains more than one packet (error = nil)
		// 3: the buffer contains invalid data (error = ErrDecodeIllegal)
		//
		// we will assume that UnmarshalBinary will always be called with a perfectly
		// framed packet, which renders 1 & 2 impossible.
		return ErrDecodeIllegal
	}

	if (buf[0]&byte(0xF8) != byte(0xC8)) || (buf[1]&byte(0x80) != byte(0x00)) {
		return ErrDecodeIllegal
	}

	t.Index = uint(buf[1]) | uint(0x07&buf[0])<<7
	t.Value = make([]byte, len(buf)-3)
	copy(t.Value, buf[2:])
	return nil
}

func (o *ISCClearOperation) MarshalBinary() ([]byte, error) {
	return []byte{0xFC}, nil
}

func (o *ISCClearOperation) UnmarshalBinary(buf []byte) error {
	if len(buf) < 1 {
		return ErrDecodeLength
	}
	if buf[0] != 0xFC {
		return ErrDecodeIllegal
	}
	return nil
}

func (o *ISCRefreshOperation) MarshalBinary() ([]byte, error) {
	return []byte{0xFD}, nil
}

func (o *ISCRefreshOperation) UnmarshalBinary(buf []byte) error {
	if len(buf) < 1 {
		return ErrDecodeLength
	}
	if buf[0] != 0xFD {
		return ErrDecodeIllegal
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"

	"encoding/json"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

var logger = shim.NewLogger("mylogger")

type SampleChaincode struct {
}

//custom data models
type PersonalInfo struct {
	Firstname string `json:"firstname"`
	Lastname  string `json:"lastname"`
	DOB       string `json:"DOB"`
	Email     string `json:"email"`
	Mobile    string `json:"mobile"`
}

type FinancialInfo struct {
	MonthlySalary      int `json:"monthlySalary"`
	MonthlyRent        int `json:"monthlyRent"`
	OtherExpenditure   int `json:"otherExpenditure"`
	MonthlyLoanPayment int `json:"monthlyLoanPayment"`
}

type LoanApplication struct {
	ID                     string        `json:"id"`
	PropertyId             string        `json:"propertyId"`
	LandId                 string        `json:"landId"`
	PermitId               string        `json:"permitId"`
	BuyerId                string        `json:"buyerId"`
	AppraisalApplicationId string        `json:"appraiserApplicationId"`
	SalesContractId        string        `json:"salesContractId"`
	PersonalInfo           PersonalInfo  `json:"personalInfo"`
	FinancialInfo          FinancialInfo `json:"financialInfo"`
	Status                 string        `json:"status"`
	RequestedAmount        int           `json:"requestedAmount"`
	FairMarketValue        int           `json:"fairMarketValue"`
	ApprovedAmount         int           `json:"approvedAmount"`
	ReviewerId             string        `json:"reviewerId"`
	LastModifiedDate       string        `json:"lastModifiedDate"`
}

func GetLoanApplication(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	logger.Debug("Entering GetLoanApplication")

	if len(args) < 1 {
		logger.Error("Invalid number of arguments")
		return nil, errors.New("Missing loan application ID")
	}

	var loanApplicationId = args[0]
	bytes, err := stub.GetState(loanApplicationId)
	if err != nil {
		logger.Error("Could not fetch loan application with id "+loanApplicationId+" from ledger", err)
		return nil, err
	}
	return bytes, nil
}

func CreateLoanApplication(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	logger.Debug("Entering CreateLoanApplication")

	if len(args) < 2 {
		logger.Error("Invalid number of args")
		return nil, errors.New("Expected atleast two arguments for loan application creation")
	}

	var loanApplicationId = args[0]
	var loanApplicationInput = args[1]

	err := stub.PutState(loanApplicationId, []byte(loanApplicationInput))
	if err != nil {
		logger.Error("Could not save loan application to ledger", err)
		return nil, err
	}

	var customEvent = "{eventType: 'loanApplicationCreation', description:" + loanApplicationId + "' Successfully created'}"
	err = stub.SetEvent("evtSender", []byte(customEvent))
	if err != nil {
		return nil, err
	}
	logger.Info("Successfully saved loan application")
	return nil, nil

}

/**
Updates the status of the loan application
**/
func UpdateLoanApplication(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	logger.Debug("Entering UpdateLoanApplication")

	if len(args) < 2 {
		logger.Error("Invalid number of args")
		return nil, errors.New("Expected atleast two arguments for loan application update")
	}

	var loanApplicationId = args[0]
	var status = args[1]

	laBytes, err := stub.GetState(loanApplicationId)
	if err != nil {
		logger.Error("Could not fetch loan application from ledger", err)
		return nil, err
	}
	var loanApplication LoanApplication
	err = json.Unmarshal(laBytes, &loanApplication)
	loanApplication.Status = status

	laBytes, err = json.Marshal(&loanApplication)
	if err != nil {
		logger.Error("Could not marshal loan application post update", err)
		return nil, err
	}

	err = stub.PutState(loanApplicationId, laBytes)
	if err != nil {
		logger.Error("Could not save loan application post update", err)
		return nil, err
	}

	var customEvent = "{eventType: 'loanApplicationUpdate', description:" + loanApplicationId + "' Successfully updated status'}"
	err = stub.SetEvent("evtSender", []byte(customEvent))
	if err != nil {
		return nil, err
	}
	logger.Info("Successfully updated loan application")
	return nil, nil

}

func (t *SampleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	return nil, nil
}

func (t *SampleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if function == "GetLoanApplication" {
		return GetLoanApplication(stub, args)
	}
	return nil, nil
}

func GetCertAttribute(stub shim.ChaincodeStubInterface, attributeName string) (string, error) {
	logger.Debug("Entering GetCertAttribute")
	attr, err := stub.ReadCertAttribute(attributeName)
	if err != nil {
		return "", errors.New("Couldn't get attribute " + attributeName + ". Error: " + err.Error())
	}
	attrString := string(attr)
	return attrString, nil
}

func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	if function == "CreateLoanApplication" {
		username, _ := GetCertAttribute(stub, "username")
		role, _ := GetCertAttribute(stub, "role")
		if role == "Bank_Home_Loan_Admin" {
			return CreateLoanApplication(stub, args)
		} else {
			return nil, errors.New(username + " with role " + role + " does not have access to create a loan application")
		}

	}
	return nil, nil
}

type customEvent struct {
	Type       string `json:"type"`
	Decription string `json:"description"`
}

func main() {

	lld, _ := shim.LogLevel("DEBUG")
	fmt.Println(lld)

	logger.SetLevel(lld)
	fmt.Println(logger.IsEnabledFor(lld))

	err := shim.Start(new(SampleChaincode))
	if err != nil {
		logger.Error("Could not start SampleChaincode")
	} else {
		logger.Info("SampleChaincode successfully started")
	}

}
<commit_msg>createtable<commit_after>/*
Copyright IBM Corp 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"fmt"
	"encoding/json"

	"github.com/hyperledger/fabric/core/chaincode/shim"

)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

type Emp struct{
	empId string `json:"empId"`
	name string `json:"name"`
	title string `json:"title"`

}

// CountApplication is for storing retreived Application count
type Empppcounter struct{
	empCounter int `json:"count"`
}

func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode: %s", err)
	}
}

// Init resets all the things
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting 1")
	}

	  err := stub.PutState("table_ibminsert", []byte(args[0]))
	if err != nil {
		return nil, err
	}

	// Check if table already exists
	_,  err = stub.GetTable("EmpTable")

	if err == nil {
		// Table already exists; do not recreate
		return nil, nil
	}
     fmt.Println("ready to create the table: ")
	// Create application Table
	err = stub.CreateTable("EmpTable", []*shim.ColumnDefinition{
		&shim.ColumnDefinition{Name: "empId", Type: shim.ColumnDefinition_STRING, Key: true},
		&shim.ColumnDefinition{Name: "name", Type: shim.ColumnDefinition_STRING, Key: false},
		&shim.ColumnDefinition{Name: "title", Type: shim.ColumnDefinition_STRING, Key: false},

	})
	if err != nil {
		return nil, errors.New("Failed creating ApplicationTable.")

	}

	return nil, nil
	}

// Invoke isur entry point to invoke a chaincode function
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("invoke is running " + function)

	// Handle different functions
	if function == "init" {
		return t.Init(stub, "init", args)
	} else if function == "write" {
		return t.write(stub, args)
	}
	fmt.Println("invoke did not find func: " + function)

	if function == "submitEmp" {
		if len(args) != 3 {
			return nil, fmt.Errorf("Incorrect number of arguments. Expecting 20. Got: %d.", len(args))
		}

		empId := args[0]
		name := args[1]
		title := args[2]
		fmt.Println("values Inserted in the table: empid"+empId)
		fmt.Println("values Inserted in the table: name"+name)
		fmt.Println("values Inserted in the table: empid"+title)

		//insert a row

		ok, err := stub.InsertRow("EmpTable", shim.Row{
		Columns: []*shim.Column{
				&shim.Column{Value: &shim.Column_String_{String_: empId}},
				&shim.Column{Value: &shim.Column_String_{String_: name}},
				&shim.Column{Value: &shim.Column_String_{String_: title}},
				}})

	if !ok && err == nil {
			return nil, errors.New("Row already exists.")
		}

	}
	fmt.Println("values Inserted in the table: ")

	return nil, errors.New("Received unknown function invocation: " + function)
}

// Query is our entry point for queries
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {

	fmt.Println("query is running " + function)

	// Handle different functions
	if function == "read" { //read a variable
		return t.read(stub, args)
	}
	fmt.Println("query did not find func: " + function)

	return nil, errors.New("Received unknown function query: " + function)
}

// write - invoke function to write key/value pair
func (t *SimpleChaincode) write(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
	var key, value string
	var err error
	fmt.Println("running write()")

	if len(args) != 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2. name of the key and value to set")
	}

	key = args[0] //rename for funsies
	value = args[1]
	err = stub.PutState(key, []byte(value)) //write the variable into the chaincode state
	if err != nil {
		return nil, err
	}
	return nil, nil
}

// read - query function to read key/value pair
func (t *SimpleChaincode) read(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {

	if len(args) != 1 {
		return nil, errors.New("Incorrect number of arguments. Expecting applicationid to query")
	}

	fmt.Println("came into read func and geting empid: ")

	empId := args[0]

fmt.Println("came into read func and geting empid: "+empId)

	var columns []shim.Column
	emplCounter := 0

	rows, err := stub.GetRows("EmpTable", columns)

	if err != nil {
		return nil, fmt.Errorf("Failed to retrieve row")
	}

	for row := range rows {
		if len(row.Columns) != 0 {
			emplCounter++
		}
	}

	res2E := Empppcounter{}
	res2E.empCounter = emplCounter
	mapB, _ := json.Marshal(res2E)
    fmt.Println(string(mapB))

	return mapB, nil

}
<|endoftext|>


<commit_before>package test

import (
	"context"
	"errors"
	"fmt"
	"net/http/httptest"
	"net/http/httptrace"
	"os"
	"strings"
	"sync/atomic"
	"testing"
	"time"

	"github.com/Clever/wag/samples/gen-go/client"
	"github.com/Clever/wag/samples/gen-go/models"
	"github.com/Clever/wag/samples/gen-go/server"
	"github.com/afex/hystrix-go/hystrix"
	"github.com/stretchr/testify/assert"
)

type ClientContextTest struct {
	getCount  int
	postCount int
}

func (c *ClientContextTest) GetBooks(ctx context.Context, input *models.GetBooksInput) ([]models.Book, error) {
	c.getCount++
	if c.getCount == 1 {
		return nil, fmt.Errorf("Error count: %d", c.getCount)
	}
	return []models.Book{}, nil
}
func (c *ClientContextTest) GetBookByID(ctx context.Context, input *models.GetBookByIDInput) (models.GetBookByIDOutput, error) {
	return nil, nil
}
func (c *ClientContextTest) GetBookByID2(ctx context.Context, input *models.GetBookByID2Input) (*models.Book, error) {
	return nil, nil
}
func (c *ClientContextTest) CreateBook(ctx context.Context, input *models.Book) (*models.Book, error) {
	c.postCount++
	if c.postCount == 1 {
		return nil, fmt.Errorf("Error count: %d", c.postCount)
	}
	return &models.Book{}, nil
}

func (c *ClientContextTest) HealthCheck(ctx context.Context) error {
	return nil
}

type ClientCircuitTest struct {
	down bool
}

func (c *ClientCircuitTest) GetBooks(ctx context.Context, input *models.GetBooksInput) ([]models.Book, error) {
	if c.down {
		return nil, errors.New("fail")
	}
	return []models.Book{}, nil
}
func (c *ClientCircuitTest) GetBookByID(ctx context.Context, input *models.GetBookByIDInput) (models.GetBookByIDOutput, error) {
	if c.down {
		return nil, errors.New("fail")
	}
	return nil, nil
}
func (c *ClientCircuitTest) GetBookByID2(ctx context.Context, input *models.GetBookByID2Input) (*models.Book, error) {
	if c.down {
		return nil, errors.New("fail")
	}
	return nil, nil
}
func (c *ClientCircuitTest) CreateBook(ctx context.Context, input *models.Book) (*models.Book, error) {
	if c.down {
		return nil, errors.New("fail")
	}
	return &models.Book{}, nil
}

func (c *ClientCircuitTest) HealthCheck(ctx context.Context) error {
	if c.down {
		return errors.New("fail")
	}
	return nil
}

func TestDefaultClientRetries(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()
	c := client.New(testServer.URL)
	_, err := c.GetBooks(context.Background(), &models.GetBooksInput{})
	assert.NoError(t, err)
	assert.Equal(t, 2, controller.getCount)
}

func TestCustomClientRetries(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()

	// Should fail if no retries
	c := client.New(testServer.URL).WithRetries(0)
	_, err := c.GetBooks(context.Background(), &models.GetBooksInput{})
	assert.Error(t, err)
	assert.Equal(t, 1, controller.getCount)
}

func TestCustomContextRetries(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()

	// Should fail if no retries
	c := client.New(testServer.URL)
	_, err := c.GetBooks(client.WithRetries(context.Background(), 0), &models.GetBooksInput{})
	assert.Error(t, err)
	assert.Equal(t, 1, controller.getCount)
}

func TestNonGetRetries(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()
	c := client.New(testServer.URL)
	_, err := c.CreateBook(context.Background(), &models.Book{})
	assert.Error(t, err)
	assert.Equal(t, 1, controller.postCount)
}

func TestNewWithDiscovery(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)

	// Should be an err if env vars aren't set
	_, err := client.NewFromDiscovery()
	assert.Error(t, err)

	splitURL := strings.Split(testServer.URL, ":")
	assert.Equal(t, 3, len(splitURL))

	os.Setenv("SERVICE_SWAGGER_TEST_DEFAULT_PROTO", "http")
	os.Setenv("SERVICE_SWAGGER_TEST_DEFAULT_PORT", splitURL[2])
	os.Setenv("SERVICE_SWAGGER_TEST_DEFAULT_HOST", splitURL[1][2:])

	c, err := client.NewFromDiscovery()
	assert.NoError(t, err)
	_, err = c.GetBooks(context.Background(), &models.GetBooksInput{})
	assert.NoError(t, err)
	assert.Equal(t, 2, controller.getCount)

	// Testing fallback
	os.Unsetenv("SERVICE_SWAGGER_TEST_DEFAULT_PROTO")
	os.Unsetenv("SERVICE_SWAGGER_TEST_DEFAULT_PORT")
	os.Unsetenv("SERVICE_SWAGGER_TEST_DEFAULT_HOST")
	os.Setenv("SERVICE_SWAGGER_TEST_HTTP_PROTO", "http")
	os.Setenv("SERVICE_SWAGGER_TEST_HTTP_PORT", splitURL[2])
	os.Setenv("SERVICE_SWAGGER_TEST_HTTP_HOST", splitURL[1][2:])

	c, err = client.NewFromDiscovery()
	assert.NoError(t, err)
	_, err = c.GetBooks(context.Background(), &models.GetBooksInput{})
	assert.NoError(t, err)
	assert.Equal(t, 3, controller.getCount)
}

func TestCircuitBreaker(t *testing.T) {
	controller := ClientCircuitTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()
	hystrix.Flush()
	c := client.New(testServer.URL)
	c.SetCircuitBreakerDebug(false)
	c.SetCircuitBreakerSettings(client.CircuitBreakerSettings{
		MaxConcurrentRequests:  client.DefaultCircuitBreakerSettings.MaxConcurrentRequests,
		RequestVolumeThreshold: 0,
		SleepWindow:            2000,
		ErrorPercentThreshold:  client.DefaultCircuitBreakerSettings.ErrorPercentThreshold,
	})

	// the circuit should open after one failed attempt, since the volume
	// threshold set above is 0.
	controller.down = true
	var connAttempts int64
	ctx := httptrace.WithClientTrace(context.Background(),
		&httptrace.ClientTrace{
			GetConn: func(hostPort string) {
				atomic.AddInt64(&connAttempts, 1)
			},
		})

	_, err := c.CreateBook(ctx, &models.Book{})
	assert.Error(t, err)
	assert.Equal(t, int64(1), connAttempts)
	_, err = c.CreateBook(ctx, &models.Book{})
	assert.Error(t, err)
	assert.Equal(t, int64(1), connAttempts)

	// we should see an attempt go through after two seconds (this is the
	// sleep window configured above).
	circuitOpened := time.Now()
	for _ = range time.Tick(100 * time.Millisecond) {
		_, err := c.CreateBook(ctx, &models.Book{})
		assert.Error(t, err)
		if connAttempts == 2 {
			assert.WithinDuration(t, time.Now(), circuitOpened,
				2*time.Second+500*time.Millisecond)
			break
		}
		if time.Now().Sub(circuitOpened) > 10*time.Second {
			t.Fatal("circuit should let through a 2nd attempt by now")
		}
	}

	// bring the server back up, and we should see successes after another
	// two seconds, for a total of 4 seconds.
	controller.down = false
	for _ = range time.Tick(100 * time.Millisecond) {
		_, err := c.CreateBook(ctx, &models.Book{})
		if err == nil {
			assert.WithinDuration(t, time.Now(), circuitOpened,
				4*time.Second+500*time.Millisecond)
			break
		}
		if time.Now().Sub(circuitOpened) > 10*time.Second {
			t.Fatal("circuit should have closed by now")
		}
	}
}
<commit_msg>fix circuit test 2<commit_after>package test

import (
	"context"
	"errors"
	"fmt"
	"net/http/httptest"
	"net/http/httptrace"
	"os"
	"strings"
	"sync/atomic"
	"testing"
	"time"

	"github.com/Clever/wag/samples/gen-go/client"
	"github.com/Clever/wag/samples/gen-go/models"
	"github.com/Clever/wag/samples/gen-go/server"
	"github.com/afex/hystrix-go/hystrix"
	"github.com/stretchr/testify/assert"
)

type ClientContextTest struct {
	getCount  int
	postCount int
}

func (c *ClientContextTest) GetBooks(ctx context.Context, input *models.GetBooksInput) ([]models.Book, error) {
	c.getCount++
	if c.getCount == 1 {
		return nil, fmt.Errorf("Error count: %d", c.getCount)
	}
	return []models.Book{}, nil
}
func (c *ClientContextTest) GetBookByID(ctx context.Context, input *models.GetBookByIDInput) (models.GetBookByIDOutput, error) {
	return nil, nil
}
func (c *ClientContextTest) GetBookByID2(ctx context.Context, input *models.GetBookByID2Input) (*models.Book, error) {
	return nil, nil
}
func (c *ClientContextTest) CreateBook(ctx context.Context, input *models.Book) (*models.Book, error) {
	c.postCount++
	if c.postCount == 1 {
		return nil, fmt.Errorf("Error count: %d", c.postCount)
	}
	return &models.Book{}, nil
}

func (c *ClientContextTest) HealthCheck(ctx context.Context) error {
	return nil
}

type ClientCircuitTest struct {
	down bool
}

func (c *ClientCircuitTest) GetBooks(ctx context.Context, input *models.GetBooksInput) ([]models.Book, error) {
	if c.down {
		return nil, errors.New("fail")
	}
	return []models.Book{}, nil
}
func (c *ClientCircuitTest) GetBookByID(ctx context.Context, input *models.GetBookByIDInput) (models.GetBookByIDOutput, error) {
	if c.down {
		return nil, errors.New("fail")
	}
	return nil, nil
}
func (c *ClientCircuitTest) GetBookByID2(ctx context.Context, input *models.GetBookByID2Input) (*models.Book, error) {
	if c.down {
		return nil, errors.New("fail")
	}
	return nil, nil
}
func (c *ClientCircuitTest) CreateBook(ctx context.Context, input *models.Book) (*models.Book, error) {
	if c.down {
		return nil, errors.New("fail")
	}
	return &models.Book{}, nil
}

func (c *ClientCircuitTest) HealthCheck(ctx context.Context) error {
	if c.down {
		return errors.New("fail")
	}
	return nil
}

func TestDefaultClientRetries(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()
	c := client.New(testServer.URL)
	_, err := c.GetBooks(context.Background(), &models.GetBooksInput{})
	assert.NoError(t, err)
	assert.Equal(t, 2, controller.getCount)
}

func TestCustomClientRetries(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()

	// Should fail if no retries
	c := client.New(testServer.URL).WithRetries(0)
	_, err := c.GetBooks(context.Background(), &models.GetBooksInput{})
	assert.Error(t, err)
	assert.Equal(t, 1, controller.getCount)
}

func TestCustomContextRetries(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()

	// Should fail if no retries
	c := client.New(testServer.URL)
	_, err := c.GetBooks(client.WithRetries(context.Background(), 0), &models.GetBooksInput{})
	assert.Error(t, err)
	assert.Equal(t, 1, controller.getCount)
}

func TestNonGetRetries(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()
	c := client.New(testServer.URL)
	_, err := c.CreateBook(context.Background(), &models.Book{})
	assert.Error(t, err)
	assert.Equal(t, 1, controller.postCount)
}

func TestNewWithDiscovery(t *testing.T) {
	controller := ClientContextTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)

	// Should be an err if env vars aren't set
	_, err := client.NewFromDiscovery()
	assert.Error(t, err)

	splitURL := strings.Split(testServer.URL, ":")
	assert.Equal(t, 3, len(splitURL))

	os.Setenv("SERVICE_SWAGGER_TEST_DEFAULT_PROTO", "http")
	os.Setenv("SERVICE_SWAGGER_TEST_DEFAULT_PORT", splitURL[2])
	os.Setenv("SERVICE_SWAGGER_TEST_DEFAULT_HOST", splitURL[1][2:])

	c, err := client.NewFromDiscovery()
	assert.NoError(t, err)
	_, err = c.GetBooks(context.Background(), &models.GetBooksInput{})
	assert.NoError(t, err)
	assert.Equal(t, 2, controller.getCount)

	// Testing fallback
	os.Unsetenv("SERVICE_SWAGGER_TEST_DEFAULT_PROTO")
	os.Unsetenv("SERVICE_SWAGGER_TEST_DEFAULT_PORT")
	os.Unsetenv("SERVICE_SWAGGER_TEST_DEFAULT_HOST")
	os.Setenv("SERVICE_SWAGGER_TEST_HTTP_PROTO", "http")
	os.Setenv("SERVICE_SWAGGER_TEST_HTTP_PORT", splitURL[2])
	os.Setenv("SERVICE_SWAGGER_TEST_HTTP_HOST", splitURL[1][2:])

	c, err = client.NewFromDiscovery()
	assert.NoError(t, err)
	_, err = c.GetBooks(context.Background(), &models.GetBooksInput{})
	assert.NoError(t, err)
	assert.Equal(t, 3, controller.getCount)
}

func TestCircuitBreaker(t *testing.T) {
	controller := ClientCircuitTest{}
	s := server.New(&controller, "")
	testServer := httptest.NewServer(s.Handler)
	defer testServer.Close()
	hystrix.Flush()
	c := client.New(testServer.URL)
	c.SetCircuitBreakerDebug(false)
	c.SetCircuitBreakerSettings(client.CircuitBreakerSettings{
		MaxConcurrentRequests:  client.DefaultCircuitBreakerSettings.MaxConcurrentRequests,
		RequestVolumeThreshold: 1,
		SleepWindow:            2000,
		ErrorPercentThreshold:  client.DefaultCircuitBreakerSettings.ErrorPercentThreshold,
	})

	// the circuit should open after one or two failed attempts, since the volume
	// threshold (set above) is 1.
	controller.down = true
	var connAttempts int64
	ctx := httptrace.WithClientTrace(context.Background(),
		&httptrace.ClientTrace{
			GetConn: func(hostPort string) {
				atomic.AddInt64(&connAttempts, 1)
			},
		})

	_, err := c.CreateBook(ctx, &models.Book{})
	assert.Error(t, err)
	_, err = c.CreateBook(ctx, &models.Book{})
	assert.Error(t, err)
	_, err = c.CreateBook(ctx, &models.Book{})
	assert.Error(t, err)
	assert.Equal(t, true, connAttempts <= int64(2), "circuit should have opened, saw too many connection attempts: %d", connAttempts)

	// we should see an attempt go through after two seconds (this is the
	// sleep window configured above).
	circuitOpened := time.Now()
	for _ = range time.Tick(100 * time.Millisecond) {
		_, err := c.CreateBook(ctx, &models.Book{})
		assert.Error(t, err)
		if connAttempts == 2 {
			assert.WithinDuration(t, time.Now(), circuitOpened,
				2*time.Second+500*time.Millisecond)
			break
		}
		if time.Now().Sub(circuitOpened) > 10*time.Second {
			t.Fatal("circuit should let through a 2nd attempt by now")
		}
	}

	// bring the server back up, and we should see successes after another
	// two seconds, for a total of 4 seconds.
	controller.down = false
	for _ = range time.Tick(100 * time.Millisecond) {
		_, err := c.CreateBook(ctx, &models.Book{})
		if err == nil {
			assert.WithinDuration(t, time.Now(), circuitOpened,
				4*time.Second+500*time.Millisecond)
			break
		}
		if time.Now().Sub(circuitOpened) > 10*time.Second {
			t.Fatal("circuit should have closed by now")
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

import (
	"crypto/rand"
	"testing"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/wire"
)

// genRandomSig returns a random message, public key, and a signature of the
// message under the public key. This function is used to generate randomized
// test data.
func genRandomSig() (*wire.ShaHash, *btcec.Signature, *btcec.PublicKey, error) {
	privKey, err := btcec.NewPrivateKey(btcec.S256())
	if err != nil {
		return nil, nil, nil, err
	}

	var msgHash wire.ShaHash
	if _, err := rand.Read(msgHash[:]); err != nil {
		return nil, nil, nil, err
	}

	sig, err := privKey.Sign(msgHash[:])
	if err != nil {
		return nil, nil, nil, err
	}

	return &msgHash, sig, privKey.PubKey(), nil
}

// TestSigCacheAddExists tests the ability to add, and later check the
// existence of a signature triplet in the signature cache.
func TestSigCacheAddExists(t *testing.T) {
	sigCache := NewSigCache(200)

	// Generate a random sigCache entry triplet.
	msg1, sig1, key1, err := genRandomSig()
	if err != nil {
		t.Errorf("unable to generate random signature test data")
	}

	// Add the triplet to the signature cache.
	sigCache.Add(*msg1, sig1, key1)

	// The previously added triplet should now be found within the sigcache.
	sig1Copy, _ := btcec.ParseSignature(sig1.Serialize(), btcec.S256())
	key1Copy, _ := btcec.ParsePubKey(key1.SerializeCompressed(), btcec.S256())
	if !sigCache.Exists(*msg1, sig1Copy, key1Copy) {
		t.Errorf("previously added item not found in signature cache")
	}
}

// TestSigCacheAddEvictEntry tests the eviction case where a new signature
// triplet is added to a full signature cache which should trigger randomized
// eviction, followed by adding the new element to the cache.
func TestSigCacheAddEvictEntry(t *testing.T) {
	// Create a sigcache that can hold up to 100 entries.
	sigCacheSize := uint(100)
	sigCache := NewSigCache(sigCacheSize)

	// Fill the sigcache up with some random sig triplets.
	for i := uint(0); i < sigCacheSize; i++ {
		msg, sig, key, err := genRandomSig()
		if err != nil {
			t.Fatalf("unable to generate random signature test data")
		}

		sigCache.Add(*msg, sig, key)

		sigCopy, _ := btcec.ParseSignature(sig.Serialize(), btcec.S256())
		keyCopy, _ := btcec.ParsePubKey(key.SerializeCompressed(), btcec.S256())
		if !sigCache.Exists(*msg, sigCopy, keyCopy) {
			t.Errorf("previously added item not found in signature" +
				"cache")
		}
	}

	// The sigcache should now have sigCacheSize entries within it.
	if uint(len(sigCache.validSigs)) != sigCacheSize {
		t.Fatalf("sigcache should now have %v entries, instead it has %v",
			sigCacheSize, len(sigCache.validSigs))
	}

	// Add a new entry, this should cause eviction of a randomly chosen
	// previously entry.
	msgNew, sigNew, keyNew, err := genRandomSig()
	if err != nil {
		t.Fatalf("unable to generate random signature test data")
	}
	sigCache.Add(*msgNew, sigNew, keyNew)

	// The sigcache should still have sigCache entries.
	if uint(len(sigCache.validSigs)) != sigCacheSize {
		t.Fatalf("sigcache should now have %v entries, instead it has %v",
			sigCacheSize, len(sigCache.validSigs))
	}

	// The entry added above should be found within the sigcache.
	sigNewCopy, _ := btcec.ParseSignature(sigNew.Serialize(), btcec.S256())
	keyNewCopy, _ := btcec.ParsePubKey(keyNew.SerializeCompressed(), btcec.S256())
	if !sigCache.Exists(*msgNew, sigNewCopy, keyNewCopy) {
		t.Fatalf("previously added item not found in signature cache")
	}
}

// TestSigCacheAddMaxEntriesZeroOrNegative tests that if a sigCache is created
// with a max size <= 0, then no entries are added to the sigcache at all.
func TestSigCacheAddMaxEntriesZeroOrNegative(t *testing.T) {
	// Create a sigcache that can hold up to 0 entries.
	sigCache := NewSigCache(0)

	// Generate a random sigCache entry triplet.
	msg1, sig1, key1, err := genRandomSig()
	if err != nil {
		t.Errorf("unable to generate random signature test data")
	}

	// Add the triplet to the signature cache.
	sigCache.Add(*msg1, sig1, key1)

	// The generated triplet should not be found.
	sig1Copy, _ := btcec.ParseSignature(sig1.Serialize(), btcec.S256())
	key1Copy, _ := btcec.ParsePubKey(key1.SerializeCompressed(), btcec.S256())
	if sigCache.Exists(*msg1, sig1Copy, key1Copy) {
		t.Errorf("previously added signature found in sigcache, but" +
			"shouldn't have been")
	}

	// There shouldn't be any entries in the sigCache.
	if len(sigCache.validSigs) != 0 {
		t.Errorf("%v items found in sigcache, no items should have"+
			"been added", len(sigCache.validSigs))
	}
}
<commit_msg>txscript: Fix docs to match function.<commit_after>// Copyright (c) 2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

import (
	"crypto/rand"
	"testing"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/wire"
)

// genRandomSig returns a random message, a signature of the message under the
// public key and the public key. This function is used to generate randomized
// test data.
func genRandomSig() (*wire.ShaHash, *btcec.Signature, *btcec.PublicKey, error) {
	privKey, err := btcec.NewPrivateKey(btcec.S256())
	if err != nil {
		return nil, nil, nil, err
	}

	var msgHash wire.ShaHash
	if _, err := rand.Read(msgHash[:]); err != nil {
		return nil, nil, nil, err
	}

	sig, err := privKey.Sign(msgHash[:])
	if err != nil {
		return nil, nil, nil, err
	}

	return &msgHash, sig, privKey.PubKey(), nil
}

// TestSigCacheAddExists tests the ability to add, and later check the
// existence of a signature triplet in the signature cache.
func TestSigCacheAddExists(t *testing.T) {
	sigCache := NewSigCache(200)

	// Generate a random sigCache entry triplet.
	msg1, sig1, key1, err := genRandomSig()
	if err != nil {
		t.Errorf("unable to generate random signature test data")
	}

	// Add the triplet to the signature cache.
	sigCache.Add(*msg1, sig1, key1)

	// The previously added triplet should now be found within the sigcache.
	sig1Copy, _ := btcec.ParseSignature(sig1.Serialize(), btcec.S256())
	key1Copy, _ := btcec.ParsePubKey(key1.SerializeCompressed(), btcec.S256())
	if !sigCache.Exists(*msg1, sig1Copy, key1Copy) {
		t.Errorf("previously added item not found in signature cache")
	}
}

// TestSigCacheAddEvictEntry tests the eviction case where a new signature
// triplet is added to a full signature cache which should trigger randomized
// eviction, followed by adding the new element to the cache.
func TestSigCacheAddEvictEntry(t *testing.T) {
	// Create a sigcache that can hold up to 100 entries.
	sigCacheSize := uint(100)
	sigCache := NewSigCache(sigCacheSize)

	// Fill the sigcache up with some random sig triplets.
	for i := uint(0); i < sigCacheSize; i++ {
		msg, sig, key, err := genRandomSig()
		if err != nil {
			t.Fatalf("unable to generate random signature test data")
		}

		sigCache.Add(*msg, sig, key)

		sigCopy, _ := btcec.ParseSignature(sig.Serialize(), btcec.S256())
		keyCopy, _ := btcec.ParsePubKey(key.SerializeCompressed(), btcec.S256())
		if !sigCache.Exists(*msg, sigCopy, keyCopy) {
			t.Errorf("previously added item not found in signature" +
				"cache")
		}
	}

	// The sigcache should now have sigCacheSize entries within it.
	if uint(len(sigCache.validSigs)) != sigCacheSize {
		t.Fatalf("sigcache should now have %v entries, instead it has %v",
			sigCacheSize, len(sigCache.validSigs))
	}

	// Add a new entry, this should cause eviction of a randomly chosen
	// previously entry.
	msgNew, sigNew, keyNew, err := genRandomSig()
	if err != nil {
		t.Fatalf("unable to generate random signature test data")
	}
	sigCache.Add(*msgNew, sigNew, keyNew)

	// The sigcache should still have sigCache entries.
	if uint(len(sigCache.validSigs)) != sigCacheSize {
		t.Fatalf("sigcache should now have %v entries, instead it has %v",
			sigCacheSize, len(sigCache.validSigs))
	}

	// The entry added above should be found within the sigcache.
	sigNewCopy, _ := btcec.ParseSignature(sigNew.Serialize(), btcec.S256())
	keyNewCopy, _ := btcec.ParsePubKey(keyNew.SerializeCompressed(), btcec.S256())
	if !sigCache.Exists(*msgNew, sigNewCopy, keyNewCopy) {
		t.Fatalf("previously added item not found in signature cache")
	}
}

// TestSigCacheAddMaxEntriesZeroOrNegative tests that if a sigCache is created
// with a max size <= 0, then no entries are added to the sigcache at all.
func TestSigCacheAddMaxEntriesZeroOrNegative(t *testing.T) {
	// Create a sigcache that can hold up to 0 entries.
	sigCache := NewSigCache(0)

	// Generate a random sigCache entry triplet.
	msg1, sig1, key1, err := genRandomSig()
	if err != nil {
		t.Errorf("unable to generate random signature test data")
	}

	// Add the triplet to the signature cache.
	sigCache.Add(*msg1, sig1, key1)

	// The generated triplet should not be found.
	sig1Copy, _ := btcec.ParseSignature(sig1.Serialize(), btcec.S256())
	key1Copy, _ := btcec.ParsePubKey(key1.SerializeCompressed(), btcec.S256())
	if sigCache.Exists(*msg1, sig1Copy, key1Copy) {
		t.Errorf("previously added signature found in sigcache, but" +
			"shouldn't have been")
	}

	// There shouldn't be any entries in the sigCache.
	if len(sigCache.validSigs) != 0 {
		t.Errorf("%v items found in sigcache, no items should have"+
			"been added", len(sigCache.validSigs))
	}
}
<|endoftext|>