public async Task <IActionResult> GetMaintenanceJobAsync(DateTime planningDate, Guid jobId)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    // get planning
                    WorkshopPlanning planning = await _planningRepo.GetWorkshopPlanningAsync(planningDate);

                    if (planning == null || planning.Jobs == null)
                    {
                        return(NotFound());
                    }
                    // get job
                    var job = planning.Jobs.FirstOrDefault(j => j.Id == jobId);
                    if (job == null)
                    {
                        return(NotFound());
                    }
                    return(Ok(job));
                }
                catch (Exception ex)
                {
                    Log.Error(ex.ToString());
                    throw;
                }
            }
            return(BadRequest());
        }
Example #2
0
        public async Task <WorkshopPlanning> HandleCommandAsync(DateTime planningDate, PlanMaintenanceJob command)
        {
            // get or create workshop-planning
            var aggregateId = WorkshopPlanningId.Create(planningDate);
            var planning    = await _planningRepo.GetByIdAsync(aggregateId);

            if (planning == null)
            {
                planning = WorkshopPlanning.Create(planningDate);
            }

            // handle command
            planning.PlanMaintenanceJob(command);

            // persist
            IEnumerable <Event> events = planning.GetEvents();
            await _planningRepo.SaveAsync(
                planning.Id, planning.OriginalVersion, planning.Version, events);

            // publish event
            foreach (var e in events)
            {
                await _messagePublisher.PublishMessageAsync(e.MessageType, e, "");
            }

            // return result
            return(planning);
        }
Example #3
0
        public void Plan_MaintenanceJob_That_Spans_Two_Days_Should_Throw_Exception()
        {
            // arrange
            DateTime date = DateTime.Today;
            var      initializingEvents = new Event[] {
                new WorkshopPlanningCreatedEventBuilder().WithDate(date).Build()
            };
            WorkshopPlanning sut = new WorkshopPlanning(date, initializingEvents);

            MaintenanceJobBuilder maintenanceJobBuilder = new MaintenanceJobBuilder();

            maintenanceJobBuilder
            .WithStartTime(DateTime.Today.AddHours(-2));     // to make the job span 2 days
            PlanMaintenanceJob command = new PlanMaintenanceJobCommandBuilder()
                                         .WithMaintenanceJobBuilder(maintenanceJobBuilder)
                                         .Build();

            // act
            var thrownException =
                Assert.Throws <BusinessRuleViolationException>(() => sut.PlanMaintenanceJob(command));

            // assert
            Assert.Equal("Start-time and end-time of a Maintenance Job must be within a 1 day.",
                         thrownException.Message);
        }
        public async Task <WorkshopPlanning> HandleCommandAsync(DateTime planningDate, FinishMaintenanceJob command)
        {
            // get planning
            WorkshopPlanning planning = await _planningRepo.GetWorkshopPlanningAsync(planningDate);

            if (planning == null)
            {
                return(null);
            }

            // handle command
            IEnumerable <Event> events = planning.FinishMaintenanceJob(command);

            // persist
            await _planningRepo.SaveWorkshopPlanningAsync(planning, events);

            // publish event
            foreach (var e in events)
            {
                await _messagePublisher.PublishMessageAsync(e.MessageType, e, "");
            }

            // return result
            return(planning);
        }
        public async Task <WorkshopPlanning> HandleCommandAsync(DateTime planningDate, PlanMaintenanceJob command)
        {
            List <Event> events = new List <Event>();

            // get or create workshop-planning
            WorkshopPlanning planning = await _planningRepo.GetWorkshopPlanningAsync(planningDate);

            if (planning == null)
            {
                events.AddRange(WorkshopPlanning.Create(planningDate, out planning));
            }

            // handle command
            events.AddRange(planning.PlanMaintenanceJob(command));

            // persist
            await _planningRepo.SaveWorkshopPlanningAsync(
                planning.Id, planning.OriginalVersion, planning.Version, events);

            // publish event
            foreach (var e in events)
            {
                await _messagePublisher.PublishMessageAsync(e.MessageType, e, "");
            }

            // return result
            return(planning);
        }
        public async Task <IActionResult> FinishMaintenanceJobAsync(DateTime planningDate, Guid jobId, [FromBody] FinishMaintenanceJob command)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    // handle command
                    WorkshopPlanning planning = await
                                                _finishMaintenanceJobCommandHandler.HandleCommandAsync(planningDate, command);

                    // handle result
                    if (planning == null)
                    {
                        return(NotFound());
                    }

                    // return result
                    return(Ok());
                }
                return(BadRequest());
            }
            catch (ConcurrencyException)
            {
                string errorMessage = "Unable to save changes. " +
                                      "Try again, and if the problem persists " +
                                      "see your system administrator.";
                Log.Error(errorMessage);
                ModelState.AddModelError("", errorMessage);
                return(StatusCode(StatusCodes.Status500InternalServerError));
            }
        }
        public async Task <WorkshopPlanning> GetWorkshopPlanningAsync(DateTime date)
        {
            WorkshopPlanning planning = null;

            using (SqlConnection conn = new SqlConnection(_connectionString))
            {
                // get aggregate
                var aggregate = await conn
                                .QuerySingleOrDefaultAsync <Aggregate>(
                    "select * from WorkshopPlanning where Id = @Id",
                    new { Id = date.ToString("yyyy-MM-dd") });

                if (aggregate == null)
                {
                    return(null);
                }

                // get events
                IEnumerable <AggregateEvent> aggregateEvents = await conn
                                                               .QueryAsync <AggregateEvent>(
                    "select * from WorkshopPlanningEvent where Id = @Id order by [Version];",
                    new { Id = date.ToString("yyyy-MM-dd") });

                List <Event> events = new List <Event>();
                foreach (var aggregateEvent in aggregateEvents)
                {
                    events.Add(DeserializeEventData(aggregateEvent.MessageType, aggregateEvent.EventData));
                }
                planning = new WorkshopPlanning(events);
            }
            return(planning);
        }
Example #8
0
        public void Planning_Too_Much_MaintenanceJobs_In_Parallel_Should_Throw_Exception()
        {
            // arrange
            var initializingEvents = new Event[] {
                new WorkshopPlanningCreatedEventBuilder().WithDate(DateTime.Today).Build()
            };
            WorkshopPlanning sut = new WorkshopPlanning(initializingEvents);

            VehicleBuilder vehicleBuilder = new VehicleBuilder();
            PlanMaintenanceJobCommandBuilder commandBuilder = new PlanMaintenanceJobCommandBuilder()
                                                              .WithVehicleBuilder(vehicleBuilder);

            PlanMaintenanceJob command1 = commandBuilder.Build();

            vehicleBuilder.WithLicenseNumber(Guid.NewGuid().ToString());
            PlanMaintenanceJob command2 = commandBuilder.Build();

            vehicleBuilder.WithLicenseNumber(Guid.NewGuid().ToString());
            PlanMaintenanceJob command3 = commandBuilder.Build();

            vehicleBuilder.WithLicenseNumber(Guid.NewGuid().ToString());
            PlanMaintenanceJob command4 = commandBuilder.Build();

            // act
            sut.PlanMaintenanceJob(command1);
            sut.PlanMaintenanceJob(command2);
            sut.PlanMaintenanceJob(command3);
            var thrownException = Assert.Throws <BusinessRuleViolationException>(() => {
                sut.PlanMaintenanceJob(command4); // 4th parallel job
            });

            // assert
            Assert.Equal("Maintenancejob overlaps with more than 3 other jobs.",
                         thrownException.Message);
        }
Example #9
0
        public async Task SaveWorkshopPlanningAsync(WorkshopPlanning planning, IEnumerable <Event> newEvents)
        {
            using (SqlConnection conn = new SqlConnection(_connectionString))
            {
                Aggregate aggregate = await conn
                                      .QueryFirstOrDefaultAsync <Aggregate>("select * from WorkshopPlanning where Id = @Id", new { Id = planning.Id });

                if (aggregate != null)
                {
                    // add new events to existing events
                    var aggregateEvents = DeserializeState(aggregate.EventData);
                    aggregateEvents.AddRange(newEvents);

                    // determine versions
                    int currentVersion = planning.Version;
                    int newVersion     = aggregateEvents.Count;

                    // update aggregate
                    await conn.ExecuteAsync(
                        "update WorkshopPlanning set Version = @NewVersion, EventData = @EventData where Id = @Id and Version = @CurrentVersion",
                        new { Id = planning.Id, CurrentVersion = currentVersion, NewVersion = newVersion, EventData = SerializeState(aggregateEvents) });
                }
                else
                {
                    // insert new aggregate
                    var aggregateEvents = new List <Event>(newEvents);
                    await conn.ExecuteAsync(
                        "insert WorkshopPlanning (Id, Version, EventData) values (@Id, @Version, @EventData)",
                        new { Id = planning.Id, Version = aggregateEvents.Count, EventData = SerializeState(aggregateEvents) });
                }
            }
        }
Example #10
0
        public async Task <WorkshopPlanning> HandleCommandAsync(DateTime planningDate, UpdateMaintenanceJob command)
        {
            // get or create workshop-planning
            WorkshopPlanning planning = await planningRepository.GetWorkshopPlanningAsync(planningDate);

            if (planning == null)
            {
                return(null);
            }

            // handle command
            planning.UpdateMaintenanceJob(command);

            // persist
            IEnumerable <Event> events = planning.GetEvents();
            await planningRepository.SaveWorkshopPlanningAsync(
                planning.Id, planning.OriginalVersion, planning.Version, events);

            // publish event
            foreach (var e in events)
            {
                await messagePublisher.PublishMessageAsync(e.MessageType, e, "");
            }

            // return result
            return(planning);
        }
        public async Task <IActionResult> Index(DateTime?date)
        {
            return(await ExecuteWithFallback(async() =>
            {
                if (date == null)
                {
                    date = DateTime.Now.Date;
                }

                var model = new WorkshopManagementViewModel
                {
                    Date = date.Value,
                    MaintenanceJobs = new List <MaintenanceJob>()
                };

                // get planning
                string dateStr = date.Value.ToString("yyyy-MM-dd");
                WorkshopPlanning planning = await _workshopManagementAPI.GetWorkshopPlanning(dateStr);
                if (planning?.Jobs?.Count > 0)
                {
                    model.MaintenanceJobs.AddRange(planning.Jobs.OrderBy(j => j.StartTime));
                }

                return View(model);
            }));
        }
        public async Task <IActionResult> Index(DateTime?planningDate)
        {
            return(await _resiliencyHelper.ExecuteResilient(async() =>
            {
                if (planningDate == null)
                {
                    planningDate = DateTime.Now.Date;
                }

                var model = new WorkshopManagementViewModel
                {
                    Date = planningDate.Value,
                    MaintenanceJobs = new List <MaintenanceJob>()
                };

                // get planning
                string dateStr = planningDate.Value.ToString("yyyy-MM-dd");
                WorkshopPlanning planning = await _workshopManagementAPI.GetWorkshopPlanning(dateStr);
                if (planning?.Jobs?.Count > 0)
                {
                    model.MaintenanceJobs.AddRange(planning.Jobs.OrderBy(j => j.StartTime));
                }

                return View(model);
            }, View("Offline", new WorkshopManagementOfflineViewModel())));
        }
Example #13
0
        public async void FinishMaintenanceJob_Handler_Should_Handle_Command()
        {
            // arrange
            DateTime date               = DateTime.Today;
            Guid     jobId              = Guid.NewGuid();
            DateTime startTime          = date.AddHours(8);
            DateTime endTime            = date.AddHours(11);
            DateTime actualStartTime    = date.AddHours(9);
            DateTime actualEndTime      = date.AddHours(12);
            var      initializingEvents = new Event[] {
                new WorkshopPlanningCreatedEventBuilder()
                .WithDate(date)
                .Build(),
                new MaintenanceJobPlannedEventBuilder()
                .WithStartTime(startTime)
                .WithEndTime(endTime)
                .WithJobId(jobId)
                .Build()
            };
            WorkshopPlanning planning = new WorkshopPlanning(initializingEvents);

            FinishMaintenanceJob command = new FinishMaintenanceJobCommandBuilder()
                                           .WithJobId(jobId)
                                           .WithActualStartTime(actualStartTime)
                                           .WithActualEndTime(actualEndTime)
                                           .Build();

            Mock <IMessagePublisher>           messagePublisherMock = new Mock <IMessagePublisher>(MockBehavior.Strict);
            Mock <IWorkshopPlanningRepository> repoMock             = new Mock <IWorkshopPlanningRepository>(MockBehavior.Strict);

            repoMock
            .Setup(m => m.GetWorkshopPlanningAsync(It.Is <DateTime>(p => p == date)))
            .Returns(Task.FromResult(planning));

            repoMock
            .Setup(m => m.SaveWorkshopPlanningAsync(
                       It.Is <string>(p => p == planning.Id),
                       It.Is <int>(p => p == 2),
                       It.Is <int>(p => p == 3),
                       It.IsAny <IEnumerable <Event> >()
                       ))
            .Returns(Task.CompletedTask);

            messagePublisherMock
            .Setup(m => m.PublishMessageAsync(
                       It.Is <string>(p => p == "MaintenanceJobFinished"),
                       It.IsAny <object>(),
                       ""))
            .Returns(Task.CompletedTask);

            FinishMaintenanceJobCommandHandler sut =
                new FinishMaintenanceJobCommandHandler(messagePublisherMock.Object, repoMock.Object);

            // act
            await sut.HandleCommandAsync(date, command);

            // assert
            messagePublisherMock.VerifyAll();
            repoMock.VerifyAll();
        }
 public static void UpdatedMaintenanceJobShouldFallWithinOneBusinessDay(
     this WorkshopPlanning planning, UpdateMaintenanceJob command)
 {
     if (command.StartTime.Date != command.EndTime.Date)
     {
         throw new BusinessRuleViolationException("Start-time and end-time of a Maintenance Job must be within a 1 day.");
     }
 }
Example #15
0
 public static void NumberOfParallelMaintenanceJobsMustNotExceedAvailableWorkStations(
     this WorkshopPlanning planning, PlanMaintenanceJob command)
 {
     if (planning.Jobs.Count(j => j.PlannedTimeslot.OverlapsWith(command.StartTime, command.EndTime)) >= AVAILABLE_WORKSTATIONS)
     {
         throw new BusinessRuleViolationException($"Maintenancejob overlaps with more than {AVAILABLE_WORKSTATIONS} other jobs.");
     }
 }
Example #16
0
    /// <summary>
    /// Creates a new instance of a workshop-planning for the specified date.
    /// </summary>
    /// <param name="date">The date to create the planning for.</param>
    public static WorkshopPlanning Create(DateTime date)
    {
        WorkshopPlanning        planning = new WorkshopPlanning(date);
        WorkshopPlanningCreated e        = new WorkshopPlanningCreated(Guid.NewGuid(), date);

        planning.RaiseEvent(e);
        return(planning);
    }
Example #17
0
 public static void NumberOfParallelMaintenanceJobsOnAVehicleMustNotExceedOne(
     this WorkshopPlanning planning, PlanMaintenanceJob command)
 {
     if (planning.Jobs.Any(j => j.Vehicle.Id == command.VehicleInfo.LicenseNumber &&
                           j.PlannedTimeslot.OverlapsWith(command.StartTime, command.EndTime)))
     {
         throw new BusinessRuleViolationException($"Only 1 maintenance job can be executed on a vehicle during a certain time-slot.");
     }
 }
        public async void FinishMaintenanceJob_Handler_Should_Handle_Command()
        {
            // arrange
            DateTime date               = DateTime.Today;
            Guid     jobId              = Guid.NewGuid();
            DateTime startTime          = date.AddHours(8);
            DateTime endTime            = date.AddHours(11);
            DateTime actualStartTime    = date.AddHours(9);
            DateTime actualEndTime      = date.AddHours(12);
            var      customerInfo       = ("customer id", "customer name", "123456780");
            var      vehicleInfo        = ("AB-123-C", "Volkswagen", "Tiguan");
            string   description        = "Job description";
            var      initializingEvents = new Event[] {
                new WorkshopPlanningCreated(Guid.NewGuid(), date),
                new MaintenanceJobPlanned(Guid.NewGuid(), jobId, startTime, endTime,
                                          customerInfo, vehicleInfo, description)
            };
            WorkshopPlanning planning = new WorkshopPlanning(initializingEvents);

            FinishMaintenanceJob command = new FinishMaintenanceJob(Guid.NewGuid(), jobId,
                                                                    actualStartTime, actualEndTime, "Notes");

            Mock <IMessagePublisher>           messagePublisherMock = new Mock <IMessagePublisher>(MockBehavior.Strict);
            Mock <IWorkshopPlanningRepository> repoMock             = new Mock <IWorkshopPlanningRepository>(MockBehavior.Strict);

            repoMock
            .Setup(m => m.GetWorkshopPlanningAsync(It.Is <DateTime>(p => p == date)))
            .Returns(Task.FromResult(planning));

            repoMock
            .Setup(m => m.SaveWorkshopPlanningAsync(
                       It.Is <string>(p => p == planning.Id),
                       It.Is <int>(p => p == 2),
                       It.Is <int>(p => p == 3),
                       It.IsAny <IEnumerable <Event> >()
                       ))
            .Returns(Task.CompletedTask);

            messagePublisherMock
            .Setup(m => m.PublishMessageAsync(
                       It.Is <string>(p => p == "MaintenanceJobFinished"),
                       It.IsAny <object>(),
                       ""))
            .Returns(Task.CompletedTask);

            FinishMaintenanceJobCommandHandler sut =
                new FinishMaintenanceJobCommandHandler(messagePublisherMock.Object, repoMock.Object);

            // act
            await sut.HandleCommandAsync(date, command);

            // assert
            messagePublisherMock.VerifyAll();
            repoMock.VerifyAll();
        }
 public static void NumberOfParallelMaintenanceJobsMustNotExceedAvailableWorkStations(
     this WorkshopPlanning planning, UpdateMaintenanceJob command)
 {
     if (planning.Jobs.Count(j =>
                             (j.Id != command.JobId) &&
                             ((j.StartTime >= command.StartTime && j.StartTime <= command.EndTime) ||
                              (j.EndTime >= command.StartTime && j.EndTime <= command.EndTime))) >= AVAILABLE_WORKSTATIONS)
     {
         throw new BusinessRuleViolationException($"Maintenancejob overlaps with more than {AVAILABLE_WORKSTATIONS} other jobs.");
     }
 }
 public static void NumberOfParallelMaintenanceJobsOnAVehicleIsOne(
     this WorkshopPlanning planning, UpdateMaintenanceJob command)
 {
     if (planning.Jobs.Any(j => j.Id != command.JobId &&
                           j.Vehicle.Id == command.VehicleInfo.LicenseNumber &&
                           (j.StartTime >= command.StartTime && j.StartTime <= command.EndTime ||
                            j.EndTime >= command.StartTime && j.EndTime <= command.EndTime)))
     {
         throw new BusinessRuleViolationException($"Only 1 maintenance job can be executed on a vehicle during a certain time-slot.");
     }
 }
        public async void Given_A_Non_Existing_Job_The_Handler_Should_Return_Null()
        {
            // arrange
            DateTime           date = DateTime.Today;
            string             workshopPlanningId = date.ToString("yyy-MM-dd");
            PlanMaintenanceJob command            = new PlanMaintenanceJobCommandBuilder()
                                                    .Build();

            Mock <IMessagePublisher> messagePublisherMock = new Mock <IMessagePublisher>();
            Mock <IEventSourceRepository <WorkshopPlanning> > repoMock =
                new Mock <IEventSourceRepository <WorkshopPlanning> >();

            repoMock
            .Setup(m => m.GetByIdAsync(It.Is <string>(p => p == workshopPlanningId)))
            .Returns(Task.FromResult <WorkshopPlanning>(null));

            repoMock
            .Setup(m => m.SaveAsync(
                       It.Is <string>(p => p == workshopPlanningId),
                       It.Is <int>(p => p == 0),
                       It.Is <int>(p => p == 2),
                       It.Is <IEnumerable <Event> >(p =>
                                                    p.First().MessageType == "WorkshopPlanningCreated" &&
                                                    p.Last().MessageType == "MaintenanceJobPlanned")
                       ))
            .Returns(Task.CompletedTask);

            messagePublisherMock
            .Setup(m => m.PublishMessageAsync(
                       It.Is <string>(p => p == "WorkshopPlanningCreated"),
                       It.IsAny <object>(),
                       ""))
            .Returns(Task.CompletedTask);

            messagePublisherMock
            .Setup(m => m.PublishMessageAsync(
                       It.Is <string>(p => p == "MaintenanceJobPlanned"),
                       It.IsAny <object>(),
                       ""))
            .Returns(Task.CompletedTask);

            PlanMaintenanceJobCommandHandler sut =
                new PlanMaintenanceJobCommandHandler(messagePublisherMock.Object, repoMock.Object);

            // act
            WorkshopPlanning result = await sut.HandleCommandAsync(date, command);

            // assert
            messagePublisherMock.VerifyAll();
            messagePublisherMock.VerifyNoOtherCalls();
            repoMock.VerifyAll();
            repoMock.VerifyNoOtherCalls();
            Assert.IsAssignableFrom <WorkshopPlanning>(result);
        }
        public async void Given_An_Existing_Job_The_Handler_Should_Handle_The_Command()
        {
            // arrange
            DateTime date = DateTime.Today;
            string   workshopPlanningId = date.ToString("yyy-MM-dd");
            var      initializingEvents = new Event[] {
                new WorkshopPlanningCreatedEventBuilder().WithDate(date).Build()
            };
            WorkshopPlanning planning = new WorkshopPlanning(date, initializingEvents);

            PlanMaintenanceJob command = new PlanMaintenanceJobCommandBuilder()
                                         .Build();

            Mock <IMessagePublisher> messagePublisherMock = new Mock <IMessagePublisher>();
            Mock <IEventSourceRepository <WorkshopPlanning> > repoMock =
                new Mock <IEventSourceRepository <WorkshopPlanning> >();

            repoMock
            .Setup(m => m.GetByIdAsync(It.Is <string>(p => p == workshopPlanningId)))
            .Returns(Task.FromResult(planning));

            repoMock
            .Setup(m => m.SaveAsync(
                       It.Is <string>(p => p == planning.Id),
                       It.Is <int>(p => p == 1),
                       It.Is <int>(p => p == 2),
                       It.IsAny <List <Event> >()
                       ))
            .Returns(Task.CompletedTask);

            messagePublisherMock
            .Setup(m => m.PublishMessageAsync(
                       It.Is <string>(p => p == "MaintenanceJobPlanned"),
                       It.IsAny <object>(),
                       ""))
            .Returns(Task.CompletedTask);

            PlanMaintenanceJobCommandHandler sut =
                new PlanMaintenanceJobCommandHandler(messagePublisherMock.Object, repoMock.Object);

            // act
            WorkshopPlanning result = await sut.HandleCommandAsync(date, command);

            // assert
            messagePublisherMock.VerifyAll();
            messagePublisherMock.VerifyNoOtherCalls();
            repoMock.VerifyAll();
            repoMock.VerifyNoOtherCalls();
            Assert.IsAssignableFrom <WorkshopPlanning>(result);
        }
        public async void Given_A_Non_Existing_Job_The_Handler_Should_Return_Null()
        {
            // arrange
            DateTime           date    = DateTime.Today;
            PlanMaintenanceJob command = new PlanMaintenanceJobCommandBuilder()
                                         .Build();

            Mock <IMessagePublisher>           messagePublisherMock = new Mock <IMessagePublisher>(MockBehavior.Strict);
            Mock <IWorkshopPlanningRepository> repoMock             = new Mock <IWorkshopPlanningRepository>(MockBehavior.Strict);

            repoMock
            .Setup(m => m.GetWorkshopPlanningAsync(It.Is <DateTime>(p => p == date)))
            .Returns(Task.FromResult <WorkshopPlanning>(null));

            repoMock
            .Setup(m => m.SaveWorkshopPlanningAsync(
                       It.Is <string>(p => p == date.ToString("yyyy-MM-dd")),
                       It.Is <int>(p => p == 0),
                       It.Is <int>(p => p == 2),
                       It.Is <List <Event> >(p =>
                                             p[0].MessageType == "WorkshopPlanningCreated" &&
                                             p[1].MessageType == "MaintenanceJobPlanned")
                       ))
            .Returns(Task.CompletedTask);

            messagePublisherMock
            .Setup(m => m.PublishMessageAsync(
                       It.Is <string>(p => p == "WorkshopPlanningCreated"),
                       It.IsAny <object>(),
                       ""))
            .Returns(Task.CompletedTask);

            messagePublisherMock
            .Setup(m => m.PublishMessageAsync(
                       It.Is <string>(p => p == "MaintenanceJobPlanned"),
                       It.IsAny <object>(),
                       ""))
            .Returns(Task.CompletedTask);

            PlanMaintenanceJobCommandHandler sut =
                new PlanMaintenanceJobCommandHandler(messagePublisherMock.Object, repoMock.Object);

            // act
            WorkshopPlanning result = await sut.HandleCommandAsync(date, command);

            // assert
            messagePublisherMock.VerifyAll();
            repoMock.VerifyAll();
            Assert.IsAssignableFrom <WorkshopPlanning>(result);
        }
Example #24
0
        public void Finish_MaintenanceJob_Should_Finish_A_New_MaintenanceJob()
        {
            // arrange
            DateTime date = DateTime.Today;
            string   workshopPlanningId = date.ToString("yyyy-MM-dd");
            Guid     jobId              = Guid.NewGuid();
            DateTime startTime          = date.AddHours(8);
            DateTime endTime            = date.AddHours(11);
            DateTime actualStartTime    = date.AddHours(9);
            DateTime actualEndTime      = date.AddHours(12);
            var      initializingEvents = new Event[] {
                new WorkshopPlanningCreatedEventBuilder()
                .WithDate(date)
                .Build(),
                new MaintenanceJobPlannedEventBuilder()
                .WithStartTime(startTime)
                .WithEndTime(endTime)
                .WithJobId(jobId)
                .Build()
            };
            WorkshopPlanning sut = new WorkshopPlanning(date, initializingEvents);

            FinishMaintenanceJob command = new FinishMaintenanceJobCommandBuilder()
                                           .WithJobId(jobId)
                                           .WithActualStartTime(actualStartTime)
                                           .WithActualEndTime(actualEndTime)
                                           .Build();

            // act
            sut.FinishMaintenanceJob(command);
            IEnumerable <Event> events = sut.GetEvents();

            // assert
            Assert.NotNull(sut);
            Assert.NotNull(sut.Id);
            Assert.Equal(workshopPlanningId, sut.Id);
            Assert.Equal(2, sut.OriginalVersion);
            Assert.Equal(3, sut.Version);
            Assert.Collection(sut.Jobs,
                              item0 =>
            {
                Assert.Equal(command.JobId, item0.Id);
                Assert.Equal(startTime, item0.StartTime);
                Assert.Equal(endTime, item0.EndTime);
                Assert.Equal(command.StartTime, item0.ActualStartTime);
                Assert.Equal(command.Notes, item0.Notes);
            }
                              );
            Assert.Collection(events, item0 => Assert.IsAssignableFrom <MaintenanceJobFinished>(item0));
        }
Example #25
0
        public void Updating_A_Job_That_Conflicts_With_MaintenanceJobs_In_Parallel_Should_Throw_Exception()
        {
            // arrange
            var date      = DateTime.Today;
            var jobId     = Guid.NewGuid();
            var startTime = date.AddHours(12);
            var endTime   = date.AddHours(13);

            var createdEvent = new WorkshopPlanningCreatedEventBuilder()
                               .WithDate(date)
                               .Build();
            var plannedEvent1 = new MaintenanceJobPlannedEventBuilder()
                                .Build();
            var plannedEvent2 = new MaintenanceJobPlannedEventBuilder()
                                .Build();
            var plannedEvent3 = new MaintenanceJobPlannedEventBuilder()
                                .Build();

            var plannedEvent4 = new MaintenanceJobPlannedEventBuilder()
                                .WithStartTime(startTime)
                                .WithEndTime(endTime)
                                .WithJobId(jobId)
                                .Build();

            var initializingEvents = new Event[] {
                createdEvent,
                plannedEvent1,
                plannedEvent2,
                plannedEvent3,
                plannedEvent4
            };

            var sut = new WorkshopPlanning(date, initializingEvents);

            var command = new UpdateMaintenanceJobCommandBuilder()
                          .WithEvent(plannedEvent4)
                          .WithChangedStartTime(plannedEvent1.StartTime)
                          .WithChangedEndTime(plannedEvent1.EndTime)
                          .Build();

            // act
            var thrownException = Assert.Throws <BusinessRuleViolationException>(() =>
            {
                sut.UpdateMaintenanceJob(command); // 4th job is updated to conflict with the 1st job
            });

            // assert
            Assert.Equal("Maintenancejob overlaps with more than 3 other jobs.", thrownException.Message);
        }
        public async Task <IActionResult> PlanMaintenanceJobAsync(DateTime date, [FromBody] PlanMaintenanceJob command)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    // get planning
                    WorkshopPlanning planning = await _planningRepo.GetWorkshopPlanningAsync(date);

                    if (planning == null)
                    {
                        return(NotFound());
                    }

                    // handle command
                    try
                    {
                        IEnumerable <Event> events = planning.PlanMaintenanceJob(command);

                        // persist
                        await _planningRepo.SaveWorkshopPlanningAsync(planning, events);

                        // publish event
                        foreach (var e in events)
                        {
                            await _messagePublisher.PublishMessageAsync(e.MessageType, e, "");
                        }

                        // return result
                        return(CreatedAtRoute("GetByDate", new { date = planning.Date }, planning));
                    }
                    catch (BusinessRuleViolationException ex)
                    {
                        return(StatusCode(StatusCodes.Status409Conflict, new BusinessRuleViolation {
                            ErrorMessage = ex.Message
                        }));
                    }
                }
                return(BadRequest());
            }
            catch (ConcurrencyException)
            {
                ModelState.AddModelError("ErrorMessage", "Unable to save changes. " +
                                         "Try again, and if the problem persists " +
                                         "see your system administrator.");
                return(StatusCode(StatusCodes.Status500InternalServerError));
            }
        }
Example #27
0
        public async void Given_An_Existing_Job_The_Handler_Should_Handle_The_Command()
        {
            // arrange
            DateTime date = DateTime.Today;
            var      initializingEvents = new Event[] {
                new WorkshopPlanningCreated(Guid.NewGuid(), date)
            };
            WorkshopPlanning planning = new WorkshopPlanning(initializingEvents);

            PlanMaintenanceJob command = new PlanMaintenanceJobCommandBuilder()
                                         .Build();

            Mock <IMessagePublisher>           messagePublisherMock = new Mock <IMessagePublisher>(MockBehavior.Strict);
            Mock <IWorkshopPlanningRepository> repoMock             = new Mock <IWorkshopPlanningRepository>(MockBehavior.Strict);

            repoMock
            .Setup(m => m.GetWorkshopPlanningAsync(It.Is <DateTime>(p => p == date)))
            .Returns(Task.FromResult(planning));

            repoMock
            .Setup(m => m.SaveWorkshopPlanningAsync(
                       It.Is <string>(p => p == planning.Id),
                       It.Is <int>(p => p == 1),
                       It.Is <int>(p => p == 2),
                       It.IsAny <List <Event> >()
                       ))
            .Returns(Task.CompletedTask);

            messagePublisherMock
            .Setup(m => m.PublishMessageAsync(
                       It.Is <string>(p => p == "MaintenanceJobPlanned"),
                       It.IsAny <object>(),
                       ""))
            .Returns(Task.CompletedTask);

            PlanMaintenanceJobCommandHandler sut =
                new PlanMaintenanceJobCommandHandler(messagePublisherMock.Object, repoMock.Object);

            // act
            WorkshopPlanning result = await sut.HandleCommandAsync(date, command);

            // assert
            messagePublisherMock.VerifyAll();
            repoMock.VerifyAll();
            Assert.IsAssignableFrom <WorkshopPlanning>(result);
        }
Example #28
0
        public void Create_Should_Create_A_New_Instance()
        {
            // arrange
            DateTime date = DateTime.Today;

            // act
            List <Event> events = new List <Event>(WorkshopPlanning.Create(date, out WorkshopPlanning sut));

            // assert
            Assert.NotNull(sut);
            Assert.NotNull(sut.Id);
            Assert.Equal(date, sut.Date);
            Assert.Equal(0, sut.OriginalVersion);
            Assert.Equal(1, sut.Version);
            Assert.Empty(sut.Jobs);
            Assert.Collection(events, item0 => Assert.IsAssignableFrom <WorkshopPlanningCreated>(item0));
        }
Example #29
0
        public async Task <WorkshopPlanning> GetWorkshopPlanningAsync(DateTime date)
        {
            WorkshopPlanning planning = null;

            using (SqlConnection conn = new SqlConnection(_connectionString))
            {
                Aggregate aggregate = await conn
                                      .QueryFirstOrDefaultAsync <Aggregate>("select * from WorkshopPlanning where Id = @Id", new { Id = date.ToString("yyyy-MM-dd") });

                if (aggregate != null)
                {
                    IEnumerable <Event> events = DeserializeState(aggregate.EventData);
                    planning = new WorkshopPlanning(events);
                }
            }

            return(planning);
        }
Example #30
0
        public void Finish_An_Already_Finished_MaintenanceJob_Should_Throw_Exception()
        {
            // arrange
            DateTime date               = DateTime.Today;
            Guid     jobId              = Guid.NewGuid();
            DateTime startTime          = date.AddHours(8);
            DateTime endTime            = date.AddHours(11);
            DateTime actualStartTime    = date.AddHours(9);
            DateTime actualEndTime      = date.AddHours(12);
            string   notes              = "Ok";
            var      initializingEvents = new Event[] {
                new WorkshopPlanningCreatedEventBuilder()
                .WithDate(date)
                .Build(),
                new MaintenanceJobPlannedEventBuilder()
                .WithStartTime(startTime)
                .WithEndTime(endTime)
                .WithJobId(jobId)
                .Build(),
                new MaintenanceJobFinishedEventBuilder()
                .WithJobId(jobId)
                .WithActualStartTime(actualStartTime)
                .WithActualEndTime(actualEndTime)
                .WithNotes(notes)
                .Build()
            };
            WorkshopPlanning sut = new WorkshopPlanning(initializingEvents);

            FinishMaintenanceJob command = new FinishMaintenanceJobCommandBuilder()
                                           .WithJobId(jobId)
                                           .WithActualStartTime(actualStartTime)
                                           .WithActualEndTime(actualEndTime)
                                           .WithNotes(notes)
                                           .Build();

            // act
            var thrownException =
                Assert.Throws <BusinessRuleViolationException>(() =>
                                                               sut.FinishMaintenanceJob(command));

            // assert
            Assert.Equal("An already finished job can not be finished.",
                         thrownException.Message);
        }