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 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>();
            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.IsTrue(child.InternalWasSaveCalled);
                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>();
            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.IsFalse(child.InternalWasSaveCalled);
                Assert.IsFalse(parent.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 GlobalList_UserParameterReplaceExisting_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}(25) 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);
            }
        }
        /// <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;
        }
        public void Should_aggregate_a_numeric_field_VB()
        {
            var logger = Substitute.For<ILogEvents>();
            var settings = TestHelpers.LoadConfigFromResourceFile("SumFieldsOnSingleWorkItemVB.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 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>();
            var runtime = RuntimeContext.MakeRuntimeContext("settingsPath", settings, context, logger);
            using (var processor = new EventProcessor(repository, 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 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[CoreFieldReferenceNames.Title] = "My bug #1";
            parent[CoreFieldReferenceNames.TeamProject] = "MyTeamProject";

            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);
            }
        }
        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);
            }
        }
Exemple #13
0
        /// <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;
        }