diff --git a/src/BirdsiteLive.Pipeline/Contracts/IRetrieveTwitterAccountsProcessor.cs b/src/BirdsiteLive.Pipeline/Contracts/IRetrieveTwitterUsersProcessor.cs similarity index 100% rename from src/BirdsiteLive.Pipeline/Contracts/IRetrieveTwitterAccountsProcessor.cs rename to src/BirdsiteLive.Pipeline/Contracts/IRetrieveTwitterUsersProcessor.cs diff --git a/src/BirdsiteLive.Pipeline/Processors/RetrieveTweetsProcessor.cs b/src/BirdsiteLive.Pipeline/Processors/RetrieveTweetsProcessor.cs index dc556ba..68ca0b0 100644 --- a/src/BirdsiteLive.Pipeline/Processors/RetrieveTweetsProcessor.cs +++ b/src/BirdsiteLive.Pipeline/Processors/RetrieveTweetsProcessor.cs @@ -44,7 +44,7 @@ namespace BirdsiteLive.Pipeline.Processors } else if (tweets.Length > 0 && user.LastTweetPostedId == -1) { - var tweetId = tweets.First().Id; + var tweetId = tweets.Last().Id; await _twitterUserDal.UpdateTwitterUserAsync(user.Id, tweetId, tweetId); } } diff --git a/src/BirdsiteLive.Pipeline/Processors/RetrieveTwitterAccountsProcessor.cs b/src/BirdsiteLive.Pipeline/Processors/RetrieveTwitterUsersProcessor.cs similarity index 100% rename from src/BirdsiteLive.Pipeline/Processors/RetrieveTwitterAccountsProcessor.cs rename to src/BirdsiteLive.Pipeline/Processors/RetrieveTwitterUsersProcessor.cs diff --git a/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/RetrieveTweetsProcessorTests.cs b/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/RetrieveTweetsProcessorTests.cs new file mode 100644 index 0000000..ce29997 --- /dev/null +++ b/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/RetrieveTweetsProcessorTests.cs @@ -0,0 +1,193 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using BirdsiteLive.DAL.Contracts; +using BirdsiteLive.DAL.Models; +using BirdsiteLive.Pipeline.Processors; +using BirdsiteLive.Twitter; +using BirdsiteLive.Twitter.Models; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace BirdsiteLive.Pipeline.Tests.Processors +{ + [TestClass] + public class RetrieveTweetsProcessorTests + { + [TestMethod] + public async Task ProcessAsync_UserNotSync_Test() + { + #region Stubs + var user1 = new SyncTwitterUser + { + Id = 1, + Acct = "acct", + LastTweetPostedId = -1 + }; + + var users = new[] + { + user1 + }; + + var tweets = new[] + { + new ExtractedTweet + { + Id = 47 + } + }; + #endregion + + #region Mocks + var twitterServiceMock = new Mock(MockBehavior.Strict); + twitterServiceMock + .Setup(x => x.GetTimeline( + It.Is(y => y == user1.Acct), + It.Is(y => y == 1), + It.Is(y => y == -1) + )) + .Returns(tweets); + + var twitterUserDalMock = new Mock(MockBehavior.Strict); + twitterUserDalMock + .Setup(x => x.UpdateTwitterUserAsync( + It.Is(y => y == user1.Id), + It.Is(y => y == tweets.Last().Id), + It.Is(y => y == tweets.Last().Id) + )) + .Returns(Task.CompletedTask); + #endregion + + var processor = new RetrieveTweetsProcessor(twitterServiceMock.Object, twitterUserDalMock.Object); + var usersResult = await processor.ProcessAsync(users, CancellationToken.None); + + #region Validations + twitterServiceMock.VerifyAll(); + twitterUserDalMock.VerifyAll(); + + Assert.AreEqual(0, usersResult.Length); + #endregion + } + + [TestMethod] + public async Task ProcessAsync_UserSync_Test() + { + #region Stubs + var user1 = new SyncTwitterUser + { + Id = 1, + Acct = "acct", + LastTweetPostedId = 46, + LastTweetSynchronizedForAllFollowersId = 46 + }; + + var users = new[] + { + user1 + }; + + var tweets = new[] + { + new ExtractedTweet + { + Id = 47 + }, + new ExtractedTweet + { + Id = 48 + }, + new ExtractedTweet + { + Id = 49 + } + }; + #endregion + + #region Mocks + var twitterServiceMock = new Mock(MockBehavior.Strict); + twitterServiceMock + .Setup(x => x.GetTimeline( + It.Is(y => y == user1.Acct), + It.Is(y => y == 200), + It.Is(y => y == user1.LastTweetSynchronizedForAllFollowersId) + )) + .Returns(tweets); + + var twitterUserDalMock = new Mock(MockBehavior.Strict); + #endregion + + var processor = new RetrieveTweetsProcessor(twitterServiceMock.Object, twitterUserDalMock.Object); + var usersResult = await processor.ProcessAsync(users, CancellationToken.None); + + #region Validations + twitterServiceMock.VerifyAll(); + twitterUserDalMock.VerifyAll(); + + Assert.AreEqual(users.Length, usersResult.Length); + Assert.AreEqual(users[0].Acct, usersResult[0].User.Acct); + Assert.AreEqual(tweets.Length, usersResult[0].Tweets.Length); + #endregion + } + + [TestMethod] + public async Task ProcessAsync_UserPartiallySync_Test() + { + #region Stubs + var user1 = new SyncTwitterUser + { + Id = 1, + Acct = "acct", + LastTweetPostedId = 49, + LastTweetSynchronizedForAllFollowersId = 46 + }; + + var users = new[] + { + user1 + }; + + var tweets = new[] + { + new ExtractedTweet + { + Id = 47 + }, + new ExtractedTweet + { + Id = 48 + }, + new ExtractedTweet + { + Id = 49 + } + }; + #endregion + + #region Mocks + var twitterServiceMock = new Mock(MockBehavior.Strict); + twitterServiceMock + .Setup(x => x.GetTimeline( + It.Is(y => y == user1.Acct), + It.Is(y => y == 200), + It.Is(y => y == user1.LastTweetSynchronizedForAllFollowersId) + )) + .Returns(tweets); + + var twitterUserDalMock = new Mock(MockBehavior.Strict); + #endregion + + var processor = new RetrieveTweetsProcessor(twitterServiceMock.Object, twitterUserDalMock.Object); + var usersResult = await processor.ProcessAsync(users, CancellationToken.None); + + #region Validations + twitterServiceMock.VerifyAll(); + twitterUserDalMock.VerifyAll(); + + Assert.AreEqual(users.Length, usersResult.Length); + Assert.AreEqual(users[0].Acct, usersResult[0].User.Acct); + Assert.AreEqual(tweets.Length, usersResult[0].Tweets.Length); + #endregion + } + } +} \ No newline at end of file diff --git a/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/RetrieveTwitterUsersProcessorTests.cs b/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/RetrieveTwitterUsersProcessorTests.cs new file mode 100644 index 0000000..d3f8b08 --- /dev/null +++ b/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/RetrieveTwitterUsersProcessorTests.cs @@ -0,0 +1,93 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using BirdsiteLive.DAL.Contracts; +using BirdsiteLive.DAL.Models; +using BirdsiteLive.Pipeline.Processors; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace BirdsiteLive.Pipeline.Tests.Processors +{ + [TestClass] + public class RetrieveTwitterUsersProcessorTests + { + [TestMethod] + public async Task GetTwitterUsersAsync_Test() + { + #region Stubs + var buffer = new BufferBlock(); + var users = new[] + { + new SyncTwitterUser(), + new SyncTwitterUser(), + new SyncTwitterUser(), + }; + #endregion + + #region Mocks + var twitterUserDalMock = new Mock(MockBehavior.Strict); + twitterUserDalMock + .Setup(x => x.GetAllTwitterUsersAsync()) + .ReturnsAsync(users); + #endregion + + var processor = new RetrieveTwitterUsersProcessor(twitterUserDalMock.Object); + processor.GetTwitterUsersAsync(buffer, CancellationToken.None); + + await Task.Delay(50); + + #region Validations + twitterUserDalMock.VerifyAll(); + Assert.AreEqual(1, buffer.Count); + buffer.TryReceive(out var result); + Assert.AreEqual(3, result.Length); + #endregion + } + + [TestMethod] + public async Task GetTwitterUsersAsync_Exception_Test() + { + #region Stubs + var buffer = new BufferBlock(); + #endregion + + #region Mocks + var twitterUserDalMock = new Mock(MockBehavior.Strict); + twitterUserDalMock + .Setup(x => x.GetAllTwitterUsersAsync()) + .Throws(new Exception()); + #endregion + + var processor = new RetrieveTwitterUsersProcessor(twitterUserDalMock.Object); + var t = processor.GetTwitterUsersAsync(buffer, CancellationToken.None); + + await Task.WhenAny(t, Task.Delay(50)); + + #region Validations + twitterUserDalMock.VerifyAll(); + Assert.AreEqual(0, buffer.Count); + #endregion + } + + + [TestMethod] + [ExpectedException(typeof(OperationCanceledException))] + public async Task GetTwitterUsersAsync_Cancellation_Test() + { + #region Stubs + var buffer = new BufferBlock(); + var canTokenS = new CancellationTokenSource(); + canTokenS.Cancel(); + #endregion + + #region Mocks + var twitterUserDalMock = new Mock(MockBehavior.Strict); + #endregion + + var processor = new RetrieveTwitterUsersProcessor(twitterUserDalMock.Object); + await processor.GetTwitterUsersAsync(buffer, canTokenS.Token); + } + } +} \ No newline at end of file diff --git a/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/SaveProgressionProcessorTests.cs b/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/SaveProgressionProcessorTests.cs new file mode 100644 index 0000000..d3880e6 --- /dev/null +++ b/src/Tests/BirdsiteLive.Pipeline.Tests/Processors/SaveProgressionProcessorTests.cs @@ -0,0 +1,210 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using BirdsiteLive.DAL.Contracts; +using BirdsiteLive.DAL.Models; +using BirdsiteLive.Pipeline.Models; +using BirdsiteLive.Pipeline.Processors; +using BirdsiteLive.Twitter.Models; +using Castle.DynamicProxy.Contributors; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace BirdsiteLive.Pipeline.Tests.Processors +{ + [TestClass] + public class SaveProgressionProcessorTests + { + [TestMethod] + public async Task ProcessAsync_Test() + { + #region Stubs + var user = new SyncTwitterUser + { + Id = 1 + }; + var tweet1 = new ExtractedTweet + { + Id = 36 + }; + var tweet2 = new ExtractedTweet + { + Id = 37 + }; + var follower1 = new Follower + { + FollowingsSyncStatus = new Dictionary + { + {1, 37} + } + }; + + var usersWithTweets = new UserWithTweetsToSync + { + Tweets = new [] + { + tweet1, + tweet2 + }, + Followers = new [] + { + follower1 + }, + User = user + }; + #endregion + + #region Mocks + var twitterUserDalMock = new Mock(MockBehavior.Strict); + twitterUserDalMock + .Setup(x => x.UpdateTwitterUserAsync( + It.Is(y => y == user.Id), + It.Is(y => y == tweet2.Id), + It.Is(y => y == tweet2.Id) + )) + .Returns(Task.CompletedTask); + #endregion + + var processor = new SaveProgressionProcessor(twitterUserDalMock.Object); + await processor.ProcessAsync(usersWithTweets, CancellationToken.None); + + #region Validations + twitterUserDalMock.VerifyAll(); + #endregion + } + + [TestMethod] + public async Task ProcessAsync_PartiallySynchronized_Test() + { + #region Stubs + var user = new SyncTwitterUser + { + Id = 1 + }; + var tweet1 = new ExtractedTweet + { + Id = 36 + }; + var tweet2 = new ExtractedTweet + { + Id = 37 + }; + var tweet3 = new ExtractedTweet + { + Id = 38 + }; + var follower1 = new Follower + { + FollowingsSyncStatus = new Dictionary + { + {1, 37} + } + }; + + var usersWithTweets = new UserWithTweetsToSync + { + Tweets = new[] + { + tweet1, + tweet2, + tweet3 + }, + Followers = new[] + { + follower1 + }, + User = user + }; + #endregion + + #region Mocks + var twitterUserDalMock = new Mock(MockBehavior.Strict); + twitterUserDalMock + .Setup(x => x.UpdateTwitterUserAsync( + It.Is(y => y == user.Id), + It.Is(y => y == tweet3.Id), + It.Is(y => y == tweet2.Id) + )) + .Returns(Task.CompletedTask); + #endregion + + var processor = new SaveProgressionProcessor(twitterUserDalMock.Object); + await processor.ProcessAsync(usersWithTweets, CancellationToken.None); + + #region Validations + twitterUserDalMock.VerifyAll(); + #endregion + } + + [TestMethod] + public async Task ProcessAsync_PartiallySynchronized_MultiUsers_Test() + { + #region Stubs + var user = new SyncTwitterUser + { + Id = 1 + }; + var tweet1 = new ExtractedTweet + { + Id = 36 + }; + var tweet2 = new ExtractedTweet + { + Id = 37 + }; + var tweet3 = new ExtractedTweet + { + Id = 38 + }; + var follower1 = new Follower + { + FollowingsSyncStatus = new Dictionary + { + {1, 37} + } + }; + var follower2 = new Follower + { + FollowingsSyncStatus = new Dictionary + { + {1, 38} + } + }; + + var usersWithTweets = new UserWithTweetsToSync + { + Tweets = new[] + { + tweet1, + tweet2, + tweet3 + }, + Followers = new[] + { + follower1, + follower2 + }, + User = user + }; + #endregion + + #region Mocks + var twitterUserDalMock = new Mock(MockBehavior.Strict); + twitterUserDalMock + .Setup(x => x.UpdateTwitterUserAsync( + It.Is(y => y == user.Id), + It.Is(y => y == tweet3.Id), + It.Is(y => y == tweet2.Id) + )) + .Returns(Task.CompletedTask); + #endregion + + var processor = new SaveProgressionProcessor(twitterUserDalMock.Object); + await processor.ProcessAsync(usersWithTweets, CancellationToken.None); + + #region Validations + twitterUserDalMock.VerifyAll(); + #endregion + } + } +} \ No newline at end of file