From 19900991a780c53a4ad59bd27281d16ede616ce9 Mon Sep 17 00:00:00 2001 From: cpb8010 Date: Thu, 19 Sep 2013 00:27:10 -0400 Subject: [PATCH] Added parallel tests --- cache/redis/redis.go | 7 ++- cache/redis/redis_test.go | 109 ++++++++++++++++++++++++++++------- cache/redis/tx_test.go | 118 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 207 insertions(+), 27 deletions(-) diff --git a/cache/redis/redis.go b/cache/redis/redis.go index dd3d245..b178363 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -297,14 +297,17 @@ func (tx *Tx) getPeers(torrentID uint64, peerTypePrefix string) (peers map[strin setKey := tx.conf.Prefix + peerTypePrefix + strconv.FormatUint(torrentID, 36) peerStrings, err := redis.Strings(tx.Do("SMEMBERS", setKey)) if err != nil { - return peers, err + return nil, err } // Keys map to peer objects stored in hashes for _, peerHashKey := range peerStrings { hashKey := tx.conf.Prefix + peerHashKey peerVals, err := redis.Strings(tx.Do("HVALS", hashKey)) if err != nil { - return peers, err + return nil, err + } + if len(peerVals) == 0 { + continue } peer, err := createPeer(peerVals) if err != nil { diff --git a/cache/redis/redis_test.go b/cache/redis/redis_test.go index b78aac1..d670bb0 100644 --- a/cache/redis/redis_test.go +++ b/cache/redis/redis_test.go @@ -19,24 +19,43 @@ import ( ) var ( - testTorrentIDCounter uint64 - testUserIDCounter uint64 - testPeerIDCounter int + testTorrentIDChannel chan uint64 + testUserIDChannel chan uint64 + testPeerIDChannel chan int ) +func init() { + testTorrentIDChannel = make(chan uint64, 100) + testUserIDChannel = make(chan uint64, 100) + testPeerIDChannel = make(chan int, 100) + // Sync access to ID counter with buffered global channels + go func() { + for i := 0; ; i++ { + testTorrentIDChannel <- uint64(i) + } + }() + go func() { + for i := 0; ; i++ { + testUserIDChannel <- uint64(i) + } + }() + go func() { + for i := 0; ; i++ { + testPeerIDChannel <- i + } + }() +} + func createTestTorrentID() uint64 { - testTorrentIDCounter++ - return testTorrentIDCounter + return <-testTorrentIDChannel } func createTestUserID() uint64 { - testUserIDCounter++ - return testUserIDCounter + return <-testUserIDChannel } func createTestPeerID() string { - testPeerIDCounter++ - return "-testPeerID-" + strconv.Itoa(testPeerIDCounter) + return "-testPeerID-" + strconv.Itoa(<-testPeerIDChannel) } func createTestInfohash() string { @@ -57,14 +76,6 @@ func createTestPasskey() string { return string(uuid) } -// Common interface for benchmarks and test error reporting -type TestReporter interface { - Error(args ...interface{}) - Errorf(format string, args ...interface{}) - Log(args ...interface{}) - Logf(format string, args ...interface{}) -} - func panicErrNil(err error) { if err != nil { fmt.Println(err) @@ -72,7 +83,7 @@ func panicErrNil(err error) { } } -func createTestTxObj() *Tx { +func createTestRedisTx() *Tx { testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH")) conf := &testConfig.Cache panicErrNil(err) @@ -115,7 +126,7 @@ 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[models.PeerMapKey(tempPeer)] = *tempPeer } return testPeers } @@ -133,9 +144,43 @@ func createTestTorrent() *models.Torrent { return &testTorrent } -func TestPeersAlone(t *testing.T) { +func comparePeers(lhPeers map[string]models.Peer, rhPeers map[string]models.Peer) bool { + if len(lhPeers) != len(rhPeers) { + return false + } + for rhKey, rhValue := range rhPeers { + lhValue, lhExists := lhPeers[rhKey] + if !lhExists || lhValue != rhValue { + return false + } + } + for lhKey, lhValue := range lhPeers { + rhValue, rhExists := rhPeers[lhKey] + if !rhExists || rhValue != lhValue { + return false + } + } + return true +} - testTx := createTestTxObj() +func torrentsEqual(lhTorrent *models.Torrent, rhTorrent *models.Torrent) bool { + fieldsEqual := lhTorrent.Infohash == rhTorrent.Infohash && + lhTorrent.ID == rhTorrent.ID && + lhTorrent.Active == rhTorrent.Active && + lhTorrent.Snatches == rhTorrent.Snatches && + lhTorrent.UpMultiplier == rhTorrent.UpMultiplier && + lhTorrent.DownMultiplier == rhTorrent.DownMultiplier && + lhTorrent.LastAction == rhTorrent.LastAction + + if !fieldsEqual { + return false + } + + return comparePeers(lhTorrent.Seeders, rhTorrent.Seeders) && comparePeers(lhTorrent.Leechers, rhTorrent.Leechers) +} + +func TestValidPeers(t *testing.T) { + testTx := createTestRedisTx() testTorrentID := createTestTorrentID() testPeers := createTestPeers(testTorrentID, 3) @@ -147,3 +192,25 @@ func TestPeersAlone(t *testing.T) { } panicErrNil(testTx.removePeers(testTorrentID, testPeers, "test:")) } + +func TestInvalidPeers(t *testing.T) { + testTx := createTestRedisTx() + testTorrentID := createTestTorrentID() + testPeers := createTestPeers(testTorrentID, 3) + tempPeer := createTestPeer(createTestUserID(), testTorrentID) + testPeers[models.PeerMapKey(tempPeer)] = *tempPeer + + panicErrNil(testTx.addPeers(testPeers, "test:")) + // Imitate a peer being removed during get + hashKey := testTx.conf.Prefix + getPeerHashKey(tempPeer) + _, err := testTx.Do("DEL", hashKey) + panicErrNil(err) + + peerMap, err := testTx.getPeers(testTorrentID, "test:") + panicErrNil(err) + // Expect 1 less peer due to delete + if len(peerMap) != len(testPeers)-1 { + t.Error("Num Peers not equal ", len(peerMap), len(testPeers)) + } + panicErrNil(testTx.removePeers(testTorrentID, testPeers, "test:")) +} diff --git a/cache/redis/tx_test.go b/cache/redis/tx_test.go index 76ff5ac..f107f1e 100644 --- a/cache/redis/tx_test.go +++ b/cache/redis/tx_test.go @@ -69,18 +69,17 @@ func TestRemoveUser(t *testing.T) { } } -func TestFindTorrent(t *testing.T) { +func TestFindTorrentSuccess(t *testing.T) { tx := createTestTx() testTorrent := createTestTorrent() - panicErrNil(tx.AddTorrent(testTorrent)) + foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash) panicErrNil(err) if !found { t.Error("torrent not found", testTorrent) } - // Incomplete comparison as maps make struct not nativly comparable - if foundTorrent.Infohash != testTorrent.Infohash { + if !torrentsEqual(foundTorrent, testTorrent) { t.Error("found torrent mismatch", foundTorrent, testTorrent) } } @@ -409,3 +408,114 @@ func TestUpdatePeer(t *testing.T) { t.Error("seeder not removed from local", seeder) } } + +func TestParallelFindUser(t *testing.T) { + t.Parallel() + if testing.Short() { + t.Skip() + } + tx := createTestTx() + testUserSuccess := createTestUser() + testUserFail := createTestUser() + panicErrNil(tx.AddUser(testUserSuccess)) + + for i := 0; i < 10; i++ { + foundUser, found, err := tx.FindUser(testUserFail.Passkey) + panicErrNil(err) + if found { + t.Error("user found", foundUser) + } + foundUser, found, err = tx.FindUser(testUserSuccess.Passkey) + panicErrNil(err) + if !found { + t.Error("user not found", testUserSuccess) + } + if *foundUser != *testUserSuccess { + t.Error("found user mismatch", *foundUser, testUserSuccess) + } + } +} + +func TestParallelFindTorrent(t *testing.T) { + t.Parallel() + if testing.Short() { + t.Skip() + } + tx := createTestTx() + testTorrentSuccess := createTestTorrent() + testTorrentFail := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrentSuccess)) + + for i := 0; i < 10; i++ { + foundTorrent, found, err := tx.FindTorrent(testTorrentSuccess.Infohash) + panicErrNil(err) + if !found { + t.Error("torrent not found", testTorrentSuccess) + } + if !torrentsEqual(foundTorrent, testTorrentSuccess) { + t.Error("found torrent mismatch", foundTorrent, testTorrentSuccess) + } + foundTorrent, found, err = tx.FindTorrent(testTorrentFail.Infohash) + panicErrNil(err) + if found { + t.Error("torrent found", foundTorrent) + } + } +} + +func TestParallelSetSeeder(t *testing.T) { + t.Parallel() + if testing.Short() { + t.Skip() + } + tx := createTestTx() + testTorrent := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent)) + testSeeder := createTestPeer(createTestUserID(), testTorrent.ID) + panicErrNil(tx.AddSeeder(testTorrent, testSeeder)) + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + for i := 0; i < 10; i++ { + testSeeder.Uploaded += uint64(r.Int63()) + + panicErrNil(tx.SetSeeder(testTorrent, testSeeder)) + + foundTorrent, _, err := tx.FindTorrent(testTorrent.Infohash) + panicErrNil(err) + foundSeeder, _ := foundTorrent.Seeders[models.PeerMapKey(testSeeder)] + if foundSeeder != *testSeeder { + t.Error("seeder not updated in cache", foundSeeder, *testSeeder) + } + foundSeeder, _ = testTorrent.Seeders[models.PeerMapKey(testSeeder)] + if foundSeeder != *testSeeder { + t.Error("seeder not updated in local", foundSeeder, *testSeeder) + } + } +} + +func TestParallelAddLeecher(t *testing.T) { + t.Parallel() + if testing.Short() { + t.Skip() + } + tx := createTestTx() + testTorrent := createTestTorrent() + panicErrNil(tx.AddTorrent(testTorrent)) + + for i := 0; i < 10; i++ { + testLeecher := createTestPeer(createTestUserID(), testTorrent.ID) + + panicErrNil(tx.AddLeecher(testTorrent, testLeecher)) + + foundTorrent, found, err := tx.FindTorrent(testTorrent.Infohash) + panicErrNil(err) + foundLeecher, found := foundTorrent.Leechers[models.PeerMapKey(testLeecher)] + if found && foundLeecher != *testLeecher { + t.Error("leecher not added to cache", testLeecher) + } + foundLeecher, found = testTorrent.Leechers[models.PeerMapKey(testLeecher)] + if found && foundLeecher != *testLeecher { + t.Error("leecher not added to local", testLeecher) + } + } +}