From 3caa06b5f6bb3e2c780763c9e8d60b5792f14916 Mon Sep 17 00:00:00 2001 From: cpb8010 Date: Tue, 10 Sep 2013 01:02:40 -0400 Subject: [PATCH] Updated tests, added LeecherFinished to cache.Tx --- cache/cache.go | 3 + cache/redis/redis.go | 77 +++++++-- cache/redis/redis_test.go | 51 +----- cache/redis/tx_test.go | 344 +++++++++++++++++++++++++++----------- server/announce.go | 12 +- 5 files changed, 313 insertions(+), 174 deletions(-) diff --git a/cache/cache.go b/cache/cache.go index 702ea49..bcd2a4d 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -73,6 +73,9 @@ type Tx interface { SetSeeder(t *models.Torrent, p *models.Peer) error IncrementSlots(u *models.User) error DecrementSlots(u *models.User) error + LeecherFinished(t *models.Torrent, p *models.Peer) error + + // Priming / Testing AddTorrent(t *models.Torrent) error RemoveTorrent(t *models.Torrent) error AddUser(u *models.User) error diff --git a/cache/redis/redis.go b/cache/redis/redis.go index 3de4ee5..90e3800 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -136,6 +136,7 @@ func createUser(userVals []string) (*models.User, error) { return &models.User{ID, Passkey, UpMultiplier, DownMultiplier, Slots, SlotsUsed, uint(Snatches)}, nil } +// This is a mulple action command, it's not internally atomic func (tx *Tx) createTorrent(torrentVals []string) (*models.Torrent, error) { if len(torrentVals) != 7 { return nil, ErrCreateTorrent @@ -177,9 +178,9 @@ func (tx *Tx) createTorrent(torrentVals []string) (*models.Torrent, error) { return &models.Torrent{ID, Infohash, Active, seeders, leechers, uint(Snatches), UpMultiplier, DownMultiplier, LastAction}, nil } -// hashkey relies on combination of peerID, userID, and torrentID being unique -func (tx *Tx) setPeer(peer *models.Peer, peerTypePrefix string) error { - hashKey := tx.conf.Prefix + peerTypePrefix + getPeerHashKey(peer) +// The peer hashkey relies on the combination of peerID, userID, and torrentID being unique +func (tx *Tx) setPeer(peer *models.Peer) error { + hashKey := tx.conf.Prefix + getPeerHashKey(peer) _, err := tx.Do("HMSET", hashKey, "id", peer.ID, "user_id", peer.UserID, @@ -199,17 +200,20 @@ func (tx *Tx) setPeer(peer *models.Peer, peerTypePrefix string) error { // Will not return an error if the peer doesn't exist func (tx *Tx) removePeer(peer *models.Peer, peerTypePrefix string) error { - setKey := tx.conf.Prefix + peerTypePrefix + strconv.FormatUint(peer.TorrentID, 36) - _, err := tx.Do("SREM", setKey, *peer) + setKey := tx.conf.Prefix + getPeerSetKey(peerTypePrefix, peer) + _, err := tx.Do("SREM", setKey, getPeerHashKey(peer)) if err != nil { return err } + hashKey := tx.conf.Prefix + getPeerHashKey(peer) + _, err = tx.Do("DEL", hashKey) return nil } +// This is a mulple action command, it's not internally atomic func (tx *Tx) removePeers(torrentID uint64, peers map[string]models.Peer, peerTypePrefix string) error { for _, peer := range peers { - hashKey := tx.conf.Prefix + peerTypePrefix + getPeerHashKey(&peer) + hashKey := tx.conf.Prefix + getPeerHashKey(&peer) _, err := tx.Do("DEL", hashKey) if err != nil { return err @@ -230,14 +234,19 @@ func getPeerHashKey(peer *models.Peer) string { return peer.ID + ":" + strconv.FormatUint(peer.UserID, 36) + ":" + strconv.FormatUint(peer.TorrentID, 36) } +func getPeerSetKey(prefix string, peer *models.Peer) string { + return prefix + strconv.FormatUint(peer.TorrentID, 36) +} + +// This is a mulple action command, it's not internally atomic func (tx *Tx) addPeers(peers map[string]models.Peer, peerTypePrefix string) error { for _, peer := range peers { - setKey := tx.conf.Prefix + peerTypePrefix + strconv.FormatUint(peer.TorrentID, 36) + setKey := tx.conf.Prefix + getPeerSetKey(peerTypePrefix, &peer) _, err := tx.Do("SADD", setKey, getPeerHashKey(&peer)) if err != nil { return err } - tx.setPeer(&peer, peerTypePrefix) + tx.setPeer(&peer) } return nil } @@ -281,6 +290,7 @@ func createPeer(peerVals []string) (*models.Peer, error) { } +// This is a mulple action command, it's not internally atomic func (tx *Tx) getPeers(torrentID uint64, peerTypePrefix string) (peers map[string]models.Peer, err error) { peers = make(map[string]models.Peer) setKey := tx.conf.Prefix + peerTypePrefix + strconv.FormatUint(torrentID, 36) @@ -290,7 +300,7 @@ func (tx *Tx) getPeers(torrentID uint64, peerTypePrefix string) (peers map[strin } // Keys map to peer objects stored in hashes for _, peerHashKey := range peerStrings { - hashKey := tx.conf.Prefix + peerTypePrefix + peerHashKey + hashKey := tx.conf.Prefix + peerHashKey peerVals, err := redis.Strings(tx.Do("HVALS", hashKey)) if err != nil { return peers, err @@ -304,6 +314,7 @@ func (tx *Tx) getPeers(torrentID uint64, peerTypePrefix string) (peers map[strin return } +// This is a mulple action command, it's not internally atomic func (tx *Tx) AddTorrent(t *models.Torrent) error { hashkey := tx.conf.Prefix + TorrentPrefix + t.Infohash _, err := tx.Do("HMSET", hashkey, @@ -318,12 +329,18 @@ func (tx *Tx) AddTorrent(t *models.Torrent) error { return err } - tx.addPeers(t.Seeders, SeederPrefix) - tx.addPeers(t.Leechers, LeecherPrefix) - + err = tx.addPeers(t.Seeders, SeederPrefix) + if err != nil { + return err + } + err = tx.addPeers(t.Leechers, LeecherPrefix) + if err != nil { + return err + } return nil } +// This is a mulple action command, it's not internally atomic func (tx *Tx) RemoveTorrent(t *models.Torrent) error { hashkey := tx.conf.Prefix + TorrentPrefix + t.Infohash _, err := tx.Do("DEL", hashkey) @@ -449,13 +466,14 @@ func (tx *Tx) MarkActive(torrent *models.Torrent) error { return nil } +// This is a mulple action command, it's not internally atomic func (tx *Tx) AddLeecher(torrent *models.Torrent, peer *models.Peer) error { setKey := tx.conf.Prefix + LeecherPrefix + strconv.FormatUint(torrent.ID, 36) _, err := tx.Do("SADD", setKey, getPeerHashKey(peer)) if err != nil { return err } - err = tx.setPeer(peer, LeecherPrefix) + err = tx.setPeer(peer) if err != nil { return err } @@ -469,7 +487,12 @@ func (tx *Tx) AddLeecher(torrent *models.Torrent, peer *models.Peer) error { // Setting assumes it is already a leecher, and just needs to be updated // Maybe eventually there will be a move from leecher to seeder method func (tx *Tx) SetLeecher(t *models.Torrent, p *models.Peer) error { - return tx.setPeer(p, LeecherPrefix) + err := tx.setPeer(p) + if err != nil { + return err + } + t.Leechers[p.ID] = *p + return nil } func (tx *Tx) RemoveLeecher(t *models.Torrent, p *models.Peer) error { @@ -481,13 +504,30 @@ func (tx *Tx) RemoveLeecher(t *models.Torrent, p *models.Peer) error { return nil } +func (tx *Tx) LeecherFinished(torrent *models.Torrent, peer *models.Peer) error { + torrentIdKey := strconv.FormatUint(torrent.ID, 36) + seederSetKey := tx.conf.Prefix + SeederPrefix + torrentIdKey + leecherSetKey := tx.conf.Prefix + LeecherPrefix + torrentIdKey + + _, err := tx.Do("SMOVE", leecherSetKey, seederSetKey, getPeerHashKey(peer)) + if err != nil { + return err + } + torrent.Seeders[peer.ID] = *peer + delete(torrent.Leechers, peer.ID) + + err = tx.setPeer(peer) + return err +} + +// This is a mulple action command, it's not internally atomic func (tx *Tx) AddSeeder(torrent *models.Torrent, peer *models.Peer) error { setKey := tx.conf.Prefix + SeederPrefix + strconv.FormatUint(torrent.ID, 36) _, err := tx.Do("SADD", setKey, getPeerHashKey(peer)) if err != nil { return err } - err = tx.setPeer(peer, SeederPrefix) + err = tx.setPeer(peer) if err != nil { return err } @@ -499,7 +539,12 @@ func (tx *Tx) AddSeeder(torrent *models.Torrent, peer *models.Peer) error { } func (tx *Tx) SetSeeder(t *models.Torrent, p *models.Peer) error { - return tx.setPeer(p, SeederPrefix) + err := tx.setPeer(p) + if err != nil { + return err + } + t.Seeders[p.ID] = *p + return nil } func (tx *Tx) RemoveSeeder(t *models.Torrent, p *models.Peer) error { diff --git a/cache/redis/redis_test.go b/cache/redis/redis_test.go index 144a7f3..777cfa8 100644 --- a/cache/redis/redis_test.go +++ b/cache/redis/redis_test.go @@ -104,21 +104,21 @@ func createTestUser() models.User { return testUser } -func createTestPeer(userID uint64, torrentID uint64) models.Peer { +func createTestPeer(userID uint64, torrentID uint64) *models.Peer { - return models.Peer{createTestPeerID(), userID, torrentID, "127.0.0.1", 6889, 1024, 3000, 4200, 11} + return &models.Peer{createTestPeerID(), userID, torrentID, "127.0.0.1", 6889, 1024, 3000, 4200, 11} } func createTestPeers(torrentID uint64, num int) map[string]models.Peer { testPeers := make(map[string]models.Peer) for i := 0; i < num; i++ { tempPeer := createTestPeer(createTestUserID(), torrentID) - testPeers[tempPeer.ID] = tempPeer + testPeers[tempPeer.ID] = *tempPeer } return testPeers } -func createTestTorrent() models.Torrent { +func createTestTorrent() *models.Torrent { torrentInfohash := createTestInfohash() torrentID := createTestTorrentID() @@ -127,34 +127,7 @@ func createTestTorrent() models.Torrent { testLeechers := createTestPeers(torrentID, 2) testTorrent := models.Torrent{torrentID, torrentInfohash, true, testSeeders, testLeechers, 11, 0.0, 0.0, 0} - return testTorrent -} - -func TestFindUserSuccess(t *testing.T) { - testUser := createTestUser() - testTx := createTestTxObj(t) - hashkey := testTx.conf.Prefix + UserPrefix + testUser.Passkey - _, err := testTx.Do("DEL", hashkey) - verifyErrNil(err, t) - - err = testTx.AddUser(&testUser) - verifyErrNil(err, t) - - compareUser, exists := ExampleRedisTypesSchemaFindUser(testUser.Passkey, t) - - if !exists { - t.Error("User not found!") - } - if testUser != *compareUser { - t.Errorf("user mismatch: %v vs. %v", compareUser, testUser) - } -} - -func TestFindUserFail(t *testing.T) { - compareUser, exists := ExampleRedisTypesSchemaFindUser("not_a_user_passkey", t) - if exists { - t.Errorf("User %v found when none should exist!", compareUser) - } + return &testTorrent } func TestAddGetPeers(t *testing.T) { @@ -174,20 +147,6 @@ func TestAddGetPeers(t *testing.T) { } } -// Legacy tests -func TestReadAfterWrite(t *testing.T) { - // Test requires panic - defer func() { - if err := recover(); err == nil { - t.Error("Read after write did not panic") - } - }() - - testTx := createTestTxObj(t) - verifyErrNil(testTx.initiateWrite(), t) - verifyErrNil(testTx.initiateRead(), t) -} - func TestCloseClosedTransaction(t *testing.T) { //require panic defer func() { diff --git a/cache/redis/tx_test.go b/cache/redis/tx_test.go index a82b771..f5d50c9 100644 --- a/cache/redis/tx_test.go +++ b/cache/redis/tx_test.go @@ -36,155 +36,295 @@ func createTestTx() cache.Tx { return txObj } -func TestUser(t *testing.T) { +func TestFindUserSuccess(t *testing.T) { tx := createTestTx() testUser1 := createTestUser() - testUser2 := createTestUser() panicErrNil(tx.AddUser(&testUser1)) foundUser, found, err := tx.FindUser(testUser1.Passkey) panicErrNil(err) if !found { - t.Error("user not found") + t.Error("user not found", testUser1) } if *foundUser != testUser1 { - t.Error("found user mismatch") - } - - foundUser, found, err = tx.FindUser(testUser2.Passkey) - panicErrNil(err) - if found { - t.Error("user found") - } - - err = tx.RemoveUser(&testUser1) - panicErrNil(err) - foundUser, found, err = tx.FindUser(testUser1.Passkey) - panicErrNil(err) - if found { - t.Error("removed user found") + t.Error("found user mismatch", *foundUser, testUser1) } } -func TestTorrent(t *testing.T) { +func TestFindUserFail(t *testing.T) { + tx := createTestTx() + testUser2 := createTestUser() + + foundUser, found, err := tx.FindUser(testUser2.Passkey) + panicErrNil(err) + if found { + t.Error("user found", foundUser) + } +} + +func TestRemoveUser(t *testing.T) { + tx := createTestTx() + testUser1 := createTestUser() + + panicErrNil(tx.AddUser(&testUser1)) + err := tx.RemoveUser(&testUser1) + panicErrNil(err) + foundUser, found, err := tx.FindUser(testUser1.Passkey) + panicErrNil(err) + if found { + t.Error("removed user found", foundUser) + } +} + +func TestFindTorrent(t *testing.T) { tx := createTestTx() testTorrent1 := createTestTorrent() - testTorrent2 := createTestTorrent() - panicErrNil(tx.AddTorrent(&testTorrent1)) + panicErrNil(tx.AddTorrent(testTorrent1)) foundTorrent, found, err := tx.FindTorrent(testTorrent1.Infohash) panicErrNil(err) if !found { - t.Error("torrent not found") + t.Error("torrent not found", testTorrent1) } - // Incomplete comparison as maps cannot be compared + // Incomplete comparison as maps make struct not nativly comparable if foundTorrent.Infohash != testTorrent1.Infohash { - t.Error("found torrent mismatch") - } - foundTorrent, found, err = tx.FindTorrent(testTorrent2.Infohash) - panicErrNil(err) - if found { - t.Error("torrent found") - } - - panicErrNil(tx.RemoveTorrent(&testTorrent1)) - foundTorrent, found, err = tx.FindTorrent(testTorrent1.Infohash) - panicErrNil(err) - if found { - t.Error("removed torrent found") + t.Error("found torrent mismatch", foundTorrent, testTorrent1) } } -func TestClient(t *testing.T) { + +func TestFindTorrentFail(t *testing.T) { + tx := createTestTx() + testTorrent2 := createTestTorrent() + + foundTorrent, found, err := tx.FindTorrent(testTorrent2.Infohash) + panicErrNil(err) + if found { + t.Error("torrent found", foundTorrent) + } +} + +func TestRemoveTorrent(t *testing.T) { + tx := createTestTx() + testTorrent1 := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent1)) + + panicErrNil(tx.RemoveTorrent(testTorrent1)) + foundTorrent, found, err := tx.FindTorrent(testTorrent1.Infohash) + panicErrNil(err) + if found { + t.Error("removed torrent found", foundTorrent) + } +} + +func TestClientWhitelistSuccess(t *testing.T) { tx := createTestTx() testPeerID1 := "-lt0D30-" - testPeerID2 := "TIX0192" panicErrNil(tx.WhitelistClient(testPeerID1)) found, err := tx.ClientWhitelisted(testPeerID1) panicErrNil(err) if !found { - t.Error("peerID not found") - } - - found, err = tx.ClientWhitelisted(testPeerID2) - panicErrNil(err) - if found { - t.Error("peerID found") - } - - panicErrNil(tx.UnWhitelistClient(testPeerID1)) - found, err = tx.ClientWhitelisted(testPeerID1) - panicErrNil(err) - if found { - t.Error("removed peerID found") + t.Error("peerID not found", testPeerID1) } } -func TestPeers(t *testing.T) { +func TestClientWhitelistFail(t *testing.T) { tx := createTestTx() + testPeerID2 := "TIX0192" - // Randomly generated strings would be safter to test with + found, err := tx.ClientWhitelisted(testPeerID2) + panicErrNil(err) + if found { + t.Error("peerID found", testPeerID2) + } + +} + +func TestClientWhitelistRemove(t *testing.T) { + tx := createTestTx() + testPeerID1 := "-lt0D30-" + panicErrNil(tx.WhitelistClient(testPeerID1)) + panicErrNil(tx.UnWhitelistClient(testPeerID1)) + + found, err := tx.ClientWhitelisted(testPeerID1) + panicErrNil(err) + if found { + t.Error("removed peerID found", testPeerID1) + } +} + +func TestAddSeeder(t *testing.T) { + tx := createTestTx() testTorrent1 := createTestTorrent() - testTorrent2 := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent1)) + testSeeder1 := createTestPeer(createTestUserID(), testTorrent1.ID) + + panicErrNil(tx.AddSeeder(testTorrent1, testSeeder1)) foundTorrent, found, err := tx.FindTorrent(testTorrent1.Infohash) panicErrNil(err) - if found { - testTorrent1 = *foundTorrent - } else { - panicErrNil(tx.AddTorrent(&testTorrent1)) + foundSeeder, found := foundTorrent.Seeders[testSeeder1.ID] + if found && foundSeeder != *testSeeder1 { + t.Error("seeder not added to cache", testSeeder1) } - foundTorrent, found, err = tx.FindTorrent(testTorrent2.Infohash) - panicErrNil(err) - if found { - testTorrent2 = *foundTorrent - } else { - panicErrNil(tx.AddTorrent(&testTorrent2)) + foundSeeder, found = testTorrent1.Seeders[testSeeder1.ID] + if found && foundSeeder != *testSeeder1 { + t.Error("seeder not added to local", testSeeder1) } +} +func TestAddLeecher(t *testing.T) { + tx := createTestTx() + testTorrent1 := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent1)) + testLeecher1 := createTestPeer(createTestUserID(), testTorrent1.ID) + + tx.AddLeecher(testTorrent1, testLeecher1) + foundTorrent, found, err := tx.FindTorrent(testTorrent1.Infohash) + panicErrNil(err) + foundLeecher, found := foundTorrent.Leechers[testLeecher1.ID] + if found && foundLeecher != *testLeecher1 { + t.Error("leecher not added to cache", testLeecher1) + } + foundLeecher, found = testTorrent1.Leechers[testLeecher1.ID] + if found && foundLeecher != *testLeecher1 { + t.Error("leecher not added to local", testLeecher1) + } +} + +func TestRemoveSeeder(t *testing.T) { + tx := createTestTx() + testTorrent1 := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent1)) testSeeder1 := createTestPeer(createTestUserID(), testTorrent1.ID) - testSeeder2 := createTestPeer(createTestUserID(), testTorrent2.ID) - if testSeeder1 == testSeeder2 { - t.Error("seeders should not be equal") + tx.AddSeeder(testTorrent1, testSeeder1) + + panicErrNil(tx.RemoveSeeder(testTorrent1, testSeeder1)) + foundSeeder, found := testTorrent1.Seeders[testSeeder1.ID] + if found || foundSeeder == *testSeeder1 { + t.Error("seeder not removed from local", foundSeeder) } - if _, exists := testTorrent1.Seeders[testSeeder1.ID]; exists { - t.Log("seeder aleady exists, removing") - err := tx.RemoveSeeder(&testTorrent1, &testSeeder1) - if err != nil { - t.Error(err) - } - if _, exists := testTorrent1.Seeders[testSeeder1.ID]; exists { - t.Error("Remove seeder failed") - } - } - - panicErrNil(tx.AddSeeder(&testTorrent1, &testSeeder1)) - if seeder1, exists := testTorrent1.Seeders[testSeeder1.ID]; !exists { - t.Error("seeder not added locally") - } else if seeder1 != testSeeder1 { - t.Error("seeder changed") - } - foundTorrent, found, err = tx.FindTorrent(testTorrent1.Infohash) + foundTorrent, found, err := tx.FindTorrent(testTorrent1.Infohash) panicErrNil(err) - if !found { - t.Error("torrent should exist") - } - if seeder1, exists := foundTorrent.Seeders[testSeeder1.ID]; !exists { - t.Error("seeder not added") - } else if seeder1 != testSeeder1 { - t.Error("seeder changed") + foundSeeder, found = foundTorrent.Seeders[testSeeder1.ID] + if found || foundSeeder == *testSeeder1 { + t.Error("seeder not removed from cache", foundSeeder) } +} +func TestRemoveLeecher(t *testing.T) { + tx := createTestTx() + testTorrent1 := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent1)) + testLeecher1 := createTestPeer(createTestUserID(), testTorrent1.ID) + tx.AddLeecher(testTorrent1, testLeecher1) + + tx.RemoveLeecher(testTorrent1, testLeecher1) + foundTorrent, found, err := tx.FindTorrent(testTorrent1.Infohash) + panicErrNil(err) + foundLeecher, found := foundTorrent.Leechers[testLeecher1.ID] + if found || foundLeecher == *testLeecher1 { + t.Error("leecher not removed from cache", foundLeecher) + } + foundLeecher, found = testTorrent1.Leechers[testLeecher1.ID] + if found || foundLeecher == *testLeecher1 { + t.Error("leecher not removed from local", foundLeecher) + } +} + +func TestSetSeeder(t *testing.T) { + tx := createTestTx() + testTorrent1 := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent1)) + testSeeder1 := createTestPeer(createTestUserID(), testTorrent1.ID) + tx.AddSeeder(testTorrent1, testSeeder1) + + testSeeder1.Uploaded += 100 + + tx.SetSeeder(testTorrent1, testSeeder1) + foundTorrent, _, err := tx.FindTorrent(testTorrent1.Infohash) + panicErrNil(err) + foundSeeder, _ := foundTorrent.Seeders[testSeeder1.ID] + if foundSeeder != *testSeeder1 { + t.Error("seeder not updated in cache", testSeeder1) + } + foundSeeder, _ = testTorrent1.Seeders[testSeeder1.ID] + if foundSeeder != *testSeeder1 { + t.Error("seeder not updated in local", testSeeder1) + } +} + +func TestSetLeecher(t *testing.T) { + tx := createTestTx() + testTorrent1 := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent1)) + testLeecher1 := createTestPeer(createTestUserID(), testTorrent1.ID) + tx.AddLeecher(testTorrent1, testLeecher1) + + testLeecher1.Uploaded += 100 + + tx.SetLeecher(testTorrent1, testLeecher1) + foundTorrent, _, err := tx.FindTorrent(testTorrent1.Infohash) + panicErrNil(err) + foundLeecher, _ := foundTorrent.Leechers[testLeecher1.ID] + if foundLeecher != *testLeecher1 { + t.Error("leecher not updated in cache", testLeecher1) + } + foundLeecher, _ = testTorrent1.Leechers[testLeecher1.ID] + if foundLeecher != *testLeecher1 { + t.Error("leecher not updated in local", testLeecher1) + } +} + +func TestLeecherFinished(t *testing.T) { + tx := createTestTx() + testTorrent1 := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent1)) + testLeecher1 := createTestPeer(createTestUserID(), testTorrent1.ID) + tx.AddLeecher(testTorrent1, testLeecher1) + testLeecher1.Left = 0 + + tx.LeecherFinished(testTorrent1, testLeecher1) + foundTorrent, _, err := tx.FindTorrent(testTorrent1.Infohash) + panicErrNil(err) + foundSeeder, _ := foundTorrent.Seeders[testLeecher1.ID] + if foundSeeder != *testLeecher1 { + t.Error("seeder not added to cache", testLeecher1, foundSeeder) + } + foundSeeder, _ = foundTorrent.Leechers[testLeecher1.ID] + if foundSeeder == *testLeecher1 { + t.Error("leecher not removed from cache", testLeecher1) + } + foundSeeder, _ = testTorrent1.Seeders[testLeecher1.ID] + if foundSeeder != *testLeecher1 { + t.Error("seeder not added to local", testLeecher1) + } + foundSeeder, _ = testTorrent1.Leechers[testLeecher1.ID] + if foundSeeder == *testLeecher1 { + t.Error("leecher not removed from local", testLeecher1) + } +} + +// Add, update, verify remove +func TestUpdatePeer(t *testing.T) { + tx := createTestTx() + testTorrent1 := createTestTorrent() + testSeeder1 := createTestPeer(createTestUserID(), testTorrent1.ID) + panicErrNil(tx.AddTorrent(testTorrent1)) + panicErrNil(tx.AddSeeder(testTorrent1, testSeeder1)) // Update a seeder, set it, then check to make sure it updated r := rand.New(rand.NewSource(time.Now().UnixNano())) - testSeeder1.Downloaded += uint64(r.Int63()) - panicErrNil(tx.SetSeeder(&testTorrent1, &testSeeder1)) - foundTorrent, found, err = tx.FindTorrent(testTorrent1.Infohash) - panicErrNil(err) - if seeder1, exists := foundTorrent.Seeders[testSeeder1.ID]; !exists { - t.Error("seeder not added") - } else if seeder1 != testSeeder1 { - t.Errorf("seeder changed from %v to %v", testSeeder1, seeder1) - } + testSeeder1.Uploaded += uint64(r.Int63()) + panicErrNil(tx.SetSeeder(testTorrent1, testSeeder1)) + + panicErrNil(tx.RemoveSeeder(testTorrent1, testSeeder1)) + foundTorrent, _, err := tx.FindTorrent(testTorrent1.Infohash) + panicErrNil(err) + if seeder1, exists := foundTorrent.Seeders[testSeeder1.ID]; exists { + t.Error("seeder not removed from cache", seeder1) + } + if seeder1, exists := testTorrent1.Seeders[testSeeder1.ID]; exists { + t.Error("seeder not removed from local", seeder1) + } } diff --git a/server/announce.go b/server/announce.go index 150ca19..3a37e81 100644 --- a/server/announce.go +++ b/server/announce.go @@ -170,11 +170,7 @@ func (s Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { log.Panicf("server: %s", err) } if leecher { - err := tx.RemoveLeecher(torrent, peer) - if err != nil { - log.Panicf("server: %s", err) - } - err = tx.AddSeeder(torrent, peer) + err := tx.LeecherFinished(torrent, peer) if err != nil { log.Panicf("server: %s", err) } @@ -182,11 +178,7 @@ func (s Server) serveAnnounce(w http.ResponseWriter, r *http.Request) { case leecher && left == 0: // A leecher completed but the event was never received - err := tx.RemoveLeecher(torrent, peer) - if err != nil { - log.Panicf("server: %s", err) - } - err = tx.AddSeeder(torrent, peer) + err := tx.LeecherFinished(torrent, peer) if err != nil { log.Panicf("server: %s", err) }