public void WorkItemLink_addNew_succeeds() { var logger = new DebugEventLogger(); var settings = TestHelpers.LoadConfigFromResourceFile("NewObjects.policies", logger); var repository = new WorkItemRepositoryMock(); var parent = new WorkItemMock(repository); parent.Id = 1; parent.TypeName = "Use Case"; parent["Title"] = "UC"; var child = new WorkItemMock(repository); child.Id = 2; child.TypeName = "Task"; child["Title"] = "TSK"; repository.SetWorkItems(new[] { parent, child }); var context = Substitute.For<IRequestContext>(); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger); using (var processor = new EventProcessor(repository, runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(2); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); Assert.IsTrue(child.InternalWasSaveCalled); Assert.AreEqual(EventNotificationStatus.ActionPermitted, result.NotificationStatus); } }
public void Can_execute_a_Powershell_noop_rule() { var logger = Substitute.For<ILogEvents>(); var settings = TestHelpers.LoadConfigFromResourceFile("NoOp.policies", logger); var repository = Substitute.For<IWorkItemRepository>(); var workItem = Substitute.For<IWorkItem>(); var context = Substitute.For<IRequestContext>(); context.GetProjectCollectionUri().Returns( new System.Uri("http://localhost:8080/tfs/DefaultCollection")); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger, (c, i, l) => repository); using (var processor = new EventProcessor(runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(1); repository.LoadedWorkItems.Returns( new ReadOnlyCollection<IWorkItem>(new List<IWorkItem>() { workItem })); repository.CreatedWorkItems.Returns( new ReadOnlyCollection<IWorkItem>(new List<IWorkItem>())); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); Assert.AreEqual(EventNotificationStatus.ActionPermitted, result.NotificationStatus); } }
public void RulesAndPolicy_SpecificCollection_TwoPoliciesTwoRulesApplies() { var logger = Substitute.For<ILogEvents>(); var settings = TestHelpers.LoadConfigFromResourceFile("RulesAndPolicy.policies", logger); var repository = this.MakeRepositoryMock(); var context = Substitute.For<IRequestContext>(); context.CollectionName.Returns("Collection1"); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger); using (var processor = new EventProcessor(repository, runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(2); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); Assert.AreEqual( Microsoft.TeamFoundation.Framework.Server.EventNotificationStatus.ActionPermitted, result.NotificationStatus); object expected = 42; logger.Received().ResultsFromScriptRun("Noop1", expected); logger.Received().ResultsFromScriptRun("Noop2", expected); logger.DidNotReceive().ResultsFromScriptRun("Noop3", expected); } }
public void GlobalList_UserParameterAddValue_Succeeded() { var logger = new DebugEventLogger(); var settings = TestHelpers.LoadConfigFromResourceFile("UserParameters.policies", logger); var repository = new WorkItemRepositoryMock(); var workItem = new WorkItemMock(repository); workItem.Id = 1; workItem.TypeName = "Use Case"; workItem["Title"] = "The car shall have a maximum speed of {myParameter} mph."; repository.SetWorkItems(new[] { workItem }); var context = Substitute.For<IRequestContext>(); context.GetProjectCollectionUri().Returns( new System.Uri("http://localhost:8080/tfs/DefaultCollection")); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger, (c, i, l) => repository); using (var processor = new EventProcessor(runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(1); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); Assert.IsTrue(workItem.InternalWasSaveCalled); Assert.AreEqual("The car shall have a maximum speed of {myParameter}(30) mph.", workItem.Fields["Title"].Value); Assert.AreEqual(EventNotificationStatus.ActionPermitted, result.NotificationStatus); } }
public void Should_aggregate_a_numeric_field_short() { var logger = Substitute.For<ILogEvents>(); var settings = TestHelpers.LoadConfigFromResourceFile("SumFieldsOnSingleWorkItem-Short.policies", logger); var alternateRepository = this.SetupFakeRepository_Short(); var context = Substitute.For<IRequestContext>(); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger); using (var processor = new EventProcessor(alternateRepository, runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(1); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); this.workItem.Received().Save(); Assert.AreEqual(3.0D, this.workItem["Estimated Work"]); Assert.AreEqual(EventNotificationStatus.ActionPermitted, result.NotificationStatus); } }
public void Should_aggregate_a_numeric_field() { var logger = Substitute.For<ILogEvents>(); var settings = TestHelpers.LoadConfigFromResourceFile("SumFieldsOnSingleWorkItem.policies", logger); var alternateRepository = this.SetupFakeRepository(); var context = Substitute.For<IRequestContext>(); context.GetProjectCollectionUri().Returns( new System.Uri("http://localhost:8080/tfs/DefaultCollection")); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger, (c, i, l) => alternateRepository); using (var processor = new EventProcessor(runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(1); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); this.workItem.Received().Save(); Assert.AreEqual(3.0D, this.workItem.Fields["Estimated Work"].Value); Assert.AreEqual(EventNotificationStatus.ActionPermitted, result.NotificationStatus); } }
public void WorkItemLink_addExisting_noop() { var logger = new DebugEventLogger(); var settings = TestHelpers.LoadConfigFromResourceFile("NewObjects.policies", logger); var repository = new WorkItemRepositoryMock(); var parent = new WorkItemMock(repository); parent.Id = 1; parent.TypeName = "Use Case"; parent["Title"] = "UC"; var child = new WorkItemMock(repository); child.Id = 2; child.TypeName = "Task"; child["Title"] = "TSK"; child.WorkItemLinks.Add(new WorkItemLinkMock(WorkItemImplementationBase.ParentRelationship, parent.Id, repository)); repository.SetWorkItems(new[] { parent, child }); var context = Substitute.For<IRequestContext>(); context.GetProjectCollectionUri().Returns( new System.Uri("http://localhost:8080/tfs/DefaultCollection")); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger, (c, i, l) => repository); using (var processor = new EventProcessor(runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(2); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); Assert.IsFalse(child.InternalWasSaveCalled); Assert.IsFalse(parent.InternalWasSaveCalled); Assert.AreEqual(EventNotificationStatus.ActionPermitted, result.NotificationStatus); } }
public void WorkItem_addNew_succeeds() { var logger = new DebugEventLogger(); var settings = TestHelpers.LoadConfigFromResourceFile("NewObjects.policies", logger); var repository = new WorkItemRepositoryMock(); var parent = new WorkItemMock(repository); parent.Id = 1; parent.TypeName = "Bug"; parent["Title"] = "My bug #1"; repository.SetWorkItems(new[] { parent }); var context = Substitute.For<IRequestContext>(); context.GetProjectCollectionUri().Returns( new System.Uri("http://localhost:8080/tfs/DefaultCollection")); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger, (c, i, l) => repository); using (var processor = new EventProcessor(runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(1); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); Assert.AreEqual(1, repository.LoadedWorkItems.Count); Assert.AreEqual(1, repository.CreatedWorkItems.Count); Assert.IsTrue(parent.InternalWasSaveCalled); Assert.IsTrue(parent.HasChildren()); } }
/// <summary> /// Called by the ManyConsole framework to execute the <i>run</i> command. /// </summary> /// <param name="remainingArguments">Unparsed command line arguments.</param> /// <returns>0 for success, error code otherwise</returns> public override int Run(string[] remainingArguments) { // need a logger to show errors in config file (Catch 22) var logger = new ConsoleEventLogger(LogLevel.Warning); var runtime = RuntimeContext.GetContext( () => this.PolicyFile, new RequestContext(this.TeamProjectCollectionUrl, this.TeamProjectName), logger); if (runtime.HasErrors) { return 99; } logger.ConfigurationLoaded(this.PolicyFile); using (EventProcessor eventProcessor = new EventProcessor(this.TeamProjectCollectionUrl, null, runtime)) { try { var context = runtime.RequestContext; var notification = new Notification(this.WorkItemId, this.TeamProjectName); logger.StartingProcessing(context, notification); ProcessingResult result = eventProcessor.ProcessEvent(context, notification); logger.ProcessingCompleted(result); return result.StatusCode; } catch (Exception e) { logger.ProcessEventException(e); return -1; } } }
public void Should_aggregate_to_parent() { var logger = Substitute.For<ILogEvents>(); var settings = TestHelpers.LoadConfigFromResourceFile("Rollup.policies", logger); var alternateRepository = new WorkItemRepositoryMock(); var grandParent = new WorkItemMock(alternateRepository); grandParent.Id = 1; grandParent.TypeName = "Feature"; grandParent["Dev Estimate"] = 0.0D; grandParent["Test Estimate"] = 0.0D; var parent = new WorkItemMock(alternateRepository); parent.Id = 2; parent.TypeName = "Use Case"; parent.WorkItemLinks.Add(new WorkItemLinkMock("Parent", 1, alternateRepository)); grandParent.WorkItemLinks.Add(new WorkItemLinkMock("Child", 2, alternateRepository)); parent["Total Work Remaining"] = 3.0D; parent["Total Estimate"] = 4.0D; var child = new WorkItemMock(alternateRepository); child.Id = 3; child.TypeName = "Task"; child.WorkItemLinks.Add(new WorkItemLinkMock("Parent", 2, alternateRepository)); parent.WorkItemLinks.Add(new WorkItemLinkMock("Child", 3, alternateRepository)); child["Estimated Dev Work"] = 10.0D; child["Estimated Test Work"] = 20.0D; child["Remaining Dev Work"] = 1.0D; child["Remaining Test Work"] = 2.0D; child["Finish Date"] = new DateTime(2015, 1, 1); child.WorkItemLinks.Add(new WorkItemLinkMock(WorkItemImplementationBase.ParentRelationship, parent.Id, alternateRepository)); parent.WorkItemLinks.Add(new WorkItemLinkMock(WorkItemImplementationBase.ParentRelationship, grandParent.Id, alternateRepository)); alternateRepository.SetWorkItems(new[] { grandParent, parent, child }); var context = Substitute.For<IRequestContext>(); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger); using (var processor = new EventProcessor(alternateRepository, runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(3); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); Assert.IsFalse(child.InternalWasSaveCalled); Assert.IsTrue(parent.InternalWasSaveCalled); Assert.IsFalse(grandParent.InternalWasSaveCalled); Assert.AreEqual(3.0D, parent["Total Work Remaining"]); Assert.AreEqual(30.0D, parent["Total Estimate"]); Assert.AreEqual(EventNotificationStatus.ActionPermitted, result.NotificationStatus); } }
/// <summary> /// This is the one where all the magic starts. Main() so to speak. I will load the settings, connect to TFS and apply the aggregation rules. /// </summary> public EventNotificationStatus ProcessEvent( IVssRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { var logger = new ServerEventLogger(LogLevel.Normal); var context = new RequestContextWrapper(requestContext, notificationType, notificationEventArgs); var runtime = RuntimeContext.GetContext( GetServerSettingsFullPath, context, logger, (collectionUri, toImpersonate, logEvents) => new WorkItemRepository(collectionUri, toImpersonate, logEvents)); if (runtime.HasErrors) { statusCode = 99; statusMessage = string.Join(". ", runtime.Errors); properties = null; return EventNotificationStatus.ActionPermitted; } var result = new ProcessingResult(); try { // Check if we have a workitem changed event before proceeding if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent) { using (EventProcessor eventProcessor = new EventProcessor(runtime)) { logger.StartingProcessing(context, context.Notification); result = eventProcessor.ProcessEvent(context, context.Notification); logger.ProcessingCompleted(result); } } } catch (Exception e) { logger.ProcessEventException(e); // notify failure result.StatusCode = -1; result.StatusMessage = "Unexpected error: " + e.Message; result.NotificationStatus = EventNotificationStatus.ActionPermitted; } statusCode = result.StatusCode; statusMessage = result.StatusMessage; properties = result.ExceptionProperties; return result.NotificationStatus; }
/// <summary> /// Called by the ManyConsole framework to execute the <i>run</i> command. /// </summary> /// <param name="remainingArguments">Unparsed command line arguments.</param> /// <returns>0 for success, error code otherwise</returns> public override int Run(string[] remainingArguments) { // cache requires absolute path this.PolicyFile = System.IO.Path.GetFullPath(this.PolicyFile); // need a logger to show errors in config file (Catch 22) var logger = new ConsoleEventLogger(LogLevel.Normal); var context = new RequestContext(this.TeamProjectCollectionUrl, this.TeamProjectName); var runtime = RuntimeContext.GetContext( () => this.PolicyFile, context, logger, (collectionUri, toImpersonate, logEvents) => new Core.Facade.WorkItemRepository(collectionUri, toImpersonate, logEvents)); if (!string.IsNullOrWhiteSpace(this.LogLevelName)) { // command line wins LogLevel logLevel = (LogLevel)Enum.Parse(typeof(LogLevel), this.LogLevelName, true); runtime.Logger.MinimumLogLevel = logLevel; } if (runtime.HasErrors) { return 3; } using (EventProcessor eventProcessor = new EventProcessor(runtime)) { try { var workItemIds = new Queue<int>(); workItemIds.Enqueue(this.WorkItemId); ProcessingResult result = null; while (workItemIds.Count > 0) { context.CurrentWorkItemId = workItemIds.Dequeue(); var notification = context.Notification; logger.StartingProcessing(context, notification); result = eventProcessor.ProcessEvent(context, notification); logger.ProcessingCompleted(result); foreach (var savedId in eventProcessor.SavedWorkItems) { workItemIds.Enqueue(savedId); } } return result.StatusCode; } catch (Exception e) { logger.ProcessEventException(e); return 1; } } }
public void RulesAndPolicy_TypeFilter_OnePoliciesOneRulesApplies() { var logger = Substitute.For<ILogEvents>(); var settings = TestHelpers.LoadConfigFromResourceFile("RulesAndPolicy.policies", logger); var repository = new WorkItemRepositoryMock(); var workItem = new WorkItemMock(repository); workItem.Id = 1; workItem.TypeName = "Bug"; workItem["Title"] = "My bug"; repository.SetWorkItems(new[] { workItem }); var context = Substitute.For<IRequestContext>(); context.GetProjectCollectionUri().Returns( new System.Uri("http://localhost:8080/tfs/DefaultCollection")); context.CollectionName.Returns("Collection2"); var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger, (c, i, l) => repository); using (var processor = new EventProcessor(runtime)) { var notification = Substitute.For<INotification>(); notification.WorkItemId.Returns(1); var result = processor.ProcessEvent(context, notification); Assert.AreEqual(0, result.ExceptionProperties.Count()); Assert.AreEqual( Microsoft.TeamFoundation.Framework.Server.EventNotificationStatus.ActionPermitted, result.NotificationStatus); object expected = 42; logger.DidNotReceive().ResultsFromScriptRun("Noop1", expected); logger.DidNotReceive().ResultsFromScriptRun("Noop2", expected); logger.Received().ResultsFromScriptRun("Noop3", expected); } }
/// <summary> /// This is the one where all the magic starts. Main() so to speak. I will load the settings, connect to TFS and apply the aggregation rules. /// </summary> public EventNotificationStatus ProcessEvent( TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { var runtime = RuntimeContext.GetContext( GetServerSettingsFullPath, new RequestContextWrapper(requestContext), new ServerEventLogger(LogLevel.Normal)); if (runtime.HasErrors) { statusCode = 99; statusMessage = string.Join(". ", runtime.Errors); properties = null; return EventNotificationStatus.ActionPermitted; } // HACK: remove cast for ProcessEventException var logger = (ServerEventLogger)runtime.Logger; var result = new ProcessingResult(); try { // Check if we have a workitem changed event before proceeding if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent) { var uri = this.GetCollectionUriFromContext(requestContext); IdentityDescriptor toImpersonate = null; if (runtime.Settings.AutoImpersonate) { toImpersonate = this.GetIdentityToImpersonate(requestContext, notificationEventArgs as WorkItemChangedEvent); } using (EventProcessor eventProcessor = new EventProcessor(uri.AbsoluteUri, toImpersonate, runtime)) { var context = runtime.RequestContext; var notification = new NotificationWrapper( notificationType, notificationEventArgs as WorkItemChangedEvent); logger.StartingProcessing(context, notification); result = eventProcessor.ProcessEvent(context, notification); logger.ProcessingCompleted(result); } } } catch (Exception e) { logger.ProcessEventException(e); // notify failure result.StatusCode = -1; result.StatusMessage = "Unexpected error: " + e.Message; result.NotificationStatus = EventNotificationStatus.ActionPermitted; } statusCode = result.StatusCode; statusMessage = result.StatusMessage; properties = result.ExceptionProperties; return result.NotificationStatus; }