public async Task GetSingleQuoteData_ShouldReturnNoDataAndQueueQuery_WhenFirstTime() { SymbolSearchResultDTO searchResult = await SearchSymbol("TSLA", ExchangeType.NASDAQ); List <StockSingleQuoteDataDTO> dataDtos = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); Assert.Single(dataDtos); var dataDto = dataDtos[0]; Assert.Equal(searchResult.SymbolId, dataDto.SymbolId); Assert.Null(dataDto.Data); var startTime = DateTime.UtcNow; while (dataDto.Data == null) { await CheckTimeOut(startTime); List <StockSingleQuoteDataDTO> newData = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); dataDto = newData[0]; } AssertSingleQuote(dataDto, searchResult.SymbolId); }
public async Task Should_DeletePortfolioWithSymbols() { // Create Portfolio var createPortfolioResponse = await _client.PostAsync(ApiPath.Portfolio(), new { name = string.Empty }.ToJsonPayload()); createPortfolioResponse.EnsureSuccessStatusCode(); var portfolio = await createPortfolioResponse.Content.ReadAsAsync <Portfolio>(); Assert.True(portfolio.Id > 0); // Search for symbols by keyword SymbolSearchResultDTO jpmSymbol = await FetchSymbol("JPM", ExchangeType.NYSE); // Add symbols to Portfolio var addJPMResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = jpmSymbol.SymbolId }.ToJsonPayload()); addJPMResponse.EnsureSuccessStatusCode(); // Verify Portfolio exists var getPortfolioResponse = await _client.GetAsync(ApiPath.Portfolio(portfolio.Id)); getPortfolioResponse.EnsureSuccessStatusCode(); // Delete and check it no longer exists var deletePortfolioResponse = await _client.DeleteAsync(ApiPath.Portfolio(portfolio.Id)); deletePortfolioResponse.EnsureSuccessStatusCode(); var getPortfolioAfterDeleteResponse = await _client.GetAsync(ApiPath.Portfolio(portfolio.Id)); Assert.Equal(HttpStatusCode.NotFound, getPortfolioAfterDeleteResponse.StatusCode); }
public async Task GetSingleQuoteData_ShouldUpdateQueryResults_WhenResultsFromDBStale() { // Trigger the query so it is saved into the database. SymbolSearchResultDTO searchResult = await SearchSymbol("TSLA", ExchangeType.NASDAQ); List <StockSingleQuoteDataDTO> dataDtos = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); Assert.Single(dataDtos); var dataDto = dataDtos[0]; Assert.Equal(searchResult.SymbolId, dataDto.SymbolId); Assert.Null(dataDto.Data); var startTime = DateTime.UtcNow; // Wait for query to execute and until there is data while (dataDto.Data == null) { await CheckTimeOut(startTime); List <StockSingleQuoteDataDTO> newData = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); dataDto = newData[0]; } AssertSingleQuote(dataDto, searchResult.SymbolId); // Make the data stale var modifiedDate = new DateTime(2000, 1, 1);; await _dbFixture.Connection.ExecuteAsync($"UPDATE SingleQuoteData SET LastUpdated = '{modifiedDate}'"); //reset the server so it will update the cache with the stale value. // System should detect the stale data and trigger an update. await RestartServer(); var dbDataDtos = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); var dbDataDto = dbDataDtos[0]; // Wait for query to execute and until there is data while (dbDataDto.LastUpdated <= modifiedDate) { await CheckTimeOut(startTime); List <StockSingleQuoteDataDTO> newData = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); dbDataDto = newData[0]; } Assert.Equal(searchResult.SymbolId, dbDataDto.SymbolId); Assert.True(dbDataDto.LastUpdated > DateTime.UtcNow.AddMinutes(-5)); }
public async Task GetSingleQuoteData_ShouldQueueQuery_ForEachStock_WhenTwoIntervals() { // First call should return no data since it does not exist. SymbolSearchResultDTO tslaSearchResult = await SearchSymbol("TSLA", ExchangeType.NASDAQ); SymbolSearchResultDTO jpmSearchResult = await SearchSymbol("JPM", ExchangeType.NYSE); SymbolSearchResultDTO shopSearchResult = await SearchSymbol("SHOP", ExchangeType.NASDAQ); SymbolSearchResultDTO faceBookSearchResult = await SearchSymbol("FB", ExchangeType.NASDAQ); var symbolIdsToGet = new int[] { tslaSearchResult.SymbolId, jpmSearchResult.SymbolId, shopSearchResult.SymbolId, faceBookSearchResult.SymbolId }; if (AppTestSettings.Instance.EventBusOptions.MaxQueriesPerInterval >= symbolIdsToGet.Length) { throw new InvalidOperationException("Number of symbols to fetch should be greater than the max per interval."); } List <StockSingleQuoteDataDTO> dataDtos = await GetSingleQuoteData(symbolIdsToGet); Assert.Equal(4, dataDtos.Count()); Assert.All(dataDtos, d => Assert.Null(d.Data)); var startTime = DateTime.UtcNow; // Wait for query to execute until all populated while (dataDtos.Count(d => d.Data == null) != 0) { await CheckTimeOut(startTime); dataDtos = await GetSingleQuoteData(symbolIdsToGet); } AssertSingleQuote(dataDtos[0], tslaSearchResult.SymbolId); AssertSingleQuote(dataDtos[1], jpmSearchResult.SymbolId); AssertSingleQuote(dataDtos[2], shopSearchResult.SymbolId); AssertSingleQuote(dataDtos[3], faceBookSearchResult.SymbolId); }
public async Task Should_OnlyShowedTheTopMembers() { TestUser testUser1 = await CreateTestUserWithPortfolio(); TestUser testUser2 = await CreateTestUserWithPortfolio(); TestUser testUser3 = await CreateTestUserWithPortfolio(); SymbolSearchResultDTO jpmStock = await FetchSymbol("JPM", ExchangeType.NYSE); // Add singlequote stocks var jpmData = new SingleQuoteData(jpmStock.SymbolId, jpmStock.Ticker, 200, 200, 200, 200, 200, 200, 0, 0, DateTime.UtcNow, DateTime.UtcNow); await SetSingleQuoteData(new UpsertSingleQuoteData(jpmStock.SymbolId, jpmData)); // Add symbols User 1 await AddSymbolToPortfolioWithAvgPrice(testUser1, jpmStock.SymbolId, 100); // Add symbols User 2 await AddSymbolToPortfolioWithAvgPrice(testUser2, jpmStock.SymbolId, 200); // Add symbols User 3 await AddSymbolToPortfolioWithAvgPrice(testUser3, jpmStock.SymbolId, 300); var leaderBoardResponse = await _client.GetAsync(ApiPath.LeaderBoard(2)); LeaderBoardViewModel leaderBoardViewModel = await leaderBoardResponse.Content.ReadAsAsync <LeaderBoardViewModel>(); // Verify calculations BoardValue bestPerformerRank1 = leaderBoardViewModel.BestPerformers.Values.ElementAt(0); BoardValue bestPerformerRank2 = leaderBoardViewModel.BestPerformers.Values.ElementAt(1); BoardValue worstPerformerRank1 = leaderBoardViewModel.WorstPerformers.Values.ElementAt(0); BoardValue worstPerformerRank2 = leaderBoardViewModel.WorstPerformers.Values.ElementAt(1); Assert.Equal(2, leaderBoardViewModel.BestPerformers.Values.Count()); Assert.Equal(2, leaderBoardViewModel.WorstPerformers.Values.Count()); Assert.Equal(testUser1.UserId, Guid.Parse(bestPerformerRank1.Id)); Assert.Equal(testUser2.UserId, Guid.Parse(bestPerformerRank2.Id)); Assert.Equal(testUser3.UserId, Guid.Parse(worstPerformerRank1.Id)); Assert.Equal(testUser2.UserId, Guid.Parse(worstPerformerRank2.Id)); }
public async Task Should_IgnorePortfolioSymbolsWithNoAveragePrice() { TestUser testUser1 = await CreateTestUserWithPortfolio(); TestUser testUser2 = await CreateTestUserWithPortfolio(); SymbolSearchResultDTO jpmStock = await FetchSymbol("JPM", ExchangeType.NYSE); SymbolSearchResultDTO fbStock = await FetchSymbol("FB", ExchangeType.NASDAQ); // Add singlequote stocks var jpmData = new SingleQuoteData(jpmStock.SymbolId, jpmStock.Ticker, 200, 200, 200, 200, 200, 200, 0, 0, DateTime.UtcNow, DateTime.UtcNow); var fbData = new SingleQuoteData(fbStock.SymbolId, fbStock.Ticker, 333.33m, 333.33m, 333.33m, 333.33m, 333.33m, 300, 0, 0, DateTime.UtcNow, DateTime.UtcNow); await SetSingleQuoteData(new UpsertSingleQuoteData(jpmStock.SymbolId, jpmData)); await SetSingleQuoteData(new UpsertSingleQuoteData(fbData.SymbolId, fbData)); // Add symbols User 1 await AddSymbolToPortfolioWithAvgPrice(testUser1, jpmStock.SymbolId, 100); await AddSymbolToPortfolio(testUser1, fbStock.SymbolId); // Add symbols User 2 await AddSymbolToPortfolio(testUser2, jpmStock.SymbolId); await AddSymbolToPortfolio(testUser2, fbStock.SymbolId); var leaderBoardResponse = await _client.GetAsync(ApiPath.LeaderBoard(2)); LeaderBoardViewModel leaderBoardViewModel = await leaderBoardResponse.Content.ReadAsAsync <LeaderBoardViewModel>(); // Verify calculations BoardValue bestPerformerRank1 = leaderBoardViewModel.BestPerformers.Values.ElementAt(0); BoardValue worstPerformerRank1 = leaderBoardViewModel.WorstPerformers.Values.ElementAt(0); Assert.Single(leaderBoardViewModel.BestPerformers.Values); Assert.Single(leaderBoardViewModel.WorstPerformers.Values); Assert.Equal(testUser1.UserId, Guid.Parse(bestPerformerRank1.Id)); Assert.Equal("100.00", bestPerformerRank1.Value); Assert.Equal(testUser1.UserId, Guid.Parse(worstPerformerRank1.Id)); Assert.Equal("100.00", worstPerformerRank1.Value); }
public async Task Should_DeleteSymbolFromPortfolio() { // Create Portfolio var createPortfolioResponse = await _client.PostAsync(ApiPath.Portfolio(), new { name = string.Empty }.ToJsonPayload()); createPortfolioResponse.EnsureSuccessStatusCode(); var portfolio = await createPortfolioResponse.Content.ReadAsAsync <Portfolio>(); Assert.True(portfolio.Id > 0); // Search for symbols by keyword SymbolSearchResultDTO tslaSymbol = await FetchSymbol("TSLA", ExchangeType.NASDAQ); SymbolSearchResultDTO jpmSymbol = await FetchSymbol("JPM", ExchangeType.NYSE); // Add symbols to Portfolio var addTSLAResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = tslaSymbol.SymbolId }.ToJsonPayload()); addTSLAResponse.EnsureSuccessStatusCode(); var addJPMResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = jpmSymbol.SymbolId }.ToJsonPayload()); addJPMResponse.EnsureSuccessStatusCode(); // Delete JPM var jpmPortfolioSymbol = await addJPMResponse.Content.ReadAsAsync <PortfolioSymbol>(); var deleteJPMResponse = await _client.DeleteAsync(ApiPath.PortfolioSymbols(portfolio.Id, jpmPortfolioSymbol.Id)); deleteJPMResponse.EnsureSuccessStatusCode(); // Check only one symbol left on Portfolio var getPortfolioResponse = await _client.GetAsync(ApiPath.Portfolio(portfolio.Id)); getPortfolioResponse.EnsureSuccessStatusCode(); var fetchedPortfolio = await getPortfolioResponse.Content.ReadAsAsync <Portfolio>(); Assert.Single(fetchedPortfolio.PortfolioSymbols); Assert.Equal("TSLA", fetchedPortfolio.PortfolioSymbols.First().Ticker); }
public async Task Should_UpdateAveragePricePortfolioSymbol() { // Create Portfolio var createPortfolioResponse = await _client.PostAsync(ApiPath.Portfolio(), new { name = string.Empty }.ToJsonPayload()); createPortfolioResponse.EnsureSuccessStatusCode(); var portfolio = await createPortfolioResponse.Content.ReadAsAsync <Portfolio>(); Assert.True(portfolio.Id > 0); // Search for symbols by keyword SymbolSearchResultDTO jpmSymbol = await FetchSymbol("JPM", ExchangeType.NYSE); // Add symbols to Portfolio var addJPMResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = jpmSymbol.SymbolId }.ToJsonPayload()); addJPMResponse.EnsureSuccessStatusCode(); var jpmPortfolioSymbol = await addJPMResponse.Content.ReadAsAsync <PortfolioSymbol>(); var newAvgPricePayload = new { AveragePrice = 1.24m }.ToJsonPayload(); var updateAveragePriceResponse = await _client.PatchAsync(ApiPath.PortfolioSymbolsAveragePrice(portfolio.Id, jpmPortfolioSymbol.Id), newAvgPricePayload); updateAveragePriceResponse.EnsureSuccessStatusCode(); var getPortfolioResponse = await _client.GetAsync(ApiPath.Portfolio(portfolio.Id)); var fetchedPortfolio = await getPortfolioResponse.Content.ReadAsAsync <Portfolio>(); Assert.Equal(portfolio.Id, fetchedPortfolio.Id); var jpm = fetchedPortfolio.PortfolioSymbols.Single(s => s.Ticker == "JPM"); Assert.Equal(1.24m, jpm.AveragePrice); }
public async Task Should_ReturnBadRequestWhenSymbolAlreadyExistsInPortfolio() { // Create Portfolio var createPortfolioResponse = await _client.PostAsync(ApiPath.Portfolio(), new { name = string.Empty }.ToJsonPayload()); createPortfolioResponse.EnsureSuccessStatusCode(); var portfolio = await createPortfolioResponse.Content.ReadAsAsync <Portfolio>(); Assert.True(portfolio.Id > 0); // Search for symbols by keyword SymbolSearchResultDTO tslaSymbol = await FetchSymbol("TSLA", ExchangeType.NASDAQ); // Add symbols to Portfolio var addTSLAResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = tslaSymbol.SymbolId }.ToJsonPayload()); addTSLAResponse.EnsureSuccessStatusCode(); var addTSLAResponse2 = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = tslaSymbol.SymbolId }.ToJsonPayload()); Assert.Equal(HttpStatusCode.BadRequest, addTSLAResponse2.StatusCode); }
public async Task GetSingleQuoteData_ShouldQueueQuery_ForEachStock() { // First call should return no data since it does not exist. SymbolSearchResultDTO tslaSearchResult = await SearchSymbol("TSLA", ExchangeType.NASDAQ); SymbolSearchResultDTO jpmSearchResult = await SearchSymbol("JPM", ExchangeType.NYSE); SymbolSearchResultDTO shopSearchResult = await SearchSymbol("SHOP", ExchangeType.NASDAQ); var symbolIdsToGet = new int[] { tslaSearchResult.SymbolId, jpmSearchResult.SymbolId, shopSearchResult.SymbolId, }; List <StockSingleQuoteDataDTO> dataDtos = await GetSingleQuoteData(symbolIdsToGet); Assert.Equal(3, dataDtos.Count()); Assert.All(dataDtos, d => Assert.Null(d.Data)); var startTime = DateTime.UtcNow; // Wait for query to execute until all populated while (dataDtos.Count(d => d.Data == null) != 0) { await CheckTimeOut(startTime); dataDtos = await GetSingleQuoteData(symbolIdsToGet); } AssertSingleQuote(dataDtos[0], tslaSearchResult.SymbolId); AssertSingleQuote(dataDtos[1], jpmSearchResult.SymbolId); AssertSingleQuote(dataDtos[2], shopSearchResult.SymbolId); }
public async Task Should_ReturnMostBearishAndMostBullishStocksByVotes() { TestUser testUser1 = await CreateTestUserWithPortfolio(); TestUser testUser2 = await CreateTestUserWithPortfolio(); TestUser testUser3 = await CreateTestUserWithPortfolio(); SymbolSearchResultDTO jpmStock = await FetchSymbol("JPM", ExchangeType.NYSE); SymbolSearchResultDTO fbStock = await FetchSymbol("FB", ExchangeType.NASDAQ); SymbolSearchResultDTO tslaStock = await FetchSymbol("TSLA", ExchangeType.NASDAQ); SymbolSearchResultDTO msftStock = await FetchSymbol("MSFT", ExchangeType.NASDAQ); // User 1 votes await SubmitVoteForUser(new VoteCommand { SymbolId = jpmStock.SymbolId, Direction = VoteDirection.UpVote }, testUser1.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = fbStock.SymbolId, Direction = VoteDirection.UpVote }, testUser1.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = tslaStock.SymbolId, Direction = VoteDirection.DownVote }, testUser1.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = msftStock.SymbolId, Direction = VoteDirection.DownVote }, testUser1.UserId); // User 2 votes await SubmitVoteForUser(new VoteCommand { SymbolId = jpmStock.SymbolId, Direction = VoteDirection.UpVote }, testUser2.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = fbStock.SymbolId, Direction = VoteDirection.DownVote }, testUser2.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = tslaStock.SymbolId, Direction = VoteDirection.DownVote }, testUser2.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = msftStock.SymbolId, Direction = VoteDirection.DownVote }, testUser2.UserId); // User 2 votes await SubmitVoteForUser(new VoteCommand { SymbolId = jpmStock.SymbolId, Direction = VoteDirection.UpVote }, testUser3.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = fbStock.SymbolId, Direction = VoteDirection.None }, testUser3.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = tslaStock.SymbolId, Direction = VoteDirection.DownVote }, testUser3.UserId); await SubmitVoteForUser(new VoteCommand { SymbolId = msftStock.SymbolId, Direction = VoteDirection.UpVote }, testUser3.UserId); var leaderBoardResponse = await _client.GetAsync(ApiPath.LeaderBoard(4)); LeaderBoardViewModel leaderBoardViewModel = await leaderBoardResponse.Content.ReadAsAsync <LeaderBoardViewModel>(); // Verify most bullish order BoardValue mostBullishRank1 = leaderBoardViewModel.MostBullish.Values.ElementAt(0); BoardValue mostBullishRank2 = leaderBoardViewModel.MostBullish.Values.ElementAt(1); BoardValue mostBullishRank3 = leaderBoardViewModel.MostBullish.Values.ElementAt(2); BoardValue mostBullishRank4 = leaderBoardViewModel.MostBullish.Values.ElementAt(3); Assert.Equal(jpmStock.SymbolId.ToString(), mostBullishRank1.Id); Assert.Equal("JPM", mostBullishRank1.Name); Assert.Equal("3", mostBullishRank1.Value); Assert.Equal(fbStock.SymbolId.ToString(), mostBullishRank2.Id); Assert.Equal("FB", mostBullishRank2.Name); Assert.Equal("0", mostBullishRank2.Value); Assert.Equal(msftStock.SymbolId.ToString(), mostBullishRank3.Id); Assert.Equal("MSFT", mostBullishRank3.Name); Assert.Equal("-1", mostBullishRank3.Value); Assert.Equal(tslaStock.SymbolId.ToString(), mostBullishRank4.Id); Assert.Equal("TSLA", mostBullishRank4.Name); Assert.Equal("-3", mostBullishRank4.Value); // Verify most bearish order BoardValue mostBearishRank1 = leaderBoardViewModel.MostBearish.Values.ElementAt(0); BoardValue mostBearishRank2 = leaderBoardViewModel.MostBearish.Values.ElementAt(1); BoardValue mostBearishRank3 = leaderBoardViewModel.MostBearish.Values.ElementAt(2); BoardValue mostBearishRank4 = leaderBoardViewModel.MostBearish.Values.ElementAt(3); Assert.Equal(tslaStock.SymbolId.ToString(), mostBearishRank1.Id); Assert.Equal("TSLA", mostBearishRank1.Name); Assert.Equal("-3", mostBearishRank1.Value); Assert.Equal(msftStock.SymbolId.ToString(), mostBearishRank2.Id); Assert.Equal("MSFT", mostBearishRank2.Name); Assert.Equal("-1", mostBearishRank2.Value); Assert.Equal(fbStock.SymbolId.ToString(), mostBearishRank3.Id); Assert.Equal("FB", mostBearishRank3.Name); Assert.Equal("0", mostBearishRank3.Value); Assert.Equal(jpmStock.SymbolId.ToString(), mostBearishRank4.Id); Assert.Equal("JPM", mostBearishRank4.Name); Assert.Equal("3", mostBearishRank4.Value); }
public async Task Should_ReturnBestAndWorstPerformers() { TestUser testUser1 = await CreateTestUserWithPortfolio(); TestUser testUser2 = await CreateTestUserWithPortfolio(); TestUser testUser3 = await CreateTestUserWithPortfolio(); SymbolSearchResultDTO jpmStock = await FetchSymbol("JPM", ExchangeType.NYSE); SymbolSearchResultDTO fbStock = await FetchSymbol("FB", ExchangeType.NASDAQ); SymbolSearchResultDTO tslaStock = await FetchSymbol("TSLA", ExchangeType.NASDAQ); SymbolSearchResultDTO msftStock = await FetchSymbol("MSFT", ExchangeType.NASDAQ); // Add singlequote stocks var jpmData = new SingleQuoteData(jpmStock.SymbolId, jpmStock.Ticker, 200, 200, 200, 200, 200, 200, 0, 0, DateTime.UtcNow, DateTime.UtcNow); var fbData = new SingleQuoteData(fbStock.SymbolId, fbStock.Ticker, 333.33m, 333.33m, 333.33m, 333.33m, 333.33m, 300, 0, 0, DateTime.UtcNow, DateTime.UtcNow); var tslaData = new SingleQuoteData(tslaStock.SymbolId, tslaStock.Ticker, 888.88m, 888.88m, 888.88m, 888.88m, 888.88m, 800, 0, 0, DateTime.UtcNow, DateTime.UtcNow); var msftData = new SingleQuoteData(msftStock.SymbolId, msftStock.Ticker, 225, 225, 225, 225, 225, 200, 0, 0, DateTime.UtcNow, DateTime.UtcNow); await SetSingleQuoteData(new UpsertSingleQuoteData(jpmStock.SymbolId, jpmData)); await SetSingleQuoteData(new UpsertSingleQuoteData(fbData.SymbolId, fbData)); await SetSingleQuoteData(new UpsertSingleQuoteData(tslaData.SymbolId, tslaData)); await SetSingleQuoteData(new UpsertSingleQuoteData(msftData.SymbolId, msftData)); // Add symbols User 1 await AddSymbolToPortfolioWithAvgPrice(testUser1, jpmStock.SymbolId, 100.25m); await AddSymbolToPortfolioWithAvgPrice(testUser1, fbStock.SymbolId, 260.35m); await AddSymbolToPortfolioWithAvgPrice(testUser1, msftStock.SymbolId, 175.50m); // Add symbols User 2 await AddSymbolToPortfolioWithAvgPrice(testUser2, jpmStock.SymbolId, 5.00m); await AddSymbolToPortfolioWithAvgPrice(testUser2, fbStock.SymbolId, 10.00m); // Add Symbols Users 3 await AddSymbolToPortfolioWithAvgPrice(testUser3, jpmStock.SymbolId, 180.88m); await AddSymbolToPortfolioWithAvgPrice(testUser3, fbStock.SymbolId, 400.00m); await AddSymbolToPortfolioWithAvgPrice(testUser3, tslaStock.SymbolId, 1000m); await AddSymbolToPortfolioWithAvgPrice(testUser3, msftStock.SymbolId, 300.90m); var leaderBoardResponse = await _client.GetAsync(ApiPath.LeaderBoard(3)); LeaderBoardViewModel leaderBoardViewModel = await leaderBoardResponse.Content.ReadAsAsync <LeaderBoardViewModel>(); // Verify calculations BoardValue bestPerformerRank1 = leaderBoardViewModel.BestPerformers.Values.ElementAt(0); BoardValue bestPerformerRank2 = leaderBoardViewModel.BestPerformers.Values.ElementAt(1); BoardValue bestPerformerRank3 = leaderBoardViewModel.BestPerformers.Values.ElementAt(2); Assert.Equal(3, leaderBoardViewModel.BestPerformers.Values.Count()); Assert.Equal(testUser2.UserId, Guid.Parse(bestPerformerRank1.Id)); Assert.Equal(testUser1.UserId, Guid.Parse(bestPerformerRank2.Id)); Assert.Equal(testUser3.UserId, Guid.Parse(bestPerformerRank3.Id)); Assert.Equal(testUser2.UserId, Guid.Parse(bestPerformerRank1.Name)); Assert.Equal(testUser1.UserId, Guid.Parse(bestPerformerRank2.Name)); Assert.Equal(testUser3.UserId, Guid.Parse(bestPerformerRank3.Name)); Assert.Equal("3,566.65", bestPerformerRank1.Value); Assert.Equal("51.91", bestPerformerRank2.Value); Assert.Equal("-10.61", bestPerformerRank3.Value); BoardValue worstPerformerRank1 = leaderBoardViewModel.WorstPerformers.Values.ElementAt(0); BoardValue worstPerformerRank2 = leaderBoardViewModel.WorstPerformers.Values.ElementAt(1); BoardValue worstPerformerRank3 = leaderBoardViewModel.WorstPerformers.Values.ElementAt(2); Assert.Equal(3, leaderBoardViewModel.WorstPerformers.Values.Count()); Assert.Equal(testUser3.UserId, Guid.Parse(worstPerformerRank1.Id)); Assert.Equal(testUser1.UserId, Guid.Parse(worstPerformerRank2.Id)); Assert.Equal(testUser2.UserId, Guid.Parse(worstPerformerRank3.Id)); Assert.Equal("-10.61", worstPerformerRank1.Value); Assert.Equal("51.91", worstPerformerRank2.Value); Assert.Equal("3,566.65", worstPerformerRank3.Value); }
public async Task GetSingleQuoteData_ShouldReturnDataFromCacheAndDB_WhenItExists() { // First call should return no data since it does not exist. SymbolSearchResultDTO searchResult = await SearchSymbol("TSLA", ExchangeType.NASDAQ); List <StockSingleQuoteDataDTO> dataDtos = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); Assert.Single(dataDtos); var dataDto = dataDtos[0]; Assert.Equal(searchResult.SymbolId, dataDto.SymbolId); Assert.Null(dataDto.Data); var startTime = DateTime.UtcNow; // Wait for query to execute and until there is data while (dataDto.Data == null) { await CheckTimeOut(startTime); List <StockSingleQuoteDataDTO> newData = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); dataDto = newData[0]; } AssertSingleQuote(dataDto, searchResult.SymbolId); // Next update the LastUpdated date of the single quote data entry in the database. // however when this single quote data is fetched it the date should not match since // the database is updated but not cache, which is where it will be fetched from. var modifiedDate = new DateTime(2000, 1, 1);; await _dbFixture.Connection.ExecuteAsync($"UPDATE SingleQuoteData SET LastUpdated = '{modifiedDate}'"); var cacheDataDtos = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); Assert.Single(cacheDataDtos); var cacheDataDto = cacheDataDtos[0]; AssertSingleQuote(cacheDataDto, searchResult.SymbolId); Assert.NotEqual(cacheDataDto.LastUpdated.Value.ToString("yyyy-mm-dd"), modifiedDate.ToString("yyyy-mm-dd")); // Restarting server will clear cache so we should get the updated DB value. await RestartServer(); var dbDtos = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); Assert.Single(dataDtos); var dbDto = dbDtos[0]; AssertSingleQuote(dbDto, searchResult.SymbolId); Assert.Equal(dbDto.LastUpdated.Value.ToString("yyyy-mm-dd"), modifiedDate.ToString("yyyy-mm-dd")); // Update the DB entry again. Getting the data should get the cache version so it will be unaffected. await _dbFixture.Connection.ExecuteAsync($"UPDATE SingleQuoteData SET LastUpdated = '2001-01-01'"); var secondCachedDtos = await GetSingleQuoteData(new int[] { searchResult.SymbolId }); var secondCachedDto = secondCachedDtos[0]; Assert.Equal(dbDto.LastUpdated, secondCachedDto.LastUpdated); }
public async Task Should_ReorderPortfolioSymbols() { var payload = new { name = "" }.ToJsonPayload(); // Create Portfolio var createPortfolioResponse = await _client.PostAsync(ApiPath.Portfolio(), payload); createPortfolioResponse.EnsureSuccessStatusCode(); var portfolio = await createPortfolioResponse.Content.ReadAsAsync <Portfolio>(); Assert.True(portfolio.Id > 0); // Search for symbols by keyword SymbolSearchResultDTO tslaSymbol = await FetchSymbol("TSLA", ExchangeType.NASDAQ); SymbolSearchResultDTO jpmSymbol = await FetchSymbol("JPM", ExchangeType.NYSE); SymbolSearchResultDTO fbSymbol = await FetchSymbol("FB", ExchangeType.NASDAQ); SymbolSearchResultDTO msftSymbol = await FetchSymbol("MSFT", ExchangeType.NASDAQ); // Add symbols to Portfolio var addTSLAResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = tslaSymbol.SymbolId }.ToJsonPayload()); addTSLAResponse.EnsureSuccessStatusCode(); var tslaPortfolioSymbol = await addTSLAResponse.Content.ReadAsAsync <PortfolioSymbol>(); var addJPMResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = jpmSymbol.SymbolId }.ToJsonPayload()); addJPMResponse.EnsureSuccessStatusCode(); var jpmPortfolioSymbol = await addJPMResponse.Content.ReadAsAsync <PortfolioSymbol>(); var addFBResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = fbSymbol.SymbolId }.ToJsonPayload()); addFBResponse.EnsureSuccessStatusCode(); var fbPortfolioSymbol = await addFBResponse.Content.ReadAsAsync <PortfolioSymbol>(); var addMSFTResponse = await _client.PostAsync(ApiPath.PortfolioSymbols(portfolio.Id), new { SymbolId = msftSymbol.SymbolId }.ToJsonPayload()); addMSFTResponse.EnsureSuccessStatusCode(); var msftPortfolioSymbol = await addMSFTResponse.Content.ReadAsAsync <PortfolioSymbol>(); // Check starting order is as expected Assert.Equal(1, tslaPortfolioSymbol.SortOrder); Assert.Equal(2, jpmPortfolioSymbol.SortOrder); Assert.Equal(3, fbPortfolioSymbol.SortOrder); Assert.Equal(4, msftPortfolioSymbol.SortOrder); var newOrder = new { PortfolioSymbolIdToSortOrder = new Dictionary <int, int> { { fbPortfolioSymbol.Id, 1 }, { tslaPortfolioSymbol.Id, 2 }, { msftPortfolioSymbol.Id, 3 }, { jpmPortfolioSymbol.Id, 4 }, } }.ToJsonPayload(); var reorderTSLAResponse = await _client.PatchAsync(ApiPath.PortfolioSymbolsReorder(portfolio.Id), newOrder); reorderTSLAResponse.EnsureSuccessStatusCode(); var getPortfolioResponse = await _client.GetAsync(ApiPath.Portfolio(portfolio.Id)); var fetchedPortfolio = await getPortfolioResponse.Content.ReadAsAsync <Portfolio>(); Assert.Equal(portfolio.Id, fetchedPortfolio.Id); var tsla = fetchedPortfolio.PortfolioSymbols.Single(s => s.Ticker == "TSLA"); var jpm = fetchedPortfolio.PortfolioSymbols.Single(s => s.Ticker == "JPM"); var fb = fetchedPortfolio.PortfolioSymbols.Single(s => s.Ticker == "FB"); var msft = fetchedPortfolio.PortfolioSymbols.Single(s => s.Ticker == "MSFT"); Assert.Equal(1, fb.SortOrder); Assert.Equal(2, tsla.SortOrder); Assert.Equal(3, msft.SortOrder); Assert.Equal(4, jpm.SortOrder); }