public async void Should_combine_ajacent_deleted_ranges_into_a_single_entry() { // Set up var req = new TimeLogUpdateRequest { Deletions = new List <TimeLogDeletedRange> { new TimeLogDeletedRange { FromTime = TestFromTime + TimeSpan.FromHours(1), ToTime = TestFromTime + TimeSpan.FromHours(2) }, new TimeLogDeletedRange { FromTime = TestFromTime, ToTime = TestFromTime + TimeSpan.FromHours(1) }, } }; // Act await _service.Update(Db, _poll.Id, req); // Assert Db.WasSaveChangesCalled.Should().BeTrue(); var addedEntries = Db.Mock.TimeLogEntries.Added; addedEntries.Should().HaveCount(1); // First entry var entry0 = addedEntries[0]; entry0.FromTime.Should().Be(TestFromTime); entry0.ToTime.Should().Be(TestFromTime + TimeSpan.FromHours(2)); }
public void If_from_time_is_on_or_before_to_time_should_throw_and_not_save_any_deletions(int hoursLength) { // Set up var req = new TimeLogUpdateRequest { Deletions = new List <TimeLogDeletedRange> { new TimeLogDeletedRange { FromTime = TestFromTime, ToTime = TestFromTime + TimeSpan.FromHours(1) }, new TimeLogDeletedRange { FromTime = TestFromTime + TimeSpan.FromHours(3), ToTime = TestFromTime + TimeSpan.FromHours(3 + hoursLength) }, } }; // Act Func <Task> action = async() => await _service.Update(Db, _poll.Id, req); // Assert action.Should().Throw <BadRequestException>() .WithMessage("*fromTime*") .WithMessage("*toTime*"); Db.WasSaveChangesCalled.Should().BeFalse(); }
public async void Truncate_from_and_to_times_to_preceding_minute() { // Set up var req = new TimeLogUpdateRequest { Deletions = new List <TimeLogDeletedRange> { new TimeLogDeletedRange { FromTime = TestFromTime + TimeSpan.FromSeconds(5), ToTime = TestFromTime + TimeSpan.FromHours(1) + TimeSpan.FromSeconds(59) }, } }; // Act await _service.Update(Db, _poll.Id, req); // Assert Db.WasSaveChangesCalled.Should().BeTrue(); var addedEntries = Db.Mock.TimeLogEntries.Added; // First entry var entry0 = addedEntries[0]; entry0.FromTime.Should().Be(TestFromTime); entry0.ToTime.Should().Be(TestFromTime + TimeSpan.FromHours(1)); }
public void Should_not_save_deletions_if_there_are_errors_with_additions() { // Set up. // Valid deletion but an invalid addition. var req = new TimeLogUpdateRequest { Deletions = new List <TimeLogDeletedRange> { new TimeLogDeletedRange { FromTime = TestFromTime, ToTime = TestFromTime + TimeSpan.FromHours(1) }, }, Additions = new List <PollResponseAddRequest> { new PollResponseAddRequest { TimeCollected = TestFromTime, TimeBlockLength = TimeSpan.FromHours(1), ResponseText = "", // This should fail TimeZone = "ABC", TimeZoneOffset = TimeSpan.FromHours(-2) } } }; // Act Func <Task> action = async() => await _service.Update(Db, _poll.Id, req); // Assert. action.Should().Throw <BadRequestException>(); // This is for a sanity check. Db.WasSaveChangesCalled.Should().BeFalse(); }
public async Task <IActionResult> Update([FromBody] TimeLogUpdateRequest req) { var poll = await GetDefaultPollAsync(); await _timeLogService.Update(Db, poll.Id, req); return(NoContent()); }
public void Must_have_additions_or_deletions() { // Set up var req = new TimeLogUpdateRequest(); // Act Func <Task> action = async() => await _service.Update(Db, _poll.Id, req); // Assert action.Should() .Throw <BadRequestException>() .WithMessage("*deletion*") .WithMessage("*addition*"); }
public async void Should_insert_deletion_entry_for_every_range() { // Set up var req = new TimeLogUpdateRequest { Deletions = new List <TimeLogDeletedRange> { new TimeLogDeletedRange { FromTime = TestFromTime, ToTime = TestFromTime + TimeSpan.FromHours(1) }, new TimeLogDeletedRange { FromTime = TestFromTime + TimeSpan.FromHours(2), ToTime = TestFromTime + TimeSpan.FromHours(3) }, } }; // Act await _service.Update(Db, _poll.Id, req); // Assert Db.WasSaveChangesCalled.Should().BeTrue(); var addedEntries = Db.Mock.TimeLogEntries.Added; addedEntries.Should().HaveCount(2); var entry0 = addedEntries[0]; entry0.IsDeletion.Should().Be(true); entry0.FromTime.Should().Be(TestFromTime + TimeSpan.FromHours(2)); entry0.ToTime.Should().Be(TestFromTime + TimeSpan.FromHours(3)); entry0.EntryText.Should().Be("[deletion]"); // Second entry var entry1 = addedEntries[1]; entry1.IsDeletion.Should().Be(true); entry1.FromTime.Should().Be(TestFromTime); entry1.ToTime.Should().Be(TestFromTime + TimeSpan.FromHours(1)); entry1.EntryText.Should().Be("[deletion]"); }
public async void Should_set_CreatedTimeUtc_to_one_msec_ago() { // Set up var req = new TimeLogUpdateRequest { Deletions = new List <TimeLogDeletedRange> { new TimeLogDeletedRange { FromTime = TestFromTime, ToTime = TestFromTime + TimeSpan.FromHours(1) }, } }; // Act await _service.Update(Db, _poll.Id, req); // Assert var expectedCreatedTimeUtc = TestUtcNow - TimeSpan.FromMilliseconds(1); var addedEntries = Db.Mock.TimeLogEntries.Added; var entry0 = addedEntries[0]; entry0.CreatedTimeUtc.Should().Be(expectedCreatedTimeUtc); }
public async Task Update(MainDbContext db, Guid pollId, TimeLogUpdateRequest req) { if ((req.Deletions == null || req.Deletions.Count == 0) && (req.Additions == null || req.Additions.Count == 0)) { throw new BadRequestException("Must provide additions or deletions."); } var createdTimeUtc = _timeService.UtcNow; // Process deletions. if (req.Deletions != null) { var sortedDeletions = req.Deletions.OrderByDescending(d => d.ToTime).ToList(); var deletionEntries = new List <TimeLogEntry>(sortedDeletions.Count); var deletionCreatedTimeUtc = createdTimeUtc - TimeSpan.FromMilliseconds(1); TimeLogEntry currentEntry = null; for (var i = 0; i < sortedDeletions.Count; i++) { var deletion = sortedDeletions[i]; // Adjust and validate time ranges. var fromTime = ToStartOfMinute(deletion.FromTime); var toTime = ToStartOfMinute(deletion.ToTime); if (fromTime >= toTime) { throw new BadRequestException( $"'fromTime' must be before 'toTime' after truncating to the start of minute. " + $"In deletion at position {i + 1} found 'fromTime': '{fromTime}', " + $"'toTime': {toTime}."); } // See if we need to extend the range or start a new one. // We don't need to compare fromTime or currentEntry.ToTime because // the entries are sorted by toTime desc. if (currentEntry != null && toTime >= currentEntry.FromTime) { // The entries overlap. Combine them into a single entry. currentEntry.FromTime = fromTime; } else { // Need to start a new entry. if (currentEntry != null) { db.TimeLogEntries.Add(currentEntry); } currentEntry = new TimeLogEntry { Id = Guid.NewGuid(), FromTime = fromTime, ToTime = toTime, EntryText = "[deletion]", TimeZone = deletion.TimeZone, TimeZoneOffset = deletion.TimeZoneOffset, CreatedTimeUtc = deletionCreatedTimeUtc, IsDeletion = true, PollId = pollId, }; } } // Save the last deletion. if (currentEntry != null) { db.TimeLogEntries.Add(currentEntry); } } // Process additions. if (req.Additions != null) { for (int i = 0; i < req.Additions.Count; i++) { var additionReq = req.Additions[i]; ValidatePollResponseAddRequest(additionReq, i); // Round down to the nearest minute. var savedFromTime = ToStartOfMinute(additionReq.TimeCollected); var newEntry = new TimeLogEntry { Id = Guid.NewGuid(), PollId = pollId, FromTime = savedFromTime, ToTime = savedFromTime + additionReq.TimeBlockLength, EntryText = additionReq.ResponseText, CreatedTimeUtc = createdTimeUtc, TimeZone = additionReq.TimeZone, TimeZoneOffset = additionReq.TimeZoneOffset, SubmissionType = additionReq.SubmissionType, }; db.TimeLogEntries.Add(newEntry); } } await db.SaveChangesAsync(); }
public Task Update(MainDbContext db, Guid pollId, TimeLogUpdateRequest req) { throw new NotImplementedException(); }