Esempio n. 1
0
        public async Task ShouldReturnEMptyIndividualReportIfNoResolutions()
        {
            var workitems = Data.TeamMembers.Select(m =>
            {
                var workItemId = m.RelatedWorkItemIds.Random();
                var workItem   = new VSTSWorkItem {
                    Id = Guid.NewGuid(), WorkItemId = workItemId, Fields = new Dictionary <string, string>()
                };
                workItem.Fields.Add(VSTSFieldNames.WorkItemType, WorkItemTypes.Bug);
                workItem.Fields.Add(VSTSFieldNames.WorkItemCreatedDate, DateTime.UtcNow.AddDays(-5).ToString());

                return(workItem);
            }).ToList();

            _classificationContextMock.Setup(c => c.Classify(It.IsAny <VSTSWorkItem>(), It.IsAny <ClassificationScope>()))
            .Returns(Enumerable.Empty <WorkItemResolution>());
            Data.RepositoryMock.Setup(r => r.GetAsync(It.IsAny <Expression <Func <VSTSWorkItem, bool> > >()))
            .Returns <Expression <Func <VSTSWorkItem, bool> > >(e => Task.FromResult(workitems.Where(e.Compile())));

            var report = await Report();

            var firstMember = Data.TeamMembers.ElementAt(0);

            report.IndividualReports.Should().HaveCount(1);
            report.IndividualReports.Should().OnlyContain(r => r.MemberEmail == firstMember.Email &&
                                                          r.MemberName == firstMember.DisplayName &&
                                                          r.TotalResolved == 0);
        }
Esempio n. 2
0
        public async Task ShouldCorrectlyCalculateResolvedCount(string workItemType, string resolution, int expectedCount)
        {
            var workitems = Data.TeamMembers.Select(m =>
            {
                var workItemId = m.RelatedWorkItemIds.Random();
                var workItem   = new VSTSWorkItem {
                    Id = Guid.NewGuid(), WorkItemId = workItemId, Fields = new Dictionary <string, string>()
                };
                workItem.Fields.Add(VSTSFieldNames.WorkItemType, workItemType);
                workItem.Fields.Add(VSTSFieldNames.WorkItemCreatedDate, DateTime.UtcNow.AddDays(-5).ToString());

                return(workItem);
            }).ToList();

            _classificationContextMock.Setup(c => c.Classify(It.IsAny <VSTSWorkItem>(), It.IsAny <ClassificationScope>()))
            .Returns <VSTSWorkItem, ClassificationScope>((w, _) =>
            {
                var member = Data.TeamMembers.Single(t => t.RelatedWorkItemIds.Contains(w.WorkItemId));
                return(new[]
                {
                    new WorkItemResolution(w, resolution, "Because", DateTime.UtcNow, member.Email, "bla")
                });
            });
            Data.RepositoryMock.Setup(r => r.GetAsync(It.IsAny <Expression <Func <VSTSWorkItem, bool> > >()))
            .Returns <Expression <Func <VSTSWorkItem, bool> > >(e => Task.FromResult(workitems.Where(e.Compile())));

            var report = await Report();

            report.TotalResolved.Should().Be(expectedCount);
        }
Esempio n. 3
0
        public static float GetActiveDuration(this VSTSWorkItem workItem, IEnumerable <TeamMember> team)
        {
            if (workItem.Updates == null || !workItem.Updates.Any())
            {
                return(0.0f);
            }

            var      activeTime     = 0.0F;
            var      isActive       = false;
            var      assignedToTeam = false;
            DateTime?lastActivated  = null;

            foreach (var update in workItem.Updates)
            {
                var isActivation = !update.State.IsEmpty && update.State.NewValue == WorkItemStates.Active;
                var isOnHold     = !update.State.IsEmpty && update.State.NewValue == WorkItemStates.New;
                var isResolved   = !update.State.IsEmpty && (update.State.NewValue == WorkItemStates.Resolved || update.State.NewValue == WorkItemStates.Closed);
                var isCodeReview = !update.Tags.IsEmpty && WorkItemTags.ContainsTag(update.Tags.NewValue, WorkItemTags.CodeReview) || update.Relations?.Added != null &&
                                   update.Relations.Added.Any(i => !string.IsNullOrWhiteSpace(i.Name) && i.Name.Equals("Pull Request", StringComparison.InvariantCultureIgnoreCase));
                var isBlocked = !update.Tags.IsEmpty &&
                                (WorkItemTags.ContainsTag(update.Tags.NewValue, WorkItemTags.Blocked) || WorkItemTags.ContainsTag(update.Tags.NewValue, WorkItemTags.OnHold));
                var isUnBlocked = !isBlocked && !update.Tags.IsEmpty &&
                                  (WorkItemTags.ContainsTag(update.Tags.OldValue, WorkItemTags.Blocked) && !WorkItemTags.ContainsTag(update.Tags.NewValue, WorkItemTags.Blocked) ||
                                   WorkItemTags.ContainsTag(update.Tags.OldValue, WorkItemTags.OnHold) && !WorkItemTags.ContainsTag(update.Tags.NewValue, WorkItemTags.OnHold));

                if (!assignedToTeam && !string.IsNullOrWhiteSpace(update.AssignedTo.NewValue))
                {
                    assignedToTeam = team.Any(m => update.AssignedTo.NewValue.Contains(m.Email));
                    if (isActive)
                    {
                        lastActivated = update.ChangedDate;
                    }
                }

                if (isActive && (isOnHold || isBlocked))
                {
                    isActive = false;
                    if (lastActivated != null && assignedToTeam)
                    {
                        activeTime += lastActivated.Value.CountBusinessDaysThrough(update.ChangedDate);
                    }
                }
                else if ((isActivation && !isBlocked) || isUnBlocked)
                {
                    lastActivated = update.ChangedDate;
                    isActive      = true;
                }

                else if (isResolved || isCodeReview)
                {
                    if (isActive && lastActivated != null && assignedToTeam)
                    {
                        activeTime += lastActivated.Value.CountBusinessDaysThrough(update.ChangedDate);
                    }
                    break;
                }
            }

            return(activeTime);
        }
Esempio n. 4
0
        public void ShouldReturnEmptyStringIfFieldIsNotInTheCollection()
        {
            var wi = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            wi.WorkItemType.Should().BeEmpty();
        }
Esempio n. 5
0
        public void ShouldReturnEmptyStringIfFieldsAreNull()
        {
            var wi = new VSTSWorkItem {
                Fields = null
            };

            wi.Reason.Should().BeEmpty();
        }
Esempio n. 6
0
        private WorkItemResolution GetResolvedResolutionFor(VSTSWorkItem workItem, TeamMember member = null, DateTime?revisedDate = null)
        {
            var date       = revisedDate ?? DateTime.UtcNow.AddDays(-2);
            var teamMember = member ?? new TeamMember {
                Id = Guid.NewGuid(), DisplayName = Guid.NewGuid().ToString(), Email = Guid.NewGuid().ToString()
            };

            return(new WorkItemResolution(workItem, "Resolved", "Because", date, teamMember.Email, teamMember.DisplayName));
        }
Esempio n. 7
0
        private static float TryGetFromUpdates(VSTSWorkItem wi, string fieldName)
        {
            var recoveredValue = wi.Updates
                                 .LastOrDefault(u => (u.State?.NewValue == WorkItemStates.Closed || u.State?.NewValue == WorkItemStates.Resolved) && u.Fields.ContainsKey(fieldName))?
                                 .Fields[fieldName].OldValue;

            float.TryParse(recoveredValue, out var result);
            return(result);
        }
Esempio n. 8
0
        public IEnumerable <WorkItemResolution> Classify(VSTSWorkItem item, ClassificationScope scope)
        {
            var rs = from c in _classifiers
                     let r = c.Classify(new WorkItemResolutionRequest {
                WorkItem = item, Team = scope.Team, StartDate = scope.StartDate, EndDate = scope.EndDate
            })
                             where !r.IsNone && (IsInRange(r, scope) || r.IsError)
                             select r;

            return(rs.ToList());
        }
Esempio n. 9
0
        public VSTSWorkItem GetWorkItemFor(TeamMember user, string type = WorkItemTypes.Bug)
        {
            var resolvedWorkItem = new VSTSWorkItem {
                Id = Guid.NewGuid(), WorkItemId = user.RelatedWorkItemIds.Random(), Fields = new Dictionary <string, string>()
            };

            resolvedWorkItem.Fields.Add(VSTSFieldNames.WorkItemType, type);
            resolvedWorkItem.Fields.Add(VSTSFieldNames.WorkItemCreatedDate, DateTime.UtcNow.AddDays(-_random.Next(1, 15)).ToString());

            return(resolvedWorkItem);
        }
Esempio n. 10
0
        public WorkItemResolution(VSTSWorkItem workitem, string resolution, string reason, DateTime resolutionDate, string memberEmail, string memberName)
        {
            WorkItemId    = workitem.WorkItemId;
            WorkItemTitle = workitem.Title;
            WorkItemType  = workitem.WorkItemType;

            Resolution     = resolution;
            Reason         = reason;
            ResolutionDate = resolutionDate;
            MemberEmail    = memberEmail;
            MemberName     = memberName;
        }
Esempio n. 11
0
        private VSTSWorkItem GetWithDates(string changedDate, string resolvedDate, string closedDate, string stateChangeDate)
        {
            var wi = new VSTSWorkItem();

            wi.Fields = new Dictionary <string, string>();
            wi.Fields.Add("System.ChangedDate", changedDate);
            wi.Fields.Add("Microsoft.VSTS.Common.ResolvedDate", resolvedDate);
            wi.Fields.Add("Microsoft.VSTS.Common.ClosedDate", closedDate);
            wi.Fields.Add("Microsoft.VSTS.Common.StateChangeDate", stateChangeDate);

            return(wi);
        }
        private float GetActiveDuration(VSTSWorkItem workItem)
        {
            if (workItem.Updates == null || !workItem.Updates.Any())
            {
                return(0.0f);
            }

            var      activeTime    = 0.0F;
            var      isActive      = false;
            DateTime?lastActivated = null;

            foreach (var update in workItem.Updates)
            {
                var isActivation = !update.State.IsEmpty && update.State.NewValue == WorkItemStates.Active;
                var isOnHold     = !update.State.IsEmpty && update.State.NewValue == WorkItemStates.New;
                var isResolved   = !update.State.IsEmpty && (update.State.NewValue == WorkItemStates.Resolved || update.State.NewValue == WorkItemStates.Closed);
                var isCodeReview = !update.Tags.IsEmpty && ContainsTag(update.Tags.NewValue, CodeReviewTag);
                var isBlocked    = !update.Tags.IsEmpty &&
                                   (ContainsTag(update.Tags.NewValue, BlockedTag) || ContainsTag(update.Tags.NewValue, OnHoldTag));
                var isUnBlocked = !isBlocked && !update.Tags.IsEmpty &&
                                  (ContainsTag(update.Tags.OldValue, BlockedTag) && !ContainsTag(update.Tags.NewValue, BlockedTag) ||
                                   ContainsTag(update.Tags.OldValue, OnHoldTag) && !ContainsTag(update.Tags.NewValue, OnHoldTag));

                if (isActive && (isOnHold || isBlocked))
                {
                    isActive = false;
                    if (lastActivated != null)
                    {
                        activeTime += lastActivated.Value.CountBusinessDaysThrough(update.ChangedDate);
                    }
                }
                else if ((isActivation && !isBlocked) || isUnBlocked)
                {
                    lastActivated = update.ChangedDate;
                    isActive      = true;
                }

                else if (isActive && (isResolved || isCodeReview))
                {
                    if (lastActivated != null)
                    {
                        activeTime += lastActivated.Value.CountBusinessDaysThrough(update.ChangedDate);
                    }
                    break;
                }
            }

            return(activeTime);
        }
Esempio n. 13
0
        public void ShouldReturnNoneIfUnexpectedOrEmptyType(string type)
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, type);

            var result = _classifier.Classify(new WorkItemResolutionRequest {
                WorkItem = workItem
            });

            result.Should().NotBeNull();
            result.IsNone.Should().BeTrue();
        }
Esempio n. 14
0
        private static WorkItemResolutionRequest GetRequest(IEnumerable <WorkItemUpdate> updates, string type = WorkItemTypes.Task)
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>(), WorkItemId = 0
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, type);
            workItem.Updates = updates;

            return(new WorkItemResolutionRequest
            {
                WorkItem = workItem,
                Team = FakeTeam
            });
        }
Esempio n. 15
0
        public static VSTSWorkItem GetWorkItemWithDate(DateTime?createdDate)
        {
            var wi = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            wi.Id         = Guid.NewGuid();
            wi.WorkItemId = _random.Next(100_000_000);
            if (createdDate.HasValue)
            {
                wi.Fields.Add(VSTSFieldNames.WorkItemCreatedDate, createdDate.Value.ToString("s"));
            }

            return(wi);
        }
        public void ShouldReturnNoneIfStateIsNotSet()
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, WorkItemTypes.Bug);
            workItem.Updates = UpdateBuilder.Create().Update().Build();

            var result = _classifier.Classify(new WorkItemResolutionRequest {
                WorkItem = workItem, Team = ResolvedWorkItemsDataProvider.FakeTeam
            });

            result.Should().NotBeNull();
            result.IsNone.Should().BeTrue();
        }
Esempio n. 17
0
        public void ShouldReturnNoneIfEmptyHistoryItems()
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, DummyClassifier.SupportedType);
            workItem.Updates = Enumerable.Empty <WorkItemUpdate>();

            var result = _classifier.Classify(new WorkItemResolutionRequest {
                WorkItem = workItem
            });

            result.Should().NotBeNull();
            result.IsNone.Should().BeTrue();
        }
Esempio n. 18
0
        private async Task <AggregatedWorkitemsETAReport> ExecuteReportWithResolutions(int?completed = null, int?remaining = null, int?original = null, IEnumerable <WorkItemUpdate> updates = null)
        {
            var workitems = Data.TeamMembers
                            .SelectMany(t => t.RelatedWorkItemIds)
                            .Select(id =>
            {
                var wi = new VSTSWorkItem
                {
                    WorkItemId = id,
                    Fields     = new Dictionary <string, string>()
                };
                wi.Fields[VSTSFieldNames.WorkItemType] = WorkItemTypes.Bug;
                wi.Fields[VSTSFieldNames.Title]        = "Bla";
                if (completed.HasValue)
                {
                    wi.Fields[CompletedWorkField] = completed.ToString();
                }
                if (remaining.HasValue)
                {
                    wi.Fields[RemainingWorkField] = remaining?.ToString();
                }
                if (original.HasValue)
                {
                    wi.Fields[OriginalEstimateField] = original?.ToString();
                }
                if (updates != null)
                {
                    wi.Updates = updates;
                }
                return(wi);
            }).ToList();

            Data.RepositoryMock.Setup(r => r.GetAsync(It.IsAny <Expression <Func <VSTSWorkItem, bool> > >()))
            .Returns <Expression <Func <VSTSWorkItem, bool> > >(e => Task.FromResult(workitems.Where(e.Compile())));
            _classificationContextMock.Setup(c => c.Classify(It.IsAny <VSTSWorkItem>(), It.IsAny <ClassificationScope>()))
            .Returns <VSTSWorkItem, ClassificationScope>((w, _) =>
            {
                var member = Data.TeamMembers.Single(t => t.RelatedWorkItemIds.Contains(w.WorkItemId));
                return(new[]
                {
                    new WorkItemResolution(w, WorkItemStates.Resolved, "Because", DateTime.UtcNow, member.Email, "bla")
                });
            });

            return(await Report());
        }
Esempio n. 19
0
        public async Task ShouldFetchWorkitemsForMembersInProfile()
        {
            // TODO: Revisit this test
            var allMembers = Data.TeamMembers
                             .Union(Data.CreateTeamMembers(2));

            var workitems = allMembers.Select(m =>
            {
                var workItemId = Data.TeamMemberIds.Contains(m.Id) ? m.RelatedWorkItemIds.Random() : -_random.Next(0, 50);
                var workItem   = new VSTSWorkItem {
                    Id = Guid.NewGuid(), WorkItemId = workItemId, Fields = new Dictionary <string, string>()
                };
                workItem.Fields.Add(VSTSFieldNames.WorkItemType, WorkItemTypes.Bug);
                workItem.Fields.Add(VSTSFieldNames.WorkItemCreatedDate, DateTime.UtcNow.AddDays(-5).ToString());
                workItem.Updates = UpdateBuilder.Create()
                                   .Activated()
                                   .Then().Resolved(m)
                                   .Build();

                return(workItem);
            }).ToList();

            _classificationContextMock.Setup(c => c.Classify(It.IsAny <VSTSWorkItem>(), It.IsAny <ClassificationScope>()))
            .Returns <VSTSWorkItem, ClassificationScope>((w, _) =>
            {
                var member = Data.TeamMembers.Single(t => t.RelatedWorkItemIds.Contains(w.WorkItemId));
                return(new[]
                {
                    new WorkItemResolution(w, WorkItemStates.Resolved, "Because", DateTime.UtcNow, member.Email, "bla")
                });
            });
            Data.RepositoryMock.Setup(r => r.GetAsync(It.IsAny <Expression <Func <VSTSWorkItem, bool> > >()))
            .Returns <Expression <Func <VSTSWorkItem, bool> > >(e => Task.FromResult(workitems.Where(e.Compile())));

            var report = await Report();

            report.Should().NotBeNull();
            report.Should().BeOfType <AggregatedWorkitemsETAReport>();
            report.IndividualReports.Should().HaveCount(2);
            report.IndividualReports.Should().OnlyContain(r => Data.TeamMembers.Any(m => m.Email == r.MemberEmail && m.DisplayName == r.MemberName));
            report.IndividualReports.Should().OnlyContain(r => r.OriginalEstimated == 0);
            report.IndividualReports.Should().OnlyContain(r => r.CompletedWithEstimates == 0);
            report.IndividualReports.Should().OnlyContain(r => r.WithoutETA == 1);
            report.IndividualReports.Should().OnlyContain(r => r.TotalResolved == 1);
        }
        public void ShouldReturnNoneIfMovedToResolvedFromClosed()
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, WorkItemTypes.Bug);
            workItem.Updates = UpdateBuilder.Create().Resolved(ResolvedWorkItemsDataProvider.FakeTeam.ElementAt(0), from: "Closed")
                               .Because("Reasons")
                               .Build();

            var result = _classifier.Classify(new WorkItemResolutionRequest {
                WorkItem = workItem, Team = ResolvedWorkItemsDataProvider.FakeTeam
            });

            result.Should().NotBeNull();
            result.IsNone.Should().BeTrue();
        }
Esempio n. 21
0
        public static float GetEtaValue(this VSTSWorkItem wi, ETAFieldType etaType, Settings settings)
        {
            var fieldName = FieldNameFor(wi.WorkItemType, etaType, settings);

            if (!wi.Fields.ContainsKey(fieldName))
            {
                return(etaType == ETAFieldType.RemainingWork ? TryGetFromUpdates(wi, fieldName) : 0);
            }

            var value = wi.Fields[fieldName];

            if (string.IsNullOrEmpty(value))
            {
                return(0);
            }

            return(float.Parse(value));
        }
Esempio n. 22
0
        public void ShouldReturnResolutionForSupportedType()
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, DummyClassifier.SupportedType);
            workItem.Updates = UpdateBuilder.Create().Resolved()
                               .Build();

            var result = _classifier.Classify(new WorkItemResolutionRequest {
                WorkItem = workItem
            });

            result.Should().NotBeNull();
            result.IsNone.Should().BeFalse();
            result.Resolution.Should().Be(DummyClassifier.ExpectedResolution);
        }
        public void ShouldReturnNoneIfNoMatchingHistoryItems()
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, WorkItemTypes.Bug);
            workItem.Updates = UpdateBuilder.Create()
                               .Activated()
                               .Then().New()
                               .Build();

            var result = _classifier.Classify(new WorkItemResolutionRequest {
                WorkItem = workItem
            });

            result.Should().NotBeNull();
            result.IsNone.Should().BeTrue();
        }
Esempio n. 24
0
        public void ShouldReturnErrorResolutionIfException()
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, ExceptionWorkItemClassifier.SupportedType);
            workItem.Updates = UpdateBuilder.Create().Resolved()
                               .Build();

            var classifier = new ExceptionWorkItemClassifier();
            var result     = classifier.Classify(new WorkItemResolutionRequest {
                WorkItem = workItem
            });

            result.Should().NotBeNull();
            result.IsError.Should().BeTrue();
            result.Reason.Should().Be(ExceptionWorkItemClassifier.ExpectedReason);
        }
        public void ShouldReturnNoneIfResolvedNotByTheTeam()
        {
            var workItem = new VSTSWorkItem {
                Fields = new Dictionary <string, string>()
            };

            workItem.Fields.Add(VSTSFieldNames.WorkItemType, WorkItemTypes.Bug);
            workItem.Updates = UpdateBuilder.Create()
                               .Resolved(new TeamMember {
                DisplayName = "Not a member", Email = "*****@*****.**"
            })
                               .Because("Reasons")
                               .Build();

            var result = _classifier.Classify(new WorkItemResolutionRequest {
                WorkItem = workItem, Team = ResolvedWorkItemsDataProvider.FakeTeam
            });

            result.Should().NotBeNull();
            result.IsNone.Should().BeTrue();
        }
Esempio n. 26
0
        public static bool IsAssignedToTeamMember(this VSTSWorkItem item, IEnumerable <TeamMember> team)
        {
            var assignedTo = item.Updates.LastOrDefault(u => !u.AssignedTo.IsEmpty)?.AssignedTo.NewValue;

            return(team.Any(m => !string.IsNullOrWhiteSpace(assignedTo) && assignedTo.Contains(m.Email)));
        }
Esempio n. 27
0
 public static bool IsInCodeReview(this VSTSWorkItem item)
 {
     return(item.State == WorkItemStates.Active &&
            (WorkItemTags.ContainsTag(item.Updates.LastOrDefault(u => !u.Tags.IsEmpty)?.Tags.NewValue, WorkItemTags.CodeReview) ||
             item.Updates.Any(u => u.Relations?.Added != null && u.Relations.Added.Any(i => i.IsPullRequest))));
 }
Esempio n. 28
0
 public VSTSWorkItem SaveWorkItem(VSTSWorkItem workItem)
 {
     return(SaveWorkItems(new VSTSWorkItem[] { workItem }).FirstOrDefault());
 }
Esempio n. 29
0
 private TeamMember GetMemberFromWorkItem(VSTSWorkItem workItem)
 {
     return(_team.SingleOrDefault(m => m.RelatedWorkItemIds != null && m.RelatedWorkItemIds.Contains(workItem.WorkItemId)));
 }