public async Task <RaceResultDTO> AnalyseAsync(CreateRaceDTO createData, FileDTO file, string uploader) { //Validar minimamente os dados de input. if (createData == null || file == null || uploader == null) { throw new BusinessException("Dados inválidos para análise"); } else if (!this.ValidateRequiredFields(createData, file, out string requiredFieldsErrorMessage)) { throw new BusinessException(requiredFieldsErrorMessage); } //Processar o arquivo. await this._raceFileReader.Read(file.Content); //Tratar retorno. if (this.ValidatePostProcessing(out string postProcessingErrorMessage)) { int newRaceId = await this.ProcessAndSaveData(createData, uploader, this._raceFileReader.Results); return(await this.GetResultByIdAsync(newRaceId)); } else { throw new BusinessException(postProcessingErrorMessage); } }
public async Task Test_AnalyseAsync_InvalidPostProcessing_NoDataInFile() { //Arrange. CreateRaceDTO createRaceDTO = new CreateRaceDTO() { Date = DateTime.Now, Description = "Descrição", TotalLaps = 10, RaceTypeId = 1 }; FileDTO fileDTO = new FileDTO() { Name = "Arquivo teste", Content = new MemoryStream(new byte[] { 125, 141, 13, 27 }), ContentType = "text/plain", Extension = "txt" }; //Mockar query para o tipo de corrida. var raceTypeByIdQuery = new Query <RaceType>(); this._raceTypeQueryMock.Setup(x => x.ById(createRaceDTO.RaceTypeId)) .Returns(raceTypeByIdQuery); //Mockar retorno do repositório quando usamos a query criada. this._raceTypeRepositoryMock .Setup(rep => rep.Exists(It.Is <Query <RaceType> >(q => q.Equals(raceTypeByIdQuery)))) .Returns(true); //Mockar mensagem, status do leitor de arquivo e coleção de voltas lidas. this._raceFileReaderMock.Setup(x => x.ErrorMessage) .Returns(string.Empty); this._raceFileReaderMock.Setup(x => x.Success) .Returns(true); this._raceFileReaderMock.Setup(x => x.Results) .Returns(Enumerable.Empty <Lap>()); //Mockar chamada pro leitor de arquivos. this._raceFileReaderMock.Setup(x => x.Read(It.IsAny <Stream>())) .Returns(Task.CompletedTask); //Act. await this._raceService.AnalyseAsync(createRaceDTO, fileDTO, "yagohf"); //Assert. }
public async Task <IActionResult> Post([FromForm] CreateRaceDTO model, [FromForm] IFormFile file) { FileDTO fileDTO = new FileDTO(); if (file != null && file.Length > 0) { fileDTO.Extension = file.FileName.Split('.').Last(); fileDTO.ContentType = file.ContentType; fileDTO.Content = new MemoryStream(); await file.CopyToAsync(fileDTO.Content); } RaceResultDTO raceResult = await this._raceService.AnalyseAsync(model, fileDTO, this.GetLoggedUser()); return(CreatedAtAction(nameof(GetResultById), new { id = raceResult.RaceId }, raceResult)); }
private async Task <int> ProcessAndSaveData(CreateRaceDTO createData, string uploader, IEnumerable <Lap> laps) { //Recuperar usuário da corrida. User user = await this._userRepository.GetSingleAsync(this._userQuery.ByLogin(uploader)); using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled)) { //Salvar corrida. Race race = new Race(); race.Date = createData.Date; race.Description = createData.Description; race.TotalLaps = createData.TotalLaps; race.UploadDate = DateTime.Now; race.UploaderId = user.Id; race.RaceTypeId = createData.RaceTypeId; await this._raceRepository.InsertAsync(race); //Salvar cada uma das voltas após atualizar o ID da corrida. foreach (var lap in laps) { lap.RaceId = race.Id; await this._lapRepository.InsertAsync(lap); } //Processar o resultado dos pilotos e persistir resultados. IEnumerable <DriverResult> driverResults = this.ProcessDriverResults(laps); foreach (var driverResult in driverResults) { driverResult.RaceId = race.Id; await this._driverResultRepository.InsertAsync(driverResult); } //Commitar transação. ts.Complete(); //Devolver ID para o chamador. return(race.Id); } }
private bool ValidateRequiredFields(CreateRaceDTO createData, FileDTO file, out string requiredFieldsErrorMessage) { requiredFieldsErrorMessage = string.Empty; if (string.IsNullOrWhiteSpace(createData.Description)) { requiredFieldsErrorMessage += "Descrição não informada;"; } if (createData.TotalLaps < 1) { requiredFieldsErrorMessage += "Número de voltas inválido;"; } if (file.Content == null || file.Content.Length == 0 || this._raceFileSettings.AllowedContentType != file.ContentType) { requiredFieldsErrorMessage += "Arquivo inválido para análise;"; } if (!this._raceTypeRepository.Exists(this._raceTypeQuery.ById(createData.RaceTypeId))) { requiredFieldsErrorMessage += "Tipo de corrida inválido;"; } return(string.IsNullOrEmpty(requiredFieldsErrorMessage)); }
public async Task Test_AnalyseAsync_InvalidFileContent() { //Arrange. CreateRaceDTO createRaceDTO = new CreateRaceDTO() { Date = DateTime.Now, Description = "Teste", TotalLaps = 1, RaceTypeId = 1 }; FileDTO fileDTO = new FileDTO() { Name = "Teste", Content = new MemoryStream(new byte[] { 125, 141, 13, 27 }), ContentType = "application/octet-stream", Extension = "pdf" }; //Mockar query para o tipo de corrida. var raceTypeByIdQuery = new Query <RaceType>(); this._raceTypeQueryMock.Setup(x => x.ById(createRaceDTO.RaceTypeId)) .Returns(raceTypeByIdQuery); //Mockar retorno do repositório quando usamos a query criada. this._raceTypeRepositoryMock .Setup(rep => rep.Exists(It.Is <IQuery <RaceType> >(q => q.Equals(raceTypeByIdQuery)))) .Returns(true); //Act. await this._raceService.AnalyseAsync(createRaceDTO, fileDTO, "yagohf"); //Assert. }
public async Task Test_AnalyseAsync_InvalidCreateData() { //Arrange. CreateRaceDTO createRaceDTO = new CreateRaceDTO() { Date = DateTime.Now, Description = "", TotalLaps = -10, RaceTypeId = 300 }; FileDTO fileDTO = new FileDTO() { Name = "", Content = null, ContentType = "", Extension = "" }; //Mockar query para o tipo de corrida. var raceTypeByIdQuery = new Query <RaceType>(); this._raceTypeQueryMock.Setup(x => x.ById(createRaceDTO.RaceTypeId)) .Returns(raceTypeByIdQuery); //Mockar retorno do repositório quando usamos a query criada. this._raceTypeRepositoryMock .Setup(rep => rep.Exists(It.Is <IQuery <RaceType> >(q => q.Equals(raceTypeByIdQuery)))) .Returns(false); //Act. await this._raceService.AnalyseAsync(createRaceDTO, fileDTO, "yagohf"); //Assert. }
public async Task Test_AnalyseAsync_Valid() { //Arrange. CreateRaceDTO createRaceDTO = new CreateRaceDTO() { Date = DateTime.Now.Date, Description = "Race Unit Test", TotalLaps = 1, RaceTypeId = 1 }; FileDTO fileDTO = new FileDTO() { Name = "Arquivo teste", Content = new MemoryStream(new byte[] { 125, 141, 13, 27 }), ContentType = "text/plain", Extension = "txt" }; List <Lap> resultsMock = new List <Lap>() { new Lap() { DriverNumber = 10, DriverName = "F. Alonso", Number = 1 }, new Lap() { DriverNumber = 11, DriverName = "F. Massa", Number = 1 } }; RaceType raceTypeMock = new RaceType() { Id = 1, Name = "F-1" }; //Mockar query para o tipo de corrida. var raceTypeByIdQuery = new Query <RaceType>(); this._raceTypeQueryMock.Setup(x => x.ById(createRaceDTO.RaceTypeId)) .Returns(raceTypeByIdQuery); //Mockar retorno do repositório quando usamos a query criada. this._raceTypeRepositoryMock .Setup(rep => rep.Exists(It.Is <Query <RaceType> >(q => q.Equals(raceTypeByIdQuery)))) .Returns(true); //Mockar retorno do repositório quando usamos a query criada. this._raceTypeRepositoryMock .Setup(rep => rep.GetSingleAsync(It.Is <IQuery <RaceType> >(q => q.Equals(raceTypeByIdQuery)))) .Returns(Task.FromResult(raceTypeMock)); //Mockar mensagem, status do leitor de arquivo e coleção de voltas lidas. this._raceFileReaderMock.Setup(x => x.ErrorMessage) .Returns(string.Empty); this._raceFileReaderMock.Setup(x => x.Success) .Returns(true); this._raceFileReaderMock.Setup(x => x.Results) .Returns(resultsMock); //Mockar chamada pro leitor de arquivos. this._raceFileReaderMock.Setup(x => x.Read(It.IsAny <Stream>())) .Returns(Task.CompletedTask); //Mockar query para o usuário por login. User userMock = new User() { Id = 1, Login = "******" }; var userByLoginQuery = new Query <User>(); this._userQueryMock.Setup(x => x.ByLogin(userMock.Login)) .Returns(userByLoginQuery); //Mockar retorno do repositório quando usamos a query criada. this._userRepositoryMock .Setup(rep => rep.GetSingleAsync(It.Is <Query <User> >(q => q.Equals(userByLoginQuery)))) .Returns(Task.FromResult(userMock)); //Mockar inserts. this._raceRepositoryMock.Setup(x => x.InsertAsync(It.IsAny <Race>())) .Returns(Task.CompletedTask); this._lapRepositoryMock.Setup(x => x.InsertAsync(It.IsAny <Lap>())) .Returns(Task.CompletedTask); this._driverResultRepositoryMock.Setup(x => x.InsertAsync(It.IsAny <DriverResult>())) .Returns(Task.CompletedTask); #region [ Preparar cenário do GetResultsById ] Race raceMock = new Race() { Date = DateTime.Now.Date, Description = "Race Unit Test", RaceTypeId = 1, TotalLaps = 1, UploadDate = DateTime.Now.Date, Uploader = new User() { Id = 1, Login = "******", Name = "Yago", Password = "******" } }; //Mockar query. var raceByIdQuery = new Query <Race>(); this._raceQueryMock.Setup(x => x.ById(raceMock.Id)) .Returns(raceByIdQuery); //Mockar retorno do repositório quando usamos a query criada. this._raceRepositoryMock .Setup(rep => rep.GetSingleAsync(It.Is <IQuery <Race> >(q => q.Equals(raceByIdQuery)))) .Returns(Task.FromResult(raceMock)); List <DriverResult> driverResultsMock = new List <DriverResult>() { new DriverResult() { Id = 1, AverageSpeed = 10, BestLap = TimeSpan.FromSeconds(10), DriverName = "F. Alonso", DriverNumber = 10, Gap = null, Laps = 1, Position = 1, RaceId = raceMock.Id, TotalRaceTime = TimeSpan.FromSeconds(10) }, new DriverResult() { Id = 2, AverageSpeed = 8, BestLap = TimeSpan.FromSeconds(15), DriverName = "F. Massa", DriverNumber = 11, Gap = TimeSpan.FromSeconds(5), Laps = 1, Position = 1, RaceId = raceMock.Id, TotalRaceTime = TimeSpan.FromSeconds(15) } }; //Mockar query de corrida por id. var driverResultsByRaceIdQuery = new Query <DriverResult>(); this._driverResultQueryMock.Setup(x => x.ByRace(raceMock.Id)) .Returns(driverResultsByRaceIdQuery); //Mockar retorno do repositório quando usamos a query criada. this._driverResultRepositoryMock .Setup(rep => rep.ListAsync(It.Is <IQuery <DriverResult> >(q => q.Equals(driverResultsByRaceIdQuery)))) .Returns(Task.FromResult(driverResultsMock.AsEnumerable())); #endregion //Act. var result = await this._raceService.AnalyseAsync(createRaceDTO, fileDTO, userMock.Login); //Assert. Assert.IsNotNull(result); }
public async Task Test_AnalyseAsync_InvalidPostProcessing_RanTheSameLapTwice() { //Arrange. CreateRaceDTO createRaceDTO = new CreateRaceDTO() { Date = DateTime.Now, Description = "Descrição", TotalLaps = 10, RaceTypeId = 1 }; FileDTO fileDTO = new FileDTO() { Name = "Arquivo teste", Content = new MemoryStream(new byte[] { 125, 141, 13, 27 }), ContentType = "text/plain", Extension = "txt" }; List <Lap> resultsMock = new List <Lap>() { new Lap() { DriverNumber = 10, DriverName = "F. Alonso", Number = 1 }, new Lap() { DriverNumber = 10, DriverName = "F. Alonso", Number = 1 } }; //Mockar query para o tipo de corrida. var raceTypeByIdQuery = new Query <RaceType>(); this._raceTypeQueryMock.Setup(x => x.ById(createRaceDTO.RaceTypeId)) .Returns(raceTypeByIdQuery); //Mockar retorno do repositório quando usamos a query criada. this._raceTypeRepositoryMock .Setup(rep => rep.Exists(It.Is <Query <RaceType> >(q => q.Equals(raceTypeByIdQuery)))) .Returns(true); //Mockar mensagem, status do leitor de arquivo e coleção de voltas lidas. this._raceFileReaderMock.Setup(x => x.ErrorMessage) .Returns(string.Empty); this._raceFileReaderMock.Setup(x => x.Success) .Returns(true); this._raceFileReaderMock.Setup(x => x.Results) .Returns(resultsMock); //Mockar chamada pro leitor de arquivos. this._raceFileReaderMock.Setup(x => x.Read(It.IsAny <Stream>())) .Returns(Task.CompletedTask); string exceptionMessage = null; //Act. try { await this._raceService.AnalyseAsync(createRaceDTO, fileDTO, "yagohf"); } catch (Exception ex) { exceptionMessage = ex.Message; } //Assert. Assert.IsNotNull(exceptionMessage); Assert.IsTrue(exceptionMessage.StartsWith("Existem voltas repetidas para o mesmo piloto:")); Assert.IsTrue(exceptionMessage.Contains($"Piloto: {resultsMock.First().DriverNumber} / Volta: { resultsMock.First().Number }")); }
public async Task Test_Post() { //Arrange. CreateRaceDTO createRaceMock = new CreateRaceDTO() { Date = DateTime.Now.AddDays(-1), Description = "2019 F-1 Racing", RaceTypeId = 1, TotalLaps = 10 }; //Arrange. int raceId = 1; RaceResultDTO raceResultMock = new RaceResultDTO() { BestLap = new BestLapDTO() { Driver = "10 - Test Driver", Time = TimeSpan.FromSeconds(60) }, RaceDate = DateTime.Now.AddDays(-1), RaceDescription = "2019 F-1 Racing", RaceId = raceId, TotalLaps = 10, UploadDate = DateTime.Now.Date, Uploader = "yagohf", Winner = "10 - Test Driver", Results = new List <DriverResultDTO>() { new DriverResultDTO() { AverageSpeed = 40, BestLap = TimeSpan.FromSeconds(60), DriverName = "Test Driver", DriverNumber = 10, Gap = null, Laps = 10, Position = 1, TotalRaceTime = TimeSpan.FromMinutes(15) }, new DriverResultDTO() { AverageSpeed = 38, BestLap = TimeSpan.FromSeconds(70), DriverName = "Test Driver 2", DriverNumber = 15, Gap = TimeSpan.FromSeconds(60), Laps = 10, Position = 2, TotalRaceTime = TimeSpan.FromMinutes(16) } } }; //Mockar arquivo. Mock <IFormFile> fileMock = new Mock <IFormFile>(); string fileName = "NO-ERRORS.txt"; string fileAssemblyPath = $"Yagohf.Gympass.RaceAnalyser.UnitTests.Embedded.{fileName}"; using (var fileAssemblyStream = Assembly.GetAssembly(typeof(RacesControllerTests)).GetManifestResourceStream(fileAssemblyPath)) { fileAssemblyStream.Position = 0; fileMock.Setup(x => x.OpenReadStream()).Returns(fileAssemblyStream); fileMock.Setup(x => x.FileName).Returns(fileName); fileMock.Setup(x => x.Length).Returns(fileAssemblyStream.Length); fileMock.Setup(x => x.ContentType).Returns("text/plain"); } //Mockar usuário logado. var claims = new List <Claim>() { new Claim(ClaimTypes.Name, "yagohf"), }; var identity = new ClaimsIdentity(claims); var claimsPrincipal = new ClaimsPrincipal(identity); var principalMock = new Mock <IPrincipal>(); principalMock.Setup(x => x.Identity).Returns(identity); var mockHttpContext = new Mock <HttpContext>(); mockHttpContext.Setup(m => m.User).Returns(claimsPrincipal); this._racesController.ControllerContext.HttpContext = mockHttpContext.Object; this._raceServiceMock .Setup(srv => srv.AnalyseAsync(It.IsAny <CreateRaceDTO>(), It.IsAny <FileDTO>(), It.IsAny <string>())) .Returns(Task.FromResult(raceResultMock)); //Act. var result = await this._racesController.Post(createRaceMock, fileMock.Object); var createdAtResult = result as CreatedAtActionResult; //Assert. Assert.IsNotNull(createdAtResult); Assert.IsInstanceOfType(createdAtResult.Value, typeof(RaceResultDTO)); Assert.AreEqual(raceResultMock, createdAtResult.Value as RaceResultDTO); //Testar URL de redirecionamento. Assert.AreEqual(createdAtResult.ActionName, nameof(this._racesController.GetResultById)); Assert.AreEqual(createdAtResult.RouteValues["id"], raceResultMock.RaceId); }