removed all references to "transaction"

This commit is contained in:
Jimmy Zelinskie 2013-11-23 23:48:38 -05:00
parent 31e618c8d9
commit 9382ac482e
10 changed files with 1698 additions and 1708 deletions

View file

@ -6,85 +6,83 @@
package config package config
import ( import (
"encoding/json" "encoding/json"
"io" "io"
"os" "os"
"time" "time"
) )
type Duration struct { type Duration struct {
time.Duration time.Duration
} }
func (d *Duration) MarshalJSON() ([]byte, error) { func (d *Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String()) return json.Marshal(d.String())
} }
func (d *Duration) UnmarshalJSON(b []byte) error { func (d *Duration) UnmarshalJSON(b []byte) error {
var str string var str string
err := json.Unmarshal(b, &str) err := json.Unmarshal(b, &str)
d.Duration, err = time.ParseDuration(str) d.Duration, err = time.ParseDuration(str)
return err return err
} }
// DataStore represents the configuration used to connect to a data store. // DataStore represents the configuration used to connect to a data store.
type DataStore struct { type DataStore struct {
Driver string `json:"driver"` Driver string `json:"driver"`
Network string `json:"network` Network string `json:"network`
Host string `json:"host"` Host string `json:"host"`
Port string `json:"port"` Port string `json:"port"`
Username string `json:"user"` Username string `json:"user"`
Password string `json:"pass"` Password string `json:"pass"`
Schema string `json:"schema,omitempty"` Schema string `json:"schema,omitempty"`
Encoding string `json:"encoding,omitempty"` Encoding string `json:"encoding,omitempty"`
Prefix string `json:"prefix,omitempty"` Prefix string `json:"prefix,omitempty"`
MaxIdleConns int `json:"max_idle_conns,omitempty"` MaxIdleConns int `json:"max_idle_conns,omitempty"`
IdleTimeout *Duration `json:"idle_timeout,omitempty"` IdleTimeout *Duration `json:"idle_timeout,omitempty"`
} }
// Config represents a configuration for a server.Server. // Config represents a configuration for a server.Server.
type Config struct { type Config struct {
Addr string `json:"addr"` Addr string `json:"addr"`
PubAddr string `json:"pub_addr"` PubAddr string `json:"pub_addr"`
Cache DataStore `json:"cache"` Cache DataStore `json:"cache"`
Storage DataStore `json:"storage"` Storage DataStore `json:"storage"`
Private bool `json:"private"` Private bool `json:"private"`
Freeleech bool `json:"freeleech"` Freeleech bool `json:"freeleech"`
Slots bool `json:"slots"` Slots bool `json:"slots"`
Announce Duration `json:"announce"` Announce Duration `json:"announce"`
MinAnnounce Duration `json:"min_announce"` MinAnnounce Duration `json:"min_announce"`
ReadTimeout Duration `json:"read_timeout"` ReadTimeout Duration `json:"read_timeout"`
DefaultNumWant int `json:"default_num_want"` DefaultNumWant int `json:"default_num_want"`
TxRetries int `json:"tx_retries"`
} }
// Open is a shortcut to open a file, read it, and generate a Config. // Open is a shortcut to open a file, read it, and generate a Config.
// It supports relative and absolute paths. // It supports relative and absolute paths.
func Open(path string) (*Config, error) { func Open(path string) (*Config, error) {
expandedPath := os.ExpandEnv(path) expandedPath := os.ExpandEnv(path)
f, err := os.Open(expandedPath) f, err := os.Open(expandedPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer f.Close() defer f.Close()
conf, err := newConfig(f) conf, err := newConfig(f)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return conf, nil return conf, nil
} }
// New decodes JSON from a Reader into a Config. // New decodes JSON from a Reader into a Config.
func newConfig(raw io.Reader) (*Config, error) { func newConfig(raw io.Reader) (*Config, error) {
conf := &Config{} conf := &Config{}
err := json.NewDecoder(raw).Decode(conf) err := json.NewDecoder(raw).Decode(conf)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return conf, nil return conf, nil
} }

View file

@ -30,8 +30,6 @@
"announce": "30m", "announce": "30m",
"min_announce": "15m", "min_announce": "15m",
"read_timeout": "20s", "read_timeout": "20s",
"default_num_want": 50, "default_num_want": 50
"tx_retries": 3
} }

View file

@ -5,357 +5,351 @@
package server package server
import ( import (
"errors" "errors"
"log" "log"
"net/http" "net/http"
"path" "path"
"strconv" "strconv"
"time" "time"
"github.com/pushrax/chihaya/storage" "github.com/pushrax/chihaya/storage"
) )
func (s Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { func (s Server) serveAnnounce(w http.ResponseWriter, r *http.Request) {
// Parse the required parameters off of a query // Parse the required parameters off of a query
compact, numWant, infohash, peerID, event, ip, port, uploaded, downloaded, left, err := s.validateAnnounceQuery(r) compact, numWant, infohash, peerID, event, ip, port, uploaded, downloaded, left, err := s.validateAnnounceQuery(r)
if err != nil { if err != nil {
fail(err, w, r) fail(err, w, r)
return return
} }
// Retry failed transactions a specified number of times // Get a connection to the tracker db
for i := 0; i < s.conf.TxRetries; i++ { conn, err := s.dbConnPool.Get()
if err != nil {
log.Panicf("server: %s", err)
}
// Start a transaction // Validate the user's passkey
tx, err := s.dbConnPool.Get() passkey, _ := path.Split(r.URL.Path)
if err != nil { user, err := validateUser(conn, passkey)
log.Panicf("server: %s", err) if err != nil {
} fail(err, w, r)
return
}
// Validate the user's passkey // Check if the user's client is whitelisted
passkey, _ := path.Split(r.URL.Path) whitelisted, err := conn.ClientWhitelisted(parsePeerID(peerID))
user, err := validateUser(tx, passkey) if err != nil {
if err != nil { log.Panicf("server: %s", err)
fail(err, w, r) }
return if !whitelisted {
} fail(errors.New("Your client is not approved"), w, r)
return
}
// Check if the user's client is whitelisted // Find the specified torrent
whitelisted, err := tx.ClientWhitelisted(parsePeerID(peerID)) torrent, exists, err := conn.FindTorrent(infohash)
if err != nil { if err != nil {
log.Panicf("server: %s", err) log.Panicf("server: %s", err)
} }
if !whitelisted { if !exists {
fail(errors.New("Your client is not approved"), w, r) fail(errors.New("This torrent does not exist"), w, r)
return return
} }
// Find the specified torrent // If the torrent was pruned and the user is seeding, unprune it
torrent, exists, err := tx.FindTorrent(infohash) if !torrent.Active && left == 0 {
if err != nil { err := conn.MarkActive(torrent)
log.Panicf("server: %s", err) if err != nil {
} log.Panicf("server: %s", err)
if !exists { }
fail(errors.New("This torrent does not exist"), w, r) }
return
}
// If the torrent was pruned and the user is seeding, unprune it // Create a new peer object from the request
if !torrent.Active && left == 0 { peer := &storage.Peer{
err := tx.MarkActive(torrent) ID: peerID,
if err != nil { UserID: user.ID,
log.Panicf("server: %s", err) TorrentID: torrent.ID,
} IP: ip,
} Port: port,
Uploaded: uploaded,
Downloaded: downloaded,
Left: left,
LastAnnounce: time.Now().Unix(),
}
// Create a new peer object from the request // Look for the user in in the pool of seeders and leechers
peer := &storage.Peer{ _, seeder := torrent.Seeders[storage.PeerMapKey(peer)]
ID: peerID, _, leecher := torrent.Leechers[storage.PeerMapKey(peer)]
UserID: user.ID,
TorrentID: torrent.ID,
IP: ip,
Port: port,
Uploaded: uploaded,
Downloaded: downloaded,
Left: left,
LastAnnounce: time.Now().Unix(),
}
// Look for the user in in the pool of seeders and leechers switch {
_, seeder := torrent.Seeders[storage.PeerMapKey(peer)] // Guarantee that no user is in both pools
_, leecher := torrent.Leechers[storage.PeerMapKey(peer)] case seeder && leecher:
if left == 0 {
err := conn.RemoveLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
leecher = false
} else {
err := conn.RemoveSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
seeder = false
}
switch { case seeder:
// Guarantee that no user is in both pools // Update the peer with the stats from the request
case seeder && leecher: err := conn.SetSeeder(torrent, peer)
if left == 0 { if err != nil {
err := tx.RemoveLeecher(torrent, peer) log.Panicf("server: %s", err)
if err != nil { }
log.Panicf("server: %s", err)
}
leecher = false
} else {
err := tx.RemoveSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
seeder = false
}
case seeder: case leecher:
// Update the peer with the stats from the request // Update the peer with the stats from the request
err := tx.SetSeeder(torrent, peer) err := conn.SetLeecher(torrent, peer)
if err != nil { if err != nil {
log.Panicf("server: %s", err) log.Panicf("server: %s", err)
} }
case leecher: default:
// Update the peer with the stats from the request // Check the user's slots to see if they're allowed to leech
err := tx.SetLeecher(torrent, peer) if s.conf.Slots && user.Slots != -1 && left != 0 {
if err != nil { if user.SlotsUsed >= user.Slots {
log.Panicf("server: %s", err) fail(errors.New("You've run out of download slots."), w, r)
} return
}
}
default: if left == 0 {
// Check the user's slots to see if they're allowed to leech // Save the peer as a new seeder
if s.conf.Slots && user.Slots != -1 && left != 0 { err := conn.AddSeeder(torrent, peer)
if user.SlotsUsed >= user.Slots { if err != nil {
fail(errors.New("You've run out of download slots."), w, r) log.Panicf("server: %s", err)
return }
} } else {
} // Save the peer as a new leecher and increment the user's slots
err := conn.IncrementSlots(user)
if err != nil {
log.Panicf("server: %s", err)
}
err = conn.AddLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
}
if left == 0 { // Handle any events in the request
// Save the peer as a new seeder switch {
err := tx.AddSeeder(torrent, peer) case event == "stopped" || event == "paused":
if err != nil { if seeder {
log.Panicf("server: %s", err) err := conn.RemoveSeeder(torrent, peer)
} if err != nil {
} else { log.Panicf("server: %s", err)
// Save the peer as a new leecher and increment the user's slots }
err := tx.IncrementSlots(user) }
if err != nil { if leecher {
log.Panicf("server: %s", err) err := conn.RemoveLeecher(torrent, peer)
} if err != nil {
err = tx.AddLeecher(torrent, peer) log.Panicf("server: %s", err)
if err != nil { }
log.Panicf("server: %s", err) err = conn.DecrementSlots(user)
} if err != nil {
} log.Panicf("server: %s", err)
} }
}
// Handle any events in the request case event == "completed":
switch { err := conn.RecordSnatch(user, torrent)
case event == "stopped" || event == "paused": if err != nil {
if seeder { log.Panicf("server: %s", err)
err := tx.RemoveSeeder(torrent, peer) }
if err != nil { if leecher {
log.Panicf("server: %s", err) err := conn.LeecherFinished(torrent, peer)
} if err != nil {
} log.Panicf("server: %s", err)
if leecher { }
err := tx.RemoveLeecher(torrent, peer) }
if err != nil {
log.Panicf("server: %s", err)
}
err = tx.DecrementSlots(user)
if err != nil {
log.Panicf("server: %s", err)
}
}
case event == "completed": case leecher && left == 0:
err := tx.RecordSnatch(user, torrent) // A leecher completed but the event was never received
if err != nil { err := conn.LeecherFinished(torrent, peer)
log.Panicf("server: %s", err) if err != nil {
} log.Panicf("server: %s", err)
if leecher { }
err := tx.LeecherFinished(torrent, peer) }
if err != nil {
log.Panicf("server: %s", err)
}
}
case leecher && left == 0: if ip != peer.IP || port != peer.Port {
// A leecher completed but the event was never received peer.Port = port
err := tx.LeecherFinished(torrent, peer) peer.IP = ip
if err != nil { }
log.Panicf("server: %s", err)
}
}
if ip != peer.IP || port != peer.Port { // Generate the response
peer.Port = port seedCount := len(torrent.Seeders)
peer.IP = ip leechCount := len(torrent.Leechers)
}
// Generate the response writeBencoded(w, "d")
seedCount := len(torrent.Seeders) writeBencoded(w, "complete")
leechCount := len(torrent.Leechers) writeBencoded(w, seedCount)
writeBencoded(w, "incomplete")
writeBencoded(w, leechCount)
writeBencoded(w, "interval")
writeBencoded(w, s.conf.Announce.Duration)
writeBencoded(w, "min interval")
writeBencoded(w, s.conf.MinAnnounce.Duration)
writeBencoded(w, "d") if numWant > 0 && event != "stopped" && event != "paused" {
writeBencoded(w, "complete") writeBencoded(w, "peers")
writeBencoded(w, seedCount) var peerCount, count int
writeBencoded(w, "incomplete")
writeBencoded(w, leechCount)
writeBencoded(w, "interval")
writeBencoded(w, s.conf.Announce.Duration)
writeBencoded(w, "min interval")
writeBencoded(w, s.conf.MinAnnounce.Duration)
if numWant > 0 && event != "stopped" && event != "paused" { if compact {
writeBencoded(w, "peers") if left > 0 {
var peerCount, count int peerCount = minInt(numWant, leechCount)
} else {
peerCount = minInt(numWant, leechCount+seedCount-1)
}
writeBencoded(w, strconv.Itoa(peerCount*6))
writeBencoded(w, ":")
} else {
writeBencoded(w, "l")
}
if compact { if left > 0 {
if left > 0 { // If they're seeding, give them only leechers
peerCount = minInt(numWant, leechCount) writeLeechers(w, torrent, count, numWant, compact)
} else { } else {
peerCount = minInt(numWant, leechCount+seedCount-1) // If they're leeching, prioritize giving them seeders
} writeSeeders(w, torrent, count, numWant, compact)
writeBencoded(w, strconv.Itoa(peerCount*6)) writeLeechers(w, torrent, count, numWant, compact)
writeBencoded(w, ":") }
} else {
writeBencoded(w, "l")
}
if left > 0 { if compact && peerCount != count {
// If they're seeding, give them only leechers log.Panicf("Calculated peer count (%d) != real count (%d)", peerCount, count)
writeLeechers(w, torrent, count, numWant, compact) }
} else {
// If they're leeching, prioritize giving them seeders
writeSeeders(w, torrent, count, numWant, compact)
writeLeechers(w, torrent, count, numWant, compact)
}
if compact && peerCount != count { if !compact {
log.Panicf("Calculated peer count (%d) != real count (%d)", peerCount, count) writeBencoded(w, "e")
} }
}
if !compact { writeBencoded(w, "e")
writeBencoded(w, "e")
}
}
writeBencoded(w, "e")
return
}
} }
func (s Server) validateAnnounceQuery(r *http.Request) (compact bool, numWant int, infohash, peerID, event, ip string, port, uploaded, downloaded, left uint64, err error) { func (s Server) validateAnnounceQuery(r *http.Request) (compact bool, numWant int, infohash, peerID, event, ip string, port, uploaded, downloaded, left uint64, err error) {
pq, err := parseQuery(r.URL.RawQuery) pq, err := parseQuery(r.URL.RawQuery)
if err != nil { if err != nil {
return false, 0, "", "", "", "", 0, 0, 0, 0, err return false, 0, "", "", "", "", 0, 0, 0, 0, err
} }
compact = pq.Params["compact"] == "1" compact = pq.Params["compact"] == "1"
numWant = requestedPeerCount(s.conf.DefaultNumWant, pq) numWant = requestedPeerCount(s.conf.DefaultNumWant, pq)
infohash, _ = pq.Params["info_hash"] infohash, _ = pq.Params["info_hash"]
peerID, _ = pq.Params["peer_id"] peerID, _ = pq.Params["peer_id"]
event, _ = pq.Params["event"] event, _ = pq.Params["event"]
ip, _ = requestedIP(r, pq) ip, _ = requestedIP(r, pq)
port, portErr := pq.getUint64("port") port, portErr := pq.getUint64("port")
uploaded, uploadedErr := pq.getUint64("uploaded") uploaded, uploadedErr := pq.getUint64("uploaded")
downloaded, downloadedErr := pq.getUint64("downloaded") downloaded, downloadedErr := pq.getUint64("downloaded")
left, leftErr := pq.getUint64("left") left, leftErr := pq.getUint64("left")
if infohash == "" || if infohash == "" ||
peerID == "" || peerID == "" ||
ip == "" || ip == "" ||
portErr != nil || portErr != nil ||
uploadedErr != nil || uploadedErr != nil ||
downloadedErr != nil || downloadedErr != nil ||
leftErr != nil { leftErr != nil {
return false, 0, "", "", "", "", 0, 0, 0, 0, errors.New("Malformed request") return false, 0, "", "", "", "", 0, 0, 0, 0, errors.New("Malformed request")
} }
return return
} }
func requestedPeerCount(fallback int, pq *parsedQuery) int { func requestedPeerCount(fallback int, pq *parsedQuery) int {
if numWantStr, exists := pq.Params["numWant"]; exists { if numWantStr, exists := pq.Params["numWant"]; exists {
numWant, err := strconv.Atoi(numWantStr) numWant, err := strconv.Atoi(numWantStr)
if err != nil { if err != nil {
return fallback return fallback
} }
return numWant return numWant
} }
return fallback return fallback
} }
func requestedIP(r *http.Request, pq *parsedQuery) (string, error) { func requestedIP(r *http.Request, pq *parsedQuery) (string, error) {
ip, ok := pq.Params["ip"] ip, ok := pq.Params["ip"]
ipv4, okv4 := pq.Params["ipv4"] ipv4, okv4 := pq.Params["ipv4"]
xRealIPs, xRealOk := pq.Params["X-Real-Ip"] xRealIPs, xRealOk := pq.Params["X-Real-Ip"]
switch { switch {
case ok: case ok:
return ip, nil return ip, nil
case okv4: case okv4:
return ipv4, nil return ipv4, nil
case xRealOk && len(xRealIPs) > 0: case xRealOk && len(xRealIPs) > 0:
return string(xRealIPs[0]), nil return string(xRealIPs[0]), nil
default: default:
portIndex := len(r.RemoteAddr) - 1 portIndex := len(r.RemoteAddr) - 1
for ; portIndex >= 0; portIndex-- { for ; portIndex >= 0; portIndex-- {
if r.RemoteAddr[portIndex] == ':' { if r.RemoteAddr[portIndex] == ':' {
break break
} }
} }
if portIndex != -1 { if portIndex != -1 {
return r.RemoteAddr[0:portIndex], nil return r.RemoteAddr[0:portIndex], nil
} }
return "", errors.New("Failed to parse IP address") return "", errors.New("Failed to parse IP address")
} }
} }
func minInt(a, b int) int { func minInt(a, b int) int {
if a < b { if a < b {
return a return a
} }
return b return b
} }
func writeSeeders(w http.ResponseWriter, t *storage.Torrent, count, numWant int, compact bool) { func writeSeeders(w http.ResponseWriter, t *storage.Torrent, count, numWant int, compact bool) {
for _, seed := range t.Seeders { for _, seed := range t.Seeders {
if count >= numWant { if count >= numWant {
break break
} }
if compact { if compact {
// TODO writeBencoded(w, compactAddr) // TODO writeBencoded(w, compactAddr)
} else { } else {
writeBencoded(w, "d") writeBencoded(w, "d")
writeBencoded(w, "ip") writeBencoded(w, "ip")
writeBencoded(w, seed.IP) writeBencoded(w, seed.IP)
writeBencoded(w, "peer id") writeBencoded(w, "peer id")
writeBencoded(w, seed.ID) writeBencoded(w, seed.ID)
writeBencoded(w, "port") writeBencoded(w, "port")
writeBencoded(w, seed.Port) writeBencoded(w, seed.Port)
writeBencoded(w, "e") writeBencoded(w, "e")
} }
count++ count++
} }
} }
func writeLeechers(w http.ResponseWriter, t *storage.Torrent, count, numWant int, compact bool) { func writeLeechers(w http.ResponseWriter, t *storage.Torrent, count, numWant int, compact bool) {
for _, leech := range t.Leechers { for _, leech := range t.Leechers {
if count >= numWant { if count >= numWant {
break break
} }
if compact { if compact {
// TODO writeBencoded(w, compactAddr) // TODO writeBencoded(w, compactAddr)
} else { } else {
writeBencoded(w, "d") writeBencoded(w, "d")
writeBencoded(w, "ip") writeBencoded(w, "ip")
writeBencoded(w, leech.IP) writeBencoded(w, leech.IP)
writeBencoded(w, "peer id") writeBencoded(w, "peer id")
writeBencoded(w, leech.ID) writeBencoded(w, leech.ID)
writeBencoded(w, "port") writeBencoded(w, "port")
writeBencoded(w, leech.Port) writeBencoded(w, leech.Port)
writeBencoded(w, "e") writeBencoded(w, "e")
} }
count++ count++
} }
} }

View file

@ -22,15 +22,15 @@ func (s *Server) serveScrape(w http.ResponseWriter, r *http.Request) {
return return
} }
// Start a transaction // Get a connection to the tracker db
tx, err := s.dbConnPool.Get() conn, err := s.dbConnPool.Get()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// Find and validate the user // Find and validate the user
passkey, _ := path.Split(r.URL.Path) passkey, _ := path.Split(r.URL.Path)
_, err = validateUser(tx, passkey) _, err = validateUser(conn, passkey)
if err != nil { if err != nil {
fail(err, w, r) fail(err, w, r)
return return
@ -40,7 +40,7 @@ func (s *Server) serveScrape(w http.ResponseWriter, r *http.Request) {
writeBencoded(w, "files") writeBencoded(w, "files")
if pq.Infohashes != nil { if pq.Infohashes != nil {
for _, infohash := range pq.Infohashes { for _, infohash := range pq.Infohashes {
torrent, exists, err := tx.FindTorrent(infohash) torrent, exists, err := conn.FindTorrent(infohash)
if err != nil { if err != nil {
log.Panicf("server: %s", err) log.Panicf("server: %s", err)
} }
@ -50,7 +50,7 @@ func (s *Server) serveScrape(w http.ResponseWriter, r *http.Request) {
} }
} }
} else if infohash, exists := pq.Params["info_hash"]; exists { } else if infohash, exists := pq.Params["info_hash"]; exists {
torrent, exists, err := tx.FindTorrent(infohash) torrent, exists, err := conn.FindTorrent(infohash)
if err != nil { if err != nil {
log.Panicf("server: %s", err) log.Panicf("server: %s", err)
} }

View file

@ -117,13 +117,13 @@ func fail(err error, w http.ResponseWriter, r *http.Request) {
w.(http.Flusher).Flush() w.(http.Flusher).Flush()
} }
func validateUser(tx tracker.Conn, dir string) (*storage.User, error) { func validateUser(conn tracker.Conn, dir string) (*storage.User, error) {
if len(dir) != 34 { if len(dir) != 34 {
return nil, errors.New("Passkey is invalid") return nil, errors.New("Passkey is invalid")
} }
passkey := dir[1:33] passkey := dir[1:33]
user, exists, err := tx.FindUser(passkey) user, exists, err := conn.FindUser(passkey)
if err != nil { if err != nil {
log.Panicf("server: %s", err) log.Panicf("server: %s", err)
} }

View file

@ -0,0 +1,563 @@
// Copyright 2013 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.
package redis
import (
"math/rand"
"os"
"reflect"
"testing"
"time"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/storage/tracker"
)
func createTestConn() tracker.Conn {
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
panicOnErr(err)
conf := &testConfig.Cache
testPool, err := tracker.Open(conf)
panicOnErr(err)
newConn, err := testPool.Get()
panicOnErr(err)
return newConn
}
func TestFindUserSuccess(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if !found {
t.Error("user not found", testUser)
}
if *foundUser != *testUser {
t.Error("found user mismatch", *foundUser, testUser)
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
}
func TestFindUserFail(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
t.Error("user found", foundUser)
}
}
func TestRemoveUser(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
err := conn.RemoveUser(testUser)
panicOnErr(err)
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
t.Error("removed user found", foundUser)
}
}
func TestFindTorrentSuccess(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if !found {
t.Error("torrent not found", testTorrent)
}
if !reflect.DeepEqual(foundTorrent, testTorrent) {
t.Error("found torrent mismatch", foundTorrent, testTorrent)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestFindTorrentFail(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
t.Error("torrent found", foundTorrent)
}
}
func TestRemoveTorrent(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
t.Error("removed torrent found", foundTorrent)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestClientWhitelistSuccess(t *testing.T) {
conn := createTestConn()
testPeerID := "-lt0D30-"
panicOnErr(conn.WhitelistClient(testPeerID))
found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err)
if !found {
t.Error("peerID not found", testPeerID)
}
// Cleanup
panicOnErr(conn.UnWhitelistClient(testPeerID))
}
func TestClientWhitelistFail(t *testing.T) {
conn := createTestConn()
testPeerID2 := "TIX0192"
found, err := conn.ClientWhitelisted(testPeerID2)
panicOnErr(err)
if found {
t.Error("peerID found", testPeerID2)
}
}
func TestRecordSnatch(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
testUser := createTestUser()
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.AddUser(testUser))
userSnatches := testUser.Snatches
torrentSnatches := testTorrent.Snatches
panicOnErr(conn.RecordSnatch(testUser, testTorrent))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if testUser.Snatches != userSnatches+1 {
t.Error("snatch not recorded to local user", testUser.Snatches, userSnatches+1)
}
if testTorrent.Snatches != torrentSnatches+1 {
t.Error("snatch not recorded to local torrent")
}
if foundUser.Snatches != userSnatches+1 {
t.Error("snatch not recorded to cached user", foundUser.Snatches, userSnatches+1)
}
if foundTorrent.Snatches != torrentSnatches+1 {
t.Error("snatch not recorded to cached torrent")
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.RemoveUser(testUser))
}
func TestMarkActive(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
testTorrent.Active = false
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.MarkActive(testTorrent))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if foundTorrent.Active != true {
t.Error("cached torrent not activated")
}
if testTorrent.Active != true {
t.Error("cached torrent not activated")
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestClientWhitelistRemove(t *testing.T) {
conn := createTestConn()
testPeerID := "-lt0D30-"
panicOnErr(conn.WhitelistClient(testPeerID))
panicOnErr(conn.UnWhitelistClient(testPeerID))
found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err)
if found {
t.Error("removed peerID found", testPeerID)
}
}
func TestAddSeeder(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, found := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found && foundSeeder != *testSeeder {
t.Error("seeder not added to cache", testSeeder)
}
foundSeeder, found = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found && foundSeeder != *testSeeder {
t.Error("seeder not added to local", testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestAddLeecher(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to cache", testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestRemoveSeeder(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
foundSeeder, found := testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found || foundSeeder == *testSeeder {
t.Error("seeder not removed from local", foundSeeder)
}
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, found = foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found || foundSeeder == *testSeeder {
t.Error("seeder not removed from cache", foundSeeder, *testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestRemoveLeecher(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
panicOnErr(conn.RemoveLeecher(testTorrent, testLeecher))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found || foundLeecher == *testLeecher {
t.Error("leecher not removed from cache", foundLeecher, *testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found || foundLeecher == *testLeecher {
t.Error("leecher not removed from local", foundLeecher, *testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestSetSeeder(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in cache", foundSeeder, *testSeeder)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in local", foundSeeder, *testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestSetLeecher(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testLeecher.Uploaded += uint64(r.Int63())
panicOnErr(conn.SetLeecher(testTorrent, testLeecher))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, _ := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundLeecher != *testLeecher {
t.Error("leecher not updated in cache", testLeecher)
}
foundLeecher, _ = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundLeecher != *testLeecher {
t.Error("leecher not updated in local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestIncrementSlots(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
numSlots := testUser.Slots
panicOnErr(conn.IncrementSlots(testUser))
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if foundUser.Slots != numSlots+1 {
t.Error("cached slots not incremented")
}
if testUser.Slots != numSlots+1 {
t.Error("local slots not incremented")
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
}
func TestDecrementSlots(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
numSlots := testUser.Slots
panicOnErr(conn.DecrementSlots(testUser))
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if foundUser.Slots != numSlots-1 {
t.Error("cached slots not incremented")
}
if testUser.Slots != numSlots-1 {
t.Error("local slots not incremented")
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
}
func TestLeecherFinished(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0
panicOnErr(conn.LeecherFinished(testTorrent, testLeecher))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testLeecher)]
if foundSeeder != *testLeecher {
t.Error("seeder not added to cache", foundSeeder, *testLeecher)
}
foundSeeder, _ = foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundSeeder == *testLeecher {
t.Error("leecher not removed from cache", testLeecher)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testLeecher)]
if foundSeeder != *testLeecher {
t.Error("seeder not added to local", testLeecher)
}
foundSeeder, _ = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundSeeder == *testLeecher {
t.Error("leecher not removed from local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
// Add, update, verify remove
func TestUpdatePeer(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
// Update a seeder, set it, then check to make sure it updated
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if seeder, exists := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]; exists {
t.Error("seeder not removed from cache", seeder)
}
if seeder, exists := testTorrent.Seeders[storage.PeerMapKey(testSeeder)]; exists {
t.Error("seeder not removed from local", seeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestParallelFindUser(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testUserSuccess := createTestUser()
testUserFail := createTestUser()
panicOnErr(conn.AddUser(testUserSuccess))
for i := 0; i < 10; i++ {
foundUser, found, err := conn.FindUser(testUserFail.Passkey)
panicOnErr(err)
if found {
t.Error("user found", foundUser)
}
foundUser, found, err = conn.FindUser(testUserSuccess.Passkey)
panicOnErr(err)
if !found {
t.Error("user not found", testUserSuccess)
}
if *foundUser != *testUserSuccess {
t.Error("found user mismatch", *foundUser, testUserSuccess)
}
}
// Cleanup
panicOnErr(conn.RemoveUser(testUserSuccess))
}
func TestParallelFindTorrent(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrentSuccess := createTestTorrent()
testTorrentFail := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrentSuccess))
for i := 0; i < 10; i++ {
foundTorrent, found, err := conn.FindTorrent(testTorrentSuccess.Infohash)
panicOnErr(err)
if !found {
t.Error("torrent not found", testTorrentSuccess)
}
if !reflect.DeepEqual(foundTorrent, testTorrentSuccess) {
t.Error("found torrent mismatch", foundTorrent, testTorrentSuccess)
}
foundTorrent, found, err = conn.FindTorrent(testTorrentFail.Infohash)
panicOnErr(err)
if found {
t.Error("torrent found", foundTorrent)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrentSuccess))
}
func TestParallelSetSeeder(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 10; i++ {
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in cache", foundSeeder, *testSeeder)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in local", foundSeeder, *testSeeder)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestParallelAddLeecher(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
for i := 0; i < 10; i++ {
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to cache", testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to local", testLeecher)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}

File diff suppressed because it is too large Load diff

View file

@ -5,284 +5,284 @@
package redis package redis
import ( import (
"math/rand" "math/rand"
"testing" "testing"
"time" "time"
) )
func BenchmarkSuccessfulFindUser(b *testing.B) { func BenchmarkSuccessfulFindUser(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testUser := createTestUser() testUser := createTestUser()
panicOnErr(tx.AddUser(testUser)) panicOnErr(conn.AddUser(testUser))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
foundUser, found, err := tx.FindUser(testUser.Passkey) foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err) panicOnErr(err)
if !found { if !found {
b.Error("user not found", testUser) b.Error("user not found", testUser)
} }
if *foundUser != *testUser { if *foundUser != *testUser {
b.Error("found user mismatch", *foundUser, testUser) b.Error("found user mismatch", *foundUser, testUser)
} }
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveUser(testUser)) panicOnErr(conn.RemoveUser(testUser))
b.StartTimer() b.StartTimer()
} }
func BenchmarkFailedFindUser(b *testing.B) { func BenchmarkFailedFindUser(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testUser := createTestUser() testUser := createTestUser()
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
_, found, err := tx.FindUser(testUser.Passkey) _, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err) panicOnErr(err)
if found { if found {
b.Error("user not found", testUser) b.Error("user not found", testUser)
} }
} }
} }
func BenchmarkSuccessfulFindTorrent(b *testing.B) { func BenchmarkSuccessfulFindTorrent(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent)) panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash) foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err) panicOnErr(err)
if !found { if !found {
b.Error("torrent not found", testTorrent) b.Error("torrent not found", testTorrent)
} }
// Incomplete comparison as maps make struct not nativly comparable // Incomplete comparison as maps make struct not nativly comparable
if foundTorrent.Infohash != testTorrent.Infohash { if foundTorrent.Infohash != testTorrent.Infohash {
b.Error("found torrent mismatch", foundTorrent, testTorrent) b.Error("found torrent mismatch", foundTorrent, testTorrent)
} }
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveTorrent(testTorrent)) panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer() b.StartTimer()
} }
func BenchmarkFailFindTorrent(b *testing.B) { func BenchmarkFailFindTorrent(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash) foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err) panicOnErr(err)
if found { if found {
b.Error("torrent found", foundTorrent) b.Error("torrent found", foundTorrent)
} }
} }
} }
func BenchmarkSuccessfulClientWhitelisted(b *testing.B) { func BenchmarkSuccessfulClientWhitelisted(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testPeerID := "-lt0D30-" testPeerID := "-lt0D30-"
panicOnErr(tx.WhitelistClient(testPeerID)) panicOnErr(conn.WhitelistClient(testPeerID))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
found, err := tx.ClientWhitelisted(testPeerID) found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err) panicOnErr(err)
if !found { if !found {
b.Error("peerID not found", testPeerID) b.Error("peerID not found", testPeerID)
} }
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.UnWhitelistClient(testPeerID)) panicOnErr(conn.UnWhitelistClient(testPeerID))
b.StartTimer() b.StartTimer()
} }
func BenchmarkFailClientWhitelisted(b *testing.B) { func BenchmarkFailClientWhitelisted(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testPeerID2 := "TIX0192" testPeerID2 := "TIX0192"
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
found, err := tx.ClientWhitelisted(testPeerID2) found, err := conn.ClientWhitelisted(testPeerID2)
panicOnErr(err) panicOnErr(err)
if found { if found {
b.Error("peerID found", testPeerID2) b.Error("peerID found", testPeerID2)
} }
} }
} }
func BenchmarkRecordSnatch(b *testing.B) { func BenchmarkRecordSnatch(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
testUser := createTestUser() testUser := createTestUser()
panicOnErr(tx.AddTorrent(testTorrent)) panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(tx.AddUser(testUser)) panicOnErr(conn.AddUser(testUser))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(tx.RecordSnatch(testUser, testTorrent)) panicOnErr(conn.RecordSnatch(testUser, testTorrent))
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveTorrent(testTorrent)) panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(tx.RemoveUser(testUser)) panicOnErr(conn.RemoveUser(testUser))
b.StartTimer() b.StartTimer()
} }
func BenchmarkMarkActive(b *testing.B) { func BenchmarkMarkActive(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
testTorrent.Active = false testTorrent.Active = false
panicOnErr(tx.AddTorrent(testTorrent)) panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(tx.MarkActive(testTorrent)) panicOnErr(conn.MarkActive(testTorrent))
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveTorrent(testTorrent)) panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer() b.StartTimer()
} }
func BenchmarkAddSeeder(b *testing.B) { func BenchmarkAddSeeder(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent)) panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer() b.StopTimer()
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID) testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
b.StartTimer() b.StartTimer()
panicOnErr(tx.AddSeeder(testTorrent, testSeeder)) panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveTorrent(testTorrent)) panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer() b.StartTimer()
} }
func BenchmarkRemoveSeeder(b *testing.B) { func BenchmarkRemoveSeeder(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent)) panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID) testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer() b.StopTimer()
tx.AddSeeder(testTorrent, testSeeder) conn.AddSeeder(testTorrent, testSeeder)
b.StartTimer() b.StartTimer()
panicOnErr(tx.RemoveSeeder(testTorrent, testSeeder)) panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveTorrent(testTorrent)) panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer() b.StartTimer()
} }
func BenchmarkSetSeeder(b *testing.B) { func BenchmarkSetSeeder(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent)) panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID) testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddSeeder(testTorrent, testSeeder)) panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano())) r := rand.New(rand.NewSource(time.Now().UnixNano()))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer() b.StopTimer()
testSeeder.Uploaded += uint64(r.Int63()) testSeeder.Uploaded += uint64(r.Int63())
b.StartTimer() b.StartTimer()
tx.SetSeeder(testTorrent, testSeeder) conn.SetSeeder(testTorrent, testSeeder)
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveTorrent(testTorrent)) panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer() b.StartTimer()
} }
func BenchmarkIncrementSlots(b *testing.B) { func BenchmarkIncrementSlots(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testUser := createTestUser() testUser := createTestUser()
panicOnErr(tx.AddUser(testUser)) panicOnErr(conn.AddUser(testUser))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(tx.IncrementSlots(testUser)) panicOnErr(conn.IncrementSlots(testUser))
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveUser(testUser)) panicOnErr(conn.RemoveUser(testUser))
b.StartTimer() b.StartTimer()
} }
func BenchmarkLeecherFinished(b *testing.B) { func BenchmarkLeecherFinished(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent)) panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer() b.StopTimer()
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID) testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddLeecher(testTorrent, testLeecher)) panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0 testLeecher.Left = 0
b.StartTimer() b.StartTimer()
panicOnErr(tx.LeecherFinished(testTorrent, testLeecher)) panicOnErr(conn.LeecherFinished(testTorrent, testLeecher))
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
panicOnErr(tx.RemoveTorrent(testTorrent)) panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer() b.StartTimer()
} }
// This is a comparision to the Leecher finished function // This is a comparision to the Leecher finished function
func BenchmarkRemoveLeecherAddSeeder(b *testing.B) { func BenchmarkRemoveLeecherAddSeeder(b *testing.B) {
b.StopTimer() b.StopTimer()
tx := createTestTx() conn := createTestConn()
testTorrent := createTestTorrent() testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent)) panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer() b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ { for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer() b.StopTimer()
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID) testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddLeecher(testTorrent, testLeecher)) panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0 testLeecher.Left = 0
b.StartTimer() b.StartTimer()
panicOnErr(tx.RemoveLeecher(testTorrent, testLeecher)) panicOnErr(conn.RemoveLeecher(testTorrent, testLeecher))
panicOnErr(tx.AddSeeder(testTorrent, testLeecher)) panicOnErr(conn.AddSeeder(testTorrent, testLeecher))
} }
// Cleanup // Cleanup
b.StopTimer() b.StopTimer()
tx.RemoveTorrent(testTorrent) conn.RemoveTorrent(testTorrent)
b.StartTimer() b.StartTimer()
} }

View file

@ -5,180 +5,180 @@
package redis package redis
import ( import (
"crypto/rand" "crypto/rand"
"fmt" "fmt"
"io" "io"
"os" "os"
"strconv" "strconv"
"testing" "testing"
"github.com/garyburd/redigo/redis" "github.com/garyburd/redigo/redis"
"github.com/pushrax/chihaya/config" "github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage" "github.com/pushrax/chihaya/storage"
) )
var ( var (
testTorrentIDChannel chan uint64 testTorrentIDChannel chan uint64
testUserIDChannel chan uint64 testUserIDChannel chan uint64
testPeerIDChannel chan int testPeerIDChannel chan int
) )
func init() { func init() {
testTorrentIDChannel = make(chan uint64, 100) testTorrentIDChannel = make(chan uint64, 100)
testUserIDChannel = make(chan uint64, 100) testUserIDChannel = make(chan uint64, 100)
testPeerIDChannel = make(chan int, 100) testPeerIDChannel = make(chan int, 100)
// Sync access to ID counter with buffered global channels // Sync access to ID counter with buffered global channels
go func() { go func() {
for i := 0; ; i++ { for i := 0; ; i++ {
testTorrentIDChannel <- uint64(i) testTorrentIDChannel <- uint64(i)
} }
}() }()
go func() { go func() {
for i := 0; ; i++ { for i := 0; ; i++ {
testUserIDChannel <- uint64(i) testUserIDChannel <- uint64(i)
} }
}() }()
go func() { go func() {
for i := 0; ; i++ { for i := 0; ; i++ {
testPeerIDChannel <- i testPeerIDChannel <- i
} }
}() }()
} }
func createTestTorrentID() uint64 { func createTestTorrentID() uint64 {
return <-testTorrentIDChannel return <-testTorrentIDChannel
} }
func createTestUserID() uint64 { func createTestUserID() uint64 {
return <-testUserIDChannel return <-testUserIDChannel
} }
func createTestPeerID() string { func createTestPeerID() string {
return "-testPeerID-" + strconv.Itoa(<-testPeerIDChannel) return "-testPeerID-" + strconv.Itoa(<-testPeerIDChannel)
} }
func createTestInfohash() string { func createTestInfohash() string {
uuid := make([]byte, 40) uuid := make([]byte, 40)
n, err := io.ReadFull(rand.Reader, uuid) n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil { if n != len(uuid) || err != nil {
panic(err) panic(err)
} }
return string(uuid) return string(uuid)
} }
func createTestPasskey() string { func createTestPasskey() string {
uuid := make([]byte, 40) uuid := make([]byte, 40)
n, err := io.ReadFull(rand.Reader, uuid) n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil { if n != len(uuid) || err != nil {
panic(err) panic(err)
} }
return string(uuid) return string(uuid)
} }
func panicOnErr(err error) { func panicOnErr(err error) {
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
panic(err) panic(err)
} }
} }
func createTestRedisTx() *Tx { func createTestRedisConn() *Conn {
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH")) testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
conf := &testConfig.Cache conf := &testConfig.Cache
panicOnErr(err) panicOnErr(err)
testPool := &Pool{ testPool := &Pool{
conf: conf, conf: conf,
pool: redis.Pool{ pool: redis.Pool{
MaxIdle: conf.MaxIdleConns, MaxIdle: conf.MaxIdleConns,
IdleTimeout: conf.IdleTimeout.Duration, IdleTimeout: conf.IdleTimeout.Duration,
Dial: makeDialFunc(conf), Dial: makeDialFunc(conf),
TestOnBorrow: testOnBorrow, TestOnBorrow: testOnBorrow,
}, },
} }
txObj := &Tx{ newConn := &Conn{
conf: testPool.conf, conf: testPool.conf,
done: false, done: false,
Conn: testPool.pool.Get(), Conn: testPool.pool.Get(),
} }
panicOnErr(err) panicOnErr(err)
// Test connection before returning // Test connection before returning
_, err = txObj.Do("PING") _, err = newConn.Do("PING")
panicOnErr(err) panicOnErr(err)
return txObj return newConn
} }
func createTestUser() *storage.User { func createTestUser() *storage.User {
return &storage.User{ID: createTestUserID(), Passkey: createTestPasskey(), return &storage.User{ID: createTestUserID(), Passkey: createTestPasskey(),
UpMultiplier: 1.01, DownMultiplier: 1.0, Slots: 4, SlotsUsed: 2, Snatches: 7} UpMultiplier: 1.01, DownMultiplier: 1.0, Slots: 4, SlotsUsed: 2, Snatches: 7}
} }
func createTestPeer(userID uint64, torrentID uint64) *storage.Peer { func createTestPeer(userID uint64, torrentID uint64) *storage.Peer {
return &storage.Peer{ID: createTestPeerID(), UserID: userID, TorrentID: torrentID, return &storage.Peer{ID: createTestPeerID(), UserID: userID, TorrentID: torrentID,
IP: "127.0.0.1", Port: 6889, Uploaded: 1024, Downloaded: 3000, Left: 4200, LastAnnounce: 11} IP: "127.0.0.1", Port: 6889, Uploaded: 1024, Downloaded: 3000, Left: 4200, LastAnnounce: 11}
} }
func createTestPeers(torrentID uint64, num int) map[string]storage.Peer { func createTestPeers(torrentID uint64, num int) map[string]storage.Peer {
testPeers := make(map[string]storage.Peer) testPeers := make(map[string]storage.Peer)
for i := 0; i < num; i++ { for i := 0; i < num; i++ {
tempPeer := createTestPeer(createTestUserID(), torrentID) tempPeer := createTestPeer(createTestUserID(), torrentID)
testPeers[storage.PeerMapKey(tempPeer)] = *tempPeer testPeers[storage.PeerMapKey(tempPeer)] = *tempPeer
} }
return testPeers return testPeers
} }
func createTestTorrent() *storage.Torrent { func createTestTorrent() *storage.Torrent {
torrentInfohash := createTestInfohash() torrentInfohash := createTestInfohash()
torrentID := createTestTorrentID() torrentID := createTestTorrentID()
testSeeders := createTestPeers(torrentID, 4) testSeeders := createTestPeers(torrentID, 4)
testLeechers := createTestPeers(torrentID, 2) testLeechers := createTestPeers(torrentID, 2)
testTorrent := storage.Torrent{ID: torrentID, Infohash: torrentInfohash, Active: true, testTorrent := storage.Torrent{ID: torrentID, Infohash: torrentInfohash, Active: true,
Seeders: testSeeders, Leechers: testLeechers, Snatches: 11, UpMultiplier: 1.0, DownMultiplier: 1.0, LastAction: 0} Seeders: testSeeders, Leechers: testLeechers, Snatches: 11, UpMultiplier: 1.0, DownMultiplier: 1.0, LastAction: 0}
return &testTorrent return &testTorrent
} }
func TestValidPeers(t *testing.T) { func TestValidPeers(t *testing.T) {
testTx := createTestRedisTx() testConn := createTestRedisConn()
testTorrentID := createTestTorrentID() testTorrentID := createTestTorrentID()
testPeers := createTestPeers(testTorrentID, 3) testPeers := createTestPeers(testTorrentID, 3)
panicOnErr(testTx.addPeers(testPeers, "test:")) panicOnErr(testConn.addPeers(testPeers, "test:"))
peerMap, err := testTx.getPeers(testTorrentID, "test:") peerMap, err := testConn.getPeers(testTorrentID, "test:")
panicOnErr(err) panicOnErr(err)
if len(peerMap) != len(testPeers) { if len(peerMap) != len(testPeers) {
t.Error("Num Peers not equal ", len(peerMap), len(testPeers)) t.Error("Num Peers not equal ", len(peerMap), len(testPeers))
} }
panicOnErr(testTx.removePeers(testTorrentID, testPeers, "test:")) panicOnErr(testConn.removePeers(testTorrentID, testPeers, "test:"))
} }
func TestInvalidPeers(t *testing.T) { func TestInvalidPeers(t *testing.T) {
testTx := createTestRedisTx() testConn := createTestRedisConn()
testTorrentID := createTestTorrentID() testTorrentID := createTestTorrentID()
testPeers := createTestPeers(testTorrentID, 3) testPeers := createTestPeers(testTorrentID, 3)
tempPeer := createTestPeer(createTestUserID(), testTorrentID) tempPeer := createTestPeer(createTestUserID(), testTorrentID)
testPeers[storage.PeerMapKey(tempPeer)] = *tempPeer testPeers[storage.PeerMapKey(tempPeer)] = *tempPeer
panicOnErr(testTx.addPeers(testPeers, "test:")) panicOnErr(testConn.addPeers(testPeers, "test:"))
// Imitate a peer being removed during get // Imitate a peer being removed during get
hashKey := testTx.conf.Prefix + getPeerHashKey(tempPeer) hashKey := testConn.conf.Prefix + getPeerHashKey(tempPeer)
_, err := testTx.Do("DEL", hashKey) _, err := testConn.Do("DEL", hashKey)
panicOnErr(err) panicOnErr(err)
peerMap, err := testTx.getPeers(testTorrentID, "test:") peerMap, err := testConn.getPeers(testTorrentID, "test:")
panicOnErr(err) panicOnErr(err)
// Expect 1 less peer due to delete // Expect 1 less peer due to delete
if len(peerMap) != len(testPeers)-1 { if len(peerMap) != len(testPeers)-1 {
t.Error("Num Peers not equal ", len(peerMap), len(testPeers)-1) t.Error("Num Peers not equal ", len(peerMap), len(testPeers)-1)
} }
panicOnErr(testTx.removePeers(testTorrentID, testPeers, "test:")) panicOnErr(testConn.removePeers(testTorrentID, testPeers, "test:"))
if len(testPeers) != 0 { if len(testPeers) != 0 {
t.Errorf("All peers not removed, %d peers remain!", len(testPeers)) t.Errorf("All peers not removed, %d peers remain!", len(testPeers))
} }
} }

View file

@ -1,563 +0,0 @@
// Copyright 2013 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.
package redis
import (
"math/rand"
"os"
"reflect"
"testing"
"time"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/storage/tracker"
)
func createTestTx() tracker.Conn {
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
panicOnErr(err)
conf := &testConfig.Cache
testPool, err := tracker.Open(conf)
panicOnErr(err)
txObj, err := testPool.Get()
panicOnErr(err)
return txObj
}
func TestFindUserSuccess(t *testing.T) {
tx := createTestTx()
testUser := createTestUser()
panicOnErr(tx.AddUser(testUser))
foundUser, found, err := tx.FindUser(testUser.Passkey)
panicOnErr(err)
if !found {
t.Error("user not found", testUser)
}
if *foundUser != *testUser {
t.Error("found user mismatch", *foundUser, testUser)
}
// Cleanup
panicOnErr(tx.RemoveUser(testUser))
}
func TestFindUserFail(t *testing.T) {
tx := createTestTx()
testUser := createTestUser()
foundUser, found, err := tx.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
t.Error("user found", foundUser)
}
}
func TestRemoveUser(t *testing.T) {
tx := createTestTx()
testUser := createTestUser()
panicOnErr(tx.AddUser(testUser))
err := tx.RemoveUser(testUser)
panicOnErr(err)
foundUser, found, err := tx.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
t.Error("removed user found", foundUser)
}
}
func TestFindTorrentSuccess(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if !found {
t.Error("torrent not found", testTorrent)
}
if !reflect.DeepEqual(foundTorrent, testTorrent) {
t.Error("found torrent mismatch", foundTorrent, testTorrent)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestFindTorrentFail(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
t.Error("torrent found", foundTorrent)
}
}
func TestRemoveTorrent(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
panicOnErr(tx.RemoveTorrent(testTorrent))
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
t.Error("removed torrent found", foundTorrent)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestClientWhitelistSuccess(t *testing.T) {
tx := createTestTx()
testPeerID := "-lt0D30-"
panicOnErr(tx.WhitelistClient(testPeerID))
found, err := tx.ClientWhitelisted(testPeerID)
panicOnErr(err)
if !found {
t.Error("peerID not found", testPeerID)
}
// Cleanup
panicOnErr(tx.UnWhitelistClient(testPeerID))
}
func TestClientWhitelistFail(t *testing.T) {
tx := createTestTx()
testPeerID2 := "TIX0192"
found, err := tx.ClientWhitelisted(testPeerID2)
panicOnErr(err)
if found {
t.Error("peerID found", testPeerID2)
}
}
func TestRecordSnatch(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
testUser := createTestUser()
panicOnErr(tx.AddTorrent(testTorrent))
panicOnErr(tx.AddUser(testUser))
userSnatches := testUser.Snatches
torrentSnatches := testTorrent.Snatches
panicOnErr(tx.RecordSnatch(testUser, testTorrent))
foundTorrent, _, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundUser, _, err := tx.FindUser(testUser.Passkey)
panicOnErr(err)
if testUser.Snatches != userSnatches+1 {
t.Error("snatch not recorded to local user", testUser.Snatches, userSnatches+1)
}
if testTorrent.Snatches != torrentSnatches+1 {
t.Error("snatch not recorded to local torrent")
}
if foundUser.Snatches != userSnatches+1 {
t.Error("snatch not recorded to cached user", foundUser.Snatches, userSnatches+1)
}
if foundTorrent.Snatches != torrentSnatches+1 {
t.Error("snatch not recorded to cached torrent")
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
panicOnErr(tx.RemoveUser(testUser))
}
func TestMarkActive(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
testTorrent.Active = false
panicOnErr(tx.AddTorrent(testTorrent))
panicOnErr(tx.MarkActive(testTorrent))
foundTorrent, _, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if foundTorrent.Active != true {
t.Error("cached torrent not activated")
}
if testTorrent.Active != true {
t.Error("cached torrent not activated")
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestClientWhitelistRemove(t *testing.T) {
tx := createTestTx()
testPeerID := "-lt0D30-"
panicOnErr(tx.WhitelistClient(testPeerID))
panicOnErr(tx.UnWhitelistClient(testPeerID))
found, err := tx.ClientWhitelisted(testPeerID)
panicOnErr(err)
if found {
t.Error("removed peerID found", testPeerID)
}
}
func TestAddSeeder(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddSeeder(testTorrent, testSeeder))
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, found := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found && foundSeeder != *testSeeder {
t.Error("seeder not added to cache", testSeeder)
}
foundSeeder, found = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found && foundSeeder != *testSeeder {
t.Error("seeder not added to local", testSeeder)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestAddLeecher(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddLeecher(testTorrent, testLeecher))
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to cache", testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to local", testLeecher)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestRemoveSeeder(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddSeeder(testTorrent, testSeeder))
panicOnErr(tx.RemoveSeeder(testTorrent, testSeeder))
foundSeeder, found := testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found || foundSeeder == *testSeeder {
t.Error("seeder not removed from local", foundSeeder)
}
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, found = foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found || foundSeeder == *testSeeder {
t.Error("seeder not removed from cache", foundSeeder, *testSeeder)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestRemoveLeecher(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddLeecher(testTorrent, testLeecher))
panicOnErr(tx.RemoveLeecher(testTorrent, testLeecher))
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found || foundLeecher == *testLeecher {
t.Error("leecher not removed from cache", foundLeecher, *testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found || foundLeecher == *testLeecher {
t.Error("leecher not removed from local", foundLeecher, *testLeecher)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestSetSeeder(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(tx.SetSeeder(testTorrent, testSeeder))
foundTorrent, _, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in cache", foundSeeder, *testSeeder)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in local", foundSeeder, *testSeeder)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestSetLeecher(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddLeecher(testTorrent, testLeecher))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testLeecher.Uploaded += uint64(r.Int63())
panicOnErr(tx.SetLeecher(testTorrent, testLeecher))
foundTorrent, _, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, _ := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundLeecher != *testLeecher {
t.Error("leecher not updated in cache", testLeecher)
}
foundLeecher, _ = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundLeecher != *testLeecher {
t.Error("leecher not updated in local", testLeecher)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestIncrementSlots(t *testing.T) {
tx := createTestTx()
testUser := createTestUser()
panicOnErr(tx.AddUser(testUser))
numSlots := testUser.Slots
panicOnErr(tx.IncrementSlots(testUser))
foundUser, _, err := tx.FindUser(testUser.Passkey)
panicOnErr(err)
if foundUser.Slots != numSlots+1 {
t.Error("cached slots not incremented")
}
if testUser.Slots != numSlots+1 {
t.Error("local slots not incremented")
}
// Cleanup
panicOnErr(tx.RemoveUser(testUser))
}
func TestDecrementSlots(t *testing.T) {
tx := createTestTx()
testUser := createTestUser()
panicOnErr(tx.AddUser(testUser))
numSlots := testUser.Slots
panicOnErr(tx.DecrementSlots(testUser))
foundUser, _, err := tx.FindUser(testUser.Passkey)
panicOnErr(err)
if foundUser.Slots != numSlots-1 {
t.Error("cached slots not incremented")
}
if testUser.Slots != numSlots-1 {
t.Error("local slots not incremented")
}
// Cleanup
panicOnErr(tx.RemoveUser(testUser))
}
func TestLeecherFinished(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0
panicOnErr(tx.LeecherFinished(testTorrent, testLeecher))
foundTorrent, _, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testLeecher)]
if foundSeeder != *testLeecher {
t.Error("seeder not added to cache", foundSeeder, *testLeecher)
}
foundSeeder, _ = foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundSeeder == *testLeecher {
t.Error("leecher not removed from cache", testLeecher)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testLeecher)]
if foundSeeder != *testLeecher {
t.Error("seeder not added to local", testLeecher)
}
foundSeeder, _ = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundSeeder == *testLeecher {
t.Error("leecher not removed from local", testLeecher)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
// Add, update, verify remove
func TestUpdatePeer(t *testing.T) {
tx := createTestTx()
testTorrent := createTestTorrent()
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddTorrent(testTorrent))
panicOnErr(tx.AddSeeder(testTorrent, testSeeder))
// Update a seeder, set it, then check to make sure it updated
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(tx.SetSeeder(testTorrent, testSeeder))
panicOnErr(tx.RemoveSeeder(testTorrent, testSeeder))
foundTorrent, _, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if seeder, exists := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]; exists {
t.Error("seeder not removed from cache", seeder)
}
if seeder, exists := testTorrent.Seeders[storage.PeerMapKey(testSeeder)]; exists {
t.Error("seeder not removed from local", seeder)
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestParallelFindUser(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
tx := createTestTx()
testUserSuccess := createTestUser()
testUserFail := createTestUser()
panicOnErr(tx.AddUser(testUserSuccess))
for i := 0; i < 10; i++ {
foundUser, found, err := tx.FindUser(testUserFail.Passkey)
panicOnErr(err)
if found {
t.Error("user found", foundUser)
}
foundUser, found, err = tx.FindUser(testUserSuccess.Passkey)
panicOnErr(err)
if !found {
t.Error("user not found", testUserSuccess)
}
if *foundUser != *testUserSuccess {
t.Error("found user mismatch", *foundUser, testUserSuccess)
}
}
// Cleanup
panicOnErr(tx.RemoveUser(testUserSuccess))
}
func TestParallelFindTorrent(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
tx := createTestTx()
testTorrentSuccess := createTestTorrent()
testTorrentFail := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrentSuccess))
for i := 0; i < 10; i++ {
foundTorrent, found, err := tx.FindTorrent(testTorrentSuccess.Infohash)
panicOnErr(err)
if !found {
t.Error("torrent not found", testTorrentSuccess)
}
if !reflect.DeepEqual(foundTorrent, testTorrentSuccess) {
t.Error("found torrent mismatch", foundTorrent, testTorrentSuccess)
}
foundTorrent, found, err = tx.FindTorrent(testTorrentFail.Infohash)
panicOnErr(err)
if found {
t.Error("torrent found", foundTorrent)
}
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrentSuccess))
}
func TestParallelSetSeeder(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 10; i++ {
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(tx.SetSeeder(testTorrent, testSeeder))
foundTorrent, _, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in cache", foundSeeder, *testSeeder)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in local", foundSeeder, *testSeeder)
}
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}
func TestParallelAddLeecher(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
tx := createTestTx()
testTorrent := createTestTorrent()
panicOnErr(tx.AddTorrent(testTorrent))
for i := 0; i < 10; i++ {
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(tx.AddLeecher(testTorrent, testLeecher))
foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to cache", testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to local", testLeecher)
}
}
// Cleanup
panicOnErr(tx.RemoveTorrent(testTorrent))
}